stash
This commit is contained in:
parent
f87b689e27
commit
0c025db799
16 changed files with 555 additions and 105 deletions
|
|
@ -81,14 +81,18 @@ const TEXT_REFERENCE_PX = 100; /* font size text leaves measure their natural a
|
|||
|
||||
// Below 10px, a general-purpose sans-serif gets illegible, so drawTextLeaf switches to a bitmap
|
||||
// font (Tom Thumb/Silkscreen) instead; see the empirical rationale (font choice, `scale`, and why
|
||||
// sizes aren't dpi-adjusted) at docs/implementation.md#pixel-font-selection.
|
||||
const PIXEL_FONT_TIERS = [
|
||||
{belowPx: 8, family: "Tom Thumb", scale: 3.2},
|
||||
{belowPx: 10, family: "Silkscreen"},
|
||||
// sizes aren't dpi-adjusted) at docs/implementation.md#pixel-font-selection. The 10px+ tier names
|
||||
// Inter explicitly (see ../scss/_label-fonts.scss) rather than falling back to the CSS generic
|
||||
// "sans-serif" keyword, which resolves to a different real font per browser/OS and would make the
|
||||
// same label print differently depending on where it was rendered from.
|
||||
const FONT_TIERS = [
|
||||
{belowPx: 8, family: "Tom Thumb", scale: 3.2, pixel: true},
|
||||
{belowPx: 10, family: "Silkscreen", pixel: true},
|
||||
{belowPx: Infinity, family: "Inter"},
|
||||
];
|
||||
|
||||
function fontFamilyFor(fontPx) {
|
||||
return PIXEL_FONT_TIERS.find(t => fontPx < t.belowPx) ?? {family: "sans-serif"};
|
||||
return FONT_TIERS.find(t => fontPx < t.belowPx);
|
||||
}
|
||||
|
||||
// Below this font size (px) or physical height (mm) - Tom Thumb's real-Chromium-tested legibility
|
||||
|
|
@ -291,11 +295,12 @@ function checkTextSizes(node, referencePx, pxPerMm, warnings, textInfo) {
|
|||
}
|
||||
}
|
||||
|
||||
// Always measures in sans-serif at the reference size, since the eventual font (see
|
||||
// PIXEL_FONT_TIERS) isn't known until layoutTree sizes the box this aspect ratio feeds into; the
|
||||
// resulting mismatch is invisible in practice, and checkTextSizes still catches real failures.
|
||||
// Always measures in Inter at the reference size, since the eventual font (see FONT_TIERS) isn't
|
||||
// known until layoutTree sizes the box this aspect ratio feeds into; the resulting mismatch (when
|
||||
// a pixel font tier ends up chosen instead) is invisible in practice, and checkTextSizes still
|
||||
// catches real failures.
|
||||
function measureTextBlock(ctx, lines, referencePx) {
|
||||
ctx.font = `${referencePx}px sans-serif`;
|
||||
ctx.font = `${referencePx}px "Inter"`;
|
||||
const width = Math.max(...lines.map(line => ctx.measureText(line).width));
|
||||
const height = referencePx * 1.15 * lines.length;
|
||||
return {width, height};
|
||||
|
|
@ -342,20 +347,18 @@ function drawQrLeaf(ctx, node) {
|
|||
// there's no "too small to draw" case left to special-case here.
|
||||
function drawTextLeaf(ctx, node, referencePx) {
|
||||
const fontPx = effectiveFontPx(node, referencePx);
|
||||
const {family, scale = 1} = fontFamilyFor(fontPx);
|
||||
const isPixelFont = family !== "sans-serif";
|
||||
const {family, scale = 1, pixel: isPixelFont = false} = fontFamilyFor(fontPx);
|
||||
// Position (not size - fontPx is already a whole pixel) still needs snapping for pixel fonts
|
||||
// to stay grid-aligned, since node.box.x/y are ordinary (fractional) layout math; sans-serif is
|
||||
// to stay grid-aligned, since node.box.x/y are ordinary (fractional) layout math; Inter is
|
||||
// left exact since anti-aliasing handles fractional positions fine.
|
||||
const snap = isPixelFont ? Math.round : (v) => v;
|
||||
// `scale` (Tom Thumb only, see PIXEL_FONT_TIERS above) corrects the size handed to ctx.font
|
||||
// for its real ink; fontPx itself stays the logical size used for centering/stacking math.
|
||||
// `scale` (Tom Thumb only, see FONT_TIERS above) corrects the size handed to ctx.font for its
|
||||
// real ink; fontPx itself stays the logical size used for centering/stacking math.
|
||||
ctx.font = `${fontPx * scale}px "${family}"`;
|
||||
// Canvas text silently falls back if drawn before a not-yet-loaded font resolves, unlike DOM
|
||||
// text. See docs/implementation.md#canvas-font-loading.
|
||||
if (isPixelFont) {
|
||||
document.fonts.load(ctx.font);
|
||||
}
|
||||
// text. See docs/implementation.md#canvas-font-loading. Every tier now names a real,
|
||||
// self-hosted webfont (see FONT_TIERS above), so this always applies, not just to pixel fonts.
|
||||
document.fonts.load(ctx.font);
|
||||
ctx.textAlign = "center";
|
||||
const centerX = snap(node.box.x + node.box.width / 2);
|
||||
const lineHeight = node.box.height / node.lines.length;
|
||||
|
|
@ -527,9 +530,9 @@ export function drawFallbackLabel(canvas, content, orientation = "along") {
|
|||
// print label should show/encode; keyed by `kind` so each kind's format is defined in one place.
|
||||
export const LABEL_CONTENT_BUILDERS = {
|
||||
// The self-contained Item URL (see docs/design-in-progress/items-labels.md), built from just
|
||||
// the prefill's {userHandle, id}; the short link (Print.vue's `shortUrl`) needs an async store
|
||||
// the prefill's {userHandle, item}; the short link (Print.vue's `shortUrl`) needs an async store
|
||||
// lookup, so it stays a separate field/template rather than being baked in here.
|
||||
"item": ({userHandle, id}) => `${window.location.origin}/i/${encodeHandleForUrl(userHandle)}/${id}`,
|
||||
"item": ({userHandle, item}) => `${window.location.origin}/i/${encodeHandleForUrl(userHandle)}/${item}`,
|
||||
// Storage locations have no long-form URL route yet (see router.js), so `text` starts blank;
|
||||
// the short link and any future location template still work via the base vars below.
|
||||
};
|
||||
|
|
@ -542,7 +545,7 @@ export function buildLabelContent(prefill) {
|
|||
return build ? build(prefill.components) : "";
|
||||
}
|
||||
|
||||
// Splits a prefill's {userHandle, id} into label-layouts.js's user/domain base vars (the same way
|
||||
// Splits a prefill's {userHandle, item/location} into label-layouts.js's user/domain base vars (the same way
|
||||
// store.js's lookupServer does), tagging on whichever id field the resource's templates key
|
||||
// required_vars by.
|
||||
function splitUserHandle(userHandle) {
|
||||
|
|
@ -560,19 +563,19 @@ function splitUserHandle(userHandle) {
|
|||
// computed live elsewhere (see DERIVED_VARS, Print.vue's `shortUrl`), and omitting a field
|
||||
// (rather than leaving it present-but-empty) signals "not available" to templateIsAvailable.
|
||||
const LABEL_FIELD_BUILDERS = {
|
||||
"item": ({userHandle, id}) => {
|
||||
"item": ({userHandle, item}) => {
|
||||
const split = splitUserHandle(userHandle);
|
||||
if (!split || !id) {
|
||||
if (!split || !item) {
|
||||
return {};
|
||||
}
|
||||
return {...split, itemId: String(id)};
|
||||
return {...split, itemId: String(item)};
|
||||
},
|
||||
"storage-location": ({userHandle, id}) => {
|
||||
"storage-location": ({userHandle, location}) => {
|
||||
const split = splitUserHandle(userHandle);
|
||||
if (!split || !id) {
|
||||
if (!split || !location) {
|
||||
return {};
|
||||
}
|
||||
return {...split, locationId: String(id)};
|
||||
return {...split, locationId: String(location)};
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue