From b96299700839b79082a5869bba698e4cc3a51146 Mon Sep 17 00:00:00 2001 From: Poulpe Date: Mon, 27 Apr 2026 21:54:19 +0000 Subject: [PATCH] feat(viewer): merge USV M1+M2 into one graph, add history window control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - USV panel: usv-m1 + usv-m2 → single usv-motors multi-trace (2 lines) - AUV panel: auv-motors already combined (6 lines), no change - Add window dropdown (10s/30s/60s/5min/15min/ALL) next to trail control - updateCursor applies xaxis.range=[T-win, T] on all panel graphs - Plots before: ~9 USV + ~9 AUV = ~18; after: ~7 USV + ~8 AUV = ~15 --- viewer/index.html | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/viewer/index.html b/viewer/index.html index 88b303a..c6b4e0c 100644 --- a/viewer/index.html +++ b/viewer/index.html @@ -306,6 +306,15 @@ flowchart LR + +
@@ -340,8 +349,7 @@ flowchart LR
-
-
+
@@ -981,11 +989,13 @@ function renderUSV(signals) { const [at, av] = _pts(signals.usbl_angle); Plotly.react('usv-usbl-angle', [{x:at, y:av, type:'scatter', mode:'lines', line:{color:'#c77dff',width:1}}], _layout('USBL angle','°'), cfg); - const [m1t, m1v] = _pts(signals.M1); - Plotly.react('usv-m1', [{x:m1t, y:m1v, type:'scatter', mode:'lines', line:{color:'#ef476f',width:1}}], _layout('Motor 1','cmd'), cfg); - - const [m2t, m2v] = _pts(signals.M2); - Plotly.react('usv-m2', [{x:m2t, y:m2v, type:'scatter', mode:'lines', line:{color:'#ff6b6b',width:1}}], _layout('Motor 2','cmd'), cfg); + const motorColorsUSV = ['#ef476f','#ff8800']; + const motorTracesUSV = ['M1','M2'].map((mk,i) => { + const [t,v] = _pts(signals[mk]); + return {x:t,y:v,type:'scatter',mode:'lines',name:mk,line:{color:motorColorsUSV[i],width:1}}; + }); + Plotly.react('usv-motors', motorTracesUSV, + Object.assign(_layout('Motors USV','cmd'), {showlegend:true, legend:{font:{size:8},bgcolor:'transparent',orientation:'h',x:0,y:1}}), cfg); const armPts = _pts(signals.Armed); const modePts = _pts(signals.Mode); @@ -1066,24 +1076,32 @@ function renderAUV(signals) { const ALL_GRAPH_IDS = [ 'chart-depth', 'chart-pwm-auv', 'chart-pwm-usv', 'chart-usbl', 'usv-yaw', 'usv-heading', 'usv-batt', 'usv-gps', - 'usv-usbl-dist', 'usv-usbl-angle', 'usv-m1', 'usv-m2', 'usv-status', + 'usv-usbl-dist', 'usv-usbl-angle', 'usv-motors', 'usv-status', 'auv-pry', 'auv-depth', 'auv-alt', 'auv-obs', 'auv-usbl-dist', 'auv-usbl-angle', 'auv-batt', 'auv-status', 'auv-motors', ]; function updateCursor(epochSec) { const ts = new Date(epochSec * 1000).toISOString(); + const tMs = epochSec * 1000; + const winMs = +document.getElementById('window-select').value; + const t0 = winMs === 0 ? null : new Date(tMs - winMs).toISOString(); + const t1 = new Date(tMs).toISOString(); const shape = { type: 'line', x0: ts, x1: ts, y0: 0, y1: 1, yref: 'paper', line: {color: '#e94560', width: 1, dash: 'dot'}, }; + const rangeUpdate = t0 ? {'xaxis.range': [t0, t1]} : {'xaxis.autorange': true}; ALL_GRAPH_IDS.forEach(id => { const el = document.getElementById(id); if (el && el._fullLayout) { - Plotly.relayout(id, {'shapes': [shape]}); + Plotly.relayout(id, {...rangeUpdate, 'shapes': [shape]}); } }); } +document.getElementById('window-select').addEventListener('change', () => { + if (tNow) updateCursor(tNow / 1000); +}); // == Task 11: loadSortieData + sorties loading + wiring == async function loadSortieData(sortieId) {