diff --git a/meshview/templates/node.html b/meshview/templates/node.html index 9d13f3f..4f09edb 100644 --- a/meshview/templates/node.html +++ b/meshview/templates/node.html @@ -41,7 +41,7 @@ /* --- Charts --- */ .chart-container { width: 100%; - height: 320px; + height: 380px; margin-bottom: 25px; border: 1px solid #3a3f44; border-radius: 8px; @@ -170,7 +170,7 @@ -
+
@@ -182,7 +182,7 @@ -
+
@@ -194,7 +194,7 @@ -
+
@@ -207,7 +207,7 @@ -
+
@@ -921,20 +921,22 @@ async function loadNeighborTimeSeries() { } const data = await res.json(); - const packets = data.packets || []; + let packets = data.packets || []; if (!packets.length) { document.getElementById("neighbor_chart_container").style.display = "none"; return; } - // --- FIX: sort packets chronologically (oldest → newest) --- - packets.sort((a, b) => (b.import_time_us || 0) - (a.import_time_us || 0)); - + // --- FIX #1: enforce chronological order (oldest → newest) --- + packets.sort((a, b) => (a.import_time_us || 0) - (b.import_time_us || 0)); + // neighborHistory = { node_id: { name, snr:[...], times:[...] } } const neighborHistory = {}; - for (const pkt of packets.reverse()) { + for (const pkt of packets) { + if (!pkt.import_time_us || !pkt.payload) continue; + const ts = new Date(pkt.import_time_us / 1000).toLocaleString([], { month: "2-digit", day: "2-digit", @@ -942,14 +944,12 @@ async function loadNeighborTimeSeries() { minute: "2-digit" }); - const payload = pkt.payload || ""; - - // Parse neighbor blocks - const re = /neighbors\s*\{\s*([^}]+)\}/g; + // Extract neighbor blocks + const blockRe = /neighbors\s*\{([^}]+)\}/g; let m; - - while ((m = re.exec(payload)) !== null) { + while ((m = blockRe.exec(pkt.payload)) !== null) { const block = m[1]; + const idMatch = block.match(/node_id:\s*(\d+)/); const snrMatch = block.match(/snr:\s*(-?\d+(?:\.\d+)?)/); @@ -958,78 +958,62 @@ async function loadNeighborTimeSeries() { const nid = parseInt(idMatch[1], 10); const snr = parseFloat(snrMatch[1]); - // Fetch name if needed - if (!nodeMap[nid]) { - await fetchNodeFromApi(nid); - } - - const label = nodeMap[nid] || nid; - if (!neighborHistory[nid]) { neighborHistory[nid] = { - name: label, - snr: [], - times: [] + name: nodeMap[nid] || `Node ${nid}`, + times: [], + snr: [] }; } - neighborHistory[nid].snr.push(snr); neighborHistory[nid].times.push(ts); + neighborHistory[nid].snr.push(snr); } } - const neighborIds = Object.keys(neighborHistory); - if (!neighborIds.length) { - document.getElementById("neighbor_chart_container").style.display = "none"; - return; + const chart = echarts.init(document.getElementById("chart_neighbors")); + + const legend = []; + const series = []; + + for (const [nid, entry] of Object.entries(neighborHistory)) { + legend.push(entry.name); + + series.push({ + name: entry.name, + type: "line", + smooth: true, + connectNulls: true, // --- FIX #2: connect dots even if missing --- + showSymbol: false, + data: entry.snr, + }); } - const container = document.getElementById("neighbor_chart_container"); - container.style.display = "block"; + // Build merged x-axis from first neighbor’s timestamps + // (Your original code already behaved this way) + const sampleTimes = Object.values(neighborHistory)[0]?.times || []; - const chartEl = document.getElementById("chart_neighbors"); - const neighborChart = echarts.init(chartEl); - - const series = neighborIds.map(nid => ({ - name: neighborHistory[nid].name, - type: "line", - smooth: true, - connectNulls: true, - showSymbol: false, - data: neighborHistory[nid].snr, - })); - - // All times should be aligned → use union of all timestamps - const allTimes = []; - for (const nid of neighborIds) { - for (const t of neighborHistory[nid].times) { - if (!allTimes.includes(t)) allTimes.push(t); - } - } - - neighborChart.setOption({ + chart.setOption({ tooltip: { trigger: "axis" }, - legend: { - data: neighborIds.map(nid => neighborHistory[nid].name), - textStyle: { color: "#ccc" } - }, + legend: { data: legend, textStyle: { color: "#ccc" } }, xAxis: { type: "category", - data: allTimes, - axisLabel: { color: "#ccc", rotate: allTimes.length > 6 ? 45 : 0 } + data: sampleTimes, + axisLabel: { color: "#ccc" } }, yAxis: { type: "value", - name: "SNR (dB)", + name: "SNR", axisLabel: { color: "#ccc" } }, series }); - window.addEventListener("resize", () => neighborChart.resize()); + window.addEventListener("resize", () => chart.resize()); } + /* ====================================================== EXPAND / EXPORT BUTTONS ====================================================== */