import React, { useEffect, useRef } from 'react'; import L from 'leaflet'; import 'leaflet/dist/leaflet.css'; export default function EditableAreaMap({ points, center, drawing, disabled, onChange }) { const host = useRef(null); const map = useRef(null); const layers = useRef(null); const current = useRef({ points, drawing, disabled, onChange }); current.current = { points, drawing, disabled, onChange }; useEffect(() => { const instance = L.map(host.current,{scrollWheelZoom:false,doubleClickZoom:false}).setView([56,10],18); map.current = instance; L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png',{ maxZoom:19,attribution:'© OpenStreetMap contributors · ODbL' }).addTo(instance); layers.current = L.layerGroup().addTo(instance); instance.on('click',event => { const state=current.current; if (state.drawing && !state.disabled && state.points.length < 500) state.onChange([...state.points,[event.latlng.lng,event.latlng.lat]]); }); const resize = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(() => instance.invalidateSize()) : null; resize?.observe(host.current); return () => {resize?.disconnect();instance.remove();}; },[]); useEffect(() => { map.current.setView(center,18); },[center]); useEffect(() => { const group=layers.current; group.clearLayers(); const latLngs=points.map(([lng,lat]) => [lat,lng]); if (points.length>=3) L.polygon(latLngs,{color:'#176a59',fillOpacity:.18,interactive:false}).addTo(group); else if(points.length>1) L.polyline(latLngs,{color:'#176a59',interactive:false}).addTo(group); points.forEach((point,index) => { const marker=L.marker([point[1],point[0]],{ draggable:!disabled,keyboard:false, icon:L.divIcon({className:'site-area-handle',html:`${index+1}`,iconSize:[44,44],iconAnchor:[22,22]}) }).addTo(group); marker.on('dragstart',() => map.current.dragging.disable()); marker.on('dragend',() => { map.current.dragging.enable(); const position=marker.getLatLng(); current.current.onChange(current.current.points.map((p,i) => i===index ? [position.lng,position.lat] : p)); }); // A midpoint is a large touch target for inserting an extra editable vertex. if (points.length>=2 && !drawing && !disabled) { const next=points[(index+1)%points.length]; const middle=[(point[0]+next[0])/2,(point[1]+next[1])/2]; L.marker([middle[1],middle[0]],{keyboard:false,icon:L.divIcon({className:'site-area-handle',html:'+',iconSize:[44,44],iconAnchor:[22,22]})}) .addTo(group).on('click',event => { L.DomEvent.stopPropagation(event); onChange([...points.slice(0,index+1),middle,...points.slice(index+1)]); }); } }); },[points,drawing,disabled,onChange]); return
; }