Visualize.Render.Segments (Visualize v0.8.1)

Copy Markdown View Source

A drawing as keyed segments, so that what a change did not touch is neither written again nor sent again (spec/09 §1.4, #813, D-203).

A segment is one element's part of a backend's output: the text of an element drawn alone — a mark's item, a label, an axis's line — or the start or the end of a group or of the root around its children. Read in order, the segments' texts are the backend's output, byte for byte (text/2): SVG markup, the :json canvas commands without the brackets around them, or the binary canvas stream in base64, one piece of the stream per segment.

Each segment is keyed. An element that names its identity (data-vis-id, spec/14 §3.10, D-167) is keyed by it, "id:" <> identity, so a thing keeps its key wherever the rows put it; a group's start and end by its path from the root — the index of each element among its parent's children, "r/2/0" — followed by < and >; and any other element by its group's path, ~ and a hash of the element and the style it inherits, so an element keeps its key when one before it comes or goes. A key is never repeated: a second element of one key is keyed as the first with #2, and so on. A hash only names a key: a text is reused only for an element equal to the last one under it.

Visualize.Components.Chart sends a drawing as a LiveView comprehension keyed by these keys, so a move that changes three cells of a grid sends three segments (D-203).

The cache

Every function takes the cache the previous call returned and returns the next one: an element drawn alone whose key, element and inherited style are the same as last time is not written again, its text is the one written then. A cache is only an economy — the segments are the same with %{} — and holds what the last drawing held, nothing older.

iex> tree = Visualize.IR.Element.group([Visualize.IR.Element.rect(0, 0, 10, 10, %{fill: "red"})])
iex> {segments, _cache} = Visualize.Render.Segments.svg(tree, %{})
iex> Enum.map(segments, &elem(&1, 1))
["<g>", ~s(<rect fill="red" height="10" width="10" x="0" y="0"/>), "</g>"]
iex> [{"r<", _}, {"r~" <> _hash, _}, {"r>", _}] = segments
iex> Visualize.Render.Segments.text(segments, :svg) == Visualize.Render.to_string(tree, backend: :svg)
true

Summary

Types

What the last call wrote, by key: opaque.

A segment's key: an identity's, or a path's.

t()

The segments of a drawing, in drawing order.

Functions

The tree's binary canvas stream as segments, each a piece of the stream in base64, the stream's head — its version and paint records — the first, and a segment of no records left out: decoded and concatenated they are the stream of Visualize.Backend.CanvasBinary.encode_element!/1.

The tree's :json canvas commands as segments, each its elements' commands as JSON objects joined by commas, a segment of no commands left out: joined by commas and put in brackets they are Visualize.Render.to_string(tree, backend: :canvas, format: :json).

The tree's SVG markup as segments: their texts concatenated are Visualize.Render.to_string(tree, backend: :svg).

The output the segments are of: the SVG markup, the :json commands, or the binary stream in base64.

Types

cache()

@type cache() :: map()

What the last call wrote, by key: opaque.

key()

@type key() :: String.t()

A segment's key: an identity's, or a path's.

t()

@type t() :: [{key(), String.t()}]

The segments of a drawing, in drawing order.

Functions

binary(tree, cache)

@spec binary(Visualize.IR.Element.t(), cache()) :: {t(), cache()}

The tree's binary canvas stream as segments, each a piece of the stream in base64, the stream's head — its version and paint records — the first, and a segment of no records left out: decoded and concatenated they are the stream of Visualize.Backend.CanvasBinary.encode_element!/1.

json(tree, cache)

@spec json(Visualize.IR.Element.t(), cache()) :: {t(), cache()}

The tree's :json canvas commands as segments, each its elements' commands as JSON objects joined by commas, a segment of no commands left out: joined by commas and put in brackets they are Visualize.Render.to_string(tree, backend: :canvas, format: :json).

svg(tree, cache)

@spec svg(Visualize.IR.Element.t(), cache()) :: {t(), cache()}

The tree's SVG markup as segments: their texts concatenated are Visualize.Render.to_string(tree, backend: :svg).

text(segments, atom)

@spec text(t(), :svg | :json | :binary) :: String.t()

The output the segments are of: the SVG markup, the :json commands, or the binary stream in base64.