The colours, font and sizes a chart draws with (spec/08 §7).
A theme is a struct of named slots: :series_1 … :series_n for the categorical
colours, :axis, :grid, :text, :background and :surface — the plane the data is laid
on, between the background and the grid — and :font_family, :font_size,
:label_size and :title_size. Nothing in the library carries a colour literal;
every axis, mark and component reads its values through resolve/3, in the mode its
render target needs:
:literal- the stored value, which a canvas needs:css- a custom-property reference with the literal as its fallback,var(--vis-axis, #666666), which the SVG output carries so a stylesheet can override it from any ancestor (D-55)
stylesheet/1 writes a .vis-theme-<name> rule declaring every slot, so a consumer
switches every chart under an element of that class without touching Elixir.
Examples
iex> Visualize.Theme.resolve(Visualize.Theme.default(), :axis, :css)
"var(--vis-axis, #666666)"
iex> Visualize.Theme.resolve(Visualize.Theme.dark(), {:series, 11}, :literal)
"#7fb3e6"
iex> Visualize.Theme.new(font_family: "Inter, sans-serif").font_family
"Inter, sans-serif"
Summary
Types
How a slot renders: a CSS reference with fallback, or the stored value.
A slot name, or {:series, i} for the i-th series colour, cycling.
Functions
The theme's colour slots — the series, then axis, grid, text, background and surface (spec/08 §7.1).
The custom-property name of a slot atom: --vis- and the slot with _ as -.
The dark theme: light text and axes on #1b1e24 (spec/08 §7.2).
The light theme: dark text and axes on white (spec/08 §7.2).
The contrast ink for a text drawn on under (spec/08 §7.3, D-123): the literal of the
theme's text or background, whichever has the higher WCAG contrast ratio against it —
text on a tie — or #000000/#ffffff, whichever contrasts more, when neither slot
reaches 4.5:1. One of black and white always does, so the ink always meets WCAG AA.
The theme with the given fields replaced; the checks of new/1 apply.
The mode a backend needs: :css for Visualize.Backend.SVG, :literal for any other.
default/0 with the given fields replaced.
The slot's value: the stored literal, or a CSS custom-property reference that falls back to it (spec/08 §7.3).
The :series_k slot the positive index i cycles to over the theme's series.
The theme's slot names: :series_1 to :series_n, then the fixed slots.
The .vis-theme-<name> CSS rule declaring every slot of the theme, one line each.
Types
@type mode() :: :css | :literal
How a slot renders: a CSS reference with fallback, or the stored value.
@type slot() :: atom() | {:series, pos_integer()}
A slot name, or {:series, i} for the i-th series colour, cycling.
Functions
The theme's colour slots — the series, then axis, grid, text, background and surface (spec/08 §7.1).
The custom-property name of a slot atom: --vis- and the slot with _ as -.
@spec dark() :: t()
The dark theme: light text and axes on #1b1e24 (spec/08 §7.2).
@spec default() :: t()
The light theme: dark text and axes on white (spec/08 §7.2).
@spec ink(t(), String.t() | Visualize.Color.t() | nil) :: String.t()
The contrast ink for a text drawn on under (spec/08 §7.3, D-123): the literal of the
theme's text or background, whichever has the higher WCAG contrast ratio against it —
text on a tie — or #000000/#ffffff, whichever contrasts more, when neither slot
reaches 4.5:1. One of black and white always does, so the ink always meets WCAG AA.
under is a colour string Visualize.Color.parse/1 reads, a %Visualize.Color{}, or
nil for nothing under the text — the theme's own background. An unreadable string is
nil, and a slot whose own value does not parse is skipped.
iex> theme = Visualize.Theme.default()
iex> Visualize.Theme.ink(theme, "#3b6fa8")
"#ffffff"
iex> Visualize.Theme.ink(theme, "#ffd098")
"#333333"
iex> Visualize.Theme.ink(theme, nil)
"#333333"
iex> Visualize.Theme.ink(theme, "#777777")
"#000000"
The theme with the given fields replaced; the checks of new/1 apply.
The mode a backend needs: :css for Visualize.Backend.SVG, :literal for any other.
Takes what Visualize.Backend.resolve/1 takes: a module, :svg, :canvas or nil.
default/0 with the given fields replaced.
An unknown field raises KeyError; an empty series raises ArgumentError.
The slot's value: the stored literal, or a CSS custom-property reference that falls back to it (spec/08 §7.3).
Sizes are numbers under :literal and gain px under :css.
@spec series_slot(t(), pos_integer()) :: atom()
The :series_k slot the positive index i cycles to over the theme's series.
The theme's slot names: :series_1 to :series_n, then the fixed slots.
The .vis-theme-<name> CSS rule declaring every slot of the theme, one line each.
Include it in a stylesheet and put class="vis-theme-<name>" on any ancestor of the
charts that should take the theme.