mirror of
https://github.com/pablorevilla-meshtastic/meshview.git
synced 2026-03-04 23:27:46 +01:00
nodelist now also works with API
This commit is contained in:
@@ -115,6 +115,24 @@
|
||||
<div id="total_portnum_71" class="total-count">Total: 0</div>
|
||||
<div id="chart_portnum_71" class="chart"></div>
|
||||
</div>
|
||||
|
||||
<!-- Hardware breakdown -->
|
||||
<div class="card-section">
|
||||
<p class="section-header">Hardware Breakdown</p>
|
||||
<div id="chart_hw_model" class="chart"></div>
|
||||
</div>
|
||||
|
||||
<!-- Role breakdown -->
|
||||
<div class="card-section">
|
||||
<p class="section-header">Role Breakdown</p>
|
||||
<div id="chart_role" class="chart"></div>
|
||||
</div>
|
||||
|
||||
<!-- Channel breakdown -->
|
||||
<div class="card-section">
|
||||
<p class="section-header">Channel Breakdown</p>
|
||||
<div id="chart_channel" class="chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@@ -137,6 +155,30 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchNodes() {
|
||||
try {
|
||||
const res = await fetch("/api/nodes");
|
||||
if (!res.ok) {
|
||||
console.error("Failed to fetch nodes:", res.status, res.statusText);
|
||||
return [];
|
||||
}
|
||||
const json = await res.json();
|
||||
return json.nodes || [];
|
||||
} catch (err) {
|
||||
console.error("Error fetching nodes:", err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function processCountField(nodes, field) {
|
||||
const counts = {};
|
||||
nodes.forEach(n => {
|
||||
const key = n[field] || "Unknown";
|
||||
counts[key] = (counts[key] || 0) + 1;
|
||||
});
|
||||
return Object.entries(counts).map(([name, value]) => ({ name, value }));
|
||||
}
|
||||
|
||||
function updateTotalCount(domId, data) {
|
||||
const el = document.getElementById(domId);
|
||||
if (!el || !data.length) return;
|
||||
@@ -144,15 +186,21 @@
|
||||
el.textContent = `Total: ${total.toLocaleString()}`;
|
||||
}
|
||||
|
||||
let chartHourlyAll = null;
|
||||
let chartPortnum1 = null;
|
||||
let chartPortnum3 = null;
|
||||
let chartPortnum4 = null;
|
||||
let chartPortnum67 = null;
|
||||
let chartPortnum70 = null;
|
||||
let chartPortnum71 = null;
|
||||
let chartDailyAll = null;
|
||||
let chartDailyPortnum1 = null;
|
||||
// Chart variables
|
||||
let chartHourlyAll, chartPortnum1, chartPortnum3, chartPortnum4, chartPortnum67, chartPortnum70, chartPortnum71;
|
||||
let chartDailyAll, chartDailyPortnum1;
|
||||
let chartHwModel, chartRole, chartChannel;
|
||||
|
||||
// Utility function for top N + "Other"
|
||||
function prepareTopN(data, n = 20) {
|
||||
data.sort((a, b) => b.value - a.value);
|
||||
let top = data.slice(0, n);
|
||||
if (data.length > n) {
|
||||
const otherValue = data.slice(n).reduce((sum, item) => sum + item.value, 0);
|
||||
top.push({ name: "Other", value: otherValue });
|
||||
}
|
||||
return top;
|
||||
}
|
||||
|
||||
function renderChart(domId, data, type, color, isHourly) {
|
||||
const el = document.getElementById(domId);
|
||||
@@ -208,6 +256,35 @@
|
||||
chart.setOption(option);
|
||||
}
|
||||
|
||||
function renderPieChart(elId, data, name) {
|
||||
const el = document.getElementById(elId);
|
||||
if (!el) return;
|
||||
const chart = echarts.init(el);
|
||||
|
||||
const top20 = prepareTopN(data, 20);
|
||||
|
||||
const option = {
|
||||
backgroundColor: "#272b2f",
|
||||
tooltip: { trigger: "item", formatter: "{b}: {d}% ({c})" },
|
||||
series: [
|
||||
{
|
||||
name: name,
|
||||
type: "pie",
|
||||
radius: ["30%", "70%"],
|
||||
center: ["50%", "50%"],
|
||||
avoidLabelOverlap: true,
|
||||
itemStyle: { borderRadius: 6, borderColor: "#272b2f", borderWidth: 2 },
|
||||
label: { show: true, formatter: "{b}\n{d}%", color: "#ccc", fontSize: 10 },
|
||||
labelLine: { show: true, length: 10, length2: 6 },
|
||||
data: top20
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
chart.setOption(option);
|
||||
return chart;
|
||||
}
|
||||
|
||||
async function init() {
|
||||
// Daily all ports
|
||||
const dailyAllData = await fetchStats('day', 14);
|
||||
@@ -227,41 +304,25 @@
|
||||
// Hourly by port
|
||||
const portnums = [1, 3, 4, 67, 70, 71];
|
||||
const colors = ['#ff5722', '#2196f3', '#9c27b0', '#ffeb3b', '#795548', '#4caf50'];
|
||||
const domIds = [
|
||||
'chart_portnum_1',
|
||||
'chart_portnum_3',
|
||||
'chart_portnum_4',
|
||||
'chart_portnum_67',
|
||||
'chart_portnum_70',
|
||||
'chart_portnum_71'
|
||||
];
|
||||
const totalIds = [
|
||||
'total_portnum_1',
|
||||
'total_portnum_3',
|
||||
'total_portnum_4',
|
||||
'total_portnum_67',
|
||||
'total_portnum_70',
|
||||
'total_portnum_71'
|
||||
];
|
||||
const domIds = ['chart_portnum_1','chart_portnum_3','chart_portnum_4','chart_portnum_67','chart_portnum_70','chart_portnum_71'];
|
||||
const totalIds = ['total_portnum_1','total_portnum_3','total_portnum_4','total_portnum_67','total_portnum_70','total_portnum_71'];
|
||||
|
||||
const allData = await Promise.all(portnums.map(pn => fetchStats('hour', 24, pn)));
|
||||
|
||||
for (let i = 0; i < portnums.length; i++) {
|
||||
updateTotalCount(totalIds[i], allData[i]);
|
||||
renderChart(domIds[i], allData[i], 'bar', colors[i], true);
|
||||
}
|
||||
|
||||
// Nodes breakdown charts
|
||||
const nodes = await fetchNodes();
|
||||
renderPieChart("chart_hw_model", processCountField(nodes, "hw_model"), "Hardware");
|
||||
renderPieChart("chart_role", processCountField(nodes, "role"), "Role");
|
||||
renderPieChart("chart_channel", processCountField(nodes, "channel"), "Channel");
|
||||
}
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
if (chartHourlyAll) chartHourlyAll.resize();
|
||||
if (chartPortnum1) chartPortnum1.resize();
|
||||
if (chartPortnum3) chartPortnum3.resize();
|
||||
if (chartPortnum4) chartPortnum4.resize();
|
||||
if (chartPortnum67) chartPortnum67.resize();
|
||||
if (chartPortnum70) chartPortnum70.resize();
|
||||
if (chartPortnum71) chartPortnum71.resize();
|
||||
if (chartDailyAll) chartDailyAll.resize();
|
||||
if (chartDailyPortnum1) chartDailyPortnum1.resize();
|
||||
[chartHourlyAll, chartPortnum1, chartPortnum3, chartPortnum4, chartPortnum67, chartPortnum70, chartPortnum71, chartDailyAll, chartDailyPortnum1, chartHwModel, chartRole, chartChannel]
|
||||
.forEach(c => c?.resize());
|
||||
});
|
||||
|
||||
init();
|
||||
|
||||
Reference in New Issue
Block a user