Add waypoint snapping to nearby POIs (50m threshold)

When placing or dragging a waypoint within 50m of a visible POI, the
waypoint snaps to the POI's exact coordinates and adopts its name.
Snapping only applies to visible POIs (enabled categories, current
viewport). Explicit name (from "Add as waypoint" button) is preserved
without snapping.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-04-11 01:59:49 +02:00
parent 3af6aee32c
commit 1067b49576
No known key found for this signature in database
GPG key ID: A32FF691A0F752D9
2 changed files with 63 additions and 7 deletions

View file

@ -10,6 +10,7 @@ import { parseGpxAsync, extractWaypoints } from "@trails-cool/gpx";
import { isOvernight } from "~/lib/overnight";
import { setOvernight } from "~/lib/overnight";
import { usePois } from "~/lib/use-pois";
import { snapToPoi } from "~/lib/poi-snap";
import { Z_CURSOR, Z_WAYPOINT, Z_WAYPOINT_HIGHLIGHTED, Z_HIGHLIGHT } from "~/lib/z-index";
import { NoGoAreaLayer } from "./NoGoAreaLayer";
import { ColoredRoute, findSegmentForPoint, type ColorMode } from "./ColoredRoute";
@ -362,15 +363,17 @@ export function PlannerMap({ yjs, onRouteRequest, highlightPosition, highlighted
const addWaypoint = useCallback(
(lat: number, lng: number, name?: string) => {
const snap = name ? { lat, lon: lng, name, snapped: false } : snapToPoi(lat, lng, poiState.pois);
yjs.doc.transact(() => {
const yMap = new Y.Map();
yMap.set("lat", lat);
yMap.set("lon", lng);
if (name) yMap.set("name", name);
yMap.set("lat", snap.lat);
yMap.set("lon", snap.snapped ? snap.lon : lng);
if (snap.name) yMap.set("name", snap.name);
else if (name) yMap.set("name", name);
yjs.waypoints.push([yMap]);
}, "local");
},
[yjs.doc, yjs.waypoints],
[yjs.doc, yjs.waypoints, poiState.pois],
);
const insertWaypointAtSegment = useCallback(
@ -396,15 +399,17 @@ export function PlannerMap({ yjs, onRouteRequest, highlightPosition, highlighted
const moveWaypoint = useCallback(
(index: number, lat: number, lng: number) => {
const snap = snapToPoi(lat, lng, poiState.pois);
const yMap = yjs.waypoints.get(index);
if (yMap) {
yjs.doc.transact(() => {
yMap.set("lat", lat);
yMap.set("lon", lng);
yMap.set("lat", snap.lat);
yMap.set("lon", snap.snapped ? snap.lon : lng);
if (snap.snapped && snap.name) yMap.set("name", snap.name);
}, "local");
}
},
[yjs.waypoints, yjs.doc],
[yjs.waypoints, yjs.doc, poiState.pois],
);
const deleteWaypoint = useCallback(