Lebensuhr clock: real 12-hour dial instead of a nonexistent 24-hour one

A clock face has 12 numbers, not 24 — the previous version invented
a 0-24 dial that doesn't exist on any real clock. Now a proper 1-12
face, with each age plotted at its 12h-mod position, labeled with
time + vorm./nachm. (every dial position is hit twice a day), and a
filled dot for vormittags vs. a hollow ring for nachmittags so the
two laps stay visually distinct.
This commit is contained in:
Marco
2026-08-26 15:54:09 +00:00
parent f0f5252d10
commit 4326072fbe
+49 -54
View File
@@ -196,24 +196,19 @@ export default function LebensuhrPage() {
</P>
{/* Decorative companion to the table below, not a replacement for
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. 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. */}
it — a real 12-hour dial (112, like an actual clock face;
an earlier version numbered it 024, which doesn't exist on
a real clock and read wrong for exactly that reason), with
the 8 ages plotted at their 12-hour position. Since every
day has two laps around a 12h dial, each point also carries
"vorm."/"nachm." — and a filled dot for vormittags vs. a
hollow ring for nachmittags, so the two laps stay visually
distinct even without reading the text. Coordinates are
hand-computed from lebensuhrRows's own age→time pairs
(hour mod 12, -90° so 12 sits at the top) — if those rows
ever change, these need updating too. */}
<div className="flex justify-center py-2">
<svg viewBox="0 0 420 420" className="w-full max-w-[22rem] h-auto" aria-hidden="true">
<svg viewBox="-10 -10 440 440" 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;
@@ -224,53 +219,51 @@ export default function LebensuhrPage() {
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} />;
})}
{/* Every hour tick labeled on the 24h scale (h*2), so the
dial can't be mistaken for a normal 12-hour clock face. */}
{/* The dial's own numerals, 112, same as a real clock face. */}
{([
[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={h % 3 === 0 ? "fill-text-primary" : "fill-text-muted"}
style={{ fontSize: h % 3 === 0 ? 13 : 10, fontWeight: h % 3 === 0 ? 700 : 400 }}
>
{label}
[1, 292.5, 67.1, "start"],
[2, 352.9, 127.5, "start"],
[3, 375, 210, "start"],
[4, 352.9, 292.5, "start"],
[5, 292.5, 352.9, "start"],
[6, 210, 375, "middle"],
[7, 127.5, 352.9, "end"],
[8, 67.1, 292.5, "end"],
[9, 45, 210, "end"],
[10, 67.1, 127.5, "end"],
[11, 127.5, 67.1, "end"],
[12, 210, 45, "middle"],
] as [number, number, number, "start" | "middle" | "end"][]).map(([h, x, y, anchor]) => (
<text key={h} x={x} y={y} textAnchor={anchor} dominantBaseline="middle" className="fill-text-muted" style={{ fontSize: 12, fontWeight: 600 }}>
{h}
</text>
))}
{/* One dot per lebensuhrRows entry, at its 12h-dial position
(hour mod 12) — filled for vormittags, hollow ring for
nachmittags, since the same dial position is hit twice a
day. */}
{([
[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]) => (
[10, "2:40", "vorm.", 326.2, 189.5, 379.4, 180.1, "start"],
[20, "5:20", "vorm.", 250.4, 320.9, 268.8, 371.6, "start"],
[30, "8:00", "vorm.", 107.8, 269.0, 61.0, 296.0, "end"],
[40, "10:40", "vorm.", 134.2, 119.6, 99.4, 78.2, "end"],
[50, "1:20", "nachm.", 285.8, 119.6, 320.6, 78.2, "start"],
[60, "4:00", "nachm.", 312.2, 269.0, 359.0, 296.0, "start"],
[70, "6:40", "nachm.", 169.6, 320.9, 151.2, 371.6, "end"],
[80, "9:20", "nachm.", 93.8, 189.5, 40.6, 180.1, "end"],
] as [number, string, string, number, number, number, number, "start" | "end"][]).map(([age, time, ampm, 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="5" fill="var(--color-brand)" />
<circle cx={dx} cy={dy} r="5" fill={ampm === "vorm." ? "var(--color-brand)" : "none"} stroke="var(--color-brand)" strokeWidth="2" />
<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 + 16} textAnchor={anchor} dominantBaseline="middle" className="fill-text-muted" style={{ fontSize: 12 }}>
<text x={lx} y={ly + 15} textAnchor={anchor} dominantBaseline="middle" className="fill-text-muted" style={{ fontSize: 11 }}>
{time}
</text>
<text x={lx} y={ly + 27} textAnchor={anchor} dominantBaseline="middle" className="fill-text-muted" style={{ fontSize: 10, fontStyle: "italic" }}>
{ampm}
</text>
</g>
))}
<text x="210" y="196" textAnchor="middle" className="fill-text-primary" style={{ fontFamily: "var(--font-caveat)", fontSize: 30 }}>
@@ -281,7 +274,9 @@ export default function LebensuhrPage() {
</text>
</svg>
</div>
<p className="text-center text-body-sm text-text-muted -mt-1">Alter (fett) und die passende Uhrzeit darunter.</p>
<p className="text-center text-body-sm text-text-muted -mt-1">
Gefüllter Punkt = vormittags, Ring = nachmittags jede Uhrzeit läuft schließlich zweimal am Tag über das Zifferblatt.
</p>
{/* Still a real table (explicit "Alter"/"Uhrzeit" headers — a
dot-on-a-line version tried here first read ambiguous