@quario/layout
v0.8.1
Published
Tiny paged layout for quario, shared by the PDF target and the on-screen surfaces. A display list in points.
Maintainers
Readme
@quario/layout
The paged layout of a quario report, as a display
list. layout(options) is a render target whose output is pages of boxes, text runs, rules
and images in points. The PDF target writes that layout, and the viewer and editor paint it on
screen, so the preview breaks its pages exactly where the document does.
You install this package directly only to consume the list yourself. @quario/pdf, @quario/viewer
and @quario/editor depend on it and run it for you.
Install
npm install quario @quario/layoutThe engine is a peer. The one runtime dependency is @pdf-lib/standard-fonts, the metrics of the
base-14 PDF families. To lay out with your own TrueType families, add the optional peer:
npm install fontkitESM-only, Node 22+, and browser-ready through a standards-based bundler. CSP-safe: no string-to-code paths anywhere.
Quick start
import { layout } from "@quario/layout";
import { quario } from "quario";
const report = quario().report(schema);
const list = await report.render(layout({ page: { size: "A4", margin: 54 } }), data);
list.pages.length; // how many pages the report needs
list.pages[0].ops; // what to draw on the first page, in order
list.pages[0].boxes; // which schema node was drawn whereEvery coordinate is in PostScript points from the page's top-left corner. list.width and
list.height are the paper every page is drawn on. A report has one paper, so a page does not
carry its own size.
A page carries:
- its
{ number, total }, - its ops:
rect,line,image, andtext. Atextop holds the string to draw, the face it uses, and, for a built-in family only, the per-character advances the measurer laid it out with. An unlicensed render adds onemarkop. - its
boxes, one per schema node drawn, named by the node's path.
Options
| Option | Takes | Default |
| ------- | ----------------------------------------------------- | -------- |
| page | { size: "A4" \| "letter" \| [w, h], margin } points | A4, 54pt |
| fonts | A font mapping: family name to TrueType bytes | none |
They are the pdf target's own page and fonts. Pass the same object to layout() and to
pdf() and the two agree, because the pdf target runs this layout and paints its list.
Painting on a canvas
import { hit, paint } from "@quario/layout";
const canvas = document.querySelector("canvas");
const page = list.pages[0];
canvas.width = list.width * 2; // 2 device pixels per point
canvas.height = list.height * 2;
await paint(canvas.getContext("2d"), page, { scale: 2, fonts });
hit(page, x, y); // -> { path, x, y, w, h } or nullpaint draws a white page and every op in order. Size the canvas to the page before you call it:
the ops are in the page's own coordinates, so a smaller canvas clips them, and paint fills the
white over the whole canvas. paint decodes images from the bytes on the list. No img-src
grant, no URLs. hit answers which schema node was drawn at a point: the smallest box
containing it.
Text is drawn in the face the document will use. paint registers a family you pass as fonts as
a FontFace from your own bytes, and the browser then shapes its runs. That is the same shaping
the PDF gets from the same file, so ligatures, joined scripts and accents look on screen the way
they will on paper. paint draws text in the built-in families character by character at the
measured advances. The typeface a browser has for Helvetica, Times or Courier only stands in for
the one the PDF writes, and without that correction a line would drift as it ran.
Inside a single run of a family you supply, the preview is not promised to place glyphs exactly where the PDF does. Both read a glyph's own advance and neither applies the font's GPOS positioning, so a browser may kern by a fraction more. Where a line breaks, how wide a column is, and where a page ends are the layout's — one measurer, so preview and document agree.
PX_PER_POINT is how big a point is on screen — 96 dpi over PostScript's 72. A surface that draws
a page at 100% therefore sizes its canvas list.width * PX_PER_POINT CSS pixels wide and paints
at PX_PER_POINT * devicePixelRatio. Any zoom is a factor on top of that.
Documentation
The quario documentation is the reference.
The report schema is the normative
specification of what a report may declare, and
@quario/layout is this package's own API.
License
quario is commercial software. Evaluation is free and fully featured, and quario marks its output as unlicensed. See LICENSE.
