Visualize.Chart.Use (Visualize v0.2.35)

Copy Markdown View Source

A fragment used at a position (spec/14 §19.3, D-101).

A layer in a composite and an entry in a style stack are the same thing: a use of a fragment at a site. The site has four parts, each written by exactly one surface, and they are applied in one order — ref → local → mask → bind → stack — so a mask removes what the site would otherwise say whichever part said it, and a bound variable is renamed before the cascade sees it wherever at the site it stands. A site the host seeded is nothing but its local, and is masked and bound like any other.

%Visualize.Chart.Use{
  id:    {:use, 7},                # this site's own identity (§19.3)
  ref:   {:style, 11},             # which fragment (§19.2); nil for an inline-only site
  mask:  [:stroke],                # removed here, so a lower layer shows through (§19.5)
  vars:  %{color: var(:color_1)},  # what the fragment's variables mean here (§19.4)
  local: %{opacity: 0.8},          # added or overridden here
  origin: nil                      # the entry an unlocked site came from (#381)
}

A struct is a leaf of every walk (D-92), which is what keeps Visualize.Chart.stack/1 from descending into a site and merging its parts.

Examples

iex> alias Visualize.Chart.Use
iex> use = Use.new({:style, 11})
iex> {use.ref, use.mask, use.vars, use.local}
{{:style, 11}, [], %{}, %{}}

iex> Visualize.Chart.Use.new({:style, 2}, [Visualize.Chart.Use.new({:style, 1})]).id
{:use, 2}

Summary

Types

A site's own identity: unique within the composite that holds it.

A path into a fragment: the keys from its root, as Visualize.Chart.explain/1 gives them.

t()

Functions

A fragment with its variables substituted (spec/14 §19.4, D-102).

A fragment with paths removed (spec/14 §19.5).

A use of a fragment with a fresh id and the three empty parts (spec/14 §19.3).

A use over a body it has already been given: the local node cascaded over it, the mask over the result, and the bindings over all of it — everything resolve/2 does after the fetch (spec/14 §19.3). Mask and bind run after local so they speak for everything the site contributes: an inline-only site is nothing but its local, and is masked and bound like any other. A mask of everything is the whole site removed — that is what disabling a layer means.

A use site resolved to the fragment it stands for, in order: the referenced body, the mask, the bindings, and the local node cascaded over it (spec/14 §19.3).

Types

id()

@type id() :: {:use, pos_integer()}

A site's own identity: unique within the composite that holds it.

path()

@type path() :: [atom() | non_neg_integer()]

A path into a fragment: the keys from its root, as Visualize.Chart.explain/1 gives them.

t()

@type t() :: %Visualize.Chart.Use{
  id: id(),
  key: atom() | nil,
  local: map(),
  mask: [path() | atom()],
  origin: Visualize.Chart.Fragment.id() | nil,
  ref: Visualize.Chart.Fragment.id() | nil,
  vars: %{required(atom()) => term()}
}

Functions

bind(fragment, vars)

@spec bind(term(), %{required(atom()) => term()}) :: term()

A fragment with its variables substituted (spec/14 §19.4, D-102).

Every %Var{name: k} becomes the map's value for k — a literal, or another var/1, which is a rename — and a variable the map does not name is left as it is. The result is a fragment with fewer, or differently named, variables in it, which every existing rule already accepts. Any other struct is a leaf.

iex> Visualize.Chart.Use.bind(%{fill: Visualize.Chart.var(:color)}, %{color: "blue"})
%{fill: "blue"}

iex> fragment = %{fill: Visualize.Chart.var(:color), text: [Visualize.Chart.var(:unit)]}
iex> Visualize.Chart.Use.bind(fragment, %{color: Visualize.Chart.var(:color_1)})
%{fill: %Visualize.Chart.Var{name: :color_1}, text: [%Visualize.Chart.Var{name: :unit}]}

mask(fragment, paths)

@spec mask(map(), [path() | atom()] | :all) :: map()

A fragment with paths removed (spec/14 §19.5).

A path is the keys from the fragment's root; a bare atom is a path of one. A path the fragment does not carry removes nothing. Masking :all removes everything, which is what disabling a layer is (D-87 restated in §19.3).

iex> Visualize.Chart.Use.mask(%{stroke: "#111", stroke_width: 5}, [:stroke])
%{stroke_width: 5}

iex> Visualize.Chart.Use.mask(%{frames: %{main: %{legend: %{}, margin: %{}}}}, [[:frames, :main, :margin]])
%{frames: %{main: %{legend: %{}}}}

iex> Visualize.Chart.Use.mask(%{a: 1}, :all)
%{}

new(ref, among \\ [])

@spec new(Visualize.Chart.Fragment.id() | nil, [t()]) :: t()

A use of a fragment with a fresh id and the three empty parts (spec/14 §19.3).

The id is one more than the highest among among — the sites this one will sit beside — so it is unique within its composite. A site's identity needs no more scope than that: nothing outside the composite refers to a site.

over(use, fragment)

@spec over(t(), map()) :: map()

A use over a body it has already been given: the local node cascaded over it, the mask over the result, and the bindings over all of it — everything resolve/2 does after the fetch (spec/14 §19.3). Mask and bind run after local so they speak for everything the site contributes: an inline-only site is nothing but its local, and is masked and bound like any other. A mask of everything is the whole site removed — that is what disabling a layer means.

resolve(use, fetch)

@spec resolve(t(), (Visualize.Chart.Fragment.id() -> {:ok, map()} | :error)) ::
  {:ok, map()} | {:missing, Visualize.Chart.Fragment.id(), map()}

A use site resolved to the fragment it stands for, in order: the referenced body, the mask, the bindings, and the local node cascaded over it (spec/14 §19.3).

fetch is how the referenced body is found — a store's get, or any function of an id — and returns {:ok, fragment} or :error. A ref the fetch cannot find is a mask of everything: the site stands for its local node alone, and the id is returned so the caller can say so (§19.2, D-100). A nil ref is an inline-only site.