From 1855c8cad4c8859241a1c047d3970a8932f08bca Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Sat, 3 Oct 2026 11:03:34 +0000 Subject: [PATCH] UPG100 poster page 1: larger people-group names and smaller header-column text (header columns 22 to 18px; names capped at 19px instead of 15, with tighter rows on dense zones) --- library/packet/poster-render.js | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/library/packet/poster-render.js b/library/packet/poster-render.js index 44c2a2827..7bed82724 100644 --- a/library/packet/poster-render.js +++ b/library/packet/poster-render.js @@ -287,11 +287,14 @@ const HEAD_COLUMNS_CSS = ` // at 22 / 21px with darker ink: about 8pt on the printed page. Only the full layout (HEAD_COLUMNS) gets this; the // series-wide rules above stay as they were, so the series' SPARSE posters are byte-identical. // Print size = sheet px x 0.92 (the packet's margins) x 0.408 (1500px = 8.5in): 22px ≈ 8.3pt, 19px ≈ 7.1pt. +// ★ THE NAMES COME FIRST (2026-10-03): the header columns step down to 18px (≈6.8pt; keys 15.5, headings 19) so +// the people-group names beside the map can be the larger type. The shorter band gives the map ~80px more height, +// and the names' cap on this layout rises to 19px (see MAXF). These sizes must equal HC's (fs, keyFs, headFs). const HEAD_COLUMNS_FULL_CSS = ` - .hcolk{font-size:19px;fill:#2f2a22;font-weight:800;letter-spacing:.1em} - .hcolt{font-size:22px;fill:#3a362c} + .hcolk{font-size:15.5px;fill:#2f2a22;font-weight:800;letter-spacing:.1em} + .hcolt{font-size:18px;fill:#3a362c} .hcolb{font-weight:700;fill:#2f2a22} - .hcolh{font-family:Georgia,'Times New Roman',serif;font-size:23px;font-weight:700;fill:#2f2a22;letter-spacing:.04em;font-variant:small-caps} + .hcolh{font-family:Georgia,'Times New Roman',serif;font-size:19px;font-weight:700;fill:#2f2a22;letter-spacing:.04em;font-variant:small-caps} .hvref{font-size:19px} .hverse{font-size:19.5px} .hsrc{font-size:22px;fill:#4a4636} @@ -691,7 +694,9 @@ function layoutLabels(pins, project) { col.forEach((it) => { it.maxNum = MAXNUM_L; }); // A map-only sheet frees the header and footer bands the same way SPARSE frees the vision // columns, so it gets SPARSE's ceiling; the solver still only uses what the column can hold. - const MAXF = (SPARSE || MAP_ONLY) ? 19 : 15; + // The three-column sheet (HEAD_COLUMNS) gets it too: there the names are the main text, and the cap of 15 + // held 21 of the 28 zones' names at 15px (≈5.6pt printed) with room to spare in the band. + const MAXF = (SPARSE || MAP_ONLY || HEAD_COLUMNS) ? 19 : 15; // AVAIL IS THE COLUMN, AND THE NAME DOES NOT GET ALL OF IT. // The renderer draws the name starting one number-column IN from the column's // map-facing edge (`nameEdge = tx ± numColW`) but does not shrink its budget by @@ -725,18 +730,23 @@ function layoutLabels(pins, project) { if (line) out.push(line); return out.length ? out : [it.name]; }; + // The air between rows, as a share of the size. The three-column sheet sets it tighter (0.22): its densest + // zones (95-118 names) are held by the band's height, and the tighter rows turn that height into type + // (west-africa 12.5 -> 13.8px, laos 15.8 -> 17.3px). A row's underline sits 0.30 below its baseline and the + // next row's capitals start 0.56 below it, so they stay clear. Every other sheet keeps 0.34. + const GAPF = HEAD_COLUMNS ? 0.22 : 0.34; let font = MAXF, wraps = null; for (let f = MAXF; f >= 8; f -= 0.25) { const ws = col.map((it) => wrapName(it, f)); const totalLines = ws.reduce((a, w) => a + w.length, 0); // Each line needs f*1.06 of pitch, plus a little air between rows. - if (totalLines * (f * 1.06) + col.length * (f * 0.34) <= bandH) { font = f; wraps = ws; break; } + if (totalLines * (f * 1.06) + col.length * (f * GAPF) <= bandH) { font = f; wraps = ws; break; } } if (!wraps) wraps = col.map((it) => wrapName(it, font)); // Re-pitch rows by LINE COUNT so a two-line name gets the room it needs and // single-line rows are not stretched to match it. const lineH = font * 1.06; - const gap = font * 0.34; + const gap = font * GAPF; const usedH = wraps.reduce((a, w) => a + w.length * lineH, 0) + col.length * gap; const slack = Math.max(0, bandH - usedH) / Math.max(1, col.length); let cursor = bandTop + slack / 2; @@ -831,7 +841,8 @@ function paraInto(push, text, { x, y, w, fs, lh, cls, lead }) { // 1 Jesus' strategy to feed the 5000 // 2 the facts: a bold key above each value (countries, administrative areas, people groups, series) // 3 what the series is -const HC = { gut: 32, fs: 22, lh: 27, keyFs: 19, keyLh: 24, headLh: 30, gap: 8, headFs: 23 }; +// The sizes equal HEAD_COLUMNS_FULL_CSS (.hcolt = fs, .hcolk = keyFs, .hcolh = headFs); leading and gaps scale with them. +const HC = { gut: 32, fs: 18, lh: 22, keyFs: 15.5, keyLh: 19.5, headLh: 24.5, gap: 7, headFs: 19 }; // textW is calibrated for Lato. Without Lato the browser falls back to a system sans that sets // these columns 2-6% wider (measured 1.05-1.06x in DejaVu Sans). Each block is centred on its // width at 1.03x, halfway, so any overrun splits across both sides instead of all running right.