63 lines
1.8 KiB
TypeScript
63 lines
1.8 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
'use client';
|
|
|
|
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
|
|
import { LatLngExpression } from 'leaflet';
|
|
import 'leaflet/dist/leaflet.css';
|
|
import L from 'leaflet';
|
|
import { useEffect } from 'react';
|
|
|
|
type MarkerData = {
|
|
position: [number, number];
|
|
popup: string;
|
|
};
|
|
|
|
type Props = {
|
|
center: [number, number];
|
|
markers: MarkerData[];
|
|
zoom?: number;
|
|
scrollWheelZoom?: boolean;
|
|
className?: string;
|
|
style?: React.CSSProperties;
|
|
};
|
|
|
|
export default function LeafletMultiMarkerMap({
|
|
center,
|
|
markers,
|
|
zoom = 13,
|
|
scrollWheelZoom = true,
|
|
className = '',
|
|
style = { height: '100%', width: '100%', zIndex: 0 },
|
|
}: Props) {
|
|
// Fix for default marker icons in Next.js
|
|
useEffect(() => {
|
|
delete (L.Icon.Default.prototype as any)._getIconUrl;
|
|
L.Icon.Default.mergeOptions({
|
|
iconRetinaUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon-2x.png',
|
|
iconUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png',
|
|
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png',
|
|
});
|
|
}, []);
|
|
|
|
return (
|
|
<div className={className} style={style}>
|
|
<MapContainer
|
|
center={center as LatLngExpression}
|
|
zoom={zoom}
|
|
scrollWheelZoom={scrollWheelZoom}
|
|
style={{ height: '100%', width: '100%' }}
|
|
>
|
|
<TileLayer
|
|
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
|
/>
|
|
{markers.map((marker, index) => (
|
|
<Marker key={index} position={marker.position as LatLngExpression}>
|
|
<Popup>{marker.popup}</Popup>
|
|
</Marker>
|
|
))}
|
|
</MapContainer>
|
|
</div>
|
|
);
|
|
}
|