Visualize.Board.Export (Visualize v0.6.0)

Copy Markdown View Source

A whole board as one picture: an SVG document, a PNG, or printed pages (spec/15 §12, D-150).

Everything here draws a Visualize.Board.Snapshot — taken from a running board with Visualize.Board.Server.snapshot/1, or purely with Visualize.Board.Snapshot.realise/4 — so an export needs no store, no feed and no process, and shows exactly the data the snapshot froze.

  • svg/2 is the board at a width: a header with the board's name and its window in the board's zone (Visualize.Board.window_text/2), and each cell at its grid box (Visualize.Board.boxes/2) — its title, its state's banner over a chart that is not live, and its chart's own SVG embedded byte for byte as the cell draws it (Visualize.Board.Snapshot.views/2). A cell with no chart — loading, down, crashed — is its state's panel, the one the board component draws.
  • png/2 is that document rasterised by Visualize.Render.to_png/2, with every theme reference resolved to the literal it carries (literal/1), since resvg reads no CSS custom property.
  • pages/2 lays the board out on paper — A4 or Letter, portrait or landscape — in Visualize.Theme.print/0 by default: the board reflowed to the page's width as a narrow container reflows it (spec/15 §1.6), its cells in bands that never split across a page (paginate/2), one SVG document per page. html/2 puts the pages in one HTML document whose @page rule is the paper size, which a browser prints as one multi-page PDF. resvg makes PNG, not PDF, and this library takes no PDF dependency.

The cells' charts carry ids derived from their content (a gradient's, a filter's, the accessible root's), so two cells that draw the same definition share its id with the same body, and embedding one cell beside another changes neither.

Summary

Types

A box on the document or the page: {x, y, w, h} in pixels.

Functions

The printed pages in one HTML document (spec/15 §12.4): an @page rule of the paper's size and no margin, and each page of pages/2 filling one sheet. A browser prints it as a multi-page PDF. The options are pages/2's.

An SVG with every CSS custom-property reference replaced by the fallback it carries (spec/15 §12.1): var(--vis-axis, #666666) becomes #666666. A theme writes each slot's literal as the fallback of its reference (spec/08 §7.3), so this is the document in :literal mode, for a reader that knows no custom property — resvg among them. A reference with no fallback is left as it is.

The board printed (spec/15 §12.4): one SVG document per page of paginate/2, each the page's size in its own unit (210mm by 297mm for A4 portrait), with the header — the board's name, and its window and the page's number — and the page's cells drawn as svg/2 draws them, a band scaled down where paginate/2 scaled it. The cells are drawn at the page's width in :theme, the print theme by default, from the snapshot's data.

The board laid out on paper (spec/15 §12.4), purely: %{size: {w, h}, width: width, pages: [%{name => box}, …]}, the page's size in pixels, the width the cells are drawn at, and each page's cells at their boxes on that page.

The board as a PNG (spec/15 §12.1): svg/2 with resolve: :literal, rasterised by Visualize.Render.to_png/2. {:ok, png, warnings} or {:error, reason}, as to_png/2 answers. The options are svg/2's, and to_png/2's :scale, :background, :timeout and font options.

The board as one SVG document (spec/15 §12.1).

Types

box()

@type box() :: {number(), number(), number(), number()}

A box on the document or the page: {x, y, w, h} in pixels.

Functions

html(snapshot, opts \\ [])

The printed pages in one HTML document (spec/15 §12.4): an @page rule of the paper's size and no margin, and each page of pages/2 filling one sheet. A browser prints it as a multi-page PDF. The options are pages/2's.

literal(svg)

@spec literal(String.t()) :: String.t()

An SVG with every CSS custom-property reference replaced by the fallback it carries (spec/15 §12.1): var(--vis-axis, #666666) becomes #666666. A theme writes each slot's literal as the fallback of its reference (spec/08 §7.3), so this is the document in :literal mode, for a reader that knows no custom property — resvg among them. A reference with no fallback is left as it is.

iex> Visualize.Board.Export.literal(~s[<rect fill="var(--vis-good, rgb(1, 2, 3))"/>])
~s[<rect fill="rgb(1, 2, 3)"/>]

pages(snapshot, opts \\ [])

@spec pages(Visualize.Board.Snapshot.t(), keyword()) :: [String.t()]

The board printed (spec/15 §12.4): one SVG document per page of paginate/2, each the page's size in its own unit (210mm by 297mm for A4 portrait), with the header — the board's name, and its window and the page's number — and the page's cells drawn as svg/2 draws them, a band scaled down where paginate/2 scaled it. The cells are drawn at the page's width in :theme, the print theme by default, from the snapshot's data.

The options are paginate/2's, svg/2's :system, :title and :resolve.

paginate(board, opts \\ [])

@spec paginate(Visualize.Board.t(), keyword()) :: %{
  size: {number(), number()},
  width: number(),
  pages: [%{required(atom()) => box()}]
}

The board laid out on paper (spec/15 §12.4), purely: %{size: {w, h}, width: width, pages: [%{name => box}, …]}, the page's size in pixels, the width the cells are drawn at, and each page's cells at their boxes on that page.

The board is arranged at the page's width less its margins, so a page narrower than the board's breakpoint stacks the cells as a phone does (spec/15 §1.6). Cells are taken in bands: a band is the cells whose rows overlap, joined until no cell of the band shares a row with one outside it, so a band is the least that can be moved without cutting a cell. Bands are placed down the page, a gap apart, and a band that does not fit below the last starts the next page. A band taller than a whole page is scaled down to fit one, its width with it, and centred. No cell is ever split, and every box is inside the page's margins, below the header.

Options

  • :paper - :a4 (default) or :letter
  • :orientation - :portrait (default) or :landscape
  • :margin - the page's margin in pixels (default 48, half an inch)
  • :theme - the theme whose sizes set the header's height (default Visualize.Theme.print/0)

png(snapshot, opts \\ [])

The board as a PNG (spec/15 §12.1): svg/2 with resolve: :literal, rasterised by Visualize.Render.to_png/2. {:ok, png, warnings} or {:error, reason}, as to_png/2 answers. The options are svg/2's, and to_png/2's :scale, :background, :timeout and font options.

svg(snapshot, opts \\ [])

The board as one SVG document (spec/15 §12.1).

The document is the grid's width and twice the board's gap wider, a gap of margin each side; the header, when there is a name or a window, stands above the grid. Each cell is a group data-vis-cell at its box, translated by the margin and the header, holding its title, its banner, and its chart or its state's panel, each in its own viewport so the cell's own SVG is placed unchanged.

Options

  • :width - the grid's width, the container width the cells are drawn at (default the snapshot's)
  • :theme - the theme the cells and the page are drawn in (default the snapshot's)
  • :system - the unit system the cells' measures are shown in (default :as_posted, spec/14 §4.4, D-156)
  • :title - the header's name (default the board's meta.name)
  • :resolve - :css (default), every theme value a custom-property reference with its literal as fallback, as the cells draw it; or :literal, each reference replaced by its literal, for a reader of no CSS (literal/1)