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.
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
Functions
@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.
@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).
@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).
The output the segments are of: the SVG markup, the :json commands, or the binary
stream in base64.