diff --git a/meshview/templates/map.html b/meshview/templates/map.html
index 4278dd9..ad6ae46 100644
--- a/meshview/templates/map.html
+++ b/meshview/templates/map.html
@@ -62,30 +62,47 @@ function isInvalidCoord(n){ return !n||!n.lat||!n.long||n.lat===0||n.long===0||N
// ---------------------- Load Config & Start Polling ----------------------
async function initMapPolling() {
try {
- const cfg = await fetch('/api/config').then(r=>r.json());
+ const cfg = await fetch('/api/config').then(r => r.json());
const site = cfg.site || {};
mapInterval = parseInt(site.map_interval, 10) || 0;
- 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)];
- if (topLeft.every(isFinite) && bottomRight.every(isFinite)) {
- map.fitBounds([topLeft, bottomRight]);
- window.configBoundsApplied = true;
- setTimeout(()=>map.invalidateSize(),100);
+ // ---- Check URL params ----
+ const params = new URLSearchParams(window.location.search);
+ const lat = parseFloat(params.get('lat'));
+ const lng = parseFloat(params.get('lng'));
+ 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
+ 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)];
+ if (topLeft.every(isFinite) && bottomRight.every(isFinite)) {
+ map.fitBounds([topLeft, bottomRight]);
+ window.configBoundsApplied = true;
+ setTimeout(() => map.invalidateSize(), 100);
+ }
}
+ // ---- Start polling if enabled ----
if (mapInterval > 0) {
console.log(`Starting map polling every ${mapInterval}s`);
startPacketFetcher();
} else {
console.log("Map polling disabled (map_interval=0)");
}
+
} catch (err) {
console.error("Failed to load /api/config:", err);
}
}
+
initMapPolling();
+
// ---------------------- Load Nodes + Edges ----------------------
fetch('/api/nodes?days_active=3').then(r=>r.json()).then(data=>{
if(!data.nodes) return;
@@ -230,7 +247,32 @@ function updateNodeVisibility(){
}
// ---------------------- Share / Reset ----------------------
-function shareCurrentView(){ alert("Sharing is not implemented yet."); }
+ // ---- 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);
+
+ 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);
+ });
+ }
+
function resetFiltersToDefaults(){
document.getElementById("filter-routers-only").checked = false;
channelSet.forEach(ch=>document.getElementById(`filter-channel-${ch}`).checked = true);