feat(stammbaum): convert pointer pixel delta to SVG units (#692)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-29 16:27:14 +02:00
parent 369a0213e5
commit 0170f79690
2 changed files with 36 additions and 0 deletions

View File

@@ -3,6 +3,7 @@ import {
clampZoom, clampZoom,
parsePanZoomParams, parsePanZoomParams,
serializePanZoomParams, serializePanZoomParams,
screenDeltaToSvg,
DEFAULT_VIEW, DEFAULT_VIEW,
DEFAULT_ZOOM, DEFAULT_ZOOM,
MIN_ZOOM, MIN_ZOOM,
@@ -75,3 +76,18 @@ describe('serializePanZoomParams', () => {
expect(parsePanZoomParams(serializePanZoomParams(state))).toEqual(state); expect(parsePanZoomParams(serializePanZoomParams(state))).toEqual(state);
}); });
}); });
describe('screenDeltaToSvg', () => {
it('scales a pixel delta by the viewBox-to-element ratio per axis', () => {
// viewBox is 2x the element in width, 2x in height → 1px == 2 SVG units.
expect(screenDeltaToSvg(10, 5, 1000, 800, 500, 400)).toEqual({ dx: 20, dy: 10 });
});
it('is identity when the viewBox matches the element pixel size', () => {
expect(screenDeltaToSvg(7, -3, 600, 600, 600, 600)).toEqual({ dx: 7, dy: -3 });
});
it('returns zero when the element has no measured size', () => {
expect(screenDeltaToSvg(10, 10, 1000, 800, 0, 0)).toEqual({ dx: 0, dy: 0 });
});
});

View File

@@ -61,3 +61,23 @@ export function parsePanZoomParams(raw: {
export function serializePanZoomParams(state: PanZoomState): { cx: string; cy: string; z: string } { export function serializePanZoomParams(state: PanZoomState): { cx: string; cy: string; z: string } {
return { cx: String(state.x), cy: String(state.y), z: String(state.z) }; return { cx: String(state.x), cy: String(state.y), z: String(state.z) };
} }
/**
* Convert a pointer delta in CSS pixels into SVG user units, using the current
* viewBox-to-element ratio per axis. This is the distance the pointer traversed
* expressed in the tree's coordinate space; the gesture handler subtracts it
* from the pan offset so the canvas follows the finger (US-PAN-001).
*/
export function screenDeltaToSvg(
dxPx: number,
dyPx: number,
viewBoxW: number,
viewBoxH: number,
elPxW: number,
elPxH: number
): { dx: number; dy: number } {
return {
dx: elPxW > 0 ? dxPx * (viewBoxW / elPxW) : 0,
dy: elPxH > 0 ? dyPx * (viewBoxH / elPxH) : 0
};
}