- minZoom, maxZoom, center, zoomOutCenter und basePath in config.json konfigurierbar gemacht - Kommentare zur Erklärung als _comment-Felder ergänzt - initializeMap.js und zoomAndCenterUtils.js angepasst, um Werte aus config.json zu lesen - OSM-Standards für Zoom-Stufen dokumentiert
141 lines
4.4 KiB
JavaScript
141 lines
4.4 KiB
JavaScript
// 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
|
|
) => {
|
|
const basePath = process.env.NEXT_PUBLIC_BASE_PATH;
|
|
|
|
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 = "";
|
|
}
|
|
|
|
let tileLayerUrl = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
|
|
let minZoom = 5;
|
|
let maxZoom = 15;
|
|
let mapCenter = [53.111111, 8.4625];
|
|
try {
|
|
if (window && window.__tileSource && window.__tileSourceUrl) {
|
|
tileLayerUrl = window.__tileSourceUrl;
|
|
minZoom = window.__tileSourceMinZoom;
|
|
maxZoom = window.__tileSourceMaxZoom;
|
|
} else {
|
|
// Synchronous config fetch using XMLHttpRequest (since fetch is async)
|
|
const xhr = new XMLHttpRequest();
|
|
xhr.open("GET", "/config.json", false); // false = synchronous
|
|
xhr.send(null);
|
|
if (xhr.status === 200) {
|
|
const config = JSON.parse(xhr.responseText);
|
|
if (config.tileSources && config.active && config.tileSources[config.active]) {
|
|
const source = config.tileSources[config.active];
|
|
tileLayerUrl = source.url;
|
|
minZoom = source.minZoom;
|
|
maxZoom = source.maxZoom;
|
|
window.__tileSourceUrl = tileLayerUrl;
|
|
window.__tileSourceMinZoom = minZoom;
|
|
window.__tileSourceMaxZoom = maxZoom;
|
|
if (source.center && Array.isArray(source.center) && source.center.length === 2) {
|
|
mapCenter = source.center;
|
|
} else if (config.center && Array.isArray(config.center) && config.center.length === 2) {
|
|
mapCenter = config.center;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
// Fallback bleibt OSM
|
|
}
|
|
|
|
let initMap;
|
|
try {
|
|
initMap = L.map(mapContainer, {
|
|
center: mapCenter,
|
|
zoom: minZoom,
|
|
minZoom: minZoom,
|
|
maxZoom: maxZoom,
|
|
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();
|
|
|
|
L.tileLayer(tileLayerUrl, {
|
|
attribution: "© Eigene Kartenquelle (offline)",
|
|
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 };
|
|
};
|