Visualize.Chart.Builder.StyleStack (Visualize v0.8.3)

Copy Markdown View Source

The stack of styles at one site (spec/14 §18.18).

§3.6 gives every style site a stack — a reference, an inline node, or a list of either. This is the control over it: one row per entry in resolution order, the first applied first and the last winning, because that is the order the cascade is defined in and a panel that reversed it would teach the opposite of the specification.

A row is the control, as a layer row is (§18.17): it carries the click and the drag itself, because a <button> spanning a draggable row defeats both gestures. Each row can be selected, removed, and dragged to a position.

An inline entry is drawn as local: it is where an edit at the site lands, there is at most one, and it is created on first edit rather than sitting empty in every document (D-98).

This module compiles only when Phoenix.Component is loaded (spec/10 §1.1, D-45, D-85).

Summary

Types

One row of the stack: what it is, what to call it, and where it sits.

Functions

The names a style entry may take, grouped (spec/14 §18.14, §18.18, #685): what the stacked design declares, then the theme's palette group by group — the built-in four are its furniture.

The columns a site's data has, offered by + field (spec/14 §18.18, #686): the declared fields of the source the node's data names, and the columns of pool's rows for it, sorted; none where the node binds no source.

A style value as the rows to draw (spec/14 §18.18).

The generators a builder knows, offered by + generator (spec/14 §18.18, #686): the registry of modules and the host's configuration, each as {name, arguments} — its arity less the context — by name.

Which entry supplied each key of the resolved style (spec/14 §18.19), by its path: a whole element's key by its key, a part's by part.key — one part is often several entries' (a stroke's color from series, its width from local).

Renders the stack at a site (spec/10 §15.3).

The site's stack cascaded in its parts, as the panel shows it (spec/14 §18.19, D-178).

Types

entry()

@type entry() :: %{
  index: non_neg_integer(),
  name: String.t(),
  local: boolean(),
  default: boolean()
}

One row of the stack: what it is, what to call it, and where it sits.

Functions

choices(design, theme)

@spec choices(map(), Visualize.Theme.t()) :: [{String.t(), [atom()]}]

The names a style entry may take, grouped (spec/14 §18.14, §18.18, #685): what the stacked design declares, then the theme's palette group by group — the built-in four are its furniture.

iex> choices = Visualize.Chart.Builder.StyleStack.choices(%{styles: %{series: %{}}}, Visualize.Theme.default())
iex> hd(choices)
{"design", [:series]}
iex> {"furniture", furniture} = List.keyfind(choices, "furniture", 0)
iex> Enum.all?([:axis, :grid, :label, :title], &(&1 in furniture))
true

columns(design, node, pool)

@spec columns(map(), term(), map()) :: [atom()]

The columns a site's data has, offered by + field (spec/14 §18.18, #686): the declared fields of the source the node's data names, and the columns of pool's rows for it, sorted; none where the node binds no source.

iex> design = %{sources: %{"load" => %{fields: ["t", "v"]}}}
iex> Visualize.Chart.Builder.StyleStack.columns(design, %{data: "load"}, %{load: [%{t: 0, v: 1, host: "a"}]})
["host", "t", "v"]

iex> Visualize.Chart.Builder.StyleStack.columns(%{}, %{}, %{})
[]

entries(value, fallback)

@spec entries(term(), atom() | nil) :: [entry()]

A style value as the rows to draw (spec/14 §18.18).

Total over the three shapes of §3.6, and over a site that carries no style key at all: the schema's default for that site is shown as the row it will resolve as, marked default: true so the panel can say it is not something the design states.

iex> Visualize.Chart.Builder.StyleStack.entries(:series, nil)
[%{index: 0, name: "series", kind: :name, local: false, default: false}]

iex> Visualize.Chart.Builder.StyleStack.entries([:series, {:field, :health}, {:generate, :tenant_style, [{:field, :tenant}]}, %{stroke: %{width: 5}}], nil)
[
  %{index: 0, name: "series", kind: :name, local: false, default: false},
  %{index: 1, name: "field health", kind: :field, local: false, default: false},
  %{index: 2, name: "generate tenant_style(field tenant)", kind: :generator, local: false, default: false},
  %{index: 3, name: "local", kind: :local, local: true, default: false}
]

iex> Visualize.Chart.Builder.StyleStack.entries(nil, :label)
[%{index: 0, name: "label", kind: :name, local: false, default: true}]

iex> Visualize.Chart.Builder.StyleStack.entries(nil, nil)
[]

generators(modules)

@spec generators([module()]) :: [{atom(), non_neg_integer()}]

The generators a builder knows, offered by + generator (spec/14 §18.18, #686): the registry of modules and the host's configuration, each as {name, arguments} — its arity less the context — by name.

origins(design, value, theme)

@spec origins(map(), term(), Visualize.Theme.t()) :: %{
  required(atom() | String.t()) => String.t()
}

Which entry supplied each key of the resolved style (spec/14 §18.19), by its path: a whole element's key by its key, a part's by part.key — one part is often several entries' (a stroke's color from series, its width from local).

A resolved style is a cascade, so a value belongs to the last entry that set it. This is Visualize.Chart.explain/1's question asked at a site: which style said this.

iex> design = %{styles: %{series: %{stroke: "#111", stroke_width: 2}, faded: %{opacity: 0.5}}}
iex> Visualize.Chart.Builder.StyleStack.origins(design, [:series, :faded, %{stroke: %{width: 5}}], Visualize.Theme.default())
%{:opacity => "faded", "stroke.color" => "series", "stroke.type" => "series", "stroke.width" => "local"}

panel(assigns)

Renders the stack at a site (spec/10 §15.3).

An <ol class="vis-builder-style-stack"> carrying BuilderHook at scope style, with one <li class="vis-builder-style-entry"> per entry at its zero-based position.

Attributes

  • id (:string) (required) - the hook element's id.
  • value (:any) - the site's style value, in any shape of §3.6. Defaults to nil.
  • fallback (:atom) - the schema's default for this site. Defaults to nil.
  • design (:map) - the stacked design, for the names on offer. Defaults to %{}.
  • theme (:any) - the theme whose palette is on offer; the default's when nil. Defaults to nil.
  • columns (:list) - the columns the site's data has, for + field. Defaults to [].
  • generators (:list) - the generators the builder knows, {name, arguments}, for + generator. Defaults to [].
  • open (:integer) - the entry the context panel is on. Defaults to nil.
  • target (:any) - the phx-target of the panel's events. Defaults to nil.
  • class (:string) - appended to the panel's class. Defaults to nil.

resolved(design, value, theme)

@spec resolved(map(), term(), Visualize.Theme.t()) :: map()

The site's stack cascaded in its parts, as the panel shows it (spec/14 §18.19, D-178).

The design's declared styles over the palette of theme — the design's own, the one its chart is drawn with (#685) — then the entries resolved left to right by §3.6 and merged part by part by §3.5 — Visualize.Chart.Style's own rule, asked here for one site, before any projection onto the element keys. A field entry and a generator lay nothing, since the panel has no datum to read.

iex> design = %{styles: %{series: %{stroke: "#111", stroke_width: 2}}}
iex> Visualize.Chart.Builder.StyleStack.resolved(design, [:series, %{stroke: %{width: 5}}], Visualize.Theme.default())
%{stroke: %{type: :solid, color: "#111", width: 5}}