@dloizides/poster-render 0.2.1 → 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 +8 -0
- package/dist/index.js +65 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +65 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
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
|
+
|
|
3
11
|
## 0.2.1
|
|
4
12
|
|
|
5
13
|
- Venue pin: an accent disc with a pin glyph beside the venue lines; `RenderReport.iconBoxes`.
|
package/dist/index.js
CHANGED
|
@@ -347,7 +347,7 @@ function bodyGroups(doc, p, u, withPrices = true) {
|
|
|
347
347
|
const groups = [];
|
|
348
348
|
const isList = doc.layout === "list" /* List */;
|
|
349
349
|
if (b.venue) {
|
|
350
|
-
groups.push({ lines: b.venue.map((v) => l.venue?.(v, isList ? 48 : 58)), gapAfter: 40 * u, rule: { color: p.accent, height: 8 * u }, icon: { color: p.accent, glyph: p.background } });
|
|
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 } });
|
|
351
351
|
}
|
|
352
352
|
groups.push(...isList ? listGroups(doc, l, u) : eventGroups(doc, l, u, withPrices));
|
|
353
353
|
if (b.includes) {
|
|
@@ -355,7 +355,7 @@ function bodyGroups(doc, p, u, withPrices = true) {
|
|
|
355
355
|
groups.push({ lines, gapAfter: 24 * u, uniform: true });
|
|
356
356
|
}
|
|
357
357
|
if (b.footer) {
|
|
358
|
-
groups.push({ lines: [l.soft?.(b.footer,
|
|
358
|
+
groups.push({ lines: [l.soft?.(b.footer, 38)], gapAfter: 0 });
|
|
359
359
|
}
|
|
360
360
|
return groups;
|
|
361
361
|
}
|
|
@@ -550,18 +550,24 @@ function placeGroup(m, k, col, y0, out) {
|
|
|
550
550
|
});
|
|
551
551
|
y = placeIcon(group, d, col.x + pad, top + pad, y, out);
|
|
552
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
|
+
}
|
|
553
558
|
if (group.card) {
|
|
554
559
|
out?.cards.unshift({ rect: { x: col.x, y: top, w: col.w, h: y - top }, color: group.card.color });
|
|
555
560
|
}
|
|
556
561
|
return y + group.gapAfter * k - y0;
|
|
557
562
|
}
|
|
558
|
-
function placeColumn(groups, k, col, out) {
|
|
563
|
+
function placeColumn(groups, k, col, out, spread = 0) {
|
|
559
564
|
let h = 0;
|
|
560
565
|
for (const g of groups) {
|
|
561
|
-
h += placeGroup(g, k, col, col.y + h, out);
|
|
566
|
+
h += placeGroup(g, k, col, col.y + h, out) + spread;
|
|
562
567
|
}
|
|
563
|
-
return h;
|
|
568
|
+
return h - spread;
|
|
564
569
|
}
|
|
570
|
+
var columnSum = (heights, from, to) => heights.slice(from, to).reduce((a, b) => a + b, 0);
|
|
565
571
|
var tallest = (heights, cut) => {
|
|
566
572
|
const left = heights.slice(0, cut).reduce((a, b) => a + b, 0);
|
|
567
573
|
const right = heights.slice(cut).reduce((a, b) => a + b, 0);
|
|
@@ -587,19 +593,17 @@ function splitColumns(groups, zone) {
|
|
|
587
593
|
if (zone.w / Math.max(zone.h, 1) <= WIDE || groups.length < 2) {
|
|
588
594
|
return [{ col: zone, groups }];
|
|
589
595
|
}
|
|
590
|
-
const heights = groups.map((g) => placeGroup(g, 1, zone, 0, null));
|
|
591
|
-
const half = heights.reduce((a, b) => a + b, 0) / 2;
|
|
592
|
-
let acc = 0;
|
|
593
|
-
let cut = 1;
|
|
594
|
-
heights.forEach((h, i) => {
|
|
595
|
-
if (acc < half) {
|
|
596
|
-
cut = i + 1;
|
|
597
|
-
}
|
|
598
|
-
acc += h;
|
|
599
|
-
});
|
|
600
|
-
cut = keepTogether(groups, heights, Math.min(cut, groups.length - 1));
|
|
601
596
|
const gap = Math.round(zone.w * 0.04);
|
|
602
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);
|
|
603
607
|
return [
|
|
604
608
|
{ col: { ...zone, w }, groups: groups.slice(0, cut) },
|
|
605
609
|
{ col: { ...zone, x: zone.x + w + gap, w }, groups: groups.slice(cut) }
|
|
@@ -629,7 +633,9 @@ function flow(ctx, groups, zone, fonts) {
|
|
|
629
633
|
}
|
|
630
634
|
}
|
|
631
635
|
const out = emptyFlow();
|
|
632
|
-
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));
|
|
633
639
|
const lines = groups.flatMap((g) => g.lines);
|
|
634
640
|
out.texts.forEach((t, i) => {
|
|
635
641
|
const line = lines[i];
|
|
@@ -638,6 +644,44 @@ function flow(ctx, groups, zone, fonts) {
|
|
|
638
644
|
return out;
|
|
639
645
|
}
|
|
640
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
|
+
|
|
641
685
|
// src/render/render.ts
|
|
642
686
|
var BASE = 1080;
|
|
643
687
|
var LOGO_SHARE = 0.26;
|
|
@@ -730,10 +774,6 @@ function drawArch(ctx, r3, color) {
|
|
|
730
774
|
ctx.arc(r3.x + rad, r3.y + rad, rad, Math.PI, Math.PI * 2);
|
|
731
775
|
ctx.fill();
|
|
732
776
|
}
|
|
733
|
-
function flankFlows(ctx, groups, flanks, fonts) {
|
|
734
|
-
const half = Math.ceil(groups.length / 2);
|
|
735
|
-
return flanks.map((zone, i) => i === 0 ? flow(ctx, groups.slice(0, half), zone, fonts) : flow(ctx, groups.slice(half), { ...zone, right: true }, fonts));
|
|
736
|
-
}
|
|
737
777
|
function capAligned(zone, head) {
|
|
738
778
|
const first = head.texts[0]?.box;
|
|
739
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;
|
|
@@ -767,7 +807,7 @@ function render(input, assets, canvas) {
|
|
|
767
807
|
const head = flow(ctx, headerGroups(doc, palette, u), zones.text, fonts);
|
|
768
808
|
const flanks = geo.flanks ?? [];
|
|
769
809
|
const body = flow(ctx, bodyGroups(doc, palette, u, flanks.length === 0), geo.body, fonts);
|
|
770
|
-
const sides = flanks.length > 0 ?
|
|
810
|
+
const sides = flanks.length > 0 ? equalFlanks(ctx, flankPriceGroups(doc, palette, u), flanks, fonts) : [emptyFlow()];
|
|
771
811
|
const radius = Math.min(width, height) * CARD_RADIUS;
|
|
772
812
|
[head, body, ...sides].forEach((f) => drawFlow(ctx, f, radius));
|
|
773
813
|
const logoImage = doc.logo ? assets[doc.logo.imageId] : void 0;
|
|
@@ -780,7 +820,8 @@ function render(input, assets, canvas) {
|
|
|
780
820
|
if (backdrop) {
|
|
781
821
|
drawArch(ctx, backdrop, palette.arch);
|
|
782
822
|
}
|
|
783
|
-
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;
|
|
784
825
|
if (image && picture) {
|
|
785
826
|
ctx.drawImage(image, picture.x, picture.y, picture.w, picture.h);
|
|
786
827
|
}
|
|
@@ -788,7 +829,7 @@ function render(input, assets, canvas) {
|
|
|
788
829
|
width,
|
|
789
830
|
height,
|
|
790
831
|
picture,
|
|
791
|
-
pictureRegion:
|
|
832
|
+
pictureRegion: region,
|
|
792
833
|
textBoxes: [head, body, ...sides].flatMap((f) => f.texts.map((t) => t.box)),
|
|
793
834
|
cardBoxes: body.cards.map((c) => c.rect),
|
|
794
835
|
iconBoxes: [head, body, ...sides].flatMap((f) => f.icons.map((i) => i.rect)),
|