Fix chart on node.html.

This commit is contained in:
Pablo Revilla
2025-12-09 16:58:38 -08:00
parent 00aa3216ff
commit 4326e12e88

View File

@@ -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 @@
<button onclick="exportCSV('battery_voltage')" data-translate-lang="export_csv">Export CSV</button>
</div>
</div>
<div id="chart_battery_voltage" style="height:260px;"></div>
<div id="chart_battery_voltage" style="height:380px;"></div>
</div>
<!-- Air/Channel -->
@@ -182,7 +182,7 @@
<button onclick="exportCSV('air_channel')" data-translate-lang="export_csv">Export CSV</button>
</div>
</div>
<div id="chart_air_channel" style="height:260px;"></div>
<div id="chart_air_channel" style="height:380px;"></div>
</div>
<!-- Env Metrics -->
@@ -194,7 +194,7 @@
<button onclick="exportCSV('environment')" data-translate-lang="export_csv">Export CSV</button>
</div>
</div>
<div id="chart_environment" style="height:260px;"></div>
<div id="chart_environment" style="height:380px;"></div>
</div>
<!-- Neighbor chart -->
@@ -207,7 +207,7 @@
<button onclick="exportCSV('neighbors')" data-translate-lang="export_csv">Export CSV</button>
</div>
</div>
<div id="chart_neighbors" style="height:260px;"></div>
<div id="chart_neighbors" style="height:380px;"></div>
</div>
@@ -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 neighbors 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
====================================================== */