From d5b1986761c806008402a7ac4a3baf4e9a427e49 Mon Sep 17 00:00:00 2001 From: Martino Ferrari Date: Wed, 27 May 2026 16:46:06 +0200 Subject: [PATCH] Improved cursors functionality --- Client/WebUI/static/app.js | 63 ++++++++++++++++++++++++++++++++++- Client/WebUI/static/style.css | 14 ++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/Client/WebUI/static/app.js b/Client/WebUI/static/app.js index 61db711..4967226 100644 --- a/Client/WebUI/static/app.js +++ b/Client/WebUI/static/app.js @@ -225,6 +225,7 @@ function setActiveSig(plotId, key) { b.classList.toggle('sig-badge-active', key != null && b.dataset.key === key)); const p = plots.find(q => q.id === plotId); if (p && p.uplot) p.uplot.redraw(false); + updatePlotCursorReadouts(); } // Mark plots containing key dirty and refresh badge vscale text. @@ -1287,8 +1288,10 @@ function drawCursorLines(u, p) { ctx.fillText(label, px + 14, bbox.top + 2); // Per-trace: diamond at crossing point + value label if (p) { - const DSZ = 5; // diamond half-size in px + const activeKey = plotActiveSignal[p.id]; p.traces.forEach((key, idx) => { + const isActive = key === activeKey || (!activeKey && p.traces.length === 1); + const DSZ = isActive ? 9 : 5; // diamond half-size in px const vNorm = interpAtTime(u, idx + 1, val); if (vNorm === null) return; const cy = u.valToPos(vNorm, 'y', true); @@ -2019,10 +2022,56 @@ document.getElementById('btn-cursor').addEventListener('click', () => { cursorsDirty = true; }); +// Format a signal value for the per-plot cursor readout. +function fmtVal(v) { + if (v === null || v === undefined) return '—'; + return Math.abs(v) >= 10000 ? v.toExponential(2) : parseFloat(v.toPrecision(4)).toString(); +} + +// Interpolate the real-unit value of the active/sole signal in plot p at time t. +function getValueAtCursor(p, t) { + if (!p.uplot || t === null) return null; + const key = plotActiveSignal[p.id] || (p.traces.length === 1 ? p.traces[0] : null); + if (!key) return null; + const idx = p.traces.indexOf(key); + if (idx < 0) return null; + const vNorm = interpAtTime(p.uplot, idx + 1, t); + if (vNorm === null) return null; + // Un-normalize: y_norm = (y_raw - offset) / divValue + screenPos + const vs = sigVScale[p.id + ':' + key]; + if (!vs) return vNorm; + const dv = vs._resolvedDiv != null ? vs._resolvedDiv : (vs.divValue || 1); + const ofs = vs._resolvedOffset != null ? vs._resolvedOffset : (vs.offset || 0); + const sp = vs.screenPos || 0; + return (vNorm - sp) * dv + ofs; +} + +// Update per-plot cursor value readouts (A, B, ΔV) for all plots. +function updatePlotCursorReadouts() { + plots.forEach(p => { + const el = document.getElementById('pcur-' + p.id); + if (!el) return; + // Show only when cursors are on and the plot has an active or sole signal. + const key = plotActiveSignal[p.id] || (p.traces.length === 1 ? p.traces[0] : null); + if (cursors.mode !== 'on' || !key || !p.uplot) { + el.style.display = 'none'; + return; + } + const vA = getValueAtCursor(p, cursors.tA); + const vB = getValueAtCursor(p, cursors.tB); + const dv = (vA !== null && vB !== null) ? vB - vA : null; + document.getElementById('pcur-a-' + p.id).textContent = 'A: ' + fmtVal(vA); + document.getElementById('pcur-b-' + p.id).textContent = 'B: ' + fmtVal(vB); + document.getElementById('pcur-dv-' + p.id).textContent = 'ΔV: ' + fmtVal(dv); + el.style.display = 'flex'; + }); +} + function updateCursorReadout() { const ro = document.getElementById('cursor-readout'); const active = cursors.mode === 'on'; ro.classList.toggle('visible', active); + updatePlotCursorReadouts(); if (!active) return; // Use the current visible x-range to pick the display unit. @@ -2605,6 +2654,13 @@ function addPlot() {
Plot ${id}
+