doxa-maps/library/constants/posterSizes.js
doxa-maps d5ba21fa76 doxa-maps — portable bundler for embeddable JAMstack maps
Standalone repo that builds embeddable JAMstack map bundles (web components),
composes them into a lazy-loaded SPA via layouts/, and optionally wraps a
Capacitor Android/iOS app — one build, choose your output/CDN. Diátaxis docs.

History reset to a single clean commit; no PII, IPs, or internal terms.
2026-09-10 01:53:07 +00:00

98 lines
3.7 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* posterSizes.js — preset poster dimensions (US + ISO).
*
* Each preset gives:
* • inches — natural unit for US sizes (and the unit jsPDF/svg2pdf accept)
* • mm — natural unit for ISO sizes (also useful for print specs)
* • px300 — pre-computed pixel size at 300 DPI (for quick lookup)
* • category — 'us' | 'iso'
* • orientation — natural orientation; the renderer can flip via PosterSpec
* • recommendedDpi — sane default DPI for the size
*
* Use `getPosterSize(id)` to fetch by id; iteration order follows POSTER_ORDER.
*
* @example
* const a3 = getPosterSize('a3');
* const spec = { widthIn: a3.inches.w, heightIn: a3.inches.h, dpi: 300, ... };
*/
const MM_PER_IN = 25.4;
const mmToIn = (mm) => mm / MM_PER_IN;
const inToMm = (i) => i * MM_PER_IN;
function size(id, label, w, h, unit, category, orientation, recommendedDpi) {
const inches = (unit === 'in')
? { w, h }
: { w: round3(mmToIn(w)), h: round3(mmToIn(h)) };
const mm = (unit === 'mm')
? { w, h }
: { w: round1(inToMm(w)), h: round1(inToMm(h)) };
const px300 = {
w: Math.round(inches.w * 300),
h: Math.round(inches.h * 300),
};
return { id, label, inches, mm, px300, category, orientation, recommendedDpi };
}
function round3(n) { return Math.round(n * 1000) / 1000; }
function round1(n) { return Math.round(n * 10) / 10; }
/**
* @typedef {Object} PosterSize
* @property {string} id
* @property {string} label
* @property {{ w: number, h: number }} inches
* @property {{ w: number, h: number }} mm
* @property {{ w: number, h: number }} px300
* @property {'us'|'iso'} category
* @property {'portrait'|'landscape'|'either'} orientation
* @property {150|200|300} recommendedDpi
*/
/** @type {Record<string, PosterSize>} */
export const POSTER_SIZES = {
// ─── US sizes ──────────────────────────────────────────────────────
letter: size('letter', 'Letter (8.5×11")', 8.5, 11, 'in', 'us', 'either', 300),
tabloid: size('tabloid', 'Tabloid (11×17")', 11, 17, 'in', 'us', 'either', 300),
'18x24': size('18x24', '18 × 24"', 18, 24, 'in', 'us', 'portrait', 300),
'24x36': size('24x36', '24 × 36"', 24, 36, 'in', 'us', 'portrait', 300),
'27x40': size('27x40', '27 × 40"', 27, 40, 'in', 'us', 'portrait', 200),
// ─── ISO sizes ─────────────────────────────────────────────────────
a4: size('a4', 'A4 (210 × 297 mm)', 210, 297, 'mm', 'iso', 'either', 300),
a3: size('a3', 'A3 (297 × 420 mm)', 297, 420, 'mm', 'iso', 'either', 300),
a2: size('a2', 'A2 (420 × 594 mm)', 420, 594, 'mm', 'iso', 'portrait', 300),
a1: size('a1', 'A1 (594 × 841 mm)', 594, 841, 'mm', 'iso', 'portrait', 200),
a0: size('a0', 'A0 (841 × 1189 mm)', 841, 1189, 'mm', 'iso', 'portrait', 150),
};
/** Display order for UI dropdowns. */
export const POSTER_ORDER = [
'letter', 'tabloid', '18x24', '24x36', '27x40',
'a4', 'a3', 'a2', 'a1', 'a0',
];
/** Default for research-map posters. */
export const DEFAULT_POSTER_ID = '24x36';
/**
* @param {string} id
* @returns {PosterSize|null}
*/
export function getPosterSize(id) {
return POSTER_SIZES[id] || null;
}
/**
* @returns {PosterSize[]}
*/
export function listPosterSizes() {
return POSTER_ORDER.map((id) => POSTER_SIZES[id]);
}
/**
* @param {'us'|'iso'} category
*/
export function listByCategory(category) {
return listPosterSizes().filter((s) => s.category === category);
}