From f7f932d82121f333e6aa6112973237a9afa62ce9 Mon Sep 17 00:00:00 2001 From: Pablo Revilla Date: Thu, 23 Oct 2025 13:53:41 -0700 Subject: [PATCH] worked on making map and base all API driven --- meshview/templates/map.html | 130 +++++++++++++++++++++--------------- 1 file changed, 76 insertions(+), 54 deletions(-) diff --git a/meshview/templates/map.html b/meshview/templates/map.html index 6fc6f3f..7bbc2e1 100644 --- a/meshview/templates/map.html +++ b/meshview/templates/map.html @@ -59,6 +59,42 @@ function timeAgo(date){ const diff=Date.now()-new Date(date), s=Math.floor(diff/ function hashToColor(str){ if(colorMap.has(str)) return colorMap.get(str); const c=palette[nextColorIndex++%palette.length]; colorMap.set(str,c); return c; } function isInvalidCoord(n){ return !n||!n.lat||!n.long||n.lat===0||n.long===0||Number.isNaN(n.lat)||Number.isNaN(n.long); } +// ---------------------- Packet Fetching ---------------------- +function fetchLatestPacket(){ fetch(`/api/packets?limit=1`).then(r=>r.json()).then(data=>{ lastImportTime=data.packets?.[0]?.import_time||new Date().toISOString(); }).catch(console.error); } +function fetchNewPackets(){ + if(mapInterval <= 0) return; + if(!lastImportTime) return; + fetch(`/api/packets?since=${encodeURIComponent(lastImportTime)}`).then(r=>r.json()).then(data=>{ + if(!data.packets||data.packets.length===0) return; + let latest = lastImportTime; + data.packets.forEach(pkt=>{ + if(pkt.import_time>latest) latest=pkt.import_time; + const marker = markerById[pkt.from_node_id]; + const nodeData = nodeMap.get(pkt.from_node_id); + if(marker && nodeData) blinkNode(marker,nodeData.long_name,pkt.portnum); + }); + lastImportTime=latest; + }).catch(console.error); +} + +// ---------------------- Polling ---------------------- +let packetInterval=null; +function startPacketFetcher(){ + if(mapInterval<=0) return; + if(!packetInterval){ + fetchLatestPacket(); + packetInterval=setInterval(fetchNewPackets,mapInterval*1000); + } +} +function stopPacketFetcher(){ + if(packetInterval){ + clearInterval(packetInterval); + packetInterval=null; + } +} +document.addEventListener("visibilitychange",()=>{ + document.hidden?stopPacketFetcher():startPacketFetcher(); +}); // ---------------------- WAIT FOR CONFIG ---------------------- async function waitForConfig() { @@ -90,10 +126,9 @@ async function initMapPolling() { const zoom = parseInt(params.get('zoom'), 10); if (!isNaN(lat) && !isNaN(lng) && !isNaN(zoom)) { map.setView([lat, lng], zoom); - window.configBoundsApplied = true; // prevent config bounds from overriding + window.configBoundsApplied = true; setTimeout(() => map.invalidateSize(), 100); } - // ---- If no URL, use config bounds ---- else { const topLeft = [parseFloat(site.map_top_left_lat), parseFloat(site.map_top_left_lon)]; const bottomRight = [parseFloat(site.map_bottom_right_lat), parseFloat(site.map_bottom_right_lon)]; @@ -104,7 +139,6 @@ async function initMapPolling() { } } - // ---- Start polling if enabled ---- if (mapInterval > 0) { console.log(`Starting map polling every ${mapInterval}s`); startPacketFetcher(); @@ -119,7 +153,6 @@ async function initMapPolling() { initMapPolling(); - // ---------------------- Load Nodes + Edges ---------------------- fetch('/api/nodes?days_active=3').then(r=>r.json()).then(data=>{ if(!data.nodes) return; @@ -206,39 +239,18 @@ function blinkNode(marker,longName,portnum){ activeBlinks.set(marker,interval); } -// ---------------------- Packet Fetching ---------------------- -function fetchLatestPacket(){ fetch(`/api/packets?limit=1`).then(r=>r.json()).then(data=>{ lastImportTime=data.packets?.[0]?.import_time||new Date().toISOString(); }).catch(console.error); } -function fetchNewPackets(){ - if(mapInterval <= 0) return; // safety guard - if(!lastImportTime) return; - fetch(`/api/packets?since=${encodeURIComponent(lastImportTime)}`).then(r=>r.json()).then(data=>{ - if(!data.packets||data.packets.length===0) return; - let latest = lastImportTime; - data.packets.forEach(pkt=>{ - if(pkt.import_time>latest) latest=pkt.import_time; - const marker = markerById[pkt.from_node_id]; - const nodeData = nodeMap.get(pkt.from_node_id); - if(marker && nodeData) blinkNode(marker,nodeData.long_name,pkt.portnum); - }); - lastImportTime=latest; - }).catch(console.error); -} - -// ---------------------- Polling ---------------------- -let packetInterval=null; -function startPacketFetcher(){ if(mapInterval<=0) return; if(!packetInterval){ fetchLatestPacket(); packetInterval=setInterval(fetchNewPackets,mapInterval*1000); } } -function stopPacketFetcher(){ if(packetInterval){ clearInterval(packetInterval); packetInterval=null; } } -document.addEventListener("visibilitychange",()=>{ document.hidden?stopPacketFetcher():startPacketFetcher(); }); - // ---------------------- Channel Filters ---------------------- function createChannelFilters(){ const filterContainer = document.getElementById("filter-container"); + const savedState = JSON.parse(localStorage.getItem("mapFilters") || "{}"); + channelSet.forEach(channel=>{ const checkbox = document.createElement("input"); checkbox.type = "checkbox"; checkbox.className = "filter-checkbox"; checkbox.id = `filter-channel-${channel}`; - checkbox.checked = true; + checkbox.checked = savedState[channel] !== false; + checkbox.addEventListener("change", saveFiltersToLocalStorage); checkbox.addEventListener("change", updateNodeVisibility); filterContainer.appendChild(checkbox); @@ -248,7 +260,23 @@ function createChannelFilters(){ label.style.color = hashToColor(channel); filterContainer.appendChild(label); }); - document.getElementById("filter-routers-only").addEventListener("change", updateNodeVisibility); + + const routerOnly = document.getElementById("filter-routers-only"); + routerOnly.checked = savedState["routersOnly"] || false; + routerOnly.addEventListener("change", saveFiltersToLocalStorage); + routerOnly.addEventListener("change", updateNodeVisibility); + + updateNodeVisibility(); +} + +function saveFiltersToLocalStorage(){ + const state = {}; + channelSet.forEach(ch => { + const el = document.getElementById(`filter-channel-${ch}`); + state[ch] = el.checked; + }); + state["routersOnly"] = document.getElementById("filter-routers-only").checked; + localStorage.setItem("mapFilters", JSON.stringify(state)); } function updateNodeVisibility(){ @@ -264,35 +292,29 @@ function updateNodeVisibility(){ } // ---------------------- Share / Reset ---------------------- - // ---- Share Current View ---- - function shareCurrentView() { - const center = map.getCenter(); - const zoom = map.getZoom(); - const lat = center.lat.toFixed(6); - const lng = center.lng.toFixed(6); +function shareCurrentView() { + const center = map.getCenter(); + const zoom = map.getZoom(); + const lat = center.lat.toFixed(6); + const lng = center.lng.toFixed(6); - const shareUrl = `${window.location.origin}/map?lat=${lat}&lng=${lng}&zoom=${zoom}`; - - // Copy to clipboard - navigator.clipboard.writeText(shareUrl).then(() => { - const button = document.getElementById('share-button'); - const originalText = button.textContent; - button.textContent = '✓ Link Copied!'; - button.style.backgroundColor = '#2196F3'; - - setTimeout(() => { - button.textContent = originalText; - button.style.backgroundColor = '#4CAF50'; - }, 2000); - }).catch(err => { - // Fallback for older browsers - alert('Share this link:\n' + shareUrl); - }); - } + const shareUrl = `${window.location.origin}/map?lat=${lat}&lng=${lng}&zoom=${zoom}`; + navigator.clipboard.writeText(shareUrl).then(() => { + const button = document.getElementById('share-button'); + const originalText = button.textContent; + button.textContent = '✓ Link Copied!'; + button.style.backgroundColor = '#2196F3'; + setTimeout(() => { + button.textContent = originalText; + button.style.backgroundColor = '#4CAF50'; + }, 2000); + }).catch(() => alert('Share this link:\n' + shareUrl)); +} function resetFiltersToDefaults(){ document.getElementById("filter-routers-only").checked = false; channelSet.forEach(ch=>document.getElementById(`filter-channel-${ch}`).checked = true); + saveFiltersToLocalStorage(); updateNodeVisibility(); }