diff --git a/frontend/src/lib/person/genealogy/panZoom.test.ts b/frontend/src/lib/person/genealogy/panZoom.test.ts new file mode 100644 index 00000000..509acdd8 --- /dev/null +++ b/frontend/src/lib/person/genealogy/panZoom.test.ts @@ -0,0 +1,26 @@ +import { describe, it, expect } from 'vitest'; +import { clampZoom, MIN_ZOOM, MAX_ZOOM } from './panZoom'; + +describe('clampZoom', () => { + it('returns the value unchanged when within range', () => { + expect(clampZoom(1)).toBe(1); + expect(clampZoom(0.5)).toBe(0.5); + expect(clampZoom(2.75)).toBe(2.75); + }); + + it('clamps below MIN_ZOOM up to MIN_ZOOM', () => { + expect(clampZoom(0.1)).toBe(MIN_ZOOM); + expect(clampZoom(0)).toBe(MIN_ZOOM); + expect(clampZoom(-5)).toBe(MIN_ZOOM); + }); + + it('clamps above MAX_ZOOM down to MAX_ZOOM', () => { + expect(clampZoom(5)).toBe(MAX_ZOOM); + expect(clampZoom(3.0001)).toBe(MAX_ZOOM); + }); + + it('exposes the resolved zoom bounds', () => { + expect(MIN_ZOOM).toBe(0.25); + expect(MAX_ZOOM).toBe(3.0); + }); +}); diff --git a/frontend/src/lib/person/genealogy/panZoom.ts b/frontend/src/lib/person/genealogy/panZoom.ts new file mode 100644 index 00000000..7b107440 --- /dev/null +++ b/frontend/src/lib/person/genealogy/panZoom.ts @@ -0,0 +1,19 @@ +/** + * Pan/zoom geometry for the Stammbaum canvas (#692). + * + * The Stammbaum renders zoom by deriving the SVG `viewBox` rather than applying + * a CSS transform (see `StammbaumTree.svelte`). This module is the single source + * of truth for the zoom bounds, the view-state shape, and every pure geometry + * helper used by the gesture action, the URL serialiser, and the page. Keeping + * the math here (and free of DOM access) makes it unit-testable in the node + * project. See ADR-026 for why this is custom rather than a third-party library. + */ + +/** Resolved zoom bounds (OQ-001). */ +export const MIN_ZOOM = 0.25; +export const MAX_ZOOM = 3.0; + +/** Clamp a zoom factor into the supported range. */ +export function clampZoom(z: number): number { + return Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, z)); +}