"use client"; import { MapContainer, TileLayer, Marker, Popup, LayersControl, useMapEvents, useMap, } from "react-leaflet"; import L from "leaflet"; import "leaflet/dist/leaflet.css"; import { useEffect } from "react"; import { mapLayers } from "./mapLayers"; // Custom WMS Layer component using Leaflet's native WMS support function WMSLayer({ url, params, opacity = 1, attribution }) { const map = useMap(); useEffect(() => { if (!map || !url) return; // Clean up params for L.tileLayer.wms const wmsOptions = { layers: params.layers, styles: params.styles || '', format: params.format || 'image/png', transparent: params.transparent !== false, version: params.version || '1.1.1', attribution: attribution, opacity: opacity }; // Add CRS/SRS parameter based on version const version = parseFloat(params.version || '1.1.1'); if (version >= 1.3) { wmsOptions.crs = L.CRS.EPSG3857; } else { wmsOptions.srs = 'EPSG:3857'; } // Create WMS layer using Leaflet's native support const wmsLayer = L.tileLayer.wms(url, wmsOptions); wmsLayer.addTo(map); return () => { map.removeLayer(wmsLayer); }; }, [map, url, params, opacity, attribution]); return null; } // Fix for default markers in react-leaflet const fixLeafletIcons = () => { if (typeof window !== "undefined") { delete L.Icon.Default.prototype._getIconUrl; L.Icon.Default.mergeOptions({ iconRetinaUrl: "/leaflet/marker-icon-2x.png", iconUrl: "/leaflet/marker-icon.png", shadowUrl: "/leaflet/marker-shadow.png", }); } }; // Create colored marker icons const createColoredMarkerIcon = (color) => { if (typeof window !== "undefined") { return new L.Icon({ iconUrl: `data:image/svg+xml;base64,${btoa(` `)}`, shadowUrl: "/leaflet/marker-shadow.png", iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41], }); } return null; }; // Component to handle map events function MapEventHandler({ onViewChange }) { const map = useMapEvents({ moveend: () => { if (onViewChange) { const center = map.getCenter(); const zoom = map.getZoom(); onViewChange([center.lat, center.lng], zoom); } }, zoomend: () => { if (onViewChange) { const center = map.getCenter(); const zoom = map.getZoom(); onViewChange([center.lat, center.lng], zoom); } }, }); return null; } // Custom zoom control component that handles external events function CustomZoomHandler() { const map = useMap(); useEffect(() => { if (!map) return; const handleZoomIn = () => { map.zoomIn(); }; const handleZoomOut = () => { map.zoomOut(); }; // Listen for custom zoom events window.addEventListener('mapZoomIn', handleZoomIn); window.addEventListener('mapZoomOut', handleZoomOut); return () => { window.removeEventListener('mapZoomIn', handleZoomIn); window.removeEventListener('mapZoomOut', handleZoomOut); }; }, [map]); return null; } export default function EnhancedLeafletMap({ center, zoom = 13, markers = [], showLayerControl = true, defaultLayer = "OpenStreetMap", activeOverlays = [], onViewChange, showOverlays = true, }) { useEffect(() => { fixLeafletIcons(); }, []); const { BaseLayer, Overlay } = LayersControl; return ( {onViewChange && } {showLayerControl ? ( {/* Base Layers */} {mapLayers.base.map((layer, index) => ( ))} {/* Overlay Layers */} {showOverlays && mapLayers.overlays && mapLayers.overlays.map((layer, index) => ( {layer.type === "wms" ? ( ) : ( )} ))} ) : ( // Custom layer rendering when no layer control <> {/* Base Layer */} {(() => { const baseLayer = mapLayers.base.find(layer => layer.name === defaultLayer) || mapLayers.base[0]; return ( ); })()} {/* Active Overlay Layers */} {mapLayers.overlays && mapLayers.overlays .filter(layer => activeOverlays.includes(layer.name)) .map((layer, index) => { if (layer.type === "wms") { return ( ); } else { return ( ); } }) } )}{" "} {markers.map((marker, index) => ( {marker.popup && {marker.popup}} ))} ); }