mirror of
https://github.com/pablorevilla-meshtastic/meshview.git
synced 2026-03-04 23:27:46 +01:00
Modified the power and battery graph to show both axis
This commit is contained in:
@@ -1,15 +1,14 @@
|
||||
<!-- Macro -->
|
||||
{% macro graph(name) %}
|
||||
<div id="{{name}}Chart" style="width: 100%; height: 100%;"></div>
|
||||
{% endmacro %}
|
||||
|
||||
<!-- Buttons for Download CSV and Expand Modal -->
|
||||
<!-- Download and Expand buttons -->
|
||||
<div class="d-flex justify-content-end mb-2">
|
||||
<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>
|
||||
|
||||
<!-- Tabs -->
|
||||
<!-- Tab Navigation -->
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
{% for name in [
|
||||
"power", "utilization", "temperature", "humidity", "pressure",
|
||||
@@ -21,7 +20,7 @@
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<!-- Tab content -->
|
||||
<!-- Tab Content -->
|
||||
<div class="tab-content mt-3" style="height: 40vh;">
|
||||
{% for name in [
|
||||
"power", "utilization", "temperature", "humidity", "pressure",
|
||||
@@ -33,7 +32,7 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Fullscreen Modal for graphs -->
|
||||
<!-- 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 text-white">
|
||||
@@ -68,11 +67,10 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
if (!resp.ok) throw new Error(`Failed to load data for ${name}`);
|
||||
const data = await resp.json();
|
||||
|
||||
// Reverse to go left-to-right
|
||||
// Reverse for chronological order
|
||||
data.timestamps.reverse();
|
||||
data.series.forEach(s => s.data.reverse());
|
||||
|
||||
// Format timestamps as MM-DD-YY
|
||||
const formattedDates = data.timestamps.map(t => {
|
||||
const d = new Date(t);
|
||||
return `${(d.getMonth() + 1).toString().padStart(2, '0')}-${d.getDate().toString().padStart(2, '0')}-${d.getFullYear().toString().slice(-2)}`;
|
||||
@@ -84,14 +82,45 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
};
|
||||
|
||||
const chart = echarts.init(chartDiv);
|
||||
|
||||
const isDualAxis = name === 'power';
|
||||
|
||||
chart.setOption({
|
||||
tooltip: { trigger: 'axis' },
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: function (params) {
|
||||
return params.map(p => {
|
||||
const label = p.seriesName.toLowerCase();
|
||||
const unit = label.includes('volt') ? 'V' : label.includes('battery') ? '%' : '';
|
||||
return `${p.marker} ${p.seriesName}: ${p.data}${unit}`;
|
||||
}).join('<br>');
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: formattedDates,
|
||||
axisLabel: { color: '#fff', rotate: 45 },
|
||||
},
|
||||
yAxis: {
|
||||
yAxis: isDualAxis ? [
|
||||
{
|
||||
type: 'value',
|
||||
name: 'Battery (%)',
|
||||
min: 0,
|
||||
max: 120,
|
||||
position: 'left',
|
||||
axisLabel: { color: '#fff' },
|
||||
nameTextStyle: { color: '#fff' }
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: 'Voltage (V)',
|
||||
min: 0,
|
||||
max: 6,
|
||||
position: 'right',
|
||||
axisLabel: { color: '#fff' },
|
||||
nameTextStyle: { color: '#fff' }
|
||||
}
|
||||
] : {
|
||||
type: 'value',
|
||||
axisLabel: { color: '#fff' },
|
||||
},
|
||||
@@ -102,6 +131,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
smooth: true,
|
||||
connectNulls: true,
|
||||
showSymbol: false,
|
||||
yAxisIndex: isDualAxis && s.name.toLowerCase().includes('volt') ? 1 : 0,
|
||||
})),
|
||||
legend: { textStyle: { color: '#fff' } }
|
||||
});
|
||||
@@ -111,11 +141,12 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
console.error(err);
|
||||
currentChartData = null;
|
||||
currentChartName = null;
|
||||
chartDiv.innerHTML = `<div class="text-white text-center mt-5">Error loading ${name} data.</div>`;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Load the first chart
|
||||
// Load first chart
|
||||
const firstTabBtn = document.querySelector('.nav-tabs button.nav-link.active');
|
||||
if (firstTabBtn) {
|
||||
const name = firstTabBtn.textContent.toLowerCase();
|
||||
@@ -123,7 +154,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
loadChart(name, chartId).then(chart => currentChart = chart);
|
||||
}
|
||||
|
||||
// Tab change event
|
||||
// On tab switch
|
||||
document.querySelectorAll('.nav-tabs button.nav-link').forEach(button => {
|
||||
button.addEventListener('shown.bs.tab', event => {
|
||||
const name = event.target.textContent.toLowerCase();
|
||||
@@ -132,7 +163,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
});
|
||||
});
|
||||
|
||||
// Download CSV button
|
||||
// CSV Download
|
||||
document.getElementById('downloadCsvBtn').addEventListener('click', () => {
|
||||
if (!currentChartData || !currentChartName) {
|
||||
alert("Chart data not loaded yet.");
|
||||
@@ -159,7 +190,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
URL.revokeObjectURL(url);
|
||||
});
|
||||
|
||||
// Expand chart modal
|
||||
// Fullscreen modal chart
|
||||
document.getElementById('fullChartModal').addEventListener('shown.bs.modal', () => {
|
||||
if (!currentChartData || !currentChartName) return;
|
||||
|
||||
@@ -167,15 +198,45 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
fullChart = echarts.init(document.getElementById('fullChartContainer'));
|
||||
}
|
||||
|
||||
const isDualAxis = currentChartName === 'power';
|
||||
|
||||
fullChart.setOption({
|
||||
title: { text: currentChartName.charAt(0).toUpperCase() + currentChartName.slice(1), textStyle: { color: '#fff' } },
|
||||
tooltip: { trigger: 'axis' },
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: function (params) {
|
||||
return params.map(p => {
|
||||
const label = p.seriesName.toLowerCase();
|
||||
const unit = label.includes('volt') ? 'V' : label.includes('battery') ? '%' : '';
|
||||
return `${p.marker} ${p.seriesName}: ${p.data}${unit}`;
|
||||
}).join('<br>');
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: currentChartData.timestamps,
|
||||
axisLabel: { color: '#fff', rotate: 45 },
|
||||
},
|
||||
yAxis: {
|
||||
yAxis: isDualAxis ? [
|
||||
{
|
||||
type: 'value',
|
||||
name: 'Battery (%)',
|
||||
min: 0,
|
||||
max: 120,
|
||||
position: 'left',
|
||||
axisLabel: { color: '#fff' },
|
||||
nameTextStyle: { color: '#fff' }
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: 'Voltage (V)',
|
||||
min: 0,
|
||||
max: 6,
|
||||
position: 'right',
|
||||
axisLabel: { color: '#fff' },
|
||||
nameTextStyle: { color: '#fff' }
|
||||
}
|
||||
] : {
|
||||
type: 'value',
|
||||
axisLabel: { color: '#fff' },
|
||||
},
|
||||
@@ -186,6 +247,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
smooth: true,
|
||||
connectNulls: true,
|
||||
showSymbol: false,
|
||||
yAxisIndex: isDualAxis && s.name.toLowerCase().includes('volt') ? 1 : 0,
|
||||
})),
|
||||
legend: { textStyle: { color: '#fff' } }
|
||||
});
|
||||
@@ -198,4 +260,4 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
if (currentChart) currentChart.resize();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -568,9 +568,6 @@ async def graph_telemetry_json(node_id, payload_type, graph_config):
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@routes.get("/graph/neighbors_json/{node_id}")
|
||||
async def graph_neighbors_json(request):
|
||||
import datetime
|
||||
|
||||
Reference in New Issue
Block a user