familytree

A self-hosted family tree builder.
Log | Files | Refs | README

commit e88bfa7864ba208f2939e6b2bc9ddea7bec43def
parent 8817fa61e397b9d30b036151ae561e4bec2923b2
Author: Julian Piribauer <julian.piribauer@gmail.com>
Date:   Sat,  9 May 2026 18:18:02 +0000

PDF: landscape, no browser headers/footers, Stammbaum title, fix connector overlap

- Switch to landscape orientation with zero page margins (suppresses browser print headers/footers)
- Title hardcoded to 'Stammbaum'
- Increase generation gap GY 188→280 and node height NH 115→130 for more breathing room
- Fix connector dropY: was midY+50 which landed inside the box (NH/2+50=107 < NH=115);
  now anchored at box bottom + 30px so the horizontal sibling bar always clears the parent box

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Diffstat:
Mstatic/app.js | 21++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/static/app.js b/static/app.js @@ -640,14 +640,14 @@ function drawPrintEdges(g, pos, { partnerships, parentLinks }, NW, NH) { const children = parentLinks.filter(pl => pl.partnership_id === ps.id).map(pl => pl.child_id); if (children.length) { - const dropY = midY + 50; + const dropY = p1.y + NH + 30; const childXs = children.map(cid => pos[cid]?.x ?? mx); if (children.length === 1 && Math.abs(childXs[0] - mx) > 1) { const cp = pos[children[0]]; if (cp) lineAttr(edgeG.append('path')) - .attr('d', `M${mx},${midY + 5} C${mx},${midY + 80} ${cp.x},${cp.y - 80} ${cp.x},${cp.y}`); + .attr('d', `M${mx},${p1.y + NH} C${mx},${dropY + 60} ${cp.x},${cp.y - 60} ${cp.x},${cp.y}`); } else { - lineAttr(edgeG.append('line')).attr('x1', mx).attr('y1', midY + 5).attr('x2', mx).attr('y2', dropY); + lineAttr(edgeG.append('line')).attr('x1', mx).attr('y1', p1.y + NH).attr('x2', mx).attr('y2', dropY); if (children.length > 1) { lineAttr(edgeG.append('line')) .attr('x1', Math.min(mx, ...childXs)).attr('y1', dropY) @@ -727,7 +727,7 @@ function drawPrintNodes(g, pos, people, NW, NH) { function downloadPDF() { if (!state.activeTreeId) return; const tree = state.trees.find(t => t.id === state.activeTreeId); - const NW = 225, NH = 115, GY = 188, CG = 52; + const NW = 225, NH = 130, GY = 280, CG = 52; const pos = computeLayout(state.graph, { nodeW: NW, genY: GY, coupleGap: CG, margin: 48 }); @@ -751,25 +751,24 @@ function downloadPDF() { const svgStr = new XMLSerializer().serializeToString(printSvg.node()); document.body.removeChild(container); - const treeName = tree ? esc(tree.name) : 'Family Tree'; const html = `<!DOCTYPE html> <html> <head> <meta charset="utf-8"> - <title>${treeName}</title> + <title>Stammbaum</title> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500&family=EB+Garamond:wght@400;600&display=swap" rel="stylesheet"> <style> - @page { size: auto; margin: 10mm; } + @page { size: landscape; margin: 0; } * { box-sizing: border-box; } - body { margin: 0; background: white; display: flex; flex-direction: column; align-items: center; } - h1 { font-family: 'EB Garamond', Georgia, serif; font-size: 22px; font-weight: 600; color: #111; margin: 16px 0 8px; } - svg { max-width: 100%; height: auto; display: block; } + body { margin: 8mm; background: white; display: flex; flex-direction: column; align-items: center; } + h1 { font-family: 'EB Garamond', Georgia, serif; font-size: 22px; font-weight: 600; color: #111; margin: 0 0 6mm; } + svg { width: 100%; height: auto; display: block; } </style> </head> <body> - <h1>${treeName}</h1> + <h1>Stammbaum</h1> ${svgStr} </body> </html>`;