habdec/code/webClient/js/drawing.js

331 wiersze
9.1 KiB
JavaScript

class Average // rolling avg classs
{
constructor(max_count, init_val=0)
{
this.max_count_ = max_count;
this.count_ = 0;
this.sum_ = 0;
this.add(init_val);
}
get_avg()
{
if(this.count_ == 0)
return this.sum_;
return this.sum_/this.count_;
}
add(val)
{
if(this.count_ == this.max_count_)
{
// console.debug("SATURATE");
this.sum_ = this.get_avg() * (this.max_count_-1) + val;
}
else
{
this.count_ += 1;
this.sum_ += val;
}
}
reset(val)
{
this.sum_ = val;
this.count_ = 1;
}
};
var AccSpectrumArray = {
arr_: new Array(),
count_: 0,
maxCount_: 3
};
var AvgCnt = 10; // Rolling average length. Smooths out spectrum drawing.
var NoiseFloorAvg = new Average(AvgCnt);
var SpectrumMinAvg = new Average(AvgCnt);
var SpectrumMaxAvg = new Average(AvgCnt);
// rolling average on array
function AccumulateSpectrumArray(i_arr)
{
if(AccSpectrumArray.arr_.length != i_arr.length)
{
AccSpectrumArray.arr_ = i_arr;
AccSpectrumArray.count_ = 1;
return AccSpectrumArray.arr_;
}
if( AccSpectrumArray.count_ < AccSpectrumArray.maxCount_ )
{
for(var i=0 ; i<AccSpectrumArray.arr_.length; ++i)
AccSpectrumArray.arr_[i] += i_arr[i];
AccSpectrumArray.count_ += 1;
}
else
{
for(var i=0 ; i<AccSpectrumArray.arr_.length; ++i)
{
AccSpectrumArray.arr_[i] =
(AccSpectrumArray.arr_[i] / AccSpectrumArray.count_) * (AccSpectrumArray.maxCount_-1) + i_arr[i];
}
}
// return value
var spectr_result = new Array(AccSpectrumArray.arr_.length);
for(var i=0 ; i<AccSpectrumArray.arr_.length; ++i)
spectr_result[i] = AccSpectrumArray.arr_[i] / AccSpectrumArray.count_;
return spectr_result;
}
function DrawPowerSpectrum(i_canvas, i_spectrum)
{
if(i_spectrum == undefined)
return;
var ctx = i_canvas.getContext("2d");
// CLEAR THE CANVAS
//
ctx.clearRect(0, 0, i_canvas.width, i_canvas.height);
// BG
//
var grd_bg = ctx.createLinearGradient(0, 0, 0, i_canvas.height);
grd_bg.addColorStop(0, HD_COLOR_SCHEME['CSS']['HD_bg']);
grd_bg.addColorStop(.5, HD_COLOR_SCHEME['CSS']['HD_fg']);
grd_bg.addColorStop(1, HD_COLOR_SCHEME['CSS']['HD_bg']);
ctx.fillStyle = grd_bg;
ctx.fillRect(0, 0, i_canvas.width, i_canvas.height);
G_SPECTRUM_ZOOM = Math.max(0, Math.min(1, G_SPECTRUM_ZOOM));
var zoom = G_SPECTRUM_ZOOM;
// LOWPASS FILTER DRAW
//
var _lowpass_bw_relative = HD_GLOBALS.lowpass_bw / i_spectrum.sampling_rate_ / (1.0 - .999*zoom);
var _lowpass_trans = HD_GLOBALS.lowpass_trans / (1.0 - .999*zoom);
var grd_lowpass = ctx.createLinearGradient(0, 0, i_canvas.width-1, 0);
var _l = Math.max(0, .5 - .5 * _lowpass_bw_relative);
var _ll = Math.max(0, .5 - .5 * (_lowpass_bw_relative + _lowpass_trans));
var _r = Math.min(1, .5 + .5 * _lowpass_bw_relative);
var _rr = Math.min(1, .5 + .5 * (_lowpass_bw_relative + _lowpass_trans));
grd_lowpass.addColorStop(_ll, HD_COLOR_SCHEME['CSS']['HD_bg']);
grd_lowpass.addColorStop(_l, HD_COLOR_SCHEME["SPECTRUM"]["FILTER"]);
grd_lowpass.addColorStop(_r, HD_COLOR_SCHEME["SPECTRUM"]["FILTER"]);
grd_lowpass.addColorStop(_rr, HD_COLOR_SCHEME['CSS']['HD_bg']);
grd_lowpass.addColorStop(1, HD_COLOR_SCHEME['CSS']['HD_bg']);
ctx.fillStyle = grd_lowpass;
ctx.fillRect(0, 0, i_canvas.width, i_canvas.height);
// SPECTRUM
//
// decode spectrum values
var spectrum_values_arr = new Array(i_canvas.width);
for(var x=0; x<i_canvas.width; ++x)
{
var x_0_1 = x/(i_canvas.width-1);
var value_encoded = i_spectrum.values_[ Math.round(x_0_1 * i_spectrum.values_.length) ];
var true_value;
if(i_spectrum.type_size_ == 1) // 8 bit char
true_value = i_spectrum.min_ + (value_encoded / 255) * (i_spectrum.max_ - i_spectrum.min_);
else if(i_spectrum.type_size_ == 2) // uint16_t
true_value = i_spectrum.min_ + (value_encoded / 65535) * (i_spectrum.max_ - i_spectrum.min_);
else if(i_spectrum.type_size_ == 4) // 32float
true_value = value_encoded;
spectrum_values_arr[x] = true_value;
}
// border values are NaN. needs fixing
spectrum_values_arr[0] = spectrum_values_arr[1];
spectrum_values_arr[spectrum_values_arr.length-1] = spectrum_values_arr[spectrum_values_arr.length-2];
// accumulate spectrum and noisefloor for nice rendering
spectrum_values_arr = AccumulateSpectrumArray(spectrum_values_arr);
NoiseFloorAvg.add(i_spectrum.noise_floor_);
SpectrumMinAvg.add(i_spectrum.min_);
SpectrumMaxAvg.add(i_spectrum.max_);
var noise_floor_avg = NoiseFloorAvg.get_avg();
var spectrum_min_avg = SpectrumMinAvg.get_avg();
var spectrum_max_avg = SpectrumMaxAvg.get_avg();
// spectrum_min_avg *= 1.3; // drawing pedestal
// draw
var power_grd = ctx.createLinearGradient(0, 0, 0, i_canvas.height);
power_grd.addColorStop(1-Math.abs(noise_floor_avg / spectrum_min_avg), HD_COLOR_SCHEME['SPECTRUM']['HIGH']);
power_grd.addColorStop(1-Math.abs(spectrum_max_avg / spectrum_min_avg), HD_COLOR_SCHEME['SPECTRUM']['MID']);
power_grd.addColorStop(1 , HD_COLOR_SCHEME['SPECTRUM']['LOW']);
ctx.strokeStyle = power_grd;
ctx.beginPath();
for(var x=0; x<i_canvas.width; ++x)
{
var val_0_1 = 1.0 - Math.abs(spectrum_values_arr[x] / spectrum_min_avg);
val_0_1 = Math.max(val_0_1, 0);
var val_pixel = (1-val_0_1) * (i_canvas.height-1);
ctx.moveTo(x, i_canvas.height - 1);
ctx.lineTo(x, val_pixel);
}
ctx.stroke();
// CENTER LINE
//
ctx.strokeStyle = '#555555';
ctx.beginPath();
ctx.moveTo(i_canvas.width/2, i_canvas.height - 1);
ctx.lineTo(i_canvas.width/2, 0);
ctx.stroke();
// NOISE FLOOR
//
ctx.strokeStyle = '#333388';
ctx.beginPath();
var nf_0_1 = 1.0 - Math.abs(noise_floor_avg / spectrum_min_avg);
nf_0_1 = Math.max(nf_0_1, 0);
ctx.moveTo(0, (1-nf_0_1)*i_canvas.height - 1);
ctx.lineTo(i_canvas.width, (1-nf_0_1)*i_canvas.height - 1);
ctx.stroke();
// PEAK LEFT
//
if(i_spectrum.peak_left_valid_)
ctx.strokeStyle = '#FF2200';
else
ctx.strokeStyle = '#113322';
ctx.beginPath();
var peak_left_0_1 = i_spectrum.peak_left_ / i_spectrum.size_;
ctx.moveTo(peak_left_0_1 * i_canvas.width, 0);
ctx.lineTo(peak_left_0_1 * i_canvas.width, i_canvas.height - 1);
ctx.stroke();
// PEAK RIGHT
//
if(i_spectrum.peak_right_valid_)
ctx.strokeStyle = '#0088FF';
else
ctx.strokeStyle = '#113322';
ctx.beginPath();
var peak_right_0_1 = i_spectrum.peak_right_ / i_spectrum.size_;
ctx.moveTo(peak_right_0_1 * i_canvas.width, 0);
ctx.lineTo(peak_right_0_1 * i_canvas.width, i_canvas.height - 1);
ctx.stroke();
}
function DrawDemod(i_canvas, i_demod)
{
if(i_demod == undefined)
return;
var ctx = i_canvas.getContext("2d");
// Clear the canvas
ctx.clearRect(0, 0, i_canvas.width, i_canvas.height);
// BG
//
var grd_bg = ctx.createLinearGradient(0, 0, 0, i_canvas.height);
grd_bg.addColorStop(0, HD_COLOR_SCHEME['CSS']['HD_bg']);
grd_bg.addColorStop(.5,HD_COLOR_SCHEME['CSS']['HD_fg']);
grd_bg.addColorStop(1, HD_COLOR_SCHEME['CSS']['HD_bg']);
ctx.fillStyle = grd_bg;
ctx.fillRect(0, 0, i_canvas.width, i_canvas.height);
// CENTER LINE
//
ctx.strokeStyle = HD_COLOR_SCHEME['SPECTRUM']['LOW'];
ctx.beginPath();
ctx.moveTo(0, i_canvas.height/2);
ctx.lineTo(i_canvas.width, i_canvas.height/2);
ctx.stroke();
// DEMOD
//
ctx.strokeStyle = HD_COLOR_SCHEME['SPECTRUM']['MID'];
ctx.beginPath();
ctx.moveTo(0, 0);
for(var x=0; x<i_canvas.width; ++x)
{
var x_0_1 = x/(i_canvas.width-1);
var encoded_value = i_demod.values_[ Math.round(x_0_1 * i_demod.values_.length) ];
var true_value = 0;
if(i_demod.type_size_ == 1) // 8 bit char
true_value = i_demod.min_ + encoded_value / 255.0 * (i_demod.max_ - i_demod.min_);
else if(i_demod.type_size_ == 2) // uint16_t
true_value = i_demod.min_ + encoded_value / 65535.0 * (i_demod.max_ - i_demod.min_);
else if(i_demod.type_size_ == 4) // 32float
true_value = encoded_value;
true_value *= .75; // scale down a little bit
var val_0_1 = .5 + .5 * true_value / Math.max( Math.abs( i_demod.min_ ), Math.abs( i_demod.max_ ) );
var val_pixel = (1.0-val_0_1) * (i_canvas.height-1);
ctx.lineTo(x, val_pixel);
}
ctx.stroke();
}
function ResizeCanvas(canvas_id)
{
var canvasNode = document.getElementById(canvas_id);
var canvasDiv = canvasNode.parentNode;
canvasNode.style.width = '100%';
canvasNode.style.height = '100%';
canvasNode.width = canvasDiv.clientWidth;
canvasNode.height = canvasDiv.clientHeight;
}
var AnimatePowerSpectrum_last = 0;
var G_PowerCanvas;
function AnimatePowerSpectrum(timestamp)
{
if(G_PowerCanvas == undefined)
G_PowerCanvas = document.getElementById("HabDec_powerSpectrumCanvas");
if(!AnimatePowerSpectrum_last)
AnimatePowerSpectrum_last = timestamp;
if( (timestamp - AnimatePowerSpectrum_last) > (1000/G_POWER_FPS) )
{
AnimatePowerSpectrum_last = timestamp;
DrawPowerSpectrum(G_PowerCanvas, G_SPECTRUM_DATA);
}
window.requestAnimationFrame(AnimatePowerSpectrum);
}
var AnimateDemod_last = 0;
var G_DemodCanvas;
function AnimateDemod(timestamp)
{
if(G_DemodCanvas == undefined)
G_DemodCanvas = document.getElementById("HabDec_demodCanvas");
if(!AnimateDemod_last)
AnimateDemod_last = timestamp;
if( (timestamp - AnimateDemod_last) > (1000/G_DEMOD_FPS) )
{
AnimateDemod_last = timestamp;
DrawDemod(G_DemodCanvas, G_DEMOD_DATA);
}
window.requestAnimationFrame(AnimateDemod);
}