diff --git a/app/static/index.html b/app/static/index.html index d5944f1..0b91845 100644 --- a/app/static/index.html +++ b/app/static/index.html @@ -833,13 +833,22 @@ async function initMap() { if (activeHls) { try { activeHls.destroy(); } catch (_) {} activeHls = null; } }); updateHeatLegend(); - // Reload overlays when the user pans/zooms. Skip when a popup is open: - // opening a camera popup auto-pans the map to fit it, and that moveend - // must NOT rebuild the marker group under the open popup (which would - // close it). Leaflet closes popups on manual drag, so a live popup here - // means the move was autopan — safe to skip. + // Reload overlays when the user pans/zooms. A live popup makes the + // rebuild skip (so the popup's autopan doesn't destroy it), but user + // zoom/drag must close the popup FIRST — otherwise zooming out with a + // camera popup open leaves the stale, zoomed-in marker group on the + // map and the cameras "vanish" until a refresh. + // + // NOTE: `map._popup` is NOT a reliable open-check in Leaflet 1.9.4 — + // Map.closePopup() never nulls it, so once any popup has been opened + // it stays truthy forever. Track the real state via popupopen/close. + let camPopupOpen = false; + map.on('popupopen', () => { camPopupOpen = true; }); + map.on('popupclose', () => { camPopupOpen = false; }); + map.on('zoomstart', () => { if (camPopupOpen) map.closePopup(); }); + map.on('dragstart', () => { if (camPopupOpen) map.closePopup(); }); map.on('moveend', () => { - if (map._popup) return; + if (camPopupOpen) return; // only the popup's own autopan now if (firesOn) loadFires(); if (camsOn) loadCams(); });