/ src / elements / page.ts
page.ts
 1  import type { PDFFont, PDFPage } from "@cantoo/pdf-lib";
 2  import type { Element } from "~/elements";
 3  import type { MemoryFont } from "~/utils/fonts";
 4  import { PageSizes } from "@cantoo/pdf-lib";
 5  import Yoga, { Direction } from "yoga-layout";
 6  
 7  export class Page {
 8    private _elements: Array<Element> = [];
 9    private _h: number;
10    private _w: number;
11  
12    constructor() {
13      [this._w, this._h] = PageSizes.A4;
14    }
15  
16    child(element: Element): Page {
17      this._elements.push(element);
18      return this;
19    }
20  
21    /**
22     * Defines the height of the page in pt.
23     * @default 841.8898 // A4
24     */
25    h(height: number): Page {
26      this._h = height;
27      return this;
28    }
29  
30    /**
31     * Calculate the layout and draw elements in the page.
32     * Internal only, you must not use the function.
33     *
34     * @internal
35     */
36    render(page: PDFPage, fonts: Map<MemoryFont, PDFFont>): void {
37      const root = Yoga.Node.create();
38      page.setSize(this._w, this._h);
39  
40      // Append all nodes to Yoga to calculate layout.
41      for (let i = 0; i < this._elements.length; i++) {
42        const element = this._elements[i]!;
43        const node = element.getLayoutNode(page, fonts);
44  
45        root.insertChild(node, i);
46      }
47  
48      // Calculate the layout of all the elements inside this page.
49      root.calculateLayout(this._w, this._h, Direction.LTR);
50  
51      // Once we have the layout with proper dimensions, we can draw to the PDF.
52      for (const element of this._elements) {
53        element.draw(page, fonts);
54      }
55    }
56  
57    /**
58     * Defines the width and height of the page in pt.
59     * @default [595.276, 841.8898] // A4
60     * @example
61     * page().size([595.276, 841.8898]);
62     * @example
63     * page().size(PageSizes.A4);
64     */
65    size(size: [w: number, h: number]): Page {
66      [this._w, this._h] = size;
67      return this;
68    }
69  
70    /**
71     * Defines the width of the page in pt.
72     * @default 595.276 // A4
73     */
74    w(width: number): Page {
75      this._w = width;
76      return this;
77    }
78  }
79  export const page = (): Page => new Page();