feat(stammbaum): mobile read path — pan, zoom, fit-to-view (#692) #694
@@ -104,11 +104,11 @@ export const panZoomGestures: Action<SVGSVGElement, PanZoomGesturesParams> = (no
|
||||
|
||||
const onPointerDown = (e: PointerEvent) => {
|
||||
cancelInertia();
|
||||
try {
|
||||
node.setPointerCapture(e.pointerId);
|
||||
} catch {
|
||||
/* pointer not capturable (e.g. synthetic event) — drag still works */
|
||||
}
|
||||
// NB: do NOT capture the pointer here — capturing on pointerdown makes the
|
||||
// browser dispatch the trailing `click` at this element instead of the
|
||||
// node under the pointer, which silently breaks node selection (a tap must
|
||||
// still reach the node's onclick). Capture is deferred to the first move
|
||||
// that crosses the drag threshold (see onPointerMove).
|
||||
pointers.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
||||
p.onGestureStart?.();
|
||||
|
||||
@@ -146,7 +146,17 @@ export const panZoomGestures: Action<SVGSVGElement, PanZoomGesturesParams> = (no
|
||||
if (!dragging) return;
|
||||
const dxPx = e.clientX - lastX;
|
||||
const dyPx = e.clientY - lastY;
|
||||
if (!moved && Math.hypot(dxPx, dyPx) >= DRAG_THRESHOLD_PX) moved = true;
|
||||
if (!moved && Math.hypot(dxPx, dyPx) >= DRAG_THRESHOLD_PX) {
|
||||
// A real drag has started — now capture so we keep receiving move/up
|
||||
// even if the pointer leaves the canvas. (Deferred from pointerdown so
|
||||
// taps still select nodes.)
|
||||
moved = true;
|
||||
try {
|
||||
node.setPointerCapture(e.pointerId);
|
||||
} catch {
|
||||
/* pointer not capturable (e.g. synthetic event) — drag still works */
|
||||
}
|
||||
}
|
||||
|
||||
const { dx, dy } = screenDeltaToSvg(
|
||||
dxPx,
|
||||
|
||||
Reference in New Issue
Block a user