The builder's stack as a list of use sites, and the pure operations over it (spec/14 §19.3, §19.6, §19.9).
The builder's state is uses — %Visualize.Chart.Use{} structs in stack order — and
everything else the panels read is derived from them: the resolved layers, each use
fetched through the store and its mask, bindings and local applied (§19.3); the
design, which is the enabled ones stacked (§19.6); and the labels a person sees,
which are a use's entry name or the name the host gave a layer it seeded.
A host's layers assign is fragments, and a fragment the host gave is seeded as an
inline-only use — ref: nil, the fragment as local — so the host's contract of
§18.2 is unchanged: it gives a stack of fragments, and the builder makes sites of them.
Disabling a layer is mask: :all (D-87 restated in §19.3). Selection is a use's id,
so it survives every insert and move without being remapped.
This module compiles only when Phoenix.Component is loaded (spec/10 §1.1, D-45, D-85).
Summary
Types
A use's id to the name a person sees for it.
A resolved layer, as every panel has always read one: its label and its fragment.
A row of the tree: the site, its depth, its parent's id, its flat position and its
owner — nil for a site of the tree, the referenced site's id for a row of a
referenced group's inside (§18.8, #388), whose index is the owner's.
Functions
Every site of the tree, depth first, as rows — the flat order the panel draws and a flat position names.
The rows of all/1 with each referenced group's inside beneath its row (spec/14
§18.8, #388): the sites its entry holds, through the fetch, depth first — a group the
entry holds followed by what it holds, a composite it references by that entry's
sites. Those sites are the library's and their ids the entry's, not the tree's, so
they have no flat position of their own: each row carries owner, the referenced
site's id, and the owner's flat position as its index, so a gesture on one is a
gesture on the group, and a flat position still indexes all/1. A row directly
under the owner names it as its parent; one deeper names the entry's site holding it.
An entry met again below itself is not opened twice.
The ids from an anchor to a sibling, in tree order — the range a Shift+click selects
(spec/14 §18.8, #382) — or :error when the two are not siblings.
The lowest tier that holds the stack (D-99): one bare inline site is its body, values and nothing else; anything more — a ref, a mask, a binding, a second site, a var — is structure.
The sites an inline group holds; [] for an object or a referenced site.
One use's contribution placed where the design keeps its kind (spec/14 §18.8, #283):
resolved through the flattening fetch, as placed/2 resolves it, so a reference to a
composite is what the composite flattens to; its mask ignored, since a disabled layer
still declares what it declares; a missing entry its local alone; a keyless site %{}.
An entry as the inline sites a copy of it is (spec/14 §18.17): a composite's sites,
each holding what its use contributed — the referenced fragment (flattened, when it is
a composite) stacked under the use's local, the use's mask, vars and key kept
— labelled with the referenced entry's name, or the composite's own for a site it
declares in place, with the composite's own vars and signals; any other body as one
inline site named for the entry. The sites carry no id: the caller issues one each
among the stack they join.
The design the stack stands for: the enabled uses as a composite over the stack's own vars, flattened through the store, every id at a reference site resolved, so the frame can draw it (spec/14 §19.6).
A copy of a site and what it holds, every id fresh among the tree, with the
{copy, original} id pairs so labels follow (spec/14 §18.8, #382).
The empty, valid fragment of a kind, for new fragment of a kind (spec/14 §19.8).
Whether a use contributes to the design: anything but a mask of everything.
The fetch a store gives resolution: an id to {:ok, fragment} or :error.
The use with an id anywhere in the tree, or nil.
A group's local: an inline composite with no objects.
Whether a use is a container: an inline composite — a layer or a group.
Sibling sites wrapped in a group at the first one's position, in their tree order
(spec/14 §18.8, #382); :error when the ids are not siblings, or none.
The flat position of a use in the tree, or nil.
The name a site of a composite is shown by (spec/14 §18.8, §18.17): a referenced
site by its entry's name — its id when the store has none — and a site the composite
declares in place by its kind (#380), or by own, the composite's name, when it
declares several. A copy's sites are labelled so, and so are a referenced group's rows.
A use inserted as the sibling after another — at the top, at the end, for nil — or,
with {:into, id}, appended inside that group.
A use inserted before the row at a flat position, in that row's own container — at the end of the top past the last row (spec/14 §18.17, #380).
The sites a referenced composite's entry holds (spec/14 §18.8, #388) — the library's,
read-only in the chart — or nil for a use that is not a reference to a composite or
whose entry the fetch cannot find.
The kinds new fragment of a kind offers, the composite first and never a design: a design is the deployed tier, and a composite deploys to one (spec/14 §19.6, §19.8).
The name a person sees for a use: its label, or its id when it has none.
The site that copies or overrides a node the use contributes (spec/14 §18.16, #379):
%{local, key, mask, lifted} — the inline site's local and key, the mask path to add
to the owner or nil, and how many members were lifted — or :error when the use does
not contribute the node. The node carries its body as the design composes it, since a
list member's index in the design is not its index in the owner's list. A :copy takes a fresh id or key, avoiding taken; an
:override keeps the node's identity and, for a node with none — a label, a mark with
no id — lifts the owner's whole list and masks it at the finest path the owner's
contribution has for it.
A use's state toward the library (spec/14 §18.8, §19.3, #381): :inline with no ref and
no origin, :linked with a ref and no local, :edited with a ref over a local — locked
again after edits — and :unlocked with an origin and no ref.
The path a design path has inside a use: a site of one kind holds its body under the
kind's key (spec/14 §19.3), so the design's sources.primary is a source site's
[:source], and a design-level site's path is its own (§18.15).
A use with an origin linked to it again, its local kept over the link (spec/14 §18.8, #381); a use with no origin has nothing to link to and is unchanged.
Whether a use is the library's word — it references an entry — and so is locked in the chart: read-only, edited by opening the entry (spec/14 §18.8, §18.15).
A move within the tree by flat positions (§19.3, #380): the row at from — a group
with everything it holds — taken out, then put before the row that stands at to
once it is out, in that row's own container; past the last row, at the end of the top.
A row cannot land inside what it holds, since those rows are out with it.
An entry as a stack (spec/14 §19.9): a composite's sites, labelled by the store's names, with its vars and its signals (§19.10); any other body as one inline site named for the entry.
The id of the group holding a use, or nil at the top.
The enabled uses as the layers the design is stacked from — {id, fragment} in stack
order, each resolved and placed where the design keeps its kind (spec/14 §18.15,
§19.6) — so Visualize.Chart.explain/1 over them says which use gave every value. A
name-keyed site with no key has nowhere to be placed and is left out, as design/3
leaves it out.
The tree without a use (and what it holds); a missing id changes nothing.
Every use resolved to a layer the panels can read — {label, fragment} — and the refs
no store could find (spec/14 §19.2, §19.3). A disabled use resolves as it would enabled:
the panels edit what a layer says whether or not the design is drawing it, and its mask
of everything has its whole effect in design/2.
A use as the library has it (spec/14 §18.8, #381): its local dropped, its ref restored from its origin where it was unlocked, mask, vars and key kept — they are the site's.
A host's layers as use sites, with their labels (spec/14 §19.9).
Each site that carries variables: the free variables of its fragment before the site's bindings — the names the fragment itself uses — and what the site binds them to, for the Variables tab's per-site rows (spec/14 §19.4, §19.10).
The stack as a composite: what saving sends and a composite stores (spec/14 §19.6).
As structure/2, with the chart's signals when it has any (spec/14 §19.10).
A use with its enabled state flipped: disabling is a mask of everything (§19.3).
An inline group's sites spliced in at its position, the group gone (spec/14 §18.8, #382); any other site leaves the tree unchanged.
A use unlocked from its entry (spec/14 §18.8, #381): the ref moved to origin and the
entry's body copied into local under whatever the site already held there; mask, vars
and key stay the site's, so the chart draws as it did. A composite entry unlocks to a
group of copies of its sites, as copies/3 reads them, the composite's vars the
group's; the inner sites come with nil ids for the caller to issue, and their labels
and the entry's signals are returned beside the use.
What a site contributes before its mask — the referenced body, or nothing, under its local — so the context panel can offer every key the mask could remove (spec/14 §19.5).
The tree with one use, anywhere, replaced by a function of it; a missing id changes nothing.
A write into a use's local at a path (spec/14 §19.3): a {:ok, value} sets the key,
:error removes it. A container the local does not carry yet is an empty node on the
way (§18.5).
A write into any fragment at a path, as write/4 does into a use's local.
Types
@type labels() :: %{required(Visualize.Chart.Use.id()) => String.t()}
A use's id to the name a person sees for it.
A resolved layer, as every panel has always read one: its label and its fragment.
@type row() :: %{ use: Visualize.Chart.Use.t(), depth: non_neg_integer(), parent: Visualize.Chart.Use.id() | nil, index: non_neg_integer(), owner: Visualize.Chart.Use.id() | nil }
A row of the tree: the site, its depth, its parent's id, its flat position and its
owner — nil for a site of the tree, the referenced site's id for a row of a
referenced group's inside (§18.8, #388), whose index is the owner's.
Functions
@spec all([Visualize.Chart.Use.t()]) :: [row()]
Every site of the tree, depth first, as rows — the flat order the panel draws and a flat position names.
iex> inner = [%Visualize.Chart.Use{id: {:use, 3}, ref: nil, local: %{style: %{}}}]
iex> uses = [%Visualize.Chart.Use{id: {:use, 1}, ref: nil, local: %{composite: %{uses: inner, vars: %{}}}}, %Visualize.Chart.Use{id: {:use, 2}, ref: nil, local: %{mark: %{}}}]
iex> for row <- Visualize.Chart.Builder.Stack.all(uses), do: {row.use.id, row.depth, row.parent, row.index}
[{{:use, 1}, 0, nil, 0}, {{:use, 3}, 1, {:use, 1}, 1}, {{:use, 2}, 0, nil, 2}]
@spec all([Visualize.Chart.Use.t()], (Visualize.Chart.Fragment.id() -> {:ok, map()} | :error)) :: [ row() ]
The rows of all/1 with each referenced group's inside beneath its row (spec/14
§18.8, #388): the sites its entry holds, through the fetch, depth first — a group the
entry holds followed by what it holds, a composite it references by that entry's
sites. Those sites are the library's and their ids the entry's, not the tree's, so
they have no flat position of their own: each row carries owner, the referenced
site's id, and the owner's flat position as its index, so a gesture on one is a
gesture on the group, and a flat position still indexes all/1. A row directly
under the owner names it as its parent; one deeper names the entry's site holding it.
An entry met again below itself is not opened twice.
iex> pair = %{composite: %{uses: [%Visualize.Chart.Use{id: {:use, 1}, ref: {:frame, 1}}, %Visualize.Chart.Use{id: {:use, 2}, ref: nil, local: %{mark: %{}}}], vars: %{}}}
iex> fetch = fn {:composite, 1} -> {:ok, pair}; _id -> :error end
iex> uses = [%Visualize.Chart.Use{id: {:use, 1}, ref: nil, local: %{style: %{}}}, %Visualize.Chart.Use{id: {:use, 2}, ref: {:composite, 1}}]
iex> for row <- Visualize.Chart.Builder.Stack.all(uses, fetch), do: {row.use.id, row.depth, row.index, row.owner}
[{{:use, 1}, 0, 0, nil}, {{:use, 2}, 0, 1, nil}, {{:use, 1}, 1, 1, {:use, 2}}, {{:use, 2}, 1, 1, {:use, 2}}]
@spec between( [Visualize.Chart.Use.t()], Visualize.Chart.Use.id(), Visualize.Chart.Use.id() ) :: {:ok, [Visualize.Chart.Use.id()]} | :error
The ids from an anchor to a sibling, in tree order — the range a Shift+click selects
(spec/14 §18.8, #382) — or :error when the two are not siblings.
iex> alias Visualize.Chart.{Builder.Stack, Use}
iex> uses = for n <- 1..3, do: %Use{id: {:use, n}, ref: nil, local: %{mark: %{}}}
iex> Stack.between(uses, {:use, 3}, {:use, 1})
{:ok, [{:use, 1}, {:use, 2}, {:use, 3}]}
iex> Stack.between([%Use{id: {:use, 4}, ref: nil, local: %{composite: %{uses: uses, vars: %{}}}}], {:use, 4}, {:use, 1})
:error
@spec body([Visualize.Chart.Use.t()], map()) :: map()
The lowest tier that holds the stack (D-99): one bare inline site is its body, values and nothing else; anything more — a ref, a mask, a binding, a second site, a var — is structure.
@spec children(Visualize.Chart.Use.t()) :: [Visualize.Chart.Use.t()]
The sites an inline group holds; [] for an object or a referenced site.
@spec contribution(Visualize.Chart.Use.t(), (Visualize.Chart.Fragment.id() -> {:ok, map()} | :error)) :: map()
One use's contribution placed where the design keeps its kind (spec/14 §18.8, #283):
resolved through the flattening fetch, as placed/2 resolves it, so a reference to a
composite is what the composite flattens to; its mask ignored, since a disabled layer
still declares what it declares; a missing entry its local alone; a keyless site %{}.
iex> use = %Visualize.Chart.Use{id: {:use, 1}, ref: nil, mask: :all, local: %{axis: %{scale: :x, side: :bottom}}}
iex> Visualize.Chart.Builder.Stack.contribution(use, fn _id -> :error end)
%{frames: %{main: %{axes: [%{scale: :x, side: :bottom}]}}}
@spec copies( %{kind: atom(), name: String.t() | nil, fragment: map()}, (Visualize.Chart.Fragment.id() -> {:ok, map()} | :error), (Visualize.Chart.Fragment.id() -> String.t() | nil) ) :: {[{Visualize.Chart.Use.t(), String.t()}], map(), map()}
An entry as the inline sites a copy of it is (spec/14 §18.17): a composite's sites,
each holding what its use contributed — the referenced fragment (flattened, when it is
a composite) stacked under the use's local, the use's mask, vars and key kept
— labelled with the referenced entry's name, or the composite's own for a site it
declares in place, with the composite's own vars and signals; any other body as one
inline site named for the entry. The sites carry no id: the caller issues one each
among the stack they join.
@spec design([Visualize.Chart.Use.t()], map(), (Visualize.Chart.Fragment.id() -> {:ok, map()} | :error)) :: {:ok, map(), Visualize.Chart.Composite.report()} | {:error, term()}
The design the stack stands for: the enabled uses as a composite over the stack's own vars, flattened through the store, every id at a reference site resolved, so the frame can draw it (spec/14 §19.6).
@spec duplicated([Visualize.Chart.Use.t()], Visualize.Chart.Use.t()) :: {Visualize.Chart.Use.t(), [{Visualize.Chart.Use.id(), Visualize.Chart.Use.id()}]}
A copy of a site and what it holds, every id fresh among the tree, with the
{copy, original} id pairs so labels follow (spec/14 §18.8, #382).
iex> alias Visualize.Chart.{Builder.Stack, Use}
iex> inner = [%Use{id: {:use, 2}, ref: nil, local: %{mark: %{}}}]
iex> group = %Use{id: {:use, 1}, ref: nil, local: %{composite: %{uses: inner, vars: %{}}}}
iex> {copy, pairs} = Stack.duplicated([group], group)
iex> {copy.id, Enum.map(Stack.children(copy), & &1.id), pairs}
{{:use, 3}, [{:use, 4}], [{{:use, 3}, {:use, 1}}, {{:use, 4}, {:use, 2}}]}
The empty, valid fragment of a kind, for new fragment of a kind (spec/14 §19.8).
@spec enabled?(Visualize.Chart.Use.t()) :: boolean()
Whether a use contributes to the design: anything but a mask of everything.
@spec fetch(Visualize.Chart.Builder.Store.store() | nil) :: (Visualize.Chart.Fragment.id() -> {:ok, map()} | :error)
The fetch a store gives resolution: an id to {:ok, fragment} or :error.
@spec get([Visualize.Chart.Use.t()], Visualize.Chart.Use.id() | nil) :: Visualize.Chart.Use.t() | nil
The use with an id anywhere in the tree, or nil.
@spec group() :: map()
A group's local: an inline composite with no objects.
@spec group?(Visualize.Chart.Use.t()) :: boolean()
Whether a use is a container: an inline composite — a layer or a group.
@spec grouped( [Visualize.Chart.Use.t()], [Visualize.Chart.Use.id()], Visualize.Chart.Use.t() ) :: {:ok, [Visualize.Chart.Use.t()]} | :error
Sibling sites wrapped in a group at the first one's position, in their tree order
(spec/14 §18.8, #382); :error when the ids are not siblings, or none.
iex> alias Visualize.Chart.{Builder.Stack, Use}
iex> uses = for n <- 1..3, do: %Use{id: {:use, n}, ref: nil, local: %{mark: %{}}}
iex> group = %{Use.new(nil, uses) | local: Stack.group()}
iex> {:ok, grouped} = Stack.grouped(uses, [{:use, 3}, {:use, 2}], group)
iex> Enum.map(grouped, & &1.id)
[{:use, 1}, {:use, 4}]
iex> grouped |> List.last() |> Stack.children() |> Enum.map(& &1.id)
[{:use, 2}, {:use, 3}]
@spec index_of([Visualize.Chart.Use.t()], Visualize.Chart.Use.id() | nil) :: non_neg_integer() | nil
The flat position of a use in the tree, or nil.
@spec inner_label( Visualize.Chart.Use.t(), (Visualize.Chart.Fragment.id() -> String.t() | nil), String.t() ) :: String.t()
The name a site of a composite is shown by (spec/14 §18.8, §18.17): a referenced
site by its entry's name — its id when the store has none — and a site the composite
declares in place by its kind (#380), or by own, the composite's name, when it
declares several. A copy's sites are labelled so, and so are a referenced group's rows.
iex> name_of = fn {:style, 1} -> "Styles::thick"; _id -> nil end
iex> Visualize.Chart.Builder.Stack.inner_label(%Visualize.Chart.Use{id: {:use, 1}, ref: {:style, 1}}, name_of, "pair")
"Styles::thick"
iex> Visualize.Chart.Builder.Stack.inner_label(%Visualize.Chart.Use{id: {:use, 1}, ref: {:frame, 9}}, name_of, "pair")
"frame 9"
iex> Visualize.Chart.Builder.Stack.inner_label(%Visualize.Chart.Use{id: {:use, 1}, ref: nil, local: %{mark: %{type: :line}}}, name_of, "pair")
"mark"
iex> Visualize.Chart.Builder.Stack.inner_label(%Visualize.Chart.Use{id: {:use, 1}, ref: nil, local: %{version: 2}}, name_of, "pair")
"pair"
@spec insert( [Visualize.Chart.Use.t()], Visualize.Chart.Use.id() | nil | {:into, Visualize.Chart.Use.id()}, Visualize.Chart.Use.t() ) :: [Visualize.Chart.Use.t()]
A use inserted as the sibling after another — at the top, at the end, for nil — or,
with {:into, id}, appended inside that group.
@spec insert_at([Visualize.Chart.Use.t()], non_neg_integer(), Visualize.Chart.Use.t()) :: [ Visualize.Chart.Use.t() ]
A use inserted before the row at a flat position, in that row's own container — at the end of the top past the last row (spec/14 §18.17, #380).
@spec inside(Visualize.Chart.Use.t(), (Visualize.Chart.Fragment.id() -> {:ok, map()} | :error)) :: [Visualize.Chart.Use.t()] | nil
The sites a referenced composite's entry holds (spec/14 §18.8, #388) — the library's,
read-only in the chart — or nil for a use that is not a reference to a composite or
whose entry the fetch cannot find.
@spec kinds() :: [atom(), ...]
The kinds new fragment of a kind offers, the composite first and never a design: a design is the deployed tier, and a composite deploys to one (spec/14 §19.6, §19.8).
@spec label(labels(), Visualize.Chart.Use.t()) :: String.t()
The name a person sees for a use: its label, or its id when it has none.
@spec lifted( :copy | :override, Visualize.Chart.Use.t(), (Visualize.Chart.Fragment.id() -> {:ok, map()} | :error), map(), [atom()] ) :: %{ local: map(), key: atom() | nil, mask: [atom()] | nil, lifted: pos_integer() } | :error
The site that copies or overrides a node the use contributes (spec/14 §18.16, #379):
%{local, key, mask, lifted} — the inline site's local and key, the mask path to add
to the owner or nil, and how many members were lifted — or :error when the use does
not contribute the node. The node carries its body as the design composes it, since a
list member's index in the design is not its index in the owner's list. A :copy takes a fresh id or key, avoiding taken; an
:override keeps the node's identity and, for a node with none — a label, a mark with
no id — lifts the owner's whole list and masks it at the finest path the owner's
contribution has for it.
iex> use = %Visualize.Chart.Use{id: {:use, 1}, ref: nil, local: %{frames: %{main: %{kind: :cartesian, axes: [%{scale: :x, side: :bottom}, %{scale: :y, side: :left}]}}}}
iex> node = %{kind: :axis, path: [:frames, :main, :axes, 1], label: "frames.main.axes[1]", body: %{scale: :y, side: :left}}
iex> Visualize.Chart.Builder.Stack.lifted(:copy, use, fn _ -> :error end, node, [])
%{local: %{axis: %{scale: :y, side: :left}}, key: nil, mask: nil, lifted: 1}
iex> style = %Visualize.Chart.Use{id: {:use, 2}, ref: nil, key: :series, local: %{style: %{stroke: "#111"}}}
iex> Visualize.Chart.Builder.Stack.lifted(:copy, style, fn _ -> :error end, %{kind: :style, path: [:styles, :series], label: "styles.series"}, [:series, :series_2])
%{local: %{style: %{stroke: "#111"}}, key: :series_3, mask: nil, lifted: 1}
iex> labels = %Visualize.Chart.Use{id: {:use, 3}, ref: nil, local: %{labels: [%{anchor: :title, text: ["a"]}, %{anchor: :caption, text: ["b"]}]}}
iex> Visualize.Chart.Builder.Stack.lifted(:override, labels, fn _ -> :error end, %{kind: :label, path: [:labels, 1], label: "labels[1]", body: %{anchor: :caption, text: ["b"]}}, [])
%{local: %{labels: [%{anchor: :title, text: ["a"]}, %{anchor: :caption, text: ["b"]}]}, key: nil, mask: [:labels], lifted: 2}
@spec linkage(Visualize.Chart.Use.t()) :: :inline | :linked | :edited | :unlocked
A use's state toward the library (spec/14 §18.8, §19.3, #381): :inline with no ref and
no origin, :linked with a ref and no local, :edited with a ref over a local — locked
again after edits — and :unlocked with an origin and no ref.
iex> alias Visualize.Chart.{Builder.Stack, Use}
iex> Stack.linkage(Use.new({:style, 3}))
:linked
iex> Stack.linkage(%{Use.new({:style, 3}) | local: %{stroke: "#111"}})
:edited
iex> Stack.linkage(%{Use.new(nil) | origin: {:style, 3}})
:unlocked
iex> Stack.linkage(Use.new(nil))
:inline
@spec local_path( Visualize.Chart.Use.t(), (Visualize.Chart.Fragment.id() -> {:ok, map()} | :error), [ term() ] ) :: [term()]
The path a design path has inside a use: a site of one kind holds its body under the
kind's key (spec/14 §19.3), so the design's sources.primary is a source site's
[:source], and a design-level site's path is its own (§18.15).
iex> use = %Visualize.Chart.Use{id: {:use, 1}, ref: nil, key: :primary, local: %{source: %{fields: [:t]}}}
iex> Visualize.Chart.Builder.Stack.local_path(use, fn _id -> :error end, [:sources, :primary])
[:source]
iex> Visualize.Chart.Builder.Stack.local_path(use, fn _id -> :error end, [:sources, :primary, :fields])
[:source, :fields]
iex> mark = %Visualize.Chart.Use{id: {:use, 2}, ref: nil, local: %{mark: %{type: :line}}}
iex> Visualize.Chart.Builder.Stack.local_path(mark, fn _id -> :error end, [:marks, 3, :channels])
[:mark, :channels]
iex> house = %Visualize.Chart.Use{id: {:use, 3}, ref: nil, local: %{frames: %{main: %{kind: :cartesian}}}}
iex> Visualize.Chart.Builder.Stack.local_path(house, fn _id -> :error end, [:frames, :main, :margin])
[:frames, :main, :margin]
@spec locked(Visualize.Chart.Use.t()) :: Visualize.Chart.Use.t()
A use with an origin linked to it again, its local kept over the link (spec/14 §18.8, #381); a use with no origin has nothing to link to and is unchanged.
iex> alias Visualize.Chart.{Builder.Stack, Use}
iex> use = %{Use.new(nil) | origin: {:style, 3}, local: %{stroke: "#111"}}
iex> Stack.locked(use) |> Map.take([:ref, :origin, :local])
%{ref: {:style, 3}, origin: nil, local: %{stroke: "#111"}}
@spec locked?(Visualize.Chart.Use.t()) :: boolean()
Whether a use is the library's word — it references an entry — and so is locked in the chart: read-only, edited by opening the entry (spec/14 §18.8, §18.15).
iex> Visualize.Chart.Builder.Stack.locked?(Visualize.Chart.Use.new({:style, 3}))
true
iex> Visualize.Chart.Builder.Stack.locked?(Visualize.Chart.Use.new(nil))
false
@spec move([Visualize.Chart.Use.t()], non_neg_integer(), non_neg_integer()) :: [ Visualize.Chart.Use.t() ]
A move within the tree by flat positions (§19.3, #380): the row at from — a group
with everything it holds — taken out, then put before the row that stands at to
once it is out, in that row's own container; past the last row, at the end of the top.
A row cannot land inside what it holds, since those rows are out with it.
@spec open( %{kind: atom(), name: String.t() | nil, fragment: map()}, (Visualize.Chart.Fragment.id() -> String.t() | nil) ) :: {[Visualize.Chart.Use.t()], labels(), map(), map()}
An entry as a stack (spec/14 §19.9): a composite's sites, labelled by the store's names, with its vars and its signals (§19.10); any other body as one inline site named for the entry.
@spec parent_of([Visualize.Chart.Use.t()], Visualize.Chart.Use.id()) :: Visualize.Chart.Use.id() | nil
The id of the group holding a use, or nil at the top.
@spec placed([Visualize.Chart.Use.t()], (Visualize.Chart.Fragment.id() -> {:ok, map()} | :error)) :: [ {Visualize.Chart.Use.id(), map()} ]
The enabled uses as the layers the design is stacked from — {id, fragment} in stack
order, each resolved and placed where the design keeps its kind (spec/14 §18.15,
§19.6) — so Visualize.Chart.explain/1 over them says which use gave every value. A
name-keyed site with no key has nowhere to be placed and is left out, as design/3
leaves it out.
iex> uses = [
...> %Visualize.Chart.Use{id: {:use, 1}, ref: nil, local: %{frames: %{main: %{kind: :cartesian}}}},
...> %Visualize.Chart.Use{id: {:use, 2}, ref: nil, key: :primary, local: %{source: %{fields: [:t]}}},
...> %Visualize.Chart.Use{id: {:use, 3}, ref: nil, mask: :all, local: %{theme: :dark}}
...> ]
iex> Visualize.Chart.Builder.Stack.placed(uses, fn _id -> :error end)
[{{:use, 1}, %{frames: %{main: %{kind: :cartesian}}}}, {{:use, 2}, %{sources: %{primary: %{fields: [:t]}}}}]
@spec remove([Visualize.Chart.Use.t()], Visualize.Chart.Use.id()) :: [ Visualize.Chart.Use.t() ]
The tree without a use (and what it holds); a missing id changes nothing.
@spec resolve([Visualize.Chart.Use.t()], labels(), (Visualize.Chart.Fragment.id() -> {:ok, map()} | :error)) :: {[resolved()], [{Visualize.Chart.Use.id(), Visualize.Chart.Fragment.id()}]}
Every use resolved to a layer the panels can read — {label, fragment} — and the refs
no store could find (spec/14 §19.2, §19.3). A disabled use resolves as it would enabled:
the panels edit what a layer says whether or not the design is drawing it, and its mask
of everything has its whole effect in design/2.
@spec reverted(Visualize.Chart.Use.t()) :: Visualize.Chart.Use.t()
A use as the library has it (spec/14 §18.8, #381): its local dropped, its ref restored from its origin where it was unlocked, mask, vars and key kept — they are the site's.
iex> alias Visualize.Chart.{Builder.Stack, Use}
iex> use = %{Use.new(nil) | origin: {:style, 3}, local: %{stroke: "#111"}, mask: [:fill]}
iex> Stack.reverted(use) |> Map.take([:ref, :origin, :local, :mask])
%{ref: {:style, 3}, origin: nil, local: %{}, mask: [:fill]}
@spec seed([term()]) :: {[Visualize.Chart.Use.t()], labels()}
A host's layers as use sites, with their labels (spec/14 §19.9).
A {name, layer} pair keeps its name; a bare layer is named by its position. A
fragment — a map, or a %Visualize.Chart{} as the map it is — becomes an inline-only
use; an id {kind, n} becomes a use referring to it, so a host may start the builder
over entries of its own library.
@spec sites([Visualize.Chart.Use.t()], labels(), (Visualize.Chart.Fragment.id() -> {:ok, map()} | :error)) :: [ %{ index: non_neg_integer(), id: Visualize.Chart.Use.id(), label: String.t(), free: [Visualize.Chart.free_var()], vars: map() } ]
Each site that carries variables: the free variables of its fragment before the site's bindings — the names the fragment itself uses — and what the site binds them to, for the Variables tab's per-site rows (spec/14 §19.4, §19.10).
@spec structure([Visualize.Chart.Use.t()], map()) :: map()
The stack as a composite: what saving sends and a composite stores (spec/14 §19.6).
As structure/2, with the chart's signals when it has any (spec/14 §19.10).
@spec toggle(Visualize.Chart.Use.t()) :: Visualize.Chart.Use.t()
A use with its enabled state flipped: disabling is a mask of everything (§19.3).
@spec ungrouped([Visualize.Chart.Use.t()], Visualize.Chart.Use.id()) :: [ Visualize.Chart.Use.t() ]
An inline group's sites spliced in at its position, the group gone (spec/14 §18.8, #382); any other site leaves the tree unchanged.
@spec unlocked( Visualize.Chart.Use.t(), %{kind: atom(), name: String.t() | nil, fragment: map()}, (Visualize.Chart.Fragment.id() -> {:ok, map()} | :error), (Visualize.Chart.Fragment.id() -> String.t() | nil) ) :: {Visualize.Chart.Use.t(), [{Visualize.Chart.Use.t(), String.t()}], map()}
A use unlocked from its entry (spec/14 §18.8, #381): the ref moved to origin and the
entry's body copied into local under whatever the site already held there; mask, vars
and key stay the site's, so the chart draws as it did. A composite entry unlocks to a
group of copies of its sites, as copies/3 reads them, the composite's vars the
group's; the inner sites come with nil ids for the caller to issue, and their labels
and the entry's signals are returned beside the use.
@spec unmasked(Visualize.Chart.Use.t(), (Visualize.Chart.Fragment.id() -> {:ok, map()} | :error)) :: map()
What a site contributes before its mask — the referenced body, or nothing, under its local — so the context panel can offer every key the mask could remove (spec/14 §19.5).
@spec update( [Visualize.Chart.Use.t()], Visualize.Chart.Use.id(), (Visualize.Chart.Use.t() -> Visualize.Chart.Use.t()) ) :: [ Visualize.Chart.Use.t() ]
The tree with one use, anywhere, replaced by a function of it; a missing id changes nothing.
@spec write(Visualize.Chart.Use.t(), [term()], atom(), {:ok, term()} | :error) :: Visualize.Chart.Use.t()
A write into a use's local at a path (spec/14 §19.3): a {:ok, value} sets the key,
:error removes it. A container the local does not carry yet is an empty node on the
way (§18.5).
A write into any fragment at a path, as write/4 does into a use's local.