Visualize.Backend.CanvasBinary (Visualize v0.8.3)

Copy Markdown View Source

Binary encoding for Canvas 2D rendering commands.

Packs an element tree into a compact little-endian stream of records that the CanvasBinaryChart hook (Visualize.Hooks.CanvasBinary) replays on a Canvas 2D context. The byte-level contract is spec/09 §4.

Records

A stream is a concatenation of records; each begins with one opcode byte from Visualize.Backend.CanvasBinary.Opcodes, which fixes its layout:

NameByteRecord
path0x01count:u32 then count points x:f64 y:f64 — one open polyline
path_cubic0x02count:u32 then count path commands, each a sub-opcode and its f64 arguments
circles0x03count:u32 then cx:f64 cy:f64 r:f64 per circle
rects0x04count:u32 then x:f64 y:f64 w:f64 h:f64 per rectangle
path320x05path with every coordinate an f32
path_cubic320x06path_cubic with every f64 argument an f32
cubic_run0x07count:u32, the start point x0:f32 y0:f32, then six f32 per cubic curve, no sub-opcodes
style0x10flags:u8 then the fields the flags select: fill RGBA, stroke RGBA, stroke_width:f32, opacity:f32
transform0x20kind:u8 then tx ty (0x01), tx ty sx sy (0x03) or a full matrix a b c d e f (0xFF), all f64
save0x30ctx.save()
restore0x31ctx.restore()
fill0x40ctx.fill() on the current path
stroke0x41ctx.stroke() on the current path
version0x00version:u8 — version 2 and later; first in a stream that draws a paint
paint0x50index:u16 kind:u8, the geometry in box units (f32), count:u8 stops at:f32 r g b a
box0x51x y w h (f32): the box the next draw's paint is built over
effect0x52kind:u8 radius:f32, and for a shadow dx dy:f32 and its RGBA color
motion0x53length:u16 then the UTF-8 JSON of a motion span's arguments, [id, box, transitions]
motion_end0x54the motion span ends
paint_state0x55version 3: flags:u8, then the fill's and the stroke's alpha (f32), the cap and the join (u8), the dash (count:u8 and f32 lengths) the flags select
clip0x56version 4: keep:u8, the current path the clip, 0x01 inside it, 0x02 outside it (even-odd against a ±100000 rectangle)
blend0x57version 4: mode:u8, the composite operation, one of the CSS mix-blend-mode words but normal

The point-list record is used only for a path that is one M followed by L commands, and the cubic run only for one M followed by C commands — the shapes those records hold without loss, the run being what a curve generator emits (D-74); every other path is a command stream, with the smooth curves S/T expanded to C/Q first so the command count is exact (D-36). Both come in an f32 and an f64 form: the encoder writes the f32 records by default, since a canvas coordinate is a pixel position and an f32 holds a value below 16,384 to within 2⁻¹¹ px, and precision: :f64 selects the f64 records (D-73; spec/09 §4.5). Transforms fold into one matrix in SVG order. Colors are parsed by Visualize.Color.parse/1.

A stream that draws a Visualize.IR.Paint is version 2 (spec/09 §4.2, D-175): it begins with version 2 and one paint record per distinct paint, its style records refer to a paint by index (bits 5 and 6), and each element drawn with one has a box record before its draws. A stream without a paint is version 1, byte for byte.

A style that sets a paint's opacity, a cap, a join or a dash makes the stream version 3 (spec/09 §4.3.17, D-180): its style record is followed by a paint_state record, which the hook keeps as state that save and restore scope. A stream without one is as it was.

A tree that clips an element or a style that blends makes the stream version 4 (spec/09 §4.3.18–4.3.19, D-208): a clipped element is save, its clip shape's geometry record, a clip record and its own records, then restore, in the order the :json commands give it; a blend is a blend record after the style record. A stream without either is as it was.

Performance

Binary encoding reduces payload size by ~80% compared to JSON and eliminates JSON parsing overhead in the browser. The browser can create typed-array views directly on the binary data.

Requirements

Requires the nx package to be installed.

Summary

Types

The coordinate width of the path records: f32 by default (D-73).

Functions

Checks if Nx is available for binary encoding.

Encodes an element tree as binary data.

Encodes element, raising on error. Options as encode_path/2.

As encode_path/2 with no options.

Encodes a path element as binary data.

As encode_path!/2 with no options.

Encodes a path element as binary, raising on error. Options as encode_path/2.

Encodes binary data as base64 for embedding in HTML attributes.

Types

precision()

@type precision() :: :f32 | :f64

The coordinate width of the path records: f32 by default (D-73).

Functions

available?()

@spec available?() :: boolean()

Checks if Nx is available for binary encoding.

encode_element(element)

@spec encode_element(Visualize.IR.Element.t() | Visualize.SVG.Element.t()) ::
  {:ok, binary()} | {:error, :nx_not_available}

As encode_element/2 with no options.

encode_element(element, opts)

@spec encode_element(Visualize.IR.Element.t() | Visualize.SVG.Element.t(), keyword()) ::
  {:ok, binary()} | {:error, :nx_not_available}

Encodes an element tree as binary data.

Returns a binary blob that can be sent to the browser and decoded by the CanvasBinaryChart JavaScript hook.

Accepts either Visualize.IR.Element or Visualize.SVG.Element structs. Options as encode_path/2; the precision governs every path record in the stream.

encode_element!(element)

@spec encode_element!(Visualize.IR.Element.t() | Visualize.SVG.Element.t()) ::
  binary()

As encode_element!/2 with no options.

encode_element!(element, opts)

@spec encode_element!(Visualize.IR.Element.t() | Visualize.SVG.Element.t(), keyword()) ::
  binary()

Encodes element, raising on error. Options as encode_path/2.

encode_path(path)

@spec encode_path(Visualize.IR.Path.t()) ::
  {:ok, binary()} | {:error, :nx_not_available}

As encode_path/2 with no options.

encode_path(path, opts)

@spec encode_path(Visualize.IR.Path.t(), keyword()) ::
  {:ok, binary()} | {:error, :nx_not_available}

Encodes a path element as binary data.

Returns {:ok, binary} on success or {:error, reason} if Nx is not available.

Options

  • :precision - :f32 (the default) writes the path32/path_cubic32 records, :f64 the path/path_cubic ones (spec/09 §4.5)

encode_path!(path)

@spec encode_path!(Visualize.IR.Path.t()) :: binary()

As encode_path!/2 with no options.

encode_path!(path, opts)

@spec encode_path!(Visualize.IR.Path.t(), keyword()) :: binary()

Encodes a path element as binary, raising on error. Options as encode_path/2.

to_base64(binary)

@spec to_base64(binary()) :: String.t()

Encodes binary data as base64 for embedding in HTML attributes.