fix(stammbaum): anchor fresh visit to content top-left, drop space above row 1 (#692)
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m35s
CI / OCR Service Tests (pull_request) Successful in 23s
CI / Backend Unit Tests (pull_request) Successful in 3m41s
CI / fail2ban Regex (pull_request) Successful in 43s
CI / Semgrep Security Scan (pull_request) Successful in 21s
CI / Compose Bucket Idempotency (pull_request) Successful in 1m6s
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m35s
CI / OCR Service Tests (pull_request) Successful in 23s
CI / Backend Unit Tests (pull_request) Successful in 3m41s
CI / fail2ban Regex (pull_request) Successful in 43s
CI / Semgrep Security Scan (pull_request) Successful in 21s
CI / Compose Bucket Idempotency (pull_request) Successful in 1m6s
The frame-corner anchor + xMidYMid letterboxing left ~290px of empty space above the first row on desktop. Anchor to the content corner (first row / leftmost node, small margin) via cornerView, and switch the canvas to xMinYMin meet so a wide/short tree pins to the top-left instead of centring vertically. Verified live: gap above row 1 is now ~20px. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -12,8 +12,9 @@ import {
|
||||
import {
|
||||
type PanZoomState,
|
||||
clampZoom,
|
||||
clampPan,
|
||||
recentreOn,
|
||||
topLeftView,
|
||||
cornerView,
|
||||
ZOOM_STEP_KB
|
||||
} from '$lib/person/genealogy/panZoom';
|
||||
import { panZoomGestures } from '$lib/person/genealogy/panZoomGestures';
|
||||
@@ -143,10 +144,30 @@ const railRows = $derived(
|
||||
.map((r) => ({ rank: r.rank, label: r.label, centerY: r.y + NODE_H / 2 }))
|
||||
);
|
||||
|
||||
// A fresh visit (no shared URL state) lands on the tree's top-left corner rather
|
||||
// than its centre (#692). Runs once after layout is available.
|
||||
// A fresh visit (no shared URL state) lands on the tree's content top-left
|
||||
// rather than its centre (#692). Anchors to the first row / leftmost node (not
|
||||
// the padded frame corner, which would leave empty space above row 1), with a
|
||||
// small margin. Runs once after layout is available.
|
||||
const ANCHOR_MARGIN = 24;
|
||||
onMount(() => {
|
||||
if (anchorTopLeft) onPanZoom(topLeftView(baseDims.w, baseDims.h, panZoom.z));
|
||||
if (!anchorTopLeft) return;
|
||||
let minX = Infinity;
|
||||
let minY = Infinity;
|
||||
for (const pos of layout.positions.values()) {
|
||||
minX = Math.min(minX, pos.x);
|
||||
minY = Math.min(minY, pos.y);
|
||||
}
|
||||
if (!Number.isFinite(minX)) return; // no nodes
|
||||
const target = cornerView(
|
||||
minX - ANCHOR_MARGIN,
|
||||
minY - ANCHOR_MARGIN,
|
||||
baseCentre.x,
|
||||
baseCentre.y,
|
||||
baseDims.w,
|
||||
baseDims.h,
|
||||
panZoom.z
|
||||
);
|
||||
onPanZoom(clampPan(target, baseDims.w, baseDims.h));
|
||||
});
|
||||
|
||||
const viewBox = $derived.by(() => {
|
||||
@@ -309,7 +330,7 @@ const parentLinks = $derived.by<ParentLinks>(() => {
|
||||
<svg
|
||||
bind:this={svgEl}
|
||||
viewBox={viewBox}
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
preserveAspectRatio="xMinYMin meet"
|
||||
role="img"
|
||||
aria-label="Stammbaum"
|
||||
tabindex="0"
|
||||
|
||||
Reference in New Issue
Block a user