mirror of
https://github.com/Roslund/sthlm-mesh.git
synced 2026-08-08 09:53:04 +02:00
Add filter to the portnum distrubation chart
This commit is contained in:
@@ -57,7 +57,17 @@ För mer info se vår [dokumentation]({{<ref position.md>}}#position-precision).
|
||||
|
||||
|
||||
## Packet typer
|
||||
Fördelningen av olika pakettyper i nätverket under de senaste dygnet. Diagrammet visar hur nätverket används, inklusive meddelanden, positionstelemetri och andra systempaket.
|
||||
Fördelningen av olika pakettyper i nätverket under de senaste dygnet. Diagrammet visar hur nätverket används, inklusive meddelanden, positionstelemetri och andra systempaket. Sökrutan till höger kan användas för att visa antalet paket av respektive typ för en given nod.
|
||||
|
||||
<div class="d-flex justify-content-end m-0 p-0" style="max-width: 1000px">
|
||||
<div class="dropdown" style="width: 33%;">
|
||||
<div class="input-group pe-3">
|
||||
<input id="nodeSearch" type="text" class="form-control" placeholder="Node Name" autocomplete="off">
|
||||
<button id="clearFilterBtn" class="btn btn-outline-info" type="button">✕</button>
|
||||
</div>
|
||||
<ul id="suggestions" class="dropdown-menu w-100" style="display: none; max-height: 300px; overflow-y: auto; position: absolute; z-index: 1000;"></ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="portnumDistributionContainer" style="width: 100%;max-width: 1000px;">
|
||||
<canvas id="portnumDistribution"></canvas>
|
||||
</div>
|
||||
|
||||
@@ -1,31 +1,150 @@
|
||||
async function portnumDistributionChart() {
|
||||
let allNodes = [];
|
||||
let highlightedIndex = -1;
|
||||
let chartInstance;
|
||||
|
||||
|
||||
async function fetchNodes() {
|
||||
const res = await fetch('https://map.sthlm-mesh.se/api/v1/nodes/');
|
||||
const data = await res.json();
|
||||
|
||||
const threshold = new Date();
|
||||
threshold.setDate(threshold.getDate() - 1);
|
||||
allNodes = data.nodes.filter(node => new Date(node.updated_at) >= threshold);
|
||||
}
|
||||
|
||||
function filterSuggestions(query) {
|
||||
const lowerQuery = query.toLowerCase();
|
||||
return allNodes?.filter(node => node.long_name?.toLowerCase().includes(lowerQuery)) || [];
|
||||
}
|
||||
|
||||
function showSuggestions(matches) {
|
||||
const ul = document.getElementById('suggestions');
|
||||
ul.innerHTML = '';
|
||||
|
||||
if (matches.length === 0) {
|
||||
ul.innerHTML = '<li class="dropdown-item text-muted disabled">No matching nodes</li>';
|
||||
ul.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
|
||||
matches.forEach(node => {
|
||||
const li = document.createElement('li');
|
||||
const a = document.createElement('a');
|
||||
a.className = 'dropdown-item';
|
||||
a.href = '#';
|
||||
a.textContent = node.long_name;
|
||||
a.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
document.getElementById('nodeSearch').value = node.long_name;
|
||||
ul.style.display = 'none';
|
||||
portnumDistributionChart(node.node_id);
|
||||
});
|
||||
li.appendChild(a);
|
||||
ul.appendChild(li);
|
||||
});
|
||||
|
||||
ul.style.display = 'block';
|
||||
}
|
||||
|
||||
function updateHighlight(suggestions) {
|
||||
suggestions.forEach((el, i) => {
|
||||
if (i === highlightedIndex) {
|
||||
el.classList.add('active');
|
||||
} else {
|
||||
el.classList.remove('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById('nodeSearch').addEventListener('keydown', (e) => {
|
||||
const suggestions = document.querySelectorAll('#suggestions .dropdown-item');
|
||||
|
||||
if (suggestions.length === 0) return;
|
||||
|
||||
switch (e.key) {
|
||||
case 'ArrowDown':
|
||||
e.preventDefault();
|
||||
highlightedIndex = (highlightedIndex + 1) % suggestions.length;
|
||||
updateHighlight(suggestions);
|
||||
break;
|
||||
|
||||
case 'ArrowUp':
|
||||
e.preventDefault();
|
||||
highlightedIndex = (highlightedIndex - 1 + suggestions.length) % suggestions.length;
|
||||
updateHighlight(suggestions);
|
||||
break;
|
||||
|
||||
case 'Enter':
|
||||
e.preventDefault();
|
||||
if (highlightedIndex >= 0) {
|
||||
suggestions[highlightedIndex].click();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Escape':
|
||||
document.getElementById('nodeSearch').value = '';
|
||||
document.getElementById('suggestions').style.display = 'none';
|
||||
portnumDistributionChart(); // Reload full chart
|
||||
highlightedIndex = -1;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('nodeSearch').addEventListener('input', (e) => {
|
||||
highlightedIndex = -1;
|
||||
const matches = filterSuggestions(e.target.value);
|
||||
showSuggestions(matches);
|
||||
});
|
||||
|
||||
document.getElementById('clearFilterBtn').addEventListener('click', () => {
|
||||
highlightedIndex = -1;
|
||||
document.getElementById('nodeSearch').value = '';
|
||||
document.getElementById('suggestions').style.display = 'none';
|
||||
portnumDistributionChart(); // Reload full chart
|
||||
});
|
||||
|
||||
// Main chart function
|
||||
async function portnumDistributionChart(nodeId = null) {
|
||||
const canvas = document.getElementById('portnumDistribution');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// Loading message
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.font = '16px Arial';
|
||||
ctx.fillStyle = 'gray';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText('Loading data...', canvas.width / 2, canvas.height / 2);
|
||||
|
||||
try {
|
||||
const response = await fetch('https://map.sthlm-mesh.se/api/v1/stats/portnum-counts');
|
||||
const url = nodeId
|
||||
? `https://map.sthlm-mesh.se/api/v1/stats/portnum-counts?nodeId=${nodeId}`
|
||||
: 'https://map.sthlm-mesh.se/api/v1/stats/portnum-counts';
|
||||
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
|
||||
const labels = data.map(entry => entry.label.replace(/_APP$/, ''));
|
||||
const counts = data.map(entry => entry.count);
|
||||
|
||||
// Optional: dynamically size the container
|
||||
const backgroundColors = counts.map(count => {
|
||||
if (nodeId) {
|
||||
// Filtered chart: use tighter thresholds
|
||||
if (count < 50) return '#7EB26D'; // Green
|
||||
if (count < 100) return '#EAB839'; // Yellow
|
||||
return '#BF1B00'; // Red
|
||||
} else {
|
||||
// Global chart: use broader thresholds
|
||||
if (count < 500) return '#7EB26D'; // Green
|
||||
if (count < 2000) return '#EAB839'; // Yellow
|
||||
return '#BF1B00'; // Red
|
||||
}
|
||||
});
|
||||
|
||||
const chartContainer = document.getElementById('portnumDistributionContainer');
|
||||
chartContainer.style.height = `${labels.length * 35}px`;
|
||||
|
||||
const backgroundColors = counts.map(count => {
|
||||
if (count < 500) return '#7EB26D'; // Green
|
||||
if (count < 2000) return '#EAB839'; // Yellow
|
||||
return '#BF1B00'; // Red
|
||||
});
|
||||
if (chartInstance) chartInstance.destroy();
|
||||
|
||||
new Chart(ctx, {
|
||||
chartInstance = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
@@ -59,4 +178,4 @@ async function portnumDistributionChart() {
|
||||
}
|
||||
}
|
||||
|
||||
portnumDistributionChart();
|
||||
fetchNodes().then(() => portnumDistributionChart());
|
||||
|
||||
Reference in New Issue
Block a user