diff --git a/htdocs/css/openwebrx.css b/htdocs/css/openwebrx.css index 441d4e1a9..d460babb2 100644 --- a/htdocs/css/openwebrx.css +++ b/htdocs/css/openwebrx.css @@ -294,14 +294,21 @@ input[type=range]:disabled { flex-grow: 1; } +#webrx-canvas-container div +{ + position: relative; + overflow: visible; + width: 100%; +} + #webrx-canvas-container canvas { position: absolute; border-style: none; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast; - width: 100%; height: 200px; + pointer-events: none; } #openwebrx-log-scroll diff --git a/htdocs/openwebrx.js b/htdocs/openwebrx.js index de65e70f9..b2a746912 100644 --- a/htdocs/openwebrx.js +++ b/htdocs/openwebrx.js @@ -1088,9 +1088,19 @@ function waterfall_measure_minmax_do(what) { // this is based on an oversampling factor of about 1,25 var ignored = .1 * what.length; var data = what.slice(ignored, -ignored); + var min = []; + var max = []; + var max_slice = 1e5; + var n = Math.ceil(data.length / max_slice); + for (var i = 0; i < n; ++i) + { + slice = data.slice(i * max_slice, (i + 1) * max_slice); + min.push(Math.min.apply(Math, slice)); + max.push(Math.max.apply(Math, slice)); + } return { - min: Math.min.apply(Math, data), - max: Math.max.apply(Math, data) + min: Math.min.apply(Math, min), + max: Math.max.apply(Math, max) }; } @@ -1226,22 +1236,30 @@ function color_between(first, second, percent) { } -var canvas_context; +var canvas_max_width = 8192; +var canvas_subcontainer; var canvases = []; var canvas_default_height = 200; var canvas_container; var canvas_actual_line; function add_canvas() { - var new_canvas = document.createElement("canvas"); - new_canvas.width = fft_size; - new_canvas.height = canvas_default_height; - canvas_actual_line = canvas_default_height - 1; - new_canvas.openwebrx_top = (-canvas_default_height + 1); - new_canvas.style.top = new_canvas.openwebrx_top.toString() + "px"; - canvas_context = new_canvas.getContext("2d"); - canvas_container.appendChild(new_canvas); - canvases.push(new_canvas); + canvas_subcontainer = document.createElement("div"); + var n = Math.max(fft_size / canvas_max_width, 1); + var w = 100 / n; + for (var i = 0; i < n; ++i) { + var new_canvas = document.createElement("canvas"); + new_canvas.width = Math.min(fft_size, canvas_max_width); + new_canvas.height = canvas_default_height; + new_canvas.style.width = w + '%'; + new_canvas.style.marginLeft = (w * i) + '%'; + canvas_actual_line = canvas_default_height - 1; + canvas_subcontainer.appendChild(new_canvas); + } + canvas_subcontainer.openwebrx_top = (-canvas_default_height + 1); + canvas_subcontainer.style.top = canvas_subcontainer.openwebrx_top.toString() + "px"; + canvas_container.appendChild(canvas_subcontainer); + canvases.push(canvas_subcontainer); while (canvas_container && canvas_container.clientHeight + canvas_default_height * 2 < canvases.length * canvas_default_height) { var c = canvases.shift(); if (!c) break; @@ -1291,7 +1309,6 @@ function waterfall_init() { function waterfall_add(data) { if (!waterfall_setup_done) return; - var w = fft_size; if (waterfall_measure_minmax_now) { var levels = waterfall_measure_minmax_do(data); @@ -1305,16 +1322,21 @@ function waterfall_add(data) { waterfallColorsContinuous(level); } - //Add line to waterfall image - var oneline_image = canvas_context.createImageData(w, 1); - for (var x = 0; x < w; x++) { - 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; - } + //Add line to waterfall + var w = Math.min(fft_size, canvas_max_width); + for (var j = 0; j < fft_size / canvas_max_width; ++j) { + var canvas_context = canvas_subcontainer.childNodes[j].getContext("2d"); + var oneline_image = canvas_context.createImageData(w, 1); + for (var x = 0; x < w; x++) { + var color = waterfall_mkcolor(data[x + canvas_max_width * j]); + for (i = 0; i < 3; i++) oneline_image.data[x * 4 + i] = color[i]; + oneline_image.data[x * 4 + 3] = 255; + } - //Draw image - canvas_context.putImageData(oneline_image, 0, canvas_actual_line--); + //Draw image + canvas_context.putImageData(oneline_image, 0, canvas_actual_line); + } + --canvas_actual_line; shift_canvases(); if (canvas_actual_line < 0) add_canvas(); }