Visualize.IR.Motion (Visualize v0.8.0)

Copy Markdown View Source

What every backend writes of an element's motion (spec/02 §2.1, spec/14 §3.10, D-176).

An element's style may carry :transition, the list of {property, duration, easing} a style's transition part resolves to — property :fill, :stroke or :opacity, duration in milliseconds, easing a Visualize.Ease name — and the element the attribute "data-vis-id", the identity the motion is keyed by. SVG writes the motion as CSS (css_easing/1, css_properties/1, oklch/1), a canvas as a motion span the hooks run (span/3, json/1); both ease along the same samples of one curve (samples/1).

Examples

iex> Visualize.IR.Motion.css_easing(:linear)
"linear"
iex> Visualize.IR.Motion.samples(:quad_in) |> Enum.take(3)
[0, 0.0025, 0.01]
iex> Visualize.IR.Motion.css_properties(:stroke)
["stroke", "stroke-width", "stroke-opacity"]
iex> Visualize.IR.Motion.oklch("#ffffff")
"oklch(1 0 0)"
iex> Visualize.IR.Motion.oklch("var(--vis-red, #c23238)")
"oklch(from var(--vis-red, #c23238) l c h / alpha)"

Summary

Types

A property a transition moves.

A resolved transition: what moves, for how long, along which curve.

Functions

The CSS animation value of a resolved animation: the keyframes — vis-<name> for a built-in, a host's name as it is — the duration, the easing, the delay and the iterations.

The easing as CSS: linear, or linear() of samples/1.

A built-in's keyframes as CSS: @keyframes vis-<name> { … }, each offset a percentage, opacity as itself, x and y as translate, rotate and scale as the individual transform properties, which compose with an element's transform.

The CSS properties a property moves.

The CSS transition value of a resolved transition: each CSS property a property moves, its duration and its easing, joined by commas.

The text of data-vis-exit for element leaving with exit (spec/14 §3.12): the name, the duration, the samples, the element's box as drawn and a built-in's keyframes, as JSON.

A span's arguments as JSON text: lists, strings, numbers and nil, numbers formatted as path data is, every string escaped — the text the :json command and the binary record both carry (spec/09 §3.3.5, §4.3.15).

A built-in animation's keyframes (spec/14 §3.11): offsets from 0 to 1, each with the values there of :opacity, :x, :y (a translation in user units), :rotate (degrees, about the center of the element's box as drawn) and :scale.

A color as oklch(), so CSS interpolates it in OKLab (spec/14 §3.10): a literal Visualize.Color.parse/1 reads as its coordinates, an oklch(…) as it is, anything else — a theme's var(--vis-…, literal), a transform's color-mix(…) — as the relative color oklch(from <value> l c h / alpha). :none, :current_color, a paint and any value that is not a string pass through.

The easing's 21 values at t = 0, 0.05, …, 1, each rounded to 4 decimals; [0, 1] for :linear, which two points draw exactly.

The arguments of a motion span (spec/09 §3.3.5): [id, box, transitions] for an element that names its identity, drawn with style, its effective style — its own over what its groups give it. An element whose style moves nothing has a span too, with no transitions: a hook then knows what it shows when a later stream moves it.

The resolved transition as the canvas encoders write it: [[property, duration, samples], …].

Types

property()

@type property() :: :fill | :stroke | :opacity

A property a transition moves.

transition()

@type transition() :: [{property(), number(), atom()}]

A resolved transition: what moves, for how long, along which curve.

Functions

css_animation(a)

@spec css_animation(map()) :: String.t()

The CSS animation value of a resolved animation: the keyframes — vis-<name> for a built-in, a host's name as it is — the duration, the easing, the delay and the iterations.

iex> Visualize.IR.Motion.css_animation(%{name: :pulse, duration: 1200, easing: :linear, iterations: :infinite, delay: 0})
"vis-pulse 1200ms linear 0ms infinite"

css_easing(easing)

@spec css_easing(atom()) :: String.t()

The easing as CSS: linear, or linear() of samples/1.

css_keyframes(name)

@spec css_keyframes(atom() | {:enter, atom()}) :: String.t()

A built-in's keyframes as CSS: @keyframes vis-<name> { … }, each offset a percentage, opacity as itself, x and y as translate, rotate and scale as the individual transform properties, which compose with an element's transform.

iex> Visualize.IR.Motion.css_keyframes(:spin)
"@keyframes vis-spin { 0% { rotate: 0deg; } 100% { rotate: 360deg; } }"

css_properties(atom)

@spec css_properties(property()) :: [String.t()]

The CSS properties a property moves.

css_transition(transition)

@spec css_transition(transition()) :: String.t()

The CSS transition value of a resolved transition: each CSS property a property moves, its duration and its easing, joined by commas.

exit_attribute(exit, element)

@spec exit_attribute(map(), Visualize.IR.Element.t()) :: String.t()

The text of data-vis-exit for element leaving with exit (spec/14 §3.12): the name, the duration, the samples, the element's box as drawn and a built-in's keyframes, as JSON.

iex> exit = %{name: :fade, duration: 300, easing: :linear}
iex> Visualize.IR.Motion.exit_attribute(exit, Visualize.IR.Element.rect(0, 0, 4, 2))
~s(["fade",300,[0,1],[0,0,4,2],[[0,1,null,null,null,null],[1,0,null,null,null,null]]])

json(value)

@spec json(term()) :: String.t()

A span's arguments as JSON text: lists, strings, numbers and nil, numbers formatted as path data is, every string escaped — the text the :json command and the binary record both carry (spec/09 §3.3.5, §4.3.15).

keyframes(arg1)

@spec keyframes(atom()) :: [{number(), map()}]

A built-in animation's keyframes (spec/14 §3.11): offsets from 0 to 1, each with the values there of :opacity, :x, :y (a translation in user units), :rotate (degrees, about the center of the element's box as drawn) and :scale.

iex> Visualize.IR.Motion.keyframes(:pulse)
[{0, %{opacity: 1}}, {0.5, %{opacity: 0.35}}, {1, %{opacity: 1}}]

oklch(color)

@spec oklch(term()) :: term()

A color as oklch(), so CSS interpolates it in OKLab (spec/14 §3.10): a literal Visualize.Color.parse/1 reads as its coordinates, an oklch(…) as it is, anything else — a theme's var(--vis-…, literal), a transform's color-mix(…) — as the relative color oklch(from <value> l c h / alpha). :none, :current_color, a paint and any value that is not a string pass through.

samples(easing)

@spec samples(atom()) :: [number()]

The easing's 21 values at t = 0, 0.05, …, 1, each rounded to 4 decimals; [0, 1] for :linear, which two points draw exactly.

span(id, element, style)

@spec span(String.t(), Visualize.IR.Element.t(), map()) :: list()

The arguments of a motion span (spec/09 §3.3.5): [id, box, transitions] for an element that names its identity, drawn with style, its effective style — its own over what its groups give it. An element whose style moves nothing has a span too, with no transitions: a hook then knows what it shows when a later stream moves it.

transitions(transition)

@spec transitions(transition()) :: [list()]

The resolved transition as the canvas encoders write it: [[property, duration, samples], …].