feat: Add measurement tool with distance calculation and visual markers on the map

This commit is contained in:
2025-09-16 16:41:08 +02:00
parent e4a4261a0e
commit 0bb0b07429
2 changed files with 210 additions and 81 deletions

View File

@@ -8,6 +8,7 @@ import {
LayersControl,
useMapEvents,
useMap,
Polyline,
} from "react-leaflet";
import L from "leaflet";
import "leaflet/dist/leaflet.css";
@@ -84,6 +85,32 @@ const createColoredMarkerIcon = (color) => {
} return null;
};
// Create numbered measurement marker icons
const createMeasurementMarkerIcon = (number) => {
if (typeof window !== "undefined") {
return new L.DivIcon({
html: `<div style="
background-color: #ef4444;
color: white;
border-radius: 50%;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 12px;
border: 2px solid white;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
">${number}</div>`,
className: 'custom-measurement-marker',
iconSize: [24, 24],
iconAnchor: [12, 12],
});
}
return null;
};
// Component to handle map events
function MapEventHandler({ onViewChange }) {
const map = useMapEvents({
@@ -106,6 +133,19 @@ function MapEventHandler({ onViewChange }) {
return null;
}
// Component to handle measurement events
function MeasurementHandler({ isMeasuring, onMeasurementClick, measurementPoints }) {
const map = useMapEvents({
click: (e) => {
if (isMeasuring && onMeasurementClick) {
onMeasurementClick(e.latlng);
}
},
});
return null;
}
// Custom zoom control component that handles external events
function CustomZoomHandler() {
const map = useMap();
@@ -143,6 +183,9 @@ export default function EnhancedLeafletMap({
activeOverlays = [],
onViewChange,
showOverlays = true,
isMeasuring = false,
measurementPoints = [],
onMeasurementClick,
}) {
useEffect(() => {
fixLeafletIcons();
@@ -157,6 +200,11 @@ export default function EnhancedLeafletMap({
>
<CustomZoomHandler />
{onViewChange && <MapEventHandler onViewChange={onViewChange} />}
{isMeasuring && <MeasurementHandler
isMeasuring={isMeasuring}
onMeasurementClick={onMeasurementClick}
measurementPoints={measurementPoints}
/>}
{showLayerControl ? (
<LayersControl position="topright">
@@ -255,6 +303,39 @@ export default function EnhancedLeafletMap({
{marker.popup && <Popup>{marker.popup}</Popup>}
</Marker>
))}
{/* Measurement elements */}
{isMeasuring && measurementPoints.length > 0 && (
<>
{/* Measurement line */}
{measurementPoints.length > 1 && (
<Polyline
positions={measurementPoints}
color="red"
weight={3}
opacity={0.8}
dashArray="10, 10"
/>
)}
{/* Measurement point markers */}
{measurementPoints.map((point, index) => (
<Marker
key={`measurement-${index}`}
position={point}
icon={createMeasurementMarkerIcon(index + 1)}
>
<Popup>
<div className="text-sm">
<strong>Point {index + 1}</strong><br />
Lat: {point.lat.toFixed(6)}<br />
Lng: {point.lng.toFixed(6)}
</div>
</Popup>
</Marker>
))}
</>
)}
</MapContainer>
);
}