fix(posters): measure the full-version header instead of guessing 460
Some checks are pending
build-gate / build (push) Waiting to run
Some checks are pending
build-gate / build (push) Waiting to run
Four zones had NO POSTER AT ALL. measureHeader() opened with
`if (!SPARSE) return HEADER_BASE` — a flat 460 — so the per-zone measurement its
own comments describe ("HEADER IS PER-ZONE, NOT A SHARED CONSTANT...
measureHeader() predicts the height from the zone's OWN content") only ever ran
in SPARSE mode. Outside it, any zone whose header was taller than 460 tripped
the fail-loud guard and rendered nothing:
oceania-indonesia 504 andean-caribbean 504
asia-china-tibet-autonomous-region 481 deaf 619
Raising the constant was not the fix. HEADER is subtracted from the map height,
so 460 -> 620 would have stolen 160px of map from the 25 healthy sheets to
rescue 4 — the exact tradeoff the per-zone measurement exists to avoid, and the
one its own comment records (tuned to North India, it overflowed west-africa;
tuned to west-africa, it stole from everything else).
MEASURED the real header on six zones instead:
HEAD_BOTTOM = (headY + 34) + 118 exact on all six
headY = 191 + 23 * tableLines exact on all four probed
The 118 is the two vision columns — a constant 104, because that copy is fixed
and wraps identically on every sheet — plus the 14px trailing gap. ALL per-zone
variation is the facts table, which advances 23px per wrapped line. So this is
arithmetic on the same inputs the renderer wraps, not an estimate, and it needs
no calibration history like the SPARSE model's +24/+52/+66/-8/+6 above it.
★ THE ERROR WORTH RECORDING: my first attempt derived the constant by READING
the code — tracing headY's assignments to 150 + 23n - 12 — and was 53px short on
every zone, because the scripture block between the table and the vision columns
also advances the cursor and I had not traced it. Every zone then failed,
including ones that worked before. Deriving it from four measured renders got it
exact. Reading selectively is not measuring.
Result: 28 posters render, zero failures. And the map GREW on the healthy
sheets, because they no longer pay for the worst case — laos' map frame starts
at y=443 against the old flat 460, while deaf takes the 627 it genuinely needs.
Still missing after this: deaf-old-world and deaf-new-world-asia-pacific, which
never reach the render at all (silent skip, exit 0 — they are `deaf_predicate`
selectors that leafZones() does not return). Different cause, carded separately.
This commit is contained in:
parent
8059eeddd5
commit
cfea0c8e70
1 changed files with 48 additions and 1 deletions
|
|
@ -448,7 +448,54 @@ const setMapBox = (headerPx) => {
|
|||
// so each poster gets exactly the header it needs and the map takes the rest.
|
||||
// The fail-loud guard still runs afterwards as the backstop.
|
||||
function measureHeader(zone, pins, ctryNames, provinces) {
|
||||
if (!SPARSE) return HEADER_BASE;
|
||||
if (!SPARSE) {
|
||||
// ── FULL VERSION: measured, not a constant ────────────────────────────────
|
||||
// This used to `return HEADER_BASE` — a flat 460 — so the per-zone measurement
|
||||
// everything above describes ONLY ever ran in SPARSE mode. Four zones' content
|
||||
// is taller than 460 and they threw the fail-loud guard, which meant they had
|
||||
// NO POSTER AT ALL: oceania-indonesia and andean-caribbean at 504, deaf at 619,
|
||||
// asia-china-tibet at 481.
|
||||
//
|
||||
// Raising the constant is the wrong fix: HEADER is subtracted from the map
|
||||
// height, so 460 -> 620 would steal 160px of map from the 25 healthy sheets to
|
||||
// rescue 4. That is exactly the tradeoff the per-zone measurement exists to
|
||||
// avoid (see the note above about tuning to North India breaking west-africa).
|
||||
//
|
||||
// MEASURED the full header on six zones and the shape is exact, not estimated:
|
||||
// HEAD_BOTTOM = (headY + 34) + 118 on laos, west-africa, deaf,
|
||||
// oceania-indonesia, andean-caribbean
|
||||
// and asia-china-tibet — all six.
|
||||
// The 118 is the two vision columns (a constant 104 — they are fixed copy, so
|
||||
// they wrap the same on every sheet) plus the 14px trailing gap. ALL per-zone
|
||||
// variation is the facts table, which advances headY by 23px PER WRAPPED LINE.
|
||||
//
|
||||
// So the prediction is arithmetic on the same inputs the renderer wraps, and it
|
||||
// needs no slack — unlike the SPARSE model below, whose long +24/+52/+66/-8/+6
|
||||
// calibration history is what an estimate costs.
|
||||
const HEAD_MAXCH = 78; // must match the renderer's wrap width
|
||||
const wrapCount = (items) => {
|
||||
let lines = 0;
|
||||
let line = '';
|
||||
for (const it of items || []) {
|
||||
const next = line ? `${line} · ${it}` : it;
|
||||
if (next.length > HEAD_MAXCH) { lines += 1; line = it; } else { line = next; }
|
||||
}
|
||||
return lines + (line ? 1 : 0);
|
||||
};
|
||||
// headY = 191 + 23 * lines, DERIVED FROM THE RENDER on four zones rather than
|
||||
// from reading the code — an earlier attempt at this reasoned the constant to
|
||||
// 138 by tracing headY's assignments and was 53px short on every zone, because
|
||||
// the scripture block between the table and the vision columns advances the
|
||||
// cursor too. Measured: laos 283 (4 lines), west-africa 306 (5),
|
||||
// oceania-indonesia 352 (7), deaf 467 (12) — headY - 23*lines = 191 on all four.
|
||||
// The 4 rows are countries, administrative areas, people groups, series.
|
||||
const tableLines = wrapCount(ctryNames) + wrapCount(provinces) + 1 + 1;
|
||||
const headY = 191 + tableLines * 23;
|
||||
// +8 of slack: the guard is the real check, and being short fails the build
|
||||
// while being long costs a few px of map. Measured exact on six zones, so the
|
||||
// slack covers a content shape none of them had rather than a known gap.
|
||||
return headY + 34 + 118 + 8;
|
||||
}
|
||||
// PREDICT WITH THE SAME COLUMN WIDTHS THE RENDERER USES. This used to assume
|
||||
// four EQUAL quarter-width columns, but the table now sizes columns to their
|
||||
// content — so a zone with one long list (deaf, europe) was predicted to wrap
|
||||
|
|
|
|||
Loading…
Reference in a new issue