"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,
}) {
useEffect(() => {
fixLeafletIcons();
}, []); const { BaseLayer, Overlay } = LayersControl;
return (
{onViewChange && }
{showLayerControl ? (
{/* Base Layers */}
{mapLayers.base.map((layer, index) => (
))}
{/* Overlay Layers */}
{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}}
))}
);
}