Split waterfall functions from the openwebrx.js.
This commit is contained in:
parent
51913320d2
commit
a5bf8e6e80
|
|
@ -257,21 +257,21 @@
|
||||||
<svg class="scanner" viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#scanner-running"></use></svg>
|
<svg class="scanner" viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#scanner-running"></use></svg>
|
||||||
</div>
|
</div>
|
||||||
<input title="Squelch" class="openwebrx-squelch-slider openwebrx-panel-slider" type="range" min="-150" max="0" value="-150" step="1">
|
<input title="Squelch" class="openwebrx-squelch-slider openwebrx-panel-slider" type="range" min="-150" max="0" value="-150" step="1">
|
||||||
<div title="Auto-adjust waterfall colors (right-click for continuous)" id="openwebrx-waterfall-colors-auto" class="openwebrx-button openwebrx-slider-button">
|
<div title="Auto-adjust waterfall colors (right-click for continuous)" id="openwebrx-waterfall-colors-auto" class="openwebrx-button openwebrx-slider-button" onclick="Waterfall.setAutoRange();">
|
||||||
<svg class="auto" viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#waterfall-auto"></use></svg>
|
<svg class="auto" viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#waterfall-auto"></use></svg>
|
||||||
<svg class="continuous" viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#waterfall-continuous"></use></svg>
|
<svg class="continuous" viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#waterfall-continuous"></use></svg>
|
||||||
</div>
|
</div>
|
||||||
<input title="Waterfall minimum level" id="openwebrx-waterfall-color-min" class="openwebrx-panel-slider" type="range" min="-200" max="100" value="50" step="1" onchange="updateWaterfallColors(0);">
|
<input title="Waterfall minimum level" id="openwebrx-waterfall-color-min" class="openwebrx-panel-slider" type="range" min="-200" max="100" value="50" step="1" onchange="Waterfall.updateColors(0);">
|
||||||
</div>
|
</div>
|
||||||
<div class="openwebrx-panel-line">
|
<div class="openwebrx-panel-line">
|
||||||
<div title="Noise reduction on/off" class="openwebrx-nr-toggle openwebrx-button openwebrx-slider-button" onclick="UI.toggleNR();">
|
<div title="Noise reduction on/off" class="openwebrx-nr-toggle openwebrx-button openwebrx-slider-button" onclick="UI.toggleNR();">
|
||||||
<svg viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#noise-reduce"></use></svg>
|
<svg viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#noise-reduce"></use></svg>
|
||||||
</div>
|
</div>
|
||||||
<input title="Noise reduction level" disabled id="openwebrx-panel-nr" class="openwebrx-panel-slider" type="range" min="-10" max="10" value="0" step="1" onchange="UI.setNR(this.value)" oninput="UI.setNR(this.value)">
|
<input title="Noise reduction level" disabled id="openwebrx-panel-nr" class="openwebrx-panel-slider" type="range" min="-10" max="10" value="0" step="1" onchange="UI.setNR(this.value)" oninput="UI.setNR(this.value)">
|
||||||
<div title="Set waterfall colors to default" id="openwebrx-waterfall-colors-default" class="openwebrx-button openwebrx-slider-button" onclick="waterfallColorsDefault()">
|
<div title="Set waterfall colors to default" id="openwebrx-waterfall-colors-default" class="openwebrx-button openwebrx-slider-button" onclick="Waterfall.setDefaultRange();">
|
||||||
<svg viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#waterfall-default"></use></svg>
|
<svg viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#waterfall-default"></use></svg>
|
||||||
</div>
|
</div>
|
||||||
<input title="Waterfall maximum level" id="openwebrx-waterfall-color-max" class="openwebrx-panel-slider" type="range" min="-200" max="100" value="50" step="1" onchange="updateWaterfallColors(1);">
|
<input title="Waterfall maximum level" id="openwebrx-waterfall-color-max" class="openwebrx-panel-slider" type="range" min="-200" max="100" value="50" step="1" onchange="Waterfall.updateColors(1);">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="openwebrx-section-settings" class="openwebrx-section-divider" onclick="UI.toggleSection(this);">▴ Settings</div>
|
<div id="openwebrx-section-settings" class="openwebrx-section-divider" onclick="UI.toggleSection(this);">▴ Settings</div>
|
||||||
|
|
|
||||||
|
|
@ -263,20 +263,23 @@ UI.setWfTheme = function(theme) {
|
||||||
// Set selector
|
// Set selector
|
||||||
$('#openwebrx-wf-themes-listbox').val(theme);
|
$('#openwebrx-wf-themes-listbox').val(theme);
|
||||||
|
|
||||||
// Generate new colors
|
// Set new colors in the waterfall
|
||||||
waterfall_colors = chroma.scale(this.wfThemes[theme]).colors(256, 'rgb');
|
Waterfall.setTheme(this.wfThemes[theme]);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set default waterfall color theme.
|
// Set default waterfall color theme.
|
||||||
UI.setDefaultWfTheme = function(colors) {
|
UI.setDefaultWfTheme = function(colors) {
|
||||||
|
// Update default waterfall theme with new colors
|
||||||
this.wfThemes['default'] = colors;
|
this.wfThemes['default'] = colors;
|
||||||
|
|
||||||
|
// If default theme currently used, update waterfall
|
||||||
if (this.wfTheme === 'default') {
|
if (this.wfTheme === 'default') {
|
||||||
this.wfTheme = null;
|
this.wfTheme = null;
|
||||||
this.setWfTheme('default');
|
this.setWfTheme('default');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Waterfall color schemes
|
// Waterfall color themes
|
||||||
UI.wfThemes = {
|
UI.wfThemes = {
|
||||||
'default' : [0x000000, 0xFFFFFF],
|
'default' : [0x000000, 0xFFFFFF],
|
||||||
'teejeez' : [0x000000, 0x0000FF, 0x00FFFF, 0x00FF00, 0xFFFF00, 0xFF0000, 0xFF00FF, 0xFFFFFF],
|
'teejeez' : [0x000000, 0x0000FF, 0x00FFFF, 0x00FF00, 0xFFFF00, 0xFF0000, 0xFF00FF, 0xFFFFFF],
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,196 @@
|
||||||
|
//
|
||||||
|
// Waterfall colors
|
||||||
|
//
|
||||||
|
|
||||||
|
function Waterfall() {}
|
||||||
|
|
||||||
|
Waterfall.colors = chroma.scale([0x000000, 0xFFFFFF]).colors(256, 'rgb');
|
||||||
|
Waterfall.levels = { min: -150, max: 0 };
|
||||||
|
Waterfall.fixed_levels = { min: -150, max: 0 };
|
||||||
|
Waterfall.auto_levels = { min: -150, max: 0 };
|
||||||
|
Waterfall.cont_levels = { min: -150, max: 0 };
|
||||||
|
Waterfall.auto_min_range = 0;
|
||||||
|
Waterfall.measure_minmax_now = false;
|
||||||
|
Waterfall.measure_minmax_continuous = false;
|
||||||
|
|
||||||
|
// Get current waterfall min/max levels range.
|
||||||
|
Waterfall.getRange = function() {
|
||||||
|
return this.levels;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set waterfall color theme, passed as an array of
|
||||||
|
// integer RGB values.
|
||||||
|
Waterfall.setTheme = function(theme) {
|
||||||
|
this.colors = chroma.scale(theme).colors(256, 'rgb');
|
||||||
|
};
|
||||||
|
|
||||||
|
// Configure waterfall parameters from the attributes
|
||||||
|
// sent by the server.
|
||||||
|
Waterfall.configure = function(config) {
|
||||||
|
if ('waterfall_levels' in config)
|
||||||
|
this.fixed_levels = config['waterfall_levels'];
|
||||||
|
if ('waterfall_auto_levels' in config)
|
||||||
|
this.auto_levels = config['waterfall_auto_levels'];
|
||||||
|
if ('waterfall_auto_min_range' in config)
|
||||||
|
this.auto_min_range = config['waterfall_auto_min_range'];
|
||||||
|
if ('waterfall_auto_level_default_mode' in config)
|
||||||
|
this.toggleContinuousRange(config['waterfall_auto_level_default_mode']);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use one-time automatic min/max level update.
|
||||||
|
Waterfall.setAutoRange = function() {
|
||||||
|
this.measure_minmax_now = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use default min/max levels.
|
||||||
|
Waterfall.setDefaultRange = function() {
|
||||||
|
this.levels.min = this.fixed_levels.min;
|
||||||
|
this.levels.max = this.fixed_levels.max;
|
||||||
|
this.updateSliders();
|
||||||
|
this.resetContinuousColors();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Enable continuous min/max level updates.
|
||||||
|
Waterfall.toggleContinuousRange = function(on) {
|
||||||
|
// If no argument given, toggle continuous mode
|
||||||
|
on = typeof(on) === 'undefined'? !this.measure_minmax_continuous : on;
|
||||||
|
|
||||||
|
this.measure_minmax_continuous = on;
|
||||||
|
|
||||||
|
var autoButton = $('#openwebrx-waterfall-colors-auto');
|
||||||
|
autoButton[on ? 'addClass' : 'removeClass']('highlighted');
|
||||||
|
$('#openwebrx-waterfall-color-min, #openwebrx-waterfall-color-max').prop('disabled', on);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update waterfall min/max levels from sliders.
|
||||||
|
Waterfall.updateColors = function(which) {
|
||||||
|
var $wfmax = $("#openwebrx-waterfall-color-max");
|
||||||
|
var $wfmin = $("#openwebrx-waterfall-color-min");
|
||||||
|
|
||||||
|
this.levels.max = parseInt($wfmax.val());
|
||||||
|
this.levels.min = parseInt($wfmin.val());
|
||||||
|
|
||||||
|
if (this.levels.min >= this.levels.max) {
|
||||||
|
if (!which) {
|
||||||
|
this.levels.min = this.levels.max -1;
|
||||||
|
} else {
|
||||||
|
this.levels.max = this.levels.min + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateSliders();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update waterfall level sliders from min/max levels.
|
||||||
|
Waterfall.updateSliders = function() {
|
||||||
|
$('#openwebrx-waterfall-color-max')
|
||||||
|
.val(this.levels.max)
|
||||||
|
.attr('title', 'Waterfall maximum level (' + Math.round(this.levels.max) + ' dB)');
|
||||||
|
$('#openwebrx-waterfall-color-min')
|
||||||
|
.val(this.levels.min)
|
||||||
|
.attr('title', 'Waterfall minimum level (' + Math.round(this.levels.min) + ' dB)');
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update automatic min/max levels.
|
||||||
|
Waterfall.updateAutoColors = function(levels) {
|
||||||
|
var min_level = levels.min - this.auto_levels.min;
|
||||||
|
var max_level = levels.max + this.auto_levels.max;
|
||||||
|
|
||||||
|
max_level = Math.max(min_level + (this.auto_min_range || 0), max_level);
|
||||||
|
|
||||||
|
this.levels.min = min_level;
|
||||||
|
this.levels.max = max_level;
|
||||||
|
this.updateSliders();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reset continuous min/max levels.
|
||||||
|
Waterfall.resetContinuousColors = function() {
|
||||||
|
this.cont_levels.min = this.levels.min;
|
||||||
|
this.cont_levels.max = this.levels.max;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update continous min/max levels.
|
||||||
|
Waterfall.updateContinuousColors = function(levels) {
|
||||||
|
if (levels.max > this.cont_levels.max + 1) {
|
||||||
|
this.cont_levels.max += 1;
|
||||||
|
} else if (levels.max < this.cont_levels.max - 1) {
|
||||||
|
this.cont_levels.max -= .1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (levels.min < this.cont_levels.min - 1) {
|
||||||
|
this.cont_levels.min -= 1;
|
||||||
|
} else if (levels.min > this.cont_levels.min + 1) {
|
||||||
|
this.cont_levels.min += .1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateAutoColors(this.cont_levels);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a color based on the dB value and current color theme.
|
||||||
|
Waterfall.makeColor = function(db) {
|
||||||
|
var v = (db - this.levels.min) / (this.levels.max - this.levels.min);
|
||||||
|
v = Math.max(0, Math.min(1, v)) * (this.colors.length - 1);
|
||||||
|
var i = Math.floor(v);
|
||||||
|
v = v - i;
|
||||||
|
|
||||||
|
if (v == 0) {
|
||||||
|
return this.colors[i];
|
||||||
|
} else {
|
||||||
|
var c0 = this.colors[i];
|
||||||
|
var c1 = this.colors[i+1];
|
||||||
|
return [
|
||||||
|
c0[0] + v * (c1[0] - c0[0]),
|
||||||
|
c0[1] + v * (c1[1] - c0[1]),
|
||||||
|
c0[2] + v * (c1[2] - c0[2])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Draw a single line of waterfall pixels based on the input data.
|
||||||
|
Waterfall.drawLine = function(out, data, offset = 0) {
|
||||||
|
var y = 0;
|
||||||
|
for (var x = 0; x < data.length; x++) {
|
||||||
|
var color = this.makeColor(data[x] + offset);
|
||||||
|
out[y++] = color[0];
|
||||||
|
out[y++] = color[1];
|
||||||
|
out[y++] = color[2];
|
||||||
|
out[y++] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Measure min/max levels from the incoming data, if necessary.
|
||||||
|
Waterfall.measureRange = function(data) {
|
||||||
|
// Drop out unless we actually need to measure levels
|
||||||
|
if (!this.measure_minmax_now && !this.measure_minmax_continuous) return;
|
||||||
|
|
||||||
|
// Get visible range of frequencies
|
||||||
|
var range = get_visible_freq_range();
|
||||||
|
var start = center_freq - bandwidth / 2;
|
||||||
|
|
||||||
|
// This is based on an oversampling factor of about 1.25
|
||||||
|
range.start = Math.max(0.1, (range.start - start) / bandwidth);
|
||||||
|
range.end = Math.min(0.9, (range.end - start) / bandwidth);
|
||||||
|
|
||||||
|
// Align to the range edges, do not let things flip over
|
||||||
|
if (range.start >= 0.9)
|
||||||
|
range.start = range.end - range.bw / bandwidth;
|
||||||
|
else if (range.end <= 0.1)
|
||||||
|
range.end = range.start + range.bw / bandwidth;
|
||||||
|
|
||||||
|
// Find min/max levels within the range
|
||||||
|
data = data.slice(range.start * data.length, range.end * data.length);
|
||||||
|
var levels = {
|
||||||
|
min: Math.min.apply(Math, data),
|
||||||
|
max: Math.max.apply(Math, data)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.measure_minmax_now) {
|
||||||
|
this.measure_minmax_now = false;
|
||||||
|
this.updateAutoColors(levels);
|
||||||
|
this.resetContinuousColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.measure_minmax_continuous) {
|
||||||
|
this.updateContinuousColors(levels);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -119,80 +119,6 @@ function jumpBySteps(steps) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var waterfall_min_level;
|
|
||||||
var waterfall_max_level;
|
|
||||||
var waterfall_min_level_default;
|
|
||||||
var waterfall_max_level_default;
|
|
||||||
var waterfall_colors;
|
|
||||||
var waterfall_auto_levels;
|
|
||||||
var waterfall_auto_min_range;
|
|
||||||
var waterfall_measure_minmax_now = false;
|
|
||||||
var waterfall_measure_minmax_continuous = false;
|
|
||||||
|
|
||||||
function updateWaterfallColors(which) {
|
|
||||||
var $wfmax = $("#openwebrx-waterfall-color-max");
|
|
||||||
var $wfmin = $("#openwebrx-waterfall-color-min");
|
|
||||||
waterfall_max_level = parseInt($wfmax.val());
|
|
||||||
waterfall_min_level = parseInt($wfmin.val());
|
|
||||||
if (waterfall_min_level >= waterfall_max_level) {
|
|
||||||
if (!which) {
|
|
||||||
waterfall_min_level = waterfall_max_level -1;
|
|
||||||
} else {
|
|
||||||
waterfall_max_level = waterfall_min_level + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateWaterfallSliders();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateWaterfallSliders() {
|
|
||||||
$('#openwebrx-waterfall-color-max')
|
|
||||||
.val(waterfall_max_level)
|
|
||||||
.attr('title', 'Waterfall maximum level (' + Math.round(waterfall_max_level) + ' dB)');
|
|
||||||
$('#openwebrx-waterfall-color-min')
|
|
||||||
.val(waterfall_min_level)
|
|
||||||
.attr('title', 'Waterfall minimum level (' + Math.round(waterfall_min_level) + ' dB)');
|
|
||||||
}
|
|
||||||
|
|
||||||
function waterfallColorsDefault() {
|
|
||||||
waterfall_min_level = waterfall_min_level_default;
|
|
||||||
waterfall_max_level = waterfall_max_level_default;
|
|
||||||
updateWaterfallSliders();
|
|
||||||
waterfallColorsContinuousReset();
|
|
||||||
}
|
|
||||||
|
|
||||||
function waterfallColorsAuto(levels) {
|
|
||||||
var min_level = levels.min - waterfall_auto_levels.min;
|
|
||||||
var max_level = levels.max + waterfall_auto_levels.max;
|
|
||||||
max_level = Math.max(min_level + (waterfall_auto_min_range || 0), max_level);
|
|
||||||
waterfall_min_level = min_level;
|
|
||||||
waterfall_max_level = max_level;
|
|
||||||
updateWaterfallSliders();
|
|
||||||
}
|
|
||||||
|
|
||||||
var waterfall_continuous = {
|
|
||||||
min: -150,
|
|
||||||
max: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
function waterfallColorsContinuousReset() {
|
|
||||||
waterfall_continuous.min = waterfall_min_level;
|
|
||||||
waterfall_continuous.max = waterfall_max_level;
|
|
||||||
}
|
|
||||||
|
|
||||||
function waterfallColorsContinuous(levels) {
|
|
||||||
if (levels.max > waterfall_continuous.max + 1) {
|
|
||||||
waterfall_continuous.max += 1;
|
|
||||||
} else if (levels.max < waterfall_continuous.max - 1) {
|
|
||||||
waterfall_continuous.max -= .1;
|
|
||||||
}
|
|
||||||
if (levels.min < waterfall_continuous.min - 1) {
|
|
||||||
waterfall_continuous.min -= 1;
|
|
||||||
} else if (levels.min > waterfall_continuous.min + 1) {
|
|
||||||
waterfall_continuous.min += .1;
|
|
||||||
}
|
|
||||||
waterfallColorsAuto(waterfall_continuous);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSmeterRelativeValue(value) {
|
function setSmeterRelativeValue(value) {
|
||||||
if (value < 0) value = 0;
|
if (value < 0) value = 0;
|
||||||
if (value > 1.0) value = 1.0;
|
if (value > 1.0) value = 1.0;
|
||||||
|
|
@ -231,10 +157,9 @@ function getLogSmeterValue(value) {
|
||||||
function setSmeterAbsoluteValue(value) //the value that comes from `csdr squelch_and_smeter_cc`
|
function setSmeterAbsoluteValue(value) //the value that comes from `csdr squelch_and_smeter_cc`
|
||||||
{
|
{
|
||||||
var logValue = getLogSmeterValue(value);
|
var logValue = getLogSmeterValue(value);
|
||||||
|
var levels = Waterfall.getRange();
|
||||||
|
var percent = (logValue - (levels.min - 20)) / ((levels.max + 20) - (levels.min - 20));
|
||||||
setSquelchSliderBackground(logValue);
|
setSquelchSliderBackground(logValue);
|
||||||
var lowLevel = waterfall_min_level - 20;
|
|
||||||
var highLevel = waterfall_max_level + 20;
|
|
||||||
var percent = (logValue - lowLevel) / (highLevel - lowLevel);
|
|
||||||
setSmeterRelativeValue(percent);
|
setSmeterRelativeValue(percent);
|
||||||
$("#openwebrx-smeter-db").html(logValue.toFixed(1) + " dB");
|
$("#openwebrx-smeter-db").html(logValue.toFixed(1) + " dB");
|
||||||
}
|
}
|
||||||
|
|
@ -976,22 +901,12 @@ function on_ws_recv(evt) {
|
||||||
switch (json.type) {
|
switch (json.type) {
|
||||||
case "config":
|
case "config":
|
||||||
var config = json['value'];
|
var config = json['value'];
|
||||||
|
|
||||||
|
// Configure waterfall min/max levels, etc
|
||||||
|
Waterfall.configure(config);
|
||||||
|
|
||||||
if ('waterfall_colors' in config)
|
if ('waterfall_colors' in config)
|
||||||
UI.setDefaultWfTheme(config['waterfall_colors']);
|
UI.setDefaultWfTheme(config['waterfall_colors']);
|
||||||
if ('waterfall_levels' in config) {
|
|
||||||
waterfall_min_level_default = config['waterfall_levels']['min'];
|
|
||||||
waterfall_max_level_default = config['waterfall_levels']['max'];
|
|
||||||
}
|
|
||||||
if ('waterfall_auto_levels' in config)
|
|
||||||
waterfall_auto_levels = config['waterfall_auto_levels'];
|
|
||||||
if ('waterfall_auto_min_range' in config)
|
|
||||||
waterfall_auto_min_range = config['waterfall_auto_min_range'];
|
|
||||||
if ('waterfall_auto_level_default_mode' in config)
|
|
||||||
waterfall_measure_minmax_continuous = config['waterfall_auto_level_default_mode'];
|
|
||||||
|
|
||||||
var waterfallAutoButton = $('#openwebrx-waterfall-colors-auto');
|
|
||||||
waterfallAutoButton[waterfall_measure_minmax_continuous ? 'addClass' : 'removeClass']('highlighted');
|
|
||||||
$('#openwebrx-waterfall-color-min, #openwebrx-waterfall-color-max').prop('disabled', waterfall_measure_minmax_continuous);
|
|
||||||
|
|
||||||
var initial_demodulator_params = {};
|
var initial_demodulator_params = {};
|
||||||
if ('start_mod' in config)
|
if ('start_mod' in config)
|
||||||
|
|
@ -1042,7 +957,7 @@ function on_ws_recv(evt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('sdr_id' in config || 'profile_id' in config || 'waterfall_levels' in config) {
|
if ('sdr_id' in config || 'profile_id' in config || 'waterfall_levels' in config) {
|
||||||
waterfallColorsDefault();
|
Waterfall.setDefaultRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('tuning_precision' in config)
|
if ('tuning_precision' in config)
|
||||||
|
|
@ -1252,28 +1167,6 @@ function on_ws_recv(evt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function waterfall_measure_minmax_do(what) {
|
|
||||||
// Get visible range
|
|
||||||
var range = get_visible_freq_range();
|
|
||||||
var start = center_freq - bandwidth / 2;
|
|
||||||
|
|
||||||
// This is based on an oversampling factor of about 1,25
|
|
||||||
range.start = Math.max(0.1, (range.start - start) / bandwidth);
|
|
||||||
range.end = Math.min(0.9, (range.end - start) / bandwidth);
|
|
||||||
|
|
||||||
// Align to the range edges, do not let things flip over
|
|
||||||
if (range.start >= 0.9)
|
|
||||||
range.start = range.end - range.bw / bandwidth;
|
|
||||||
else if (range.end <= 0.1)
|
|
||||||
range.end = range.start + range.bw / bandwidth;
|
|
||||||
|
|
||||||
var data = what.slice(range.start * what.length, range.end * what.length);
|
|
||||||
return {
|
|
||||||
min: Math.min.apply(Math, data),
|
|
||||||
max: Math.max.apply(Math, data)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function on_ws_opened() {
|
function on_ws_opened() {
|
||||||
$('#openwebrx-error-overlay').hide();
|
$('#openwebrx-error-overlay').hide();
|
||||||
ws.send("SERVER DE CLIENT client=openwebrx.js type=receiver");
|
ws.send("SERVER DE CLIENT client=openwebrx.js type=receiver");
|
||||||
|
|
@ -1389,26 +1282,6 @@ function open_websocket() {
|
||||||
ws.onerror = on_ws_error;
|
ws.onerror = on_ws_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
function waterfall_mkcolor(db_value, waterfall_colors_arg) {
|
|
||||||
waterfall_colors_arg = waterfall_colors_arg || waterfall_colors;
|
|
||||||
var value_percent = (db_value - waterfall_min_level) / (waterfall_max_level - waterfall_min_level);
|
|
||||||
value_percent = Math.max(0, Math.min(1, value_percent));
|
|
||||||
|
|
||||||
var scaled = value_percent * (waterfall_colors_arg.length - 1);
|
|
||||||
var index = Math.floor(scaled);
|
|
||||||
var remain = scaled - index;
|
|
||||||
if (remain === 0) return waterfall_colors_arg[index];
|
|
||||||
return color_between(waterfall_colors_arg[index], waterfall_colors_arg[index + 1], remain);}
|
|
||||||
|
|
||||||
function color_between(first, second, percent) {
|
|
||||||
return [
|
|
||||||
first[0] + percent * (second[0] - first[0]),
|
|
||||||
first[1] + percent * (second[1] - first[1]),
|
|
||||||
first[2] + percent * (second[2] - first[2])
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var canvas_context;
|
var canvas_context;
|
||||||
var canvases = [];
|
var canvases = [];
|
||||||
var canvas_default_height = 200;
|
var canvas_default_height = 200;
|
||||||
|
|
@ -1478,30 +1351,17 @@ function waterfall_add(data) {
|
||||||
if (!waterfall_setup_done) return;
|
if (!waterfall_setup_done) return;
|
||||||
var w = fft_size;
|
var w = fft_size;
|
||||||
|
|
||||||
if (waterfall_measure_minmax_now) {
|
// measure waterfall min/max levels, if necessary
|
||||||
var levels = waterfall_measure_minmax_do(data);
|
Waterfall.measureRange(data);
|
||||||
waterfall_measure_minmax_now = false;
|
|
||||||
waterfallColorsAuto(levels);
|
|
||||||
waterfallColorsContinuousReset();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waterfall_measure_minmax_continuous) {
|
|
||||||
var level = waterfall_measure_minmax_do(data);
|
|
||||||
waterfallColorsContinuous(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create new canvas if the current one is full (or there isn't one)
|
// create new canvas if the current one is full (or there isn't one)
|
||||||
if (canvas_actual_line <= 0) add_canvas();
|
if (canvas_actual_line <= 0) add_canvas();
|
||||||
|
|
||||||
//Add line to waterfall image
|
// add line to waterfall image
|
||||||
var oneline_image = canvas_context.createImageData(w, 1);
|
var oneline_image = canvas_context.createImageData(w, 1);
|
||||||
for (var x = 0; x < w; x++) {
|
Waterfall.drawLine(oneline_image.data, data);
|
||||||
var color = waterfall_mkcolor(data[x]);
|
|
||||||
for (i = 0; i < 3; i++) oneline_image.data[x * 4 + i] = color[i];
|
|
||||||
oneline_image.data[x * 4 + 3] = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Draw image
|
// draw image
|
||||||
canvas_context.putImageData(oneline_image, 0, --canvas_actual_line);
|
canvas_context.putImageData(oneline_image, 0, --canvas_actual_line);
|
||||||
shift_canvases();
|
shift_canvases();
|
||||||
}
|
}
|
||||||
|
|
@ -1593,15 +1453,10 @@ function initSliders() {
|
||||||
$slider.trigger('change');
|
$slider.trigger('change');
|
||||||
});
|
});
|
||||||
|
|
||||||
var waterfallAutoButton = $('#openwebrx-waterfall-colors-auto');
|
// Enable continuous waterfall color adjustment by pressing the
|
||||||
waterfallAutoButton.on('click', function() {
|
// right mouse button on AUTO
|
||||||
waterfall_measure_minmax_now=true;
|
$('#openwebrx-waterfall-colors-auto').on('contextmenu', function() {
|
||||||
}).on('contextmenu', function(){
|
Waterfall.toggleContinuousRange();
|
||||||
waterfall_measure_minmax_continuous = !waterfall_measure_minmax_continuous;
|
|
||||||
waterfallColorsContinuousReset();
|
|
||||||
waterfallAutoButton[waterfall_measure_minmax_continuous ? 'addClass' : 'removeClass']('highlighted');
|
|
||||||
$('#openwebrx-waterfall-color-min, #openwebrx-waterfall-color-max').prop('disabled', waterfall_measure_minmax_continuous);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1867,20 +1722,14 @@ function secondary_demod_push_data(x) {
|
||||||
function secondary_demod_waterfall_add(data) {
|
function secondary_demod_waterfall_add(data) {
|
||||||
var w = secondary_fft_size;
|
var w = secondary_fft_size;
|
||||||
|
|
||||||
//Add line to waterfall image
|
// add line to waterfall image
|
||||||
var oneline_image = secondary_demod_current_canvas_context.createImageData(w, 1);
|
var oneline_image = secondary_demod_current_canvas_context.createImageData(w, 1);
|
||||||
for (var x = 0; x < w; x++) {
|
Waterfall.drawLine(oneline_image.data, data, secondary_demod_fft_offset_db);
|
||||||
var color = waterfall_mkcolor(data[x] + secondary_demod_fft_offset_db);
|
|
||||||
for (var i = 0; i < 3; i++) oneline_image.data[x * 4 + i] = color[i];
|
|
||||||
oneline_image.data[x * 4 + 3] = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Draw image
|
// draw image
|
||||||
secondary_demod_current_canvas_context.putImageData(oneline_image, 0, secondary_demod_current_canvas_actual_line--);
|
secondary_demod_current_canvas_context.putImageData(oneline_image, 0, secondary_demod_current_canvas_actual_line--);
|
||||||
secondary_demod_canvases.map(function (x) {
|
secondary_demod_canvases.map(function (x) { x.openwebrx_top += 1; });
|
||||||
x.openwebrx_top += 1;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
secondary_demod_canvases_update_top();
|
secondary_demod_canvases_update_top();
|
||||||
if (secondary_demod_current_canvas_actual_line < 0) secondary_demod_swap_canvases();
|
if (secondary_demod_current_canvas_actual_line < 0) secondary_demod_swap_canvases();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,7 @@ class CompiledAssetsController(GzipMixin, ModificationAwareController):
|
||||||
"lib/Js8Threads.js",
|
"lib/Js8Threads.js",
|
||||||
"lib/Modes.js",
|
"lib/Modes.js",
|
||||||
"lib/MetaPanel.js",
|
"lib/MetaPanel.js",
|
||||||
|
"lib/Waterfall.js",
|
||||||
"lib/Spectrum.js",
|
"lib/Spectrum.js",
|
||||||
"lib/Scanner.js",
|
"lib/Scanner.js",
|
||||||
"lib/Utils.js",
|
"lib/Utils.js",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue