diff --git a/public/js/components/ConfigManager.js b/public/js/components/ConfigManager.js index 04d3718..d823d62 100644 --- a/public/js/components/ConfigManager.js +++ b/public/js/components/ConfigManager.js @@ -709,120 +709,62 @@ class ConfigManager { if (e.target === mapModal) closeMap(); }); - // Load transit stops - search for common Stockholm areas - const loadSitesOnMap = async () => { + // Load nearby transit stops based on map center + const markersLayer = L.layerGroup().addTo(map); + const loadedSiteIds = new Set(); + + const loadNearbySites = async () => { + const center = map.getCenter(); + const zoom = map.getZoom(); + // Scale radius based on zoom: wider view = larger radius + const radius = zoom >= 15 ? 500 : zoom >= 13 ? 1500 : zoom >= 11 ? 4000 : 8000; + try { - // Start with focused search to avoid too many markers - const searchTerms = ['Ambassaderna']; - const allSites = new Map(); - - for (const term of searchTerms) { - try { - const response = await fetch(`/api/sites/search?q=${encodeURIComponent(term)}`); - const data = await response.json(); - console.log(`Search "${term}" returned:`, data); - if (data.sites) { - data.sites.forEach(site => { - // Only add sites with valid coordinates from API - const lat = site.lat || site.latitude; - const lon = site.lon || site.longitude; - - if (lat && lon && !isNaN(parseFloat(lat)) && !isNaN(parseFloat(lon))) { - if (!allSites.has(site.id)) { - allSites.set(site.id, { - id: site.id, - name: site.name, - lat: parseFloat(lat), - lon: parseFloat(lon) - }); - } - } else { - console.log(`Site ${site.id} (${site.name}) missing coordinates, skipping`); - } - }); - } - } catch (err) { - console.error(`Error searching for ${term}:`, err); - } - } - - // Add known site with coordinates as fallback - const knownSites = [ - { id: '1411', name: 'Ambassaderna', lat: 59.3293, lon: 18.0686 } - ]; - - knownSites.forEach(site => { - if (!allSites.has(site.id)) { - allSites.set(site.id, site); - } - }); - - const sitesArray = Array.from(allSites.values()); - console.log(`Loading ${sitesArray.length} sites on map with coordinates:`, sitesArray); - - if (sitesArray.length > 0) { - const markers = []; - sitesArray.forEach(site => { - const lat = site.lat; - const lon = site.lon; - - if (!lat || !lon || isNaN(lat) || isNaN(lon)) { - console.warn(`Invalid coordinates for site ${site.id}, skipping`); - return; - } - - // Create custom icon + const response = await fetch(`/api/sites/nearby?lat=${center.lat}&lon=${center.lng}&radius=${radius}`); + const data = await response.json(); + + if (data.sites) { + data.sites.forEach(site => { + if (loadedSiteIds.has(site.id)) return; + const lat = parseFloat(site.lat); + const lon = parseFloat(site.lon); + if (!lat || !lon || isNaN(lat) || isNaN(lon)) return; + + loadedSiteIds.add(site.id); + const customIcon = L.divIcon({ className: 'custom-marker', - html: `
🚌
`, + html: '
🚌
', iconSize: [30, 30], iconAnchor: [15, 15] }); - - const marker = L.marker([lat, lon], { icon: customIcon }).addTo(map); - + + const marker = L.marker([lat, lon], { icon: customIcon }); + const popupContent = `
${site.name}
ID: ${site.id}
-
`; - + marker.bindPopup(popupContent); - markers.push(marker); - - // Make marker clickable to open popup - marker.on('click', function() { - this.openPopup(); - }); + markersLayer.addLayer(marker); }); - - // Fit map to show all markers, or center on first marker - if (markers.length > 0) { - if (markers.length === 1) { - map.setView(markers[0].getLatLng(), 15); - } else { - const group = new L.featureGroup(markers); - map.fitBounds(group.getBounds().pad(0.1)); - } - } else { - // If no markers, show message - console.log('No sites with coordinates found'); - } + console.log(`Loaded ${data.sites.length} nearby sites (${loadedSiteIds.size} total on map)`); } } catch (error) { - console.error('Error loading sites on map:', error); + console.error('Error loading nearby sites:', error); } }; - - // Load sites after map is initialized - setTimeout(() => { - loadSitesOnMap(); - }, 500); + + // Load sites on init and when map is panned/zoomed + setTimeout(() => loadNearbySites(), 300); + map.on('moveend', loadNearbySites); // Handle site selection from map popup - use event delegation on the modal mapModal.addEventListener('click', (e) => { @@ -874,73 +816,42 @@ class ConfigManager { const data = await response.json(); if (data.sites && data.sites.length > 0) { - // Clear existing markers - map.eachLayer((layer) => { - if (layer instanceof L.Marker) { - map.removeLayer(layer); - } - }); - - // Clear existing markers - map.eachLayer((layer) => { - if (layer instanceof L.Marker) { - map.removeLayer(layer); - } - }); - - // Add markers for search results - const markers = []; + // Clear existing markers and reset tracking + markersLayer.clearLayers(); + loadedSiteIds.clear(); + + const searchMarkers = []; data.sites.forEach(site => { - let lat = site.lat || site.latitude; - let lon = site.lon || site.longitude; - - // If no coordinates, use approximate location based on map center - if (!lat || !lon) { - const center = map.getCenter(); - lat = center.lat + (Math.random() - 0.5) * 0.05; - lon = center.lon + (Math.random() - 0.5) * 0.05; - } - - // Create custom icon + const lat = parseFloat(site.lat); + const lon = parseFloat(site.lon); + if (!lat || !lon || isNaN(lat) || isNaN(lon)) return; + + loadedSiteIds.add(site.id); + const customIcon = L.divIcon({ - className: 'custom-transit-marker', - html: `
🚌
`, + className: 'custom-marker', + html: '
🚌
', iconSize: [32, 32], - iconAnchor: [16, 16], - popupAnchor: [0, -16] + iconAnchor: [16, 16] }); - - const marker = L.marker([lat, lon], { - icon: customIcon, - title: site.name - }).addTo(map); - - const popupContent = document.createElement('div'); - popupContent.style.minWidth = '220px'; - popupContent.innerHTML = ` -
- ${site.name} - ID: ${site.id} + + const marker = L.marker([lat, lon], { icon: customIcon }); + marker.bindPopup(` +
+ ${site.name}
+ ID: ${site.id}
+
- - `; - - marker.bindPopup(popupContent); - markers.push(marker); - - marker.on('click', function() { - this.openPopup(); - }); + `); + markersLayer.addLayer(marker); + searchMarkers.push(marker); }); - - // Fit map to show results - if (markers.length > 0) { - const group = new L.featureGroup(markers); + + if (searchMarkers.length > 0) { + const group = new L.featureGroup(searchMarkers); map.fitBounds(group.getBounds().pad(0.1)); } }