feat(stammbaum): drive viewBox from PanZoomState (pan + zoom) (#692)

Replace the scalar zoom prop with a {x,y,z} PanZoomState. The viewBox centre
is offset by the pan and width/height scaled by zoom; the default {0,0,1}
frames the whole tree (fit-to-screen). Page header buttons now step view.z
through clampZoom over the resolved 0.25–3.0 range.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-29 16:35:49 +02:00
parent 197b668f20
commit 0422af8980
4 changed files with 77 additions and 36 deletions

View File

@@ -3,6 +3,12 @@ import { m } from '$lib/paraglide/messages.js';
import { page } from '$app/state';
import StammbaumTree from '$lib/person/genealogy/StammbaumTree.svelte';
import StammbaumSidePanel from '$lib/person/genealogy/StammbaumSidePanel.svelte';
import {
type PanZoomState,
DEFAULT_VIEW,
clampZoom,
ZOOM_STEP_KB
} from '$lib/person/genealogy/panZoom';
import type { components } from '$lib/generated/api';
type PersonNodeDTO = components['schemas']['PersonNodeDTO'];
@@ -23,12 +29,12 @@ let selectedId = $state<string | null>(
const selectedNode = $derived(data.nodes.find((n) => n.id === selectedId) ?? null);
let zoom = $state(1);
let view = $state<PanZoomState>(DEFAULT_VIEW);
function zoomIn() {
zoom = Math.min(2, zoom + 0.1);
view = { ...view, z: clampZoom(view.z + ZOOM_STEP_KB) };
}
function zoomOut() {
zoom = Math.max(0.4, zoom - 0.1);
view = { ...view, z: clampZoom(view.z - ZOOM_STEP_KB) };
}
</script>
@@ -97,7 +103,7 @@ function zoomOut() {
nodes={data.nodes}
edges={data.edges}
selectedId={selectedId}
zoom={zoom}
panZoom={view}
onSelect={(id) => (selectedId = id)}
/>
</div>