mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-05-15 09:25:06 +00:00
Add hash size labels for repeater markers on map
- Compute hash_size from ADVERT packets in /api/nodes response - Show colored rectangle markers with hash size (e.g. '2B') for repeaters - Add 'Hash size labels' toggle in map controls (default ON, saved to localStorage) - Non-repeater markers unchanged
This commit is contained in:
+1
-1
@@ -83,7 +83,7 @@
|
||||
<script src="app.js?v=1774052279"></script>
|
||||
<script src="home.js?v=1774042199"></script>
|
||||
<script src="packets.js?v=1774052279"></script>
|
||||
<script src="map.js?v=1774028201" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="map.js?v=1774052355" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="channels.js?v=1774050030" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="nodes.js?v=1774050030" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="traces.js?v=1774048777" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
|
||||
+24
-2
@@ -8,7 +8,7 @@
|
||||
let clusterGroup = null;
|
||||
let nodes = [];
|
||||
let observers = [];
|
||||
let filters = { repeater: true, companion: true, room: true, sensor: true, observer: true, lastHeard: '30d', neighbors: false, clusters: false };
|
||||
let filters = { repeater: true, companion: true, room: true, sensor: true, observer: true, lastHeard: '30d', neighbors: false, clusters: false, hashLabels: localStorage.getItem('meshcore-map-hash-labels') !== 'false' };
|
||||
let wsHandler = null;
|
||||
let heatLayer = null;
|
||||
let userHasMoved = false;
|
||||
@@ -60,6 +60,20 @@
|
||||
});
|
||||
}
|
||||
|
||||
function makeRepeaterLabelIcon(node) {
|
||||
var hashSize = node.hash_size || 1;
|
||||
var s = ROLE_STYLE['repeater'] || ROLE_STYLE.companion;
|
||||
var label = hashSize + 'B';
|
||||
var html = '<div style="background:' + s.color + ';color:#fff;font-weight:bold;font-size:12px;padding:3px 7px;border-radius:4px;border:2px solid #fff;box-shadow:0 1px 3px rgba(0,0,0,0.4);text-align:center;line-height:1;">' + label + '</div>';
|
||||
return L.divIcon({
|
||||
html: html,
|
||||
className: 'meshcore-marker meshcore-label-marker',
|
||||
iconSize: null,
|
||||
iconAnchor: [14, 12],
|
||||
popupAnchor: [0, -12],
|
||||
});
|
||||
}
|
||||
|
||||
function init(container) {
|
||||
container.innerHTML = `
|
||||
<div id="map-wrap" style="position:relative;width:100%;height:100%;">
|
||||
@@ -79,6 +93,7 @@
|
||||
<fieldset class="mc-section">
|
||||
<legend class="mc-label">Filters</legend>
|
||||
<label for="mcNeighbors"><input type="checkbox" id="mcNeighbors"> Show direct neighbors</label>
|
||||
<label for="mcHashLabels"><input type="checkbox" id="mcHashLabels"> Hash size labels</label>
|
||||
</fieldset>
|
||||
<fieldset class="mc-section">
|
||||
<legend class="mc-label">Last Heard</legend>
|
||||
@@ -154,6 +169,13 @@
|
||||
document.getElementById('mcClusters').addEventListener('change', e => { filters.clusters = e.target.checked; renderMarkers(); });
|
||||
document.getElementById('mcHeatmap').addEventListener('change', e => { toggleHeatmap(e.target.checked); });
|
||||
document.getElementById('mcNeighbors').addEventListener('change', e => { filters.neighbors = e.target.checked; renderMarkers(); });
|
||||
|
||||
// Hash Labels toggle
|
||||
const hashLabelEl = document.getElementById('mcHashLabels');
|
||||
if (hashLabelEl) {
|
||||
hashLabelEl.checked = filters.hashLabels;
|
||||
hashLabelEl.addEventListener('change', e => { filters.hashLabels = e.target.checked; localStorage.setItem('meshcore-map-hash-labels', filters.hashLabels); renderMarkers(); });
|
||||
}
|
||||
document.getElementById('mcLastHeard').addEventListener('change', e => { filters.lastHeard = e.target.value; loadNodes(); });
|
||||
|
||||
// WS for live advert updates
|
||||
@@ -355,7 +377,7 @@
|
||||
});
|
||||
|
||||
for (const node of filtered) {
|
||||
const icon = makeMarkerIcon(node.role || 'companion');
|
||||
const icon = (node.role === 'repeater' && filters.hashLabels) ? makeRepeaterLabelIcon(node) : makeMarkerIcon(node.role || 'companion');
|
||||
const marker = L.marker([node.lat, node.lon], {
|
||||
icon,
|
||||
alt: `${node.name || 'Unknown'} (${node.role || 'node'})`,
|
||||
|
||||
@@ -973,6 +973,24 @@ app.get('/api/nodes', (req, res) => {
|
||||
counts[r + 's'] = db.db.prepare(`SELECT COUNT(*) as count FROM nodes WHERE role = ?`).get(r).count;
|
||||
}
|
||||
|
||||
// Compute hash_size for each node from latest ADVERT packets
|
||||
const hashSizeMap = new Map();
|
||||
for (const p of pktStore.packets) {
|
||||
if (p.payload_type === 4 && p.decoded_json) {
|
||||
try {
|
||||
const d = JSON.parse(p.decoded_json);
|
||||
const pk = d.pubKey || d.public_key;
|
||||
if (pk && p.raw_hex && !hashSizeMap.has(pk)) {
|
||||
const pathByte = parseInt(p.raw_hex.slice(2, 4), 16);
|
||||
hashSizeMap.set(pk, ((pathByte >> 6) & 0x3) + 1);
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
for (const node of nodes) {
|
||||
node.hash_size = hashSizeMap.get(node.public_key) || null;
|
||||
}
|
||||
|
||||
res.json({ nodes, total, counts });
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user