Fix waypoint drag creating unwanted split points
The ghost marker (route split indicator) was interfering with waypoint dragging because it sat above waypoints (zIndexOffset 1000) and stayed active during drag operations. Adopt brouter-web's suspension pattern: - Suspend route interaction on waypoint mouseover (not just dragstart), unsuspend on mouseout — ghost marker hides before any click/drag - Lower ghost marker zIndexOffset to -100 so waypoints always receive clicks first - Keep drag guards as a safety net Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
26dd1a4d83
commit
400189d9c1
2 changed files with 29 additions and 5 deletions
|
|
@ -179,6 +179,8 @@ export function PlannerMap({ yjs, onRouteRequest, highlightPosition }: PlannerMa
|
|||
const [noGoDrawing, setNoGoDrawing] = useState(false);
|
||||
const toggleNoGoDraw = useCallback(() => setNoGoDrawing((v) => !v), []);
|
||||
const suppressMapClickRef = useRef(false);
|
||||
const routeInteractionSuspendedRef = useRef(false);
|
||||
const waypointDraggingRef = useRef(false);
|
||||
|
||||
// Sync waypoints from Yjs
|
||||
useEffect(() => {
|
||||
|
|
@ -324,7 +326,21 @@ export function PlannerMap({ yjs, onRouteRequest, highlightPosition }: PlannerMa
|
|||
draggable
|
||||
icon={waypointIcon(i)}
|
||||
eventHandlers={{
|
||||
mouseover: () => {
|
||||
routeInteractionSuspendedRef.current = true;
|
||||
},
|
||||
mouseout: () => {
|
||||
if (!waypointDraggingRef.current) {
|
||||
routeInteractionSuspendedRef.current = false;
|
||||
}
|
||||
},
|
||||
dragstart: () => {
|
||||
waypointDraggingRef.current = true;
|
||||
routeInteractionSuspendedRef.current = true;
|
||||
},
|
||||
dragend: (e) => {
|
||||
waypointDraggingRef.current = false;
|
||||
routeInteractionSuspendedRef.current = false;
|
||||
const { lat, lng } = e.target.getLatLng();
|
||||
moveWaypoint(i, lat, lng);
|
||||
},
|
||||
|
|
@ -347,6 +363,7 @@ export function PlannerMap({ yjs, onRouteRequest, highlightPosition }: PlannerMa
|
|||
coordinates={routeCoordinates}
|
||||
segmentBoundaries={segmentBoundaries}
|
||||
onInsertWaypoint={handleRouteInsert}
|
||||
suspendedRef={routeInteractionSuspendedRef}
|
||||
disabled={noGoDrawing}
|
||||
/>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ interface RouteInteractionProps {
|
|||
segmentBoundaries: number[];
|
||||
onInsertWaypoint: (pointIndex: number, lat: number, lon: number) => void;
|
||||
disabled?: boolean;
|
||||
/** Set true to suspend ghost marker (e.g. while hovering/dragging a waypoint) */
|
||||
suspendedRef?: React.RefObject<boolean>;
|
||||
}
|
||||
|
||||
const SNAP_TOLERANCE_PX = 15;
|
||||
|
|
@ -26,13 +28,14 @@ const ghostIcon = L.divIcon({
|
|||
/**
|
||||
* Route interaction layer: shows a ghost marker on hover that can be
|
||||
* clicked or dragged to insert a waypoint. Follows brouter-web's pattern
|
||||
* of a single persistent draggable Marker with distance-based mouseout.
|
||||
* of suspending when the mouse is over a waypoint marker.
|
||||
*/
|
||||
export function RouteInteraction({
|
||||
coordinates,
|
||||
segmentBoundaries,
|
||||
onInsertWaypoint,
|
||||
disabled,
|
||||
suspendedRef,
|
||||
}: RouteInteractionProps) {
|
||||
const map = useMap();
|
||||
const markerRef = useRef<L.Marker | null>(null);
|
||||
|
|
@ -86,7 +89,7 @@ export function RouteInteraction({
|
|||
icon: ghostIcon,
|
||||
draggable: true,
|
||||
interactive: true,
|
||||
zIndexOffset: 1000,
|
||||
zIndexOffset: -100,
|
||||
});
|
||||
markerRef.current = marker;
|
||||
|
||||
|
|
@ -115,7 +118,11 @@ export function RouteInteraction({
|
|||
|
||||
// Listen for mousemove on the map (distance-based approach, not polyline events)
|
||||
const onMouseMove = (e: L.LeafletMouseEvent) => {
|
||||
if (draggingRef.current) return;
|
||||
// Suspended while hovering over or dragging a waypoint marker (brouter-web pattern)
|
||||
if (draggingRef.current || suspendedRef?.current) {
|
||||
hideMarker();
|
||||
return;
|
||||
}
|
||||
|
||||
const snap = findClosestOnRoute(e.latlng);
|
||||
if (!snap || snap.distPx > SNAP_TOLERANCE_PX) {
|
||||
|
|
@ -131,7 +138,7 @@ export function RouteInteraction({
|
|||
hideMarker();
|
||||
};
|
||||
|
||||
// Drag events on the ghost marker (Leaflet's L.Draggable handles text selection)
|
||||
// Drag events on the ghost marker
|
||||
marker.on("dragstart", () => {
|
||||
draggingRef.current = true;
|
||||
trailer1.setStyle({ opacity: 0.6 });
|
||||
|
|
@ -200,7 +207,7 @@ export function RouteInteraction({
|
|||
trailer2.remove();
|
||||
markerRef.current = null;
|
||||
};
|
||||
}, [map, disabled, findClosestOnRoute]);
|
||||
}, [map, disabled, findClosestOnRoute, suspendedRef]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue