Lebensuhr clock: bigger, unclipped, every hour tick labeled

Sized the SVG up (viewBox 250->420) after labels clipped at the
edge, and gave all 12 ticks a real 24h-scale number (0,2,4…22, full
"HH:00" at the 4 cardinal points) instead of just 00/06/12/18 — with
only 4 numbers shown at those same 4 positions, the dial read like
an ordinary 12-hour clock face (implying two laps/day) rather than
the single 24h lap it actually represents.
This commit is contained in:
Marco
2026-08-26 15:48:58 +00:00
parent 0de2e1c1be
commit f0f5252d10
+54 -33
View File
@@ -199,63 +199,84 @@ export default function LebensuhrPage() {
it (a version that tried to carry the actual Alter/Uhrzeit
pairs on its own read ambiguous — see the table's own
comment) — the 8 ages plotted at their proportional clock
position, each labeled with its matching time too (age alone
didn't make the time connection obvious), plus 00/06/12/18
markers on the ring itself so it reads as an actual 24h
clock. Coordinates are hand-computed (evenly spaced every
40°/2h, since age/90, time/24 and tick/12 are all the same
proportion, with -90° so age/hour 0 sits at the top), not
derived from lebensuhrRows — if the rows above ever change,
these need updating too. */}
position, each labeled with its matching time too. All 12
ticks now carry their real 24h-scale hour (0,2,4…22, full
"HH:00" at the four cardinal ones) instead of just 4 bare
numbers — a dial showing only 00/06/12/18 read like an
ordinary 12-hour clock face (same 4 positions), which
wrongly implied two laps per day instead of one. Sized up
(viewBox 420 vs. the original 250) after the smaller version
clipped the longer time labels at the edge. Coordinates are
hand-computed (evenly spaced every 40°/2h, since age/90,
time/24 and tick/12 are all the same proportion, with -90°
so age/hour 0 sits at the top), not derived from
lebensuhrRows — if the rows above ever change, these need
updating too. */}
<div className="flex justify-center py-2">
<svg viewBox="0 0 250 250" className="w-full max-w-[17rem] h-auto" aria-hidden="true">
<circle cx="125" cy="125" r="100" stroke="var(--color-border)" strokeWidth="1.5" fill="none" />
<svg viewBox="0 0 420 420" className="w-full max-w-[22rem] h-auto" aria-hidden="true">
<circle cx="210" cy="210" r="150" stroke="var(--color-border)" strokeWidth="1.5" fill="none" />
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].map((h) => {
const deg = (h / 12) * 360 - 90;
const rad = (deg * Math.PI) / 180;
const major = h % 3 === 0;
const rIn = major ? 88 : 92;
const x1 = 125 + rIn * Math.cos(rad), y1 = 125 + rIn * Math.sin(rad);
const x2 = 125 + 100 * Math.cos(rad), y2 = 125 + 100 * Math.sin(rad);
const rIn = major ? 140 : 145;
const x1 = 210 + rIn * Math.cos(rad), y1 = 210 + rIn * Math.sin(rad);
const x2 = 210 + 150 * Math.cos(rad), y2 = 210 + 150 * Math.sin(rad);
return <line key={h} x1={x1} y1={y1} x2={x2} y2={y2} stroke="var(--color-border)" strokeWidth={major ? 2 : 1.5} />;
})}
{/* 00/06/12/18 — the ring's own hour markers, so the age
labels below have a time scale to read against. */}
{/* Every hour tick labeled on the 24h scale (h*2), so the
dial can't be mistaken for a normal 12-hour clock face. */}
{([
[0, "00", 125, 12, "middle"],
[3, "06", 238, 125, "start"],
[6, "12", 125, 238, "middle"],
[9, "18", 12, 125, "end"],
[0, "00:00", 210, 45, "middle"],
[1, "02", 289.0, 73.2, "start"],
[2, "04", 346.8, 131.0, "start"],
[3, "06:00", 375, 210, "start"],
[4, "08", 346.8, 289.0, "start"],
[5, "10", 289.0, 346.8, "start"],
[6, "12:00", 210, 375, "middle"],
[7, "14", 131.0, 346.8, "end"],
[8, "16", 73.2, 289.0, "end"],
[9, "18:00", 45, 210, "end"],
[10, "20", 73.2, 131.0, "end"],
[11, "22", 131.0, 73.2, "end"],
] as [number, string, number, number, "start" | "middle" | "end"][]).map(([h, label, x, y, anchor]) => (
<text key={h} x={x} y={y} textAnchor={anchor} dominantBaseline="middle" className="fill-text-muted" style={{ fontSize: 10 }}>
<text
key={h}
x={x}
y={y}
textAnchor={anchor}
dominantBaseline="middle"
className={h % 3 === 0 ? "fill-text-primary" : "fill-text-muted"}
style={{ fontSize: h % 3 === 0 ? 13 : 10, fontWeight: h % 3 === 0 ? 700 : 400 }}
>
{label}
</text>
))}
{([
[10, "02:40", 175.1, 65.2, 200.8, 34.6, "start"],
[20, "05:20", 201.8, 111.5, 241.2, 104.5, "start"],
[30, "08:00", 192.5, 164.0, 227.2, 184.0, "start"],
[40, "10:40", 151.7, 198.3, 165.4, 235.9, "start"],
[50, "13:20", 98.3, 198.3, 84.6, 235.9, "end"],
[60, "16:00", 57.5, 164.0, 22.8, 184.0, "end"],
[70, "18:40", 48.2, 111.5, 8.8, 104.5, "end"],
[80, "21:20", 74.9, 65.2, 49.2, 34.6, "end"],
[10, "02:40", 285.8, 119.6, 320.6, 78.2, "start"],
[20, "05:20", 326.2, 189.5, 379.4, 180.1, "start"],
[30, "08:00", 312.2, 269.0, 359.0, 296.0, "start"],
[40, "10:40", 250.4, 320.9, 268.8, 371.6, "start"],
[50, "13:20", 169.6, 320.9, 151.2, 371.6, "end"],
[60, "16:00", 107.8, 269.0, 61.0, 296.0, "end"],
[70, "18:40", 93.8, 189.5, 40.6, 180.1, "end"],
[80, "21:20", 134.2, 119.6, 99.4, 78.2, "end"],
] as [number, string, number, number, number, number, "start" | "end"][]).map(([age, time, dx, dy, lx, ly, anchor]) => (
<g key={age}>
<line x1={dx} y1={dy} x2={lx} y2={ly} stroke="var(--color-border)" strokeWidth="1" />
<circle cx={dx} cy={dy} r="4" fill="var(--color-brand)" />
<text x={lx} y={ly} textAnchor={anchor} dominantBaseline="middle" className="fill-text-primary" style={{ fontSize: 12, fontWeight: 700 }}>
<circle cx={dx} cy={dy} r="5" fill="var(--color-brand)" />
<text x={lx} y={ly} textAnchor={anchor} dominantBaseline="middle" className="fill-text-primary" style={{ fontSize: 15, fontWeight: 700 }}>
{age}
</text>
<text x={lx} y={ly + 13} textAnchor={anchor} dominantBaseline="middle" className="fill-text-muted" style={{ fontSize: 9.5 }}>
<text x={lx} y={ly + 16} textAnchor={anchor} dominantBaseline="middle" className="fill-text-muted" style={{ fontSize: 12 }}>
{time}
</text>
</g>
))}
<text x="125" y="118" textAnchor="middle" className="fill-text-primary" style={{ fontFamily: "var(--font-caveat)", fontSize: 24 }}>
<text x="210" y="196" textAnchor="middle" className="fill-text-primary" style={{ fontFamily: "var(--font-caveat)", fontSize: 30 }}>
dein
</text>
<text x="125" y="142" textAnchor="middle" className="fill-text-primary" style={{ fontFamily: "var(--font-caveat)", fontSize: 24 }}>
<text x="210" y="228" textAnchor="middle" className="fill-text-primary" style={{ fontFamily: "var(--font-caveat)", fontSize: 30 }}>
Leben
</text>
</svg>