Compare commits

...

2 commits

Author SHA1 Message Date
d73ecc2b20 Fix JavaScript error when switching between view tabs
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 <noreply@anthropic.com>
2025-08-24 00:09:25 +02:00
5a4f9e2e20 Fix source popup closing immediately after opening
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 <noreply@anthropic.com>
2025-08-24 00:06:59 +02:00

View file

@ -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();
}
}
@ -333,27 +343,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);
}
}
}