fix: eraser tool works on polygon areas and line edges, not just vertices

This commit is contained in:
Pepe Ziberi
2026-02-22 00:09:02 +01:00
parent 5bf4106db2
commit 0abc1c6b02

View File

@@ -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)