@dloizides/poster-render 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +147 -37
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +147 -37
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.2
|
|
4
|
+
|
|
5
|
+
- Arch flanks: both flank price groups use one size per line, so "per hour" and "Party pass" match.
|
|
6
|
+
- Two-column bodies: the break is chosen from heights measured at the column width, and the shorter column spreads its group gaps so both columns end together.
|
|
7
|
+
- Footer base size 38 (was 34): includes and footer stay at 30 px or more on story and phone arch layouts.
|
|
8
|
+
- `picture-bottom`: the picture region starts 40u under the body's measured end, spans the middle 80% of the width and runs to the frame edge.
|
|
9
|
+
- Venue gets a rule below as well as above (`FlowGroup.ruleBelow`).
|
|
10
|
+
|
|
11
|
+
## 0.2.1
|
|
12
|
+
|
|
13
|
+
- Venue pin: an accent disc with a pin glyph beside the venue lines; `RenderReport.iconBoxes`.
|
|
14
|
+
- Includes block drawn as a heading plus bullets, with no card.
|
|
15
|
+
- Price groups stay in one column when a wide body splits into two (`FlowGroup.keepWithNext`).
|
|
16
|
+
- `desktop-safe` landscape gets an explicit logo rect beside the title; `desktop-arch` logo enlarged and no longer pushed down to the title cap; `RenderReport.logo`.
|
|
17
|
+
- List rows: date at 0.7x, 48 px between dated rows.
|
|
18
|
+
|
|
3
19
|
## 0.2.0
|
|
4
20
|
|
|
5
21
|
- Layouts `arch`, `phone-clock-safe`, `phone-arch`, `desktop-safe`, `desktop-arch` (FLIER-1 D4 "Keep all layouts"); `LAYOUT_CATALOGUE` + `defaultLayoutFor`.
|
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -314,18 +314,19 @@ function headerGroups(doc, p, u) {
|
|
|
314
314
|
return [{ lines: lines.filter((x) => x !== void 0), gapAfter: 0 }];
|
|
315
315
|
}
|
|
316
316
|
function itemGroup(item, l, u) {
|
|
317
|
-
const lines = [l.script?.(item.date,
|
|
317
|
+
const lines = [l.script?.(item.date, 67)];
|
|
318
318
|
item.schedule.forEach((row) => lines.push(l.strong?.(`${row.label} ${row.time}`, 42)));
|
|
319
319
|
if (item.price) {
|
|
320
320
|
lines.push(l.accent?.(item.price, 42));
|
|
321
321
|
}
|
|
322
|
-
return { lines, gapAfter:
|
|
322
|
+
return { lines, gapAfter: 48 * u };
|
|
323
323
|
}
|
|
324
324
|
function eventGroups(doc, l, u, withPrices) {
|
|
325
325
|
const b = doc.blocks;
|
|
326
326
|
const groups = [];
|
|
327
327
|
b.schedule?.forEach((row) => groups.push({ lines: [l.strong?.(row.label, 66), l.accent?.(row.time, 60)], gapAfter: 30 * u }));
|
|
328
|
-
(withPrices ? b.prices : void 0)
|
|
328
|
+
const prices = (withPrices ? b.prices : void 0) ?? [];
|
|
329
|
+
prices.forEach((row, i) => groups.push({ lines: [l.strong?.(row.amount, 66), l.accent?.(row.label, 52)], gapAfter: 30 * u, keepWithNext: i < prices.length - 1 }));
|
|
329
330
|
return groups;
|
|
330
331
|
}
|
|
331
332
|
function listGroups(doc, l, u) {
|
|
@@ -346,15 +347,15 @@ function bodyGroups(doc, p, u, withPrices = true) {
|
|
|
346
347
|
const groups = [];
|
|
347
348
|
const isList = doc.layout === "list" /* List */;
|
|
348
349
|
if (b.venue) {
|
|
349
|
-
groups.push({ lines: b.venue.map((v) => l.venue?.(v, isList ? 48 : 58)), gapAfter: 40 * u, rule: { color: p.accent, height: 8 * u } });
|
|
350
|
+
groups.push({ lines: b.venue.map((v) => l.venue?.(v, isList ? 48 : 58)), gapAfter: 40 * u, rule: { color: p.accent, height: 8 * u }, ruleBelow: true, icon: { color: p.accent, glyph: p.background } });
|
|
350
351
|
}
|
|
351
352
|
groups.push(...isList ? listGroups(doc, l, u) : eventGroups(doc, l, u, withPrices));
|
|
352
353
|
if (b.includes) {
|
|
353
354
|
const lines = [l.accent?.(b.includes.heading, 38), ...b.includes.items.map((i) => l.item?.(i, 38))];
|
|
354
|
-
groups.push({ lines, gapAfter: 24 * u,
|
|
355
|
+
groups.push({ lines, gapAfter: 24 * u, uniform: true });
|
|
355
356
|
}
|
|
356
357
|
if (b.footer) {
|
|
357
|
-
groups.push({ lines: [l.soft?.(b.footer,
|
|
358
|
+
groups.push({ lines: [l.soft?.(b.footer, 38)], gapAfter: 0 });
|
|
358
359
|
}
|
|
359
360
|
return groups;
|
|
360
361
|
}
|
|
@@ -390,11 +391,11 @@ var LAYOUT_SPECS = {
|
|
|
390
391
|
},
|
|
391
392
|
["desktop-safe" /* DesktopSafe */]: {
|
|
392
393
|
portrait: { header: [0.08, 0.06, 0.84, 0.24], body: [0.08, 0.31, 0.46, 0.58], picture: [0.56, 0.36, 0.44, 0.64], alignX: 1 },
|
|
393
|
-
landscape: { header: [0.0625, 0.05, 0.58, 0.44], body: [0.0625, 0.5, 0.58, 0.38], picture: [0.67, 0.0972, 0.29, 0.9028], alignX: 1 }
|
|
394
|
+
landscape: { header: [0.0625, 0.05, 0.58, 0.44], body: [0.0625, 0.5, 0.58, 0.38], picture: [0.67, 0.0972, 0.29, 0.9028], alignX: 1, logo: [0.4, 0.045, 0.09, 0.17] }
|
|
394
395
|
},
|
|
395
396
|
["desktop-arch" /* DesktopArch */]: {
|
|
396
397
|
portrait: { header: [0.08, 0.06, 0.84, 0.2], body: [0.08, 0.27, 0.84, 0.2], picture: [0.14, 0.48, 0.72, 0.52], alignX: 0.5, arch: 0.05 },
|
|
397
|
-
landscape: { header: [0.07, 0.3, 0.26, 0.45], body: [0.7, 0.25, 0.27, 0.65], picture: DESK_ARCH_PIC, alignX: 0.5, logo: [0.
|
|
398
|
+
landscape: { header: [0.07, 0.3, 0.26, 0.45], body: [0.7, 0.25, 0.27, 0.65], picture: DESK_ARCH_PIC, alignX: 0.5, logo: [0.86, 0.03, 0.11, 0.18], arch: 0.05 }
|
|
398
399
|
}
|
|
399
400
|
};
|
|
400
401
|
var r = Math.round;
|
|
@@ -496,8 +497,14 @@ var RULE_WIDTH = 0.9;
|
|
|
496
497
|
var WIDE = 1.6;
|
|
497
498
|
var MIN_K = 0.02;
|
|
498
499
|
var STEPS = 22;
|
|
500
|
+
var ICON_SCALE = 1.6;
|
|
501
|
+
var ICON_GAP = 0.35;
|
|
499
502
|
var fontOf = (line, size, fonts) => `${line.weight} ${size}px ${fonts[line.role]}`;
|
|
500
|
-
var emptyFlow = () => ({ texts: [], cards: [], rules: [], bullets: [] });
|
|
503
|
+
var emptyFlow = () => ({ texts: [], cards: [], rules: [], bullets: [], icons: [] });
|
|
504
|
+
var iconSize = (group, k) => {
|
|
505
|
+
const first = group.lines[0];
|
|
506
|
+
return group.icon && first ? first.size * k * LINE_HEIGHT * ICON_SCALE : 0;
|
|
507
|
+
};
|
|
501
508
|
function lineSize(line, width, k, avail) {
|
|
502
509
|
const indent = line.bullet ? line.size * k * BULLET_INDENT : 0;
|
|
503
510
|
return Math.max(0, Math.min(line.size * k, line.size * (avail - indent) / Math.max(width, 1)));
|
|
@@ -508,6 +515,14 @@ function groupRatio(m, k, avail) {
|
|
|
508
515
|
}
|
|
509
516
|
return Math.min(...m.group.lines.map((line, i) => lineSize(line, m.widths[i] ?? 1, k, avail) / line.size));
|
|
510
517
|
}
|
|
518
|
+
function placeIcon(group, d, x, textTop, textBottom, out) {
|
|
519
|
+
if (!group.icon || d <= 0) {
|
|
520
|
+
return textBottom;
|
|
521
|
+
}
|
|
522
|
+
const textH = textBottom - textTop;
|
|
523
|
+
out?.icons.push({ rect: { x, y: textTop + Math.max(0, (textH - d) / 2), w: d, h: d }, color: group.icon.color, glyph: group.icon.glyph });
|
|
524
|
+
return textTop + Math.max(textH, d);
|
|
525
|
+
}
|
|
511
526
|
function placeGroup(m, k, col, y0, out) {
|
|
512
527
|
const { group } = m;
|
|
513
528
|
let y = y0;
|
|
@@ -518,10 +533,13 @@ function placeGroup(m, k, col, y0, out) {
|
|
|
518
533
|
const pad = group.card ? group.card.pad * k : 0;
|
|
519
534
|
const top = y;
|
|
520
535
|
y += pad;
|
|
521
|
-
const
|
|
536
|
+
const d = iconSize(group, k);
|
|
537
|
+
const iconIndent = d > 0 ? d * (1 + ICON_GAP) : 0;
|
|
538
|
+
const avail = col.w - 2 * pad - iconIndent;
|
|
539
|
+
const ratio = groupRatio(m, k, avail);
|
|
522
540
|
group.lines.forEach((line, i) => {
|
|
523
|
-
const size = ratio === null ? lineSize(line, m.widths[i] ?? 1, k,
|
|
524
|
-
const indent = line.bullet ? line.size * k * BULLET_INDENT : 0;
|
|
541
|
+
const size = ratio === null ? lineSize(line, m.widths[i] ?? 1, k, avail) : line.size * ratio;
|
|
542
|
+
const indent = (line.bullet ? line.size * k * BULLET_INDENT : 0) + iconIndent;
|
|
525
543
|
const w = (m.widths[i] ?? 0) * size / line.size;
|
|
526
544
|
const x = col.right ? col.x + col.w - pad - w : col.x + pad + indent;
|
|
527
545
|
out?.texts.push({ text: line.text, font: "", color: line.color, box: { x, y, w, h: size * LINE_HEIGHT } });
|
|
@@ -530,36 +548,62 @@ function placeGroup(m, k, col, y0, out) {
|
|
|
530
548
|
}
|
|
531
549
|
y += size * LINE_HEIGHT;
|
|
532
550
|
});
|
|
551
|
+
y = placeIcon(group, d, col.x + pad, top + pad, y, out);
|
|
533
552
|
y += pad;
|
|
553
|
+
if (group.rule && group.ruleBelow) {
|
|
554
|
+
y += group.rule.height * k * (RULE_GAP - 1);
|
|
555
|
+
out?.rules.push({ rect: { x: col.x, y, w: col.w * RULE_WIDTH, h: group.rule.height * k }, color: group.rule.color });
|
|
556
|
+
y += group.rule.height * k;
|
|
557
|
+
}
|
|
534
558
|
if (group.card) {
|
|
535
559
|
out?.cards.unshift({ rect: { x: col.x, y: top, w: col.w, h: y - top }, color: group.card.color });
|
|
536
560
|
}
|
|
537
561
|
return y + group.gapAfter * k - y0;
|
|
538
562
|
}
|
|
539
|
-
function placeColumn(groups, k, col, out) {
|
|
563
|
+
function placeColumn(groups, k, col, out, spread = 0) {
|
|
540
564
|
let h = 0;
|
|
541
565
|
for (const g of groups) {
|
|
542
|
-
h += placeGroup(g, k, col, col.y + h, out);
|
|
566
|
+
h += placeGroup(g, k, col, col.y + h, out) + spread;
|
|
567
|
+
}
|
|
568
|
+
return h - spread;
|
|
569
|
+
}
|
|
570
|
+
var columnSum = (heights, from, to) => heights.slice(from, to).reduce((a, b) => a + b, 0);
|
|
571
|
+
var tallest = (heights, cut) => {
|
|
572
|
+
const left = heights.slice(0, cut).reduce((a, b) => a + b, 0);
|
|
573
|
+
const right = heights.slice(cut).reduce((a, b) => a + b, 0);
|
|
574
|
+
return Math.max(left, right);
|
|
575
|
+
};
|
|
576
|
+
function keepTogether(groups, heights, cut) {
|
|
577
|
+
const breaks = (c) => groups[c - 1]?.group.keepWithNext === true;
|
|
578
|
+
let back = cut;
|
|
579
|
+
while (back > 1 && breaks(back)) {
|
|
580
|
+
back--;
|
|
581
|
+
}
|
|
582
|
+
let fwd = cut;
|
|
583
|
+
while (fwd < groups.length - 1 && breaks(fwd)) {
|
|
584
|
+
fwd++;
|
|
585
|
+
}
|
|
586
|
+
const candidates = [back, fwd].filter((c) => !breaks(c));
|
|
587
|
+
if (candidates.length === 0) {
|
|
588
|
+
return cut;
|
|
543
589
|
}
|
|
544
|
-
return
|
|
590
|
+
return candidates.reduce((best, c) => tallest(heights, c) < tallest(heights, best) ? c : best);
|
|
545
591
|
}
|
|
546
592
|
function splitColumns(groups, zone) {
|
|
547
593
|
if (zone.w / Math.max(zone.h, 1) <= WIDE || groups.length < 2) {
|
|
548
594
|
return [{ col: zone, groups }];
|
|
549
595
|
}
|
|
550
|
-
const heights = groups.map((g) => placeGroup(g, 1, zone, 0, null));
|
|
551
|
-
const half = heights.reduce((a, b) => a + b, 0) / 2;
|
|
552
|
-
let acc = 0;
|
|
553
|
-
let cut = 1;
|
|
554
|
-
heights.forEach((h, i) => {
|
|
555
|
-
if (acc < half) {
|
|
556
|
-
cut = i + 1;
|
|
557
|
-
}
|
|
558
|
-
acc += h;
|
|
559
|
-
});
|
|
560
|
-
cut = Math.min(cut, groups.length - 1);
|
|
561
596
|
const gap = Math.round(zone.w * 0.04);
|
|
562
597
|
const w = (zone.w - gap) / 2;
|
|
598
|
+
const heights = groups.map((g) => placeGroup(g, 1, { ...zone, w }, 0, null));
|
|
599
|
+
const total = columnSum(heights, 0, heights.length);
|
|
600
|
+
let cut = 1;
|
|
601
|
+
for (let c = 2; c < groups.length; c++) {
|
|
602
|
+
if (Math.abs(total - 2 * columnSum(heights, 0, c)) < Math.abs(total - 2 * columnSum(heights, 0, cut))) {
|
|
603
|
+
cut = c;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
cut = keepTogether(groups, heights, cut);
|
|
563
607
|
return [
|
|
564
608
|
{ col: { ...zone, w }, groups: groups.slice(0, cut) },
|
|
565
609
|
{ col: { ...zone, x: zone.x + w + gap, w }, groups: groups.slice(cut) }
|
|
@@ -589,7 +633,9 @@ function flow(ctx, groups, zone, fonts) {
|
|
|
589
633
|
}
|
|
590
634
|
}
|
|
591
635
|
const out = emptyFlow();
|
|
592
|
-
columns.
|
|
636
|
+
const heights = columns.map((c) => placeColumn(c.groups, lo, c.col, null));
|
|
637
|
+
const end = Math.max(...heights);
|
|
638
|
+
columns.forEach((c, i) => placeColumn(c.groups, lo, c.col, out, c.groups.length > 1 && columns.length > 1 ? (end - (heights[i] ?? end)) / (c.groups.length - 1) : 0));
|
|
593
639
|
const lines = groups.flatMap((g) => g.lines);
|
|
594
640
|
out.texts.forEach((t, i) => {
|
|
595
641
|
const line = lines[i];
|
|
@@ -598,11 +644,75 @@ function flow(ctx, groups, zone, fonts) {
|
|
|
598
644
|
return out;
|
|
599
645
|
}
|
|
600
646
|
|
|
647
|
+
// src/render/regions.ts
|
|
648
|
+
var LINE_HEIGHT2 = 1.2;
|
|
649
|
+
var BODY_GAP = 40;
|
|
650
|
+
var BOTTOM_SIDE = 0.1;
|
|
651
|
+
function flowFlanks(ctx, groups, flanks, fonts) {
|
|
652
|
+
const half = Math.ceil(groups.length / 2);
|
|
653
|
+
return flanks.map((zone, i) => i === 0 ? flow(ctx, groups.slice(0, half), zone, fonts) : flow(ctx, groups.slice(half), { ...zone, right: true }, fonts));
|
|
654
|
+
}
|
|
655
|
+
function smallestPerLine(groups, results) {
|
|
656
|
+
const sizes = results.flatMap((r3) => r3.texts.map((t) => t.box.h / LINE_HEIGHT2));
|
|
657
|
+
const smallest = [];
|
|
658
|
+
let i = 0;
|
|
659
|
+
groups.forEach(
|
|
660
|
+
(g) => g.lines.forEach((_line, j) => {
|
|
661
|
+
smallest[j] = Math.min(smallest[j] ?? Infinity, sizes[i] ?? Infinity);
|
|
662
|
+
i++;
|
|
663
|
+
})
|
|
664
|
+
);
|
|
665
|
+
return smallest;
|
|
666
|
+
}
|
|
667
|
+
function equalFlanks(ctx, groups, flanks, fonts) {
|
|
668
|
+
const smallest = smallestPerLine(groups, flowFlanks(ctx, groups, flanks, fonts));
|
|
669
|
+
const sized = groups.map((g) => ({ ...g, lines: g.lines.map((line, j) => ({ ...line, size: Math.min(line.size, smallest[j] ?? line.size) })) }));
|
|
670
|
+
return flowFlanks(ctx, sized, flanks, fonts);
|
|
671
|
+
}
|
|
672
|
+
function measuredEnd(f, fallback) {
|
|
673
|
+
const bottoms = [...f.texts.map((t) => t.box), ...f.rules.map((r3) => r3.rect), ...f.icons.map((i) => i.rect)].map((r3) => r3.y + r3.h);
|
|
674
|
+
return bottoms.length > 0 ? Math.max(...bottoms) : fallback;
|
|
675
|
+
}
|
|
676
|
+
function pictureRegion(layout, geo, body, u, frame) {
|
|
677
|
+
if (layout !== "picture-bottom" /* PictureBottom */) {
|
|
678
|
+
return geo.picture;
|
|
679
|
+
}
|
|
680
|
+
const y = Math.ceil(measuredEnd(body, geo.body.y) + BODY_GAP * u);
|
|
681
|
+
const x = Math.round(frame.width * BOTTOM_SIDE);
|
|
682
|
+
return { x, y, w: frame.width - 2 * x, h: frame.height - y };
|
|
683
|
+
}
|
|
684
|
+
|
|
601
685
|
// src/render/render.ts
|
|
602
686
|
var BASE = 1080;
|
|
603
687
|
var LOGO_SHARE = 0.26;
|
|
604
688
|
var CARD_RADIUS = 0.035;
|
|
605
689
|
var CAP_TOP = 0.15;
|
|
690
|
+
var PIN_HEAD_Y = 0.08;
|
|
691
|
+
var PIN_HEAD_R = 0.19;
|
|
692
|
+
var PIN_TIP_Y = 0.28;
|
|
693
|
+
var PIN_HOLE = 0.42;
|
|
694
|
+
var ARC_START = 0.75;
|
|
695
|
+
var ARC_END = 2.25;
|
|
696
|
+
function drawPin(ctx, r3, color, glyph) {
|
|
697
|
+
const cx = r3.x + r3.w / 2;
|
|
698
|
+
const cy = r3.y + r3.h / 2;
|
|
699
|
+
const hy = cy - r3.w * PIN_HEAD_Y;
|
|
700
|
+
const rad = r3.w * PIN_HEAD_R;
|
|
701
|
+
ctx.fillStyle = color;
|
|
702
|
+
ctx.beginPath();
|
|
703
|
+
ctx.arc(cx, cy, r3.w / 2, 0, Math.PI * 2);
|
|
704
|
+
ctx.fill();
|
|
705
|
+
ctx.fillStyle = glyph;
|
|
706
|
+
ctx.beginPath();
|
|
707
|
+
ctx.moveTo(cx, cy + r3.w * PIN_TIP_Y);
|
|
708
|
+
ctx.arc(cx, hy, rad, Math.PI * ARC_START, Math.PI * ARC_END);
|
|
709
|
+
ctx.closePath();
|
|
710
|
+
ctx.fill();
|
|
711
|
+
ctx.fillStyle = color;
|
|
712
|
+
ctx.beginPath();
|
|
713
|
+
ctx.arc(cx, hy, rad * PIN_HOLE, 0, Math.PI * 2);
|
|
714
|
+
ctx.fill();
|
|
715
|
+
}
|
|
606
716
|
function roundRect(ctx, r3, radius) {
|
|
607
717
|
const rad = Math.min(radius, r3.w / 2, r3.h / 2);
|
|
608
718
|
ctx.beginPath();
|
|
@@ -629,6 +739,7 @@ function drawFlow(ctx, f, radius) {
|
|
|
629
739
|
ctx.arc(b.x, b.y, b.r, 0, Math.PI * 2);
|
|
630
740
|
ctx.fill();
|
|
631
741
|
});
|
|
742
|
+
f.icons.forEach((i) => drawPin(ctx, i.rect, i.color, i.glyph));
|
|
632
743
|
ctx.textAlign = "left";
|
|
633
744
|
ctx.textBaseline = "top";
|
|
634
745
|
f.texts.forEach((t) => {
|
|
@@ -663,10 +774,6 @@ function drawArch(ctx, r3, color) {
|
|
|
663
774
|
ctx.arc(r3.x + rad, r3.y + rad, rad, Math.PI, Math.PI * 2);
|
|
664
775
|
ctx.fill();
|
|
665
776
|
}
|
|
666
|
-
function flankFlows(ctx, groups, flanks, fonts) {
|
|
667
|
-
const half = Math.ceil(groups.length / 2);
|
|
668
|
-
return flanks.map((zone, i) => i === 0 ? flow(ctx, groups.slice(0, half), zone, fonts) : flow(ctx, groups.slice(half), { ...zone, right: true }, fonts));
|
|
669
|
-
}
|
|
670
777
|
function capAligned(zone, head) {
|
|
671
778
|
const first = head.texts[0]?.box;
|
|
672
779
|
const shift = first ? Math.min(Math.max(0, Math.round(first.y + first.h * CAP_TOP) - zone.y), Math.round(zone.h / 2)) : 0;
|
|
@@ -700,20 +807,21 @@ function render(input, assets, canvas) {
|
|
|
700
807
|
const head = flow(ctx, headerGroups(doc, palette, u), zones.text, fonts);
|
|
701
808
|
const flanks = geo.flanks ?? [];
|
|
702
809
|
const body = flow(ctx, bodyGroups(doc, palette, u, flanks.length === 0), geo.body, fonts);
|
|
703
|
-
const sides = flanks.length > 0 ?
|
|
810
|
+
const sides = flanks.length > 0 ? equalFlanks(ctx, flankPriceGroups(doc, palette, u), flanks, fonts) : [emptyFlow()];
|
|
704
811
|
const radius = Math.min(width, height) * CARD_RADIUS;
|
|
705
812
|
[head, body, ...sides].forEach((f) => drawFlow(ctx, f, radius));
|
|
706
813
|
const logoImage = doc.logo ? assets[doc.logo.imageId] : void 0;
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
ctx.drawImage(logoImage,
|
|
814
|
+
const logo = logoImage ? placeContain(logoImage, geo.logo ? zones.logo : capAligned(zones.logo, head), "top" /* Top */, 1, 1) : null;
|
|
815
|
+
if (logoImage && logo) {
|
|
816
|
+
ctx.drawImage(logoImage, logo.x, logo.y, logo.w, logo.h);
|
|
710
817
|
}
|
|
711
818
|
const image = doc.picture ? assets[doc.picture.imageId] : void 0;
|
|
712
819
|
const backdrop = image ? archRect(geo) : null;
|
|
713
820
|
if (backdrop) {
|
|
714
821
|
drawArch(ctx, backdrop, palette.arch);
|
|
715
822
|
}
|
|
716
|
-
const
|
|
823
|
+
const region = pictureRegion(doc.layout, geo, body, u, { width, height });
|
|
824
|
+
const picture = image && doc.picture ? placeContain(image, region, doc.picture.anchor, geo.alignX, doc.picture.scale) : null;
|
|
717
825
|
if (image && picture) {
|
|
718
826
|
ctx.drawImage(image, picture.x, picture.y, picture.w, picture.h);
|
|
719
827
|
}
|
|
@@ -721,9 +829,11 @@ function render(input, assets, canvas) {
|
|
|
721
829
|
width,
|
|
722
830
|
height,
|
|
723
831
|
picture,
|
|
724
|
-
pictureRegion:
|
|
832
|
+
pictureRegion: region,
|
|
725
833
|
textBoxes: [head, body, ...sides].flatMap((f) => f.texts.map((t) => t.box)),
|
|
726
834
|
cardBoxes: body.cards.map((c) => c.rect),
|
|
835
|
+
iconBoxes: [head, body, ...sides].flatMap((f) => f.icons.map((i) => i.rect)),
|
|
836
|
+
logo,
|
|
727
837
|
backdrop
|
|
728
838
|
};
|
|
729
839
|
}
|