feat(viewer): merge USV M1+M2 into one graph, add history window control
- 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
This commit is contained in:
@@ -306,6 +306,15 @@ flowchart LR
|
|||||||
</select>
|
</select>
|
||||||
<button id="btn-viewall" onclick="viewAll()">View all</button>
|
<button id="btn-viewall" onclick="viewAll()">View all</button>
|
||||||
<button id="btn-play">▶</button>
|
<button id="btn-play">▶</button>
|
||||||
|
<label for="window-select" style="font-size:10px;color:#666;white-space:nowrap;">win</label>
|
||||||
|
<select id="window-select" style="background:#0f3460;border:1px solid #a855f7;color:#a855f7;font-family:monospace;font-size:11px;padding:2px 6px;border-radius:2px;cursor:pointer;">
|
||||||
|
<option value="10000">10s</option>
|
||||||
|
<option value="30000">30s</option>
|
||||||
|
<option value="60000" selected>60s</option>
|
||||||
|
<option value="300000">5min</option>
|
||||||
|
<option value="900000">15min</option>
|
||||||
|
<option value="0">ALL</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div id="ctrl-row2">
|
<div id="ctrl-row2">
|
||||||
<span id="cursor-info" style="font-size:10px;color:#888;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">—</span>
|
<span id="cursor-info" style="font-size:10px;color:#888;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">—</span>
|
||||||
@@ -340,8 +349,7 @@ flowchart LR
|
|||||||
<div class="graph-cell" id="usv-gps"></div>
|
<div class="graph-cell" id="usv-gps"></div>
|
||||||
<div class="graph-cell" id="usv-usbl-dist"></div>
|
<div class="graph-cell" id="usv-usbl-dist"></div>
|
||||||
<div class="graph-cell" id="usv-usbl-angle"></div>
|
<div class="graph-cell" id="usv-usbl-angle"></div>
|
||||||
<div class="graph-cell" id="usv-m1"></div>
|
<div class="graph-cell wide" id="usv-motors"></div>
|
||||||
<div class="graph-cell" id="usv-m2"></div>
|
|
||||||
<div class="graph-cell wide" id="usv-status"></div>
|
<div class="graph-cell wide" id="usv-status"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-header" id="auv-panel-header">
|
<div class="panel-header" id="auv-panel-header">
|
||||||
@@ -981,11 +989,13 @@ function renderUSV(signals) {
|
|||||||
const [at, av] = _pts(signals.usbl_angle);
|
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);
|
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);
|
const motorColorsUSV = ['#ef476f','#ff8800'];
|
||||||
Plotly.react('usv-m1', [{x:m1t, y:m1v, type:'scatter', mode:'lines', line:{color:'#ef476f',width:1}}], _layout('Motor 1','cmd'), cfg);
|
const motorTracesUSV = ['M1','M2'].map((mk,i) => {
|
||||||
|
const [t,v] = _pts(signals[mk]);
|
||||||
const [m2t, m2v] = _pts(signals.M2);
|
return {x:t,y:v,type:'scatter',mode:'lines',name:mk,line:{color:motorColorsUSV[i],width:1}};
|
||||||
Plotly.react('usv-m2', [{x:m2t, y:m2v, type:'scatter', mode:'lines', line:{color:'#ff6b6b',width:1}}], _layout('Motor 2','cmd'), cfg);
|
});
|
||||||
|
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 armPts = _pts(signals.Armed);
|
||||||
const modePts = _pts(signals.Mode);
|
const modePts = _pts(signals.Mode);
|
||||||
@@ -1066,24 +1076,32 @@ function renderAUV(signals) {
|
|||||||
const ALL_GRAPH_IDS = [
|
const ALL_GRAPH_IDS = [
|
||||||
'chart-depth', 'chart-pwm-auv', 'chart-pwm-usv', 'chart-usbl',
|
'chart-depth', 'chart-pwm-auv', 'chart-pwm-usv', 'chart-usbl',
|
||||||
'usv-yaw', 'usv-heading', 'usv-batt', 'usv-gps',
|
'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-pry', 'auv-depth', 'auv-alt', 'auv-obs',
|
||||||
'auv-usbl-dist', 'auv-usbl-angle', 'auv-batt', 'auv-status', 'auv-motors',
|
'auv-usbl-dist', 'auv-usbl-angle', 'auv-batt', 'auv-status', 'auv-motors',
|
||||||
];
|
];
|
||||||
|
|
||||||
function updateCursor(epochSec) {
|
function updateCursor(epochSec) {
|
||||||
const ts = new Date(epochSec * 1000).toISOString();
|
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 = {
|
const shape = {
|
||||||
type: 'line', x0: ts, x1: ts, y0: 0, y1: 1,
|
type: 'line', x0: ts, x1: ts, y0: 0, y1: 1,
|
||||||
yref: 'paper', line: {color: '#e94560', width: 1, dash: 'dot'},
|
yref: 'paper', line: {color: '#e94560', width: 1, dash: 'dot'},
|
||||||
};
|
};
|
||||||
|
const rangeUpdate = t0 ? {'xaxis.range': [t0, t1]} : {'xaxis.autorange': true};
|
||||||
ALL_GRAPH_IDS.forEach(id => {
|
ALL_GRAPH_IDS.forEach(id => {
|
||||||
const el = document.getElementById(id);
|
const el = document.getElementById(id);
|
||||||
if (el && el._fullLayout) {
|
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 ==
|
// == Task 11: loadSortieData + sorties loading + wiring ==
|
||||||
async function loadSortieData(sortieId) {
|
async function loadSortieData(sortieId) {
|
||||||
|
|||||||
Reference in New Issue
Block a user