feat(stammbaum): touch/mouse/wheel pan & pinch zoom gestures (#692)
Add a panZoomGestures action: one-finger/left-button drag pans, two-finger pinch and Ctrl+wheel zoom around the centroid, plain wheel pans. Pan is edge-clamped via clampPan (no infinite scroll), a real drag suppresses the trailing node click, and inertia decays after release unless prefers-reduced- motion. Canvas container switches from native scroll to overflow-hidden. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -113,6 +113,20 @@ export function zoomAtPoint(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamp the pan offset so the canvas cannot be dragged off the edge (US-PAN-001
|
||||
* AC4 — no infinite scroll). The pannable range on each axis is half the
|
||||
* difference between the base frame and the (smaller) zoomed viewBox; when the
|
||||
* whole tree fits (z ≤ 1) the range collapses to zero, so the view stays centred.
|
||||
*/
|
||||
export function clampPan(state: PanZoomState, baseW: number, baseH: number): PanZoomState {
|
||||
const clampAxis = (pan: number, base: number) => {
|
||||
const limit = Math.max(0, (base - base / state.z) / 2);
|
||||
return Math.min(limit, Math.max(-limit, pan)) || 0; // normalise -0 → 0
|
||||
};
|
||||
return { x: clampAxis(state.x, baseW), y: clampAxis(state.y, baseH), z: state.z };
|
||||
}
|
||||
|
||||
/**
|
||||
* Pan so a node sits at the viewBox centre (US-PAN-005). Because the viewBox
|
||||
* centre is `baseCentre + pan` independent of zoom, centring is a pure pan:
|
||||
|
||||
Reference in New Issue
Block a user