From 5a4f9e2e2027d45efba18c7cf29952881b3899d2 Mon Sep 17 00:00:00 2001 From: Ole-Morten Duesund Date: Sun, 24 Aug 2025 00:06:59 +0200 Subject: [PATCH 1/2] Fix source popup closing immediately after opening MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Source markers were being recreated on every WebSocket update (every second), which destroyed any open popups. Solution: Modified updateSourceMarkers() to: - Only remove markers for sources that no longer exist - Update existing markers in-place instead of recreating them - Preserve open popups by updating content instead of recreating markers - Only create new markers when sources are actually added This ensures that clicking on a source marker opens a popup that stays open for user interaction, similar to aircraft popups. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- static/js/app.js | 59 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/static/js/app.js b/static/js/app.js index a94cd9e..5c7fa58 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -333,27 +333,50 @@ class SkyView { } updateSourceMarkers() { - // Clear existing source markers - this.sourceMarkers.forEach(marker => this.map.removeLayer(marker)); - this.sourceMarkers.clear(); + // Remove markers for sources that no longer exist + const currentSourceIds = new Set(this.sourcesData.keys()); + for (const [id, marker] of this.sourceMarkers) { + if (!currentSourceIds.has(id)) { + this.map.removeLayer(marker); + this.sourceMarkers.delete(id); + } + } - // Add source markers + // Update or create markers for current sources for (const [id, source] of this.sourcesData) { if (source.latitude && source.longitude) { - const marker = L.circleMarker([source.latitude, source.longitude], { - radius: source.active ? 10 : 6, - fillColor: source.active ? '#00d4ff' : '#666666', - color: '#ffffff', - weight: 2, - fillOpacity: 0.8, - className: 'source-marker' - }).addTo(this.map); - - marker.bindPopup(this.createSourcePopupContent(source), { - maxWidth: 300 - }); - - this.sourceMarkers.set(id, marker); + if (this.sourceMarkers.has(id)) { + // Update existing marker + const marker = this.sourceMarkers.get(id); + + // Update marker style if status changed + marker.setStyle({ + radius: source.active ? 10 : 6, + fillColor: source.active ? '#00d4ff' : '#666666', + fillOpacity: 0.8 + }); + + // Update popup content if it's open + if (marker.isPopupOpen()) { + marker.setPopupContent(this.createSourcePopupContent(source)); + } + } else { + // Create new marker + const marker = L.circleMarker([source.latitude, source.longitude], { + radius: source.active ? 10 : 6, + fillColor: source.active ? '#00d4ff' : '#666666', + color: '#ffffff', + weight: 2, + fillOpacity: 0.8, + className: 'source-marker' + }).addTo(this.map); + + marker.bindPopup(this.createSourcePopupContent(source), { + maxWidth: 300 + }); + + this.sourceMarkers.set(id, marker); + } } } From d73ecc2b202580bcb24ed5b0e7be26e3c2e51c0c Mon Sep 17 00:00:00 2001 From: Ole-Morten Duesund Date: Sun, 24 Aug 2025 00:09:25 +0200 Subject: [PATCH 2/2] Fix JavaScript error when switching between view tabs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Clicking on tabs other than Map caused JavaScript errors due to incorrect DOM element ID resolution in switchView() method. Root cause: The viewId extraction from button IDs didn't match the expected view element IDs, causing null reference errors when trying to add classes. Solution: - Fixed switchView() to correctly handle view IDs (e.g., "map-view") - Added null checks for DOM elements to prevent crashes - Updated this.currentView initialization and comparisons to match full IDs - Ensured view-specific initialization works with correct baseName extraction Now all tabs (Map, Table, Statistics, Coverage, 3D Radar) work without errors. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- static/js/app.js | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/static/js/app.js b/static/js/app.js index 5c7fa58..0ca2c8d 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -22,7 +22,7 @@ class SkyView { this.heatmapLayer = null; // UI state - this.currentView = 'map'; + this.currentView = 'map-view'; this.showTrails = false; this.showRange = false; this.showSources = true; @@ -70,16 +70,26 @@ class SkyView { switchView(viewId) { // Update buttons document.querySelectorAll('.view-btn').forEach(btn => btn.classList.remove('active')); - document.getElementById(`${viewId}-btn`).classList.add('active'); + const activeBtn = document.getElementById(`${viewId}-btn`); + if (activeBtn) { + activeBtn.classList.add('active'); + } - // Update views + // Update views (viewId already includes the full view ID like "map-view") document.querySelectorAll('.view').forEach(view => view.classList.remove('active')); - document.getElementById(`${viewId}-view`).classList.add('active'); + const activeView = document.getElementById(viewId); + if (activeView) { + activeView.classList.add('active'); + } else { + console.warn(`View element not found: ${viewId}`); + return; + } this.currentView = viewId; - // Handle view-specific initialization - switch (viewId) { + // Handle view-specific initialization (extract base name for switch) + const baseName = viewId.replace('-view', ''); + switch (baseName) { case 'coverage': this.initializeCoverageMap(); break; @@ -208,7 +218,7 @@ class SkyView { this.updateStatistics(); this.updateHeaderInfo(); - if (this.currentView === 'radar3d') { + if (this.currentView === 'radar3d-view') { this.update3DRadar(); } }