diff --git a/meshview/templates/map.html b/meshview/templates/map.html index d17c3fb..130a75d 100644 --- a/meshview/templates/map.html +++ b/meshview/templates/map.html @@ -75,6 +75,7 @@ var nodes = [ {% endfor %} ]; +// Helper maps const portMap = { 1: "Text", 67: "Telemetry", @@ -86,19 +87,19 @@ const portMap = { }; function timeAgo(date) { - var now = new Date(); + var now = Date.now(); var diff = now - new Date(date); var seconds = Math.floor(diff / 1000); var minutes = Math.floor(seconds / 60); var hours = Math.floor(minutes / 60); var days = Math.floor(hours / 24); - if (days > 0) return days + "d"; if (hours > 0) return hours + "h"; if (minutes > 0) return minutes + "m"; return seconds + "s"; } +// Color palette const palette = [ "#e6194b","#4363d8","#f58231","#911eb4","#46f0f0","#f032e6","#bcf60c","#fabebe", "#008080","#e6beff","#9a6324","#fffac8","#800000","#aaffc3","#808000","#ffd8b1","#000075","#808080" @@ -113,10 +114,14 @@ function hashToColor(str) { return color; } -// Plot nodes +// Create node map for fast lookup +const nodeMap = new Map(); +nodes.forEach(n => nodeMap.set(n.id, n)); + var bounds = L.latLngBounds(); var channels = new Set(); +// --- Plot nodes --- nodes.forEach(function(node) { if (node.lat !== null && node.long !== null) { let category = node.channel; @@ -142,6 +147,7 @@ nodes.forEach(function(node) { var marker = L.circleMarker([node.lat, node.long], markerOptions).addTo(map); marker.nodeId = node.id; + marker.originalColor = color; markerById[node.id] = marker; marker.on('click', function() { @@ -163,7 +169,7 @@ var bayAreaBounds = [ ]; map.fitBounds(bayAreaBounds); -// Channel filters +// --- Filters --- let filterContainer = document.getElementById("filter-container"); channels.forEach(channel => { let filterId = `filter-${channel.replace(/\s+/g, '-').toLowerCase()}`; @@ -174,15 +180,25 @@ channels.forEach(channel => { filterContainer.appendChild(label); }); +function isMarkerVisible(marker) { + return map.hasLayer(marker); +} + function updateMarkers() { let showRoutersOnly = document.getElementById("filter-routers-only").checked; - channels.forEach(channel => { - let filterId = `filter-${channel.replace(/\s+/g, '-').toLowerCase()}`; - let isChecked = document.getElementById(filterId).checked; - markers[channel].forEach(obj => { - let shouldShow = isChecked && (!showRoutersOnly || obj.isRouter); - shouldShow ? map.addLayer(obj.marker) : map.removeLayer(obj.marker); - }); + nodes.forEach(node => { + let category = node.channel; + let checkbox = document.getElementById(`filter-${category.replace(/\s+/g,'-').toLowerCase()}`); + let shouldShow = checkbox.checked && (!showRoutersOnly || node.isRouter); + let marker = markerById[node.id]; + if (shouldShow) map.addLayer(marker); + else map.removeLayer(marker); + + // Remove blinking tooltip if hidden + if (!shouldShow && marker.tooltip) { + map.removeLayer(marker.tooltip); + marker.tooltip = null; + } }); } @@ -205,46 +221,29 @@ function loadEdges(callback) { } function onNodeClick(node) { - console.log(`Clicked node ${node.long_name}: lat=${node.lat}, long=${node.long}`); - loadEdges(edges => { edgeLayer.clearLayers(); edges.forEach(edge => { - // Only draw edges connected to the clicked node if (edge.from !== node.id && edge.to !== node.id) return; + let fromNode = nodeMap.get(edge.from); + let toNode = nodeMap.get(edge.to); + if (!fromNode || !toNode) return; + if (!fromNode.lat || !fromNode.long || !toNode.lat || !toNode.long) return; - let fromNode = nodes.find(n => n.id === edge.from); - let toNode = nodes.find(n => n.id === edge.to); + let lineColor = edge.type === "neighbor" ? "red" : "blue"; + let dash = edge.type === "traceroute" ? "5,5" : null; - // Only draw if lat/long are not 0 - if (fromNode && toNode && - fromNode.lat !== 0 && fromNode.long !== 0 && - toNode.lat !== 0 && toNode.long !== 0) { - - let otherNode = edge.from === node.id ? toNode : fromNode; - console.log(` Connected to node ${otherNode.long_name}: lat=${otherNode.lat}, long=${otherNode.long}`); - - L.polyline( - [[fromNode.lat, fromNode.long], [toNode.lat, toNode.long]], - { - color: edge.type === "neighbor" ? "red" : "blue", - weight: 2, - opacity: 1, - dashArray: edge.type === "traceroute" ? "5,5" : null - } - ).addTo(edgeLayer); - } + L.polyline( + [[fromNode.lat, fromNode.long], [toNode.lat, toNode.long]], + { color: lineColor, weight: 2, opacity: 1, dashArray: dash } + ).addTo(edgeLayer); }); }); } - -// Attach edge click events nodes.forEach(node => { - if (node.lat != null && node.long != null) { - let marker = markerById[node.id]; - if (marker) marker.on('click', () => onNodeClick(node)); - } + let marker = markerById[node.id]; + if (marker) marker.on('click', () => onNodeClick(node)); }); // --- Blinking nodes --- @@ -257,19 +256,20 @@ function fetchLatestPacket() { .then(data => { if (data.packets && data.packets.length > 0) lastFetchTime = data.packets[0].import_time; else lastFetchTime = new Date().toISOString(); - console.log("Starting from:", lastFetchTime); }) .catch(err => console.error("Error fetching latest packet:", err)); } function blinkNode(marker, longName, portnum) { + if (!isMarkerVisible(marker)) return; // skip if hidden + + // Clear previous blink if any if (activeBlinks.has(marker)) { clearInterval(activeBlinks.get(marker)); marker.setStyle({ fillColor: marker.originalColor }); if (marker.tooltip) map.removeLayer(marker.tooltip); } - marker.originalColor = marker.options.fillColor; let blinkCount = 0; let portName = portMap[portnum] || `Port ${portnum}`; @@ -280,13 +280,14 @@ function blinkNode(marker, longName, portnum) { className: 'blinking-tooltip' }).setContent(`${longName} (${portName})`) .setLatLng(marker.getLatLng()); - tooltip.addTo(map); marker.tooltip = tooltip; let interval = setInterval(() => { - marker.setStyle({ fillColor: blinkCount % 2 === 0 ? 'yellow' : marker.originalColor }); - marker.bringToFront(); + if (isMarkerVisible(marker)) { + marker.setStyle({ fillColor: blinkCount % 2 === 0 ? 'yellow' : marker.originalColor }); + marker.bringToFront(); // <-- ensures blinking node stays on top + } blinkCount++; if (blinkCount > 7) { clearInterval(interval); @@ -309,7 +310,7 @@ function fetchNewPackets() { data.packets.forEach(packet => { let marker = markerById[packet.from_node_id]; if (marker) { - let nodeData = nodes.find(n => n.id === packet.from_node_id); + let nodeData = nodeMap.get(packet.from_node_id); if (nodeData) blinkNode(marker, nodeData.long_name, packet.portnum); } }); @@ -322,5 +323,6 @@ function fetchNewPackets() { fetchLatestPacket(); setInterval(fetchNewPackets, 1000); + {% endblock %}