// utils/initializeMap.js import L from "leaflet"; import "leaflet-contextmenu"; import "leaflet/dist/leaflet.css"; import "leaflet-contextmenu/dist/leaflet.contextmenu.css"; import "overlapping-marker-spiderfier-leaflet"; export const initializeMap = ( mapContainer, setMenuItemAdded, addItemsToMapContextMenu, hasRights, setPolylineEventsDisabled, logError = false ) => { // basePath wird aus config.json geladen (siehe unten) let basePath = undefined; if ( !mapContainer || !(mapContainer instanceof HTMLElement) || !document.body.contains(mapContainer) ) { if (logError) { console.error("❌ Fehler: map container ist nicht definiert oder nicht im DOM."); } return null; } // Robuste Entfernung einer evtl. alten Leaflet-Instanz und Reset des DOM-Elements if (mapContainer) { if (mapContainer._leaflet_id) { try { // Leaflet-Instanz entfernen if (mapContainer._leaflet_map && typeof mapContainer._leaflet_map.remove === "function") { mapContainer._leaflet_map.remove(); } // Leaflet 1.7+ speichert die Map-Instanz in L.Map._instances if (L && L.Map && L.Map._instances && mapContainer._leaflet_id) { delete L.Map._instances[mapContainer._leaflet_id]; } // Auch in L.DomUtil._store ggf. entfernen if (L && L.DomUtil && L.DomUtil._store && mapContainer._leaflet_id) { delete L.DomUtil._store[mapContainer._leaflet_id]; } // _leaflet_id vom DOM-Element entfernen delete mapContainer._leaflet_id; // Alle weiteren _leaflet-Properties entfernen for (const key in mapContainer) { if (key.startsWith("_leaflet")) { try { delete mapContainer[key]; } catch (e) {} } } } catch (e) { console.warn("Fehler beim Entfernen der alten Leaflet-Instanz:", e); } } // Container leeren (immer, auch wenn keine Map-Instanz) mapContainer.innerHTML = ""; } // --- CONFIG LOADING --- let config = null; let tileLayerUrl = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"; let mapCenter = [53.111111, 8.4625]; let mapZoom = 12; let minZoom = 5; let maxZoom = 20; try { if (window && window.__leafletConfig) { config = window.__leafletConfig; } else { const xhr = new XMLHttpRequest(); xhr.open("GET", "/config.json", false); // false = synchronous xhr.send(null); if (xhr.status === 200) { config = JSON.parse(xhr.responseText); window.__leafletConfig = config; } } if (config) { // basePath aus config.json if (typeof config.basePath === "string") { basePath = config.basePath; } // Tile source if (config.tileSources && config.active && config.tileSources[config.active]) { const tileSource = config.tileSources[config.active]; tileLayerUrl = tileSource.url || tileLayerUrl; // Dynamische URL für Server-Tiles if (tileLayerUrl.startsWith("/tiles") || tileLayerUrl.startsWith("tiles")) { tileLayerUrl = `${window.location.origin.replace(/\/$/, "")}${ tileLayerUrl.startsWith("/") ? tileLayerUrl : "/" + tileLayerUrl }`; } minZoom = tileSource.minZoom ?? minZoom; maxZoom = tileSource.maxZoom ?? maxZoom; } // Center if (Array.isArray(config.center)) { mapCenter = config.center; } // Zoom (optional, fallback to 12) if (typeof config.zoom === "number") { mapZoom = config.zoom; } // minZoom/maxZoom global fallback if (typeof config.minZoom === "number") { minZoom = config.minZoom; } if (typeof config.maxZoom === "number") { maxZoom = config.maxZoom; } } } catch (e) { // Fallback bleibt OSM und Defaults } let initMap; try { initMap = L.map(mapContainer, { center: mapCenter, zoom: mapZoom, minZoom: minZoom, maxZoom: maxZoom, // Disable default position; we'll add our own control at bottom-right zoomControl: false, dragging: true, contextmenu: true, layers: [], }); } catch (e) { if (e.message && e.message.includes("Map container is already initialized")) { console.warn( "Leaflet: Map container is already initialized. Map wird nicht erneut initialisiert." ); return; } throw e; } initMap.dragging.enable(); // Add visible +/- zoom control bottom-right (playwright-friendly) try { L.control.zoom({ position: "bottomright" }).addTo(initMap); } catch (_) {} L.tileLayer(tileLayerUrl, { attribution: "© OpenStreetMap contributors", tileSize: 256, minZoom: minZoom, maxZoom: maxZoom, noWrap: true, errorTileUrl: "/img/empty-tile.png", // Optional }).addTo(initMap); const overlappingMarkerSpiderfier = new OverlappingMarkerSpiderfier(initMap, { nearbyDistance: 20, }); if (typeof addItemsToMapContextMenu === "function") { addItemsToMapContextMenu(initMap, setMenuItemAdded, setPolylineEventsDisabled); } return { map: initMap, oms: overlappingMarkerSpiderfier }; };