Modified the Neighbours graphs to eliminate the errors.

This commit is contained in:
Pablo Revilla
2025-05-21 09:37:23 -07:00
parent a6c9970054
commit 2b3be8bf93
+118 -83
View File
@@ -4,7 +4,6 @@
</a>
{% endmacro %}
<!-- Tabs -->
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#overview" type="button" role="tab">Overview</button>
@@ -20,7 +19,6 @@
</li>
</ul>
<!-- Tab Content -->
<div class="tab-content mt-3">
<div class="tab-pane fade show active" id="overview" role="tabpanel">
<dl>
@@ -36,9 +34,10 @@
<div class="tab-pane fade" id="neighbors" role="tabpanel">
<div class="d-flex justify-content-between align-items-center mb-2">
<h5 class="text-white">Neighbor SNR</h5>
<button class="btn btn-sm btn-outline-light" data-bs-toggle="modal" data-bs-target="#fullChartModal">
Expand
</button>
<div>
<button class="btn btn-sm btn-outline-light me-2" id="downloadCsvBtn">Download CSV</button>
<button class="btn btn-sm btn-outline-light" data-bs-toggle="modal" data-bs-target="#fullChartModal">Expand</button>
</div>
</div>
<div id="neighborChart" style="width: 100%; height: 400px;"></div>
<noscript>
@@ -49,25 +48,46 @@
</div>
<div class="tab-pane fade" id="weather" role="tabpanel">
<dl><dt>Temperature</dt><dd>{{ graph("temperature") }}</dd></dl>
<dl><dt>Humidity</dt><dd>{{ graph("humidity") }}</dd></dl>
<dl><dt>Pressure</dt><dd>{{ graph("pressure") }}</dd></dl>
<dl><dt>Indoor Air Quality</dt><dd>{{ graph("iaq") }}</dd></dl>
<dl><dt>Wind Speed</dt><dd>{{ graph("wind_speed") }}</dd></dl>
<dl><dt>Wind Direction</dt><dd>{{ graph("wind_direction") }}</dd></dl>
<dl>
<dt>Temperature</dt>
<dd>{{ graph("temperature") }}</dd>
</dl>
<dl>
<dt>Humidity</dt>
<dd>{{ graph("humidity") }}</dd>
</dl>
<dl>
<dt>Pressure</dt>
<dd>{{ graph("pressure") }}</dd>
</dl>
<dl>
<dt>Indoor Air Quality</dt>
<dd>{{ graph("iaq") }}</dd>
</dl>
<dl>
<dt>Wind Speed</dt>
<dd>{{ graph("wind_speed") }}</dd>
</dl>
<dl>
<dt>Wind Direction</dt>
<dd>{{ graph("wind_direction") }}</dd>
</dl>
</div>
<div class="tab-pane fade" id="power" role="tabpanel">
<dl><dt>Power Metrics</dt><dd>{{ graph("power_metrics") }}</dd></dl>
<dl>
<dt>Power Metrics</dt>
<dd>{{ graph("power_metrics") }}</dd>
</dl>
</div>
</div>
<!-- Fullscreen Modal for Neighbor Chart -->
<!-- Fullscreen Modal -->
<div class="modal fade" id="fullChartModal" tabindex="-1" aria-labelledby="fullChartModalLabel" aria-hidden="true">
<div class="modal-dialog modal-fullscreen">
<div class="modal-content bg-dark">
<div class="modal-content bg-dark text-white">
<div class="modal-header">
<h5 class="modal-title text-white" id="fullChartModalLabel">Full Neighbor SNR Chart</h5>
<h5 class="modal-title" id="fullChartModalLabel">Full Graph</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
@@ -80,46 +100,33 @@
<!-- ECharts Library -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
<!-- JavaScript -->
<script>
document.addEventListener("DOMContentLoaded", function () {
const neighborTab = document.querySelector('button[data-bs-target="#neighbors"]');
neighborTab.addEventListener('shown.bs.tab', function () {
const chartContainer = document.getElementById('neighborChart');
const tab = document.querySelector('button[data-bs-target="#neighbors"]');
const chartContainer = document.getElementById('neighborChart');
const fullChartContainer = document.getElementById('fullNeighborChart');
let neighborChartData = null;
tab.addEventListener('shown.bs.tab', function () {
if (chartContainer.dataset.loaded) return;
fetch("/graph/neighbors_json/{{ node_id }}")
.then(res => res.json())
.then(json => {
neighborChartData = json;
const option = getChartOption(json);
const chart = echarts.init(chartContainer);
chart.setOption({
title: { text: 'Neighbor SNR over Time', textStyle: { color: '#ffffff' }},
tooltip: { trigger: 'axis' },
legend: { type: 'scroll', top: 30, textStyle: { color: '#ffffff' }},
grid: { left: 60, right: 30, bottom: 80, top: 60, containLabel: true },
xAxis: {
type: 'category',
data: json.timestamps,
name: 'Time',
axisLabel: { rotate: 45, color: '#ffffff' },
nameTextStyle: { color: '#ffffff' }
},
yAxis: {
type: 'value',
name: 'SNR',
axisLabel: { color: '#ffffff' },
nameTextStyle: { color: '#ffffff' }
},
series: json.series.map(s => ({
name: s.name,
type: 'line',
data: s.data,
connectNulls: true,
showSymbol: false,
smooth: true
}))
});
chart.setOption(option);
chartContainer.dataset.loaded = "true";
// Modal chart
const modal = document.getElementById('fullChartModal');
modal.addEventListener('shown.bs.modal', () => {
const fullChart = echarts.init(fullChartContainer);
fullChart.setOption(option);
fullChart.resize();
});
})
.catch(err => {
chartContainer.innerText = "Failed to load graph.";
@@ -127,44 +134,72 @@ document.addEventListener("DOMContentLoaded", function () {
});
});
// Fullscreen chart loader
document.getElementById('fullChartModal').addEventListener('shown.bs.modal', function () {
const container = document.getElementById('fullNeighborChart');
container.innerHTML = ''; // clear
function getChartOption(json) {
return {
title: {
text: 'Neighbor SNR over Time',
textStyle: { color: '#ffffff' }
},
tooltip: {
trigger: 'axis',
},
legend: {
type: 'scroll',
top: 30,
textStyle: { color: '#ffffff' }
},
grid: {
left: '5%',
right: '5%',
bottom: '10%',
containLabel: true
},
xAxis: {
type: 'category',
data: json.timestamps,
name: 'Time',
axisLabel: { rotate: 45, color: '#ffffff' },
nameTextStyle: { color: '#ffffff' }
},
yAxis: {
type: 'value',
name: 'SNR',
axisLabel: { color: '#ffffff' },
nameTextStyle: { color: '#ffffff' }
},
series: json.series.map(s => ({
name: s.name,
type: 'line',
data: s.data,
connectNulls: true,
showSymbol: false,
smooth: true
}))
};
}
fetch("/graph/neighbors_json/{{ node_id }}")
.then(res => res.json())
.then(json => {
const chart = echarts.init(container);
chart.setOption({
title: { text: 'Neighbor SNR over Time', textStyle: { color: '#ffffff' }},
tooltip: { trigger: 'axis' },
legend: { type: 'scroll', top: 30, textStyle: { color: '#ffffff' }},
grid: { left: 60, right: 30, bottom: 80, top: 60, containLabel: true },
xAxis: {
type: 'category',
data: json.timestamps,
name: 'Time',
axisLabel: { rotate: 45, color: '#ffffff' },
nameTextStyle: { color: '#ffffff' }
},
yAxis: {
type: 'value',
name: 'SNR',
axisLabel: { color: '#ffffff' },
nameTextStyle: { color: '#ffffff' }
},
series: json.series.map(s => ({
name: s.name,
type: 'line',
data: s.data,
connectNulls: true,
showSymbol: false,
smooth: true
}))
});
window.addEventListener('resize', () => chart.resize());
});
// Download CSV logic
document.getElementById('downloadCsvBtn').addEventListener('click', function () {
if (!neighborChartData) return alert("Chart data not loaded yet.");
const { timestamps, series } = neighborChartData;
let csv = 'Time,' + series.map(s => s.name).join(',') + '\n';
for (let i = 0; i < timestamps.length; i++) {
const row = [timestamps[i]];
for (const s of series) {
row.push(s.data[i] != null ? s.data[i] : '');
}
csv += row.join(',') + '\n';
}
const blob = new Blob([csv], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `neighbor_snr_{{ node_id }}.csv`;
a.click();
URL.revokeObjectURL(url);
});
});
</script>