From 369a0213e5a4321175f7bee5b40461cd975ff541 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 29 May 2026 16:26:07 +0200 Subject: [PATCH] feat(stammbaum): serialise pan/zoom state to URL params (#692) Co-Authored-By: Claude Opus 4.8 --- .../src/lib/person/genealogy/panZoom.test.ts | 16 ++++++++++++++++ frontend/src/lib/person/genealogy/panZoom.ts | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/frontend/src/lib/person/genealogy/panZoom.test.ts b/frontend/src/lib/person/genealogy/panZoom.test.ts index fed80448..4e1a8fd6 100644 --- a/frontend/src/lib/person/genealogy/panZoom.test.ts +++ b/frontend/src/lib/person/genealogy/panZoom.test.ts @@ -2,6 +2,7 @@ import { describe, it, expect } from 'vitest'; import { clampZoom, parsePanZoomParams, + serializePanZoomParams, DEFAULT_VIEW, DEFAULT_ZOOM, MIN_ZOOM, @@ -59,3 +60,18 @@ describe('parsePanZoomParams', () => { expect(parsePanZoomParams({ z: '-3' }).z).toBe(MIN_ZOOM); }); }); + +describe('serializePanZoomParams', () => { + it('produces string cx/cy/z keys', () => { + expect(serializePanZoomParams({ x: 120, y: -40, z: 1.5 })).toEqual({ + cx: '120', + cy: '-40', + z: '1.5' + }); + }); + + it('round-trips through parsePanZoomParams', () => { + const state = { x: 87.5, y: -12.25, z: 2.4 }; + expect(parsePanZoomParams(serializePanZoomParams(state))).toEqual(state); + }); +}); diff --git a/frontend/src/lib/person/genealogy/panZoom.ts b/frontend/src/lib/person/genealogy/panZoom.ts index 1ec304ed..714764f5 100644 --- a/frontend/src/lib/person/genealogy/panZoom.ts +++ b/frontend/src/lib/person/genealogy/panZoom.ts @@ -56,3 +56,8 @@ export function parsePanZoomParams(raw: { z: clampZoom(finiteOr(raw.z, DEFAULT_ZOOM)) }; } + +/** Serialise a view state into URL query params (the inverse of {@link parsePanZoomParams}). */ +export function serializePanZoomParams(state: PanZoomState): { cx: string; cy: string; z: string } { + return { cx: String(state.x), cy: String(state.y), z: String(state.z) }; +}