fix: add favorites filter to live map

Fixes Kpa-clawbot/meshcore-analyzer#106
This commit is contained in:
you
2026-03-21 05:34:51 +00:00
parent 0ef1eb2595
commit dc6df38c9a
2 changed files with 54 additions and 1 deletions
+1 -1
View File
@@ -88,7 +88,7 @@
<script src="nodes.js?v=1774064852" onerror="console.error('Failed to load:', this.src)"></script>
<script src="traces.js?v=1774048777" onerror="console.error('Failed to load:', this.src)"></script>
<script src="analytics.js?v=1774083840" onerror="console.error('Failed to load:', this.src)"></script>
<script src="live.js?v=1774083841" onerror="console.error('Failed to load:', this.src)"></script>
<script src="live.js?v=1774256400" onerror="console.error('Failed to load:', this.src)"></script>
<script src="observers.js?v=1774018095" onerror="console.error('Failed to load:', this.src)"></script>
<script src="observer-detail.js?v=1774028201" onerror="console.error('Failed to load:', this.src)"></script>
<script src="node-analytics.js?v=1774042199" onerror="console.error('Failed to load:', this.src)"></script>
+53
View File
@@ -12,6 +12,7 @@
let soundEnabled = false;
let showGhostHops = localStorage.getItem('live-ghost-hops') !== 'false';
let realisticPropagation = localStorage.getItem('live-realistic-propagation') === 'true';
let showOnlyFavorites = localStorage.getItem('live-favorites-only') === 'true';
const propagationBuffer = new Map(); // hash -> {timer, packets[]}
let _onResize = null;
let _navCleanup = null;
@@ -630,6 +631,8 @@
<span id="ghostDesc" class="sr-only">Show interpolated ghost markers for unknown hops</span>
<label><input type="checkbox" id="liveRealisticToggle" aria-describedby="realisticDesc"> Realistic</label>
<span id="realisticDesc" class="sr-only">Buffer packets by hash and animate all paths simultaneously</span>
<label><input type="checkbox" id="liveFavoritesToggle" aria-describedby="favDesc"> ⭐ Favorites</label>
<span id="favDesc" class="sr-only">Show only favorited and claimed nodes</span>
</div>
</div>
<div class="live-overlay live-feed" id="liveFeed">
@@ -775,6 +778,14 @@
localStorage.setItem('live-realistic-propagation', realisticPropagation);
});
const favoritesToggle = document.getElementById('liveFavoritesToggle');
favoritesToggle.checked = showOnlyFavorites;
favoritesToggle.addEventListener('change', (e) => {
showOnlyFavorites = e.target.checked;
localStorage.setItem('live-favorites-only', showOnlyFavorites);
applyFavoritesFilter();
});
// Feed show/hide
const feedEl = document.getElementById('liveFeed');
// Keyboard support for feed items (event delegation)
@@ -1181,6 +1192,37 @@
if (heatLayer) { map.removeLayer(heatLayer); heatLayer = null; }
}
function getLiveFavorites() {
try { return new Set(JSON.parse(localStorage.getItem('meshcore-favorites') || '[]')); } catch { return new Set(); }
}
function getLiveMyNodes() {
try { return new Set(JSON.parse(localStorage.getItem('meshcore-my-nodes') || '[]')); } catch { return new Set(); }
}
function isNodeFavorited(pubkey) {
const favs = getLiveFavorites();
const mine = getLiveMyNodes();
return favs.has(pubkey) || mine.has(pubkey);
}
function applyFavoritesFilter() {
Object.keys(nodeMarkers).forEach(key => {
const marker = nodeMarkers[key];
if (!marker) return;
const visible = !showOnlyFavorites || isNodeFavorited(key);
if (visible) {
if (!nodesLayer.hasLayer(marker)) { marker.addTo(nodesLayer); if (marker._glowMarker) marker._glowMarker.addTo(nodesLayer); }
} else {
if (nodesLayer.hasLayer(marker)) { nodesLayer.removeLayer(marker); if (marker._glowMarker) nodesLayer.removeLayer(marker._glowMarker); }
}
});
const _el2 = document.getElementById('liveNodeCount');
if (_el2) {
const count = showOnlyFavorites
? Object.keys(nodeMarkers).filter(k => isNodeFavorited(k)).length
: Object.keys(nodeMarkers).length;
_el2.textContent = count;
}
}
function addNodeMarker(n) {
if (nodeMarkers[n.public_key]) return nodeMarkers[n.public_key];
const color = ROLE_COLORS[n.role] || ROLE_COLORS.unknown;
@@ -1208,6 +1250,10 @@
marker._baseColor = color;
marker._baseSize = size;
nodeMarkers[n.public_key] = marker;
if (showOnlyFavorites && !isNodeFavorited(n.public_key)) {
nodesLayer.removeLayer(marker);
nodesLayer.removeLayer(glow);
}
return marker;
}
@@ -1269,6 +1315,13 @@
playSound(typeName);
addFeedItem(icon, typeName, payload, hops, color, pkt);
// Favorites filter: skip animation if no involved nodes are favorited
if (showOnlyFavorites) {
const involvedKeys = hops.map(h => h.id || h.public_key).filter(Boolean);
if (payload.pubKey) involvedKeys.push(payload.pubKey);
if (!involvedKeys.some(k => isNodeFavorited(k))) return;
}
// If ADVERT, ensure node appears on map
if (typeName === 'ADVERT' && payload.pubKey) {
const key = payload.pubKey;