diff --git a/src/components/map/map-view.tsx b/src/components/map/map-view.tsx index e077293..d12580b 100644 --- a/src/components/map/map-view.tsx +++ b/src/components/map/map-view.tsx @@ -983,7 +983,7 @@ export function MapView({ // Eraser mode: click on/near a feature to delete it if (mode === 'eraser') { const pixel = e.point - const tolerance = 10 // px + const tolerance = 20 // px const currentFeatures = featuresRef.current let closestIdx = -1 let closestDist = Infinity @@ -992,29 +992,44 @@ export function MapView({ const f = currentFeatures[i] const geom = f.geometry - // Get all coordinates to check proximity - let allCoords: number[][] = [] if (geom.type === 'Point') { - allCoords = [geom.coordinates as number[]] - } else if (geom.type === 'LineString') { - allCoords = geom.coordinates as number[][] - } else if (geom.type === 'Polygon') { - allCoords = (geom.coordinates as number[][][])[0] || [] - } - - for (const c of allCoords) { - const projected = m.project([c[0], c[1]]) + const projected = m.project(geom.coordinates as [number, number]) const dx = projected.x - pixel.x const dy = projected.y - pixel.y const dist = Math.sqrt(dx * dx + dy * dy) - if (dist < closestDist) { - closestDist = dist - closestIdx = i + if (dist < closestDist) { closestDist = dist; closestIdx = i } + } else if (geom.type === 'LineString') { + const lineCoords = geom.coordinates as number[][] + for (let j = 0; j < lineCoords.length - 1; j++) { + const p1 = m.project(lineCoords[j] as [number, number]) + const p2 = m.project(lineCoords[j + 1] as [number, number]) + const dist = pointToSegmentDist(pixel.x, pixel.y, p1.x, p1.y, p2.x, p2.y) + if (dist < closestDist) { closestDist = dist; closestIdx = i } } + } else if (geom.type === 'Polygon') { + const ring = (geom.coordinates as number[][][])[0] || [] + // Check edges + for (let j = 0; j < ring.length - 1; j++) { + const p1 = m.project(ring[j] as [number, number]) + const p2 = m.project(ring[j + 1] as [number, number]) + const dist = pointToSegmentDist(pixel.x, pixel.y, p1.x, p1.y, p2.x, p2.y) + if (dist < closestDist) { closestDist = dist; closestIdx = i } + } + // Point-in-polygon test (screen space) + const projected = ring.map(c => m.project(c as [number, number])) + let inside = false + for (let j = 0, k = projected.length - 1; j < projected.length; k = j++) { + const xi = projected[j].x, yi = projected[j].y + const xk = projected[k].x, yk = projected[k].y + if (((yi > pixel.y) !== (yk > pixel.y)) && (pixel.x < (xk - xi) * (pixel.y - yi) / (yk - yi) + xi)) { + inside = !inside + } + } + if (inside) { closestDist = 0; closestIdx = i } } } - if (closestIdx >= 0 && closestDist < tolerance * 3) { + if (closestIdx >= 0 && closestDist < tolerance) { const deleted = currentFeatures[closestIdx] const newFeatures = currentFeatures.filter((_, i) => i !== closestIdx) onFeaturesChangeRef.current(newFeatures)