Visualize.IR.Element (Visualize v0.2.35)

Copy Markdown View Source

Backend-agnostic element representation for building scene graphs.

Elements represent visual primitives that can be rendered by any backend. The structure separates concerns:

  • type: The kind of element (:path, :rect, :circle, etc.)
  • attrs: Geometric attributes (x, y, width, height, cx, cy, r, etc.)
  • style: Visual styling (fill, stroke, opacity, etc.)
  • transform: Transformation to apply
  • children: Child elements (for groups)
  • content: Text content (for text elements)
  • path: Path IR (for path elements)

Examples

iex> alias Visualize.IR.{Element, Path}
iex> path = Path.new() |> Path.move_to(0, 0) |> Path.line_to(100, 100)
iex> element = Element.path(path, %{stroke: "blue", fill: :none})
iex> element.type
:path
iex> element.style
%{stroke: "blue", fill: :none}
iex> element.path
%Visualize.IR.Path{commands: [{:M, 0, 0}, {:L, 100, 100}]}

Summary

Types

Where an element is drawn (spec/02 §2.1): only where the shape is, or only where it is not — how a stroke is kept inside or outside an edge (spec/14 §5.6).

t()

Functions

Appends a child element.

Creates a circle element.

The element drawn only where shape is (:inside) or only where it is not (:outside) (spec/02 §2.1). The shape's style is ignored by every backend.

Creates a clip path element.

Writes a datum's fields onto the element as the data attributes TooltipHook reads (spec/10 §12.2, D-75).

Creates a defs element (for gradients, patterns, etc.).

Creates a desc element: the accessible description of its parent.

A drop shadow primitive of the offset and the blur radius, at 0.35 opacity.

Creates an ellipse element.

A filter (spec/02 §2.1): its id and its primitives, for an element's effect.

A Gaussian blur primitive of the radius.

Creates a group element.

Creates a line element.

Creates a linear gradient element.

Creates a new element of the specified type.

Creates a path element from a Path IR.

Creates a polygon element. Points should be a list of {x, y} tuples.

Creates a polyline element. Points should be a list of {x, y} tuples.

Prepends a child element.

The element with one attribute set: key — an atom, or a string for an attribute the IR has no name for, such as a data- attribute — to value.

Creates a radial gradient element.

Creates a rectangle element.

Creates a root SVG element, role="img".

Sets attributes on an element, merging with existing attrs.

Sets the text content of an element.

Sets style properties on an element, merging with existing style.

Sets the transform on an element.

Creates a gradient stop element.

Creates a text element with dx/dy offsets (useful for tick labels).

Creates a text element.

Creates a title element: the accessible name of the element it is the first child of.

Adds a translation transform.

Wraps element(s) in a group with a translation transform.

One line of a :text (spec/02 §2.1): a :tspan with its content and attrs, x and dy among them. A :text whose children are tspans and whose content is nil is a text of several lines (spec/14 §7.1).

Types

clip()

@type clip() :: %{shape: t(), keep: :inside | :outside}

Where an element is drawn (spec/02 §2.1): only where the shape is, or only where it is not — how a stroke is kept inside or outside an edge (spec/14 §5.6).

element_type()

@type element_type() ::
  :path
  | :rect
  | :circle
  | :ellipse
  | :line
  | :polyline
  | :polygon
  | :text
  | :group
  | :image
  | :defs
  | :clip_path
  | :linear_gradient
  | :radial_gradient
  | :stop
  | :filter
  | :fe_drop_shadow
  | :fe_gaussian_blur
  | :tspan
  | :root
  | :title
  | :desc

style()

@type style() :: %{
  optional(:fill) => String.t() | :none | :current_color,
  optional(:stroke) => String.t() | :none | :current_color,
  optional(:stroke_width) => number(),
  optional(:stroke_linecap) => :butt | :round | :square,
  optional(:stroke_linejoin) => :miter | :round | :bevel,
  optional(:stroke_dasharray) => String.t(),
  optional(:opacity) => number(),
  optional(:fill_opacity) => number(),
  optional(:stroke_opacity) => number(),
  optional(:font_size) => number() | String.t(),
  optional(:font_family) => String.t(),
  optional(:font_weight) => String.t() | number() | :normal | :bold,
  optional(:font_style) => :normal | :italic,
  optional(:text_anchor) => :start | :middle | :end,
  optional(:dominant_baseline) => atom(),
  optional(:class) => String.t(),
  optional(:line_height) => number(),
  optional(:blend) => atom(),
  optional(:effect) => :none | :shadow | :blur,
  optional(:effect_radius) => number()
}

t()

@type t() :: %Visualize.IR.Element{
  attrs: map(),
  children: [t()],
  clip: clip() | nil,
  content: String.t() | nil,
  path: Visualize.IR.Path.t() | nil,
  style: style(),
  transform: Visualize.IR.Transform.t() | nil,
  type: element_type()
}

Functions

append(parent, child)

@spec append(t(), t() | [t()]) :: t()

Appends a child element.

circle(cx, cy, r, style \\ %{})

@spec circle(number(), number(), number(), style()) :: t()

Creates a circle element.

clip(element, shape, keep)

@spec clip(t(), t(), :inside | :outside) :: t()

The element drawn only where shape is (:inside) or only where it is not (:outside) (spec/02 §2.1). The shape's style is ignored by every backend.

iex> square = Visualize.IR.Element.rect(0, 0, 10, 10)
iex> Visualize.IR.Element.clip(square, square, :inside).clip.keep
:inside

clip_path(id, children)

@spec clip_path(String.t(), [t()]) :: t()

Creates a clip path element.

datum(element, fields)

@spec datum(t(), map() | keyword()) :: t()

Writes a datum's fields onto the element as the data attributes TooltipHook reads (spec/10 §12.2, D-75).

fields is a map — written in Enum.sort/1 order — or a keyword list, in its order. data-datum lists the field names; data-datum-<field> carries to_string/1 of each value, with every _ in the name as -, and a nil value writes no attribute. The keys are strings, so no atom is created from a row's names.

Examples

iex> Visualize.IR.Element.circle(1, 2, 3)
...> |> Visualize.IR.Element.datum(at: ~U[2024-01-01 00:00:00Z], big_v: 4, gap: nil)
...> |> Map.fetch!(:attrs)
%{
  "data-datum" => "at big_v gap",
  "data-datum-at" => "2024-01-01 00:00:00Z",
  "data-datum-big-v" => "4",
  cx: 1,
  cy: 2,
  r: 3
}

defs(children \\ [])

@spec defs([t()]) :: t()

Creates a defs element (for gradients, patterns, etc.).

desc(text)

@spec desc(String.t()) :: t()

Creates a desc element: the accessible description of its parent.

drop_shadow(dx, dy, radius)

@spec drop_shadow(number(), number(), number()) :: t()

A drop shadow primitive of the offset and the blur radius, at 0.35 opacity.

ellipse(cx, cy, rx, ry, style \\ %{})

@spec ellipse(number(), number(), number(), number(), style()) :: t()

Creates an ellipse element.

filter(id, children)

@spec filter(String.t(), [t()]) :: t()

A filter (spec/02 §2.1): its id and its primitives, for an element's effect.

gaussian_blur(radius)

@spec gaussian_blur(number()) :: t()

A Gaussian blur primitive of the radius.

group(children \\ [], opts \\ [])

@spec group([t()], keyword()) :: t()

Creates a group element.

image(href, x, y, width, height, style \\ %{})

@spec image(String.t(), number(), number(), number(), number(), style()) :: t()

Creates an image element.

line(x1, y1, x2, y2, style \\ %{})

@spec line(number(), number(), number(), number(), style()) :: t()

Creates a line element.

linear_gradient(id, opts \\ [])

@spec linear_gradient(String.t(), keyword()) :: t()

Creates a linear gradient element.

new(type, opts \\ [])

@spec new(element_type(), keyword()) :: t()

Creates a new element of the specified type.

path(path_ir, style \\ %{})

@spec path(Visualize.IR.Path.t(), style()) :: t()

Creates a path element from a Path IR.

polygon(points, style \\ %{})

@spec polygon([{number(), number()}], style()) :: t()

Creates a polygon element. Points should be a list of {x, y} tuples.

polyline(points, style \\ %{})

@spec polyline([{number(), number()}], style()) :: t()

Creates a polyline element. Points should be a list of {x, y} tuples.

prepend(parent, child)

@spec prepend(t(), t() | [t()]) :: t()

Prepends a child element.

put_attr(element, key, value)

@spec put_attr(t(), atom() | String.t(), term()) :: t()

The element with one attribute set: key — an atom, or a string for an attribute the IR has no name for, such as a data- attribute — to value.

iex> Visualize.IR.Element.group([]) |> Visualize.IR.Element.put_attr("data-node", "marks[0]") |> Map.fetch!(:attrs)
%{"data-node" => "marks[0]"}

radial_gradient(id, opts \\ [])

@spec radial_gradient(String.t(), keyword()) :: t()

Creates a radial gradient element.

rect(x, y, width, height, style \\ %{})

@spec rect(number(), number(), number(), number(), style()) :: t()

Creates a rectangle element.

root(width, height, opts \\ [])

@spec root(number(), number(), keyword()) :: t()

Creates a root SVG element, role="img".

Options

  • :view_box - the viewBox (default "0 0 <width> <height>")
  • :children - the child elements (default [])
  • :preserve_aspect_ratio - the preserveAspectRatio attribute; absent by default
  • :responsive - when true, preserveAspectRatio="xMidYMid meet" (unless given) and style="width:100%;height:auto", so the <svg> fills its container's width at the drawing's aspect ratio while width and height stay its intrinsic size (D-54)
  • :title, :description - the accessible name and description (D-56): a <title> and a <desc> become the first children, each with an id, and aria-labelledby names them
  • :id - the root's id and the prefix of the two child ids (<id>-title, <id>-desc); defaults to vis- and a hash of the two texts, and is only set when a title or description is given

set_attrs(element, new_attrs)

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

Sets attributes on an element, merging with existing attrs.

set_content(element, content)

@spec set_content(t(), String.t()) :: t()

Sets the text content of an element.

set_style(element, new_style)

@spec set_style(t(), style()) :: t()

Sets style properties on an element, merging with existing style.

set_transform(element, transform)

@spec set_transform(t(), Visualize.IR.Transform.t()) :: t()

Sets the transform on an element.

stop(offset, color, opts \\ [])

@spec stop(String.t(), String.t(), keyword()) :: t()

Creates a gradient stop element.

text(content, opts)

@spec text(String.t(), keyword()) :: t()

Creates a text element with dx/dy offsets (useful for tick labels).

text(content, x, y, style \\ %{})

@spec text(String.t(), number(), number(), style()) :: t()

Creates a text element.

title(text)

@spec title(String.t()) :: t()

Creates a title element: the accessible name of the element it is the first child of.

translate(element, x, y)

@spec translate(t(), number(), number()) :: t()

Adds a translation transform.

translate_group(elements, x, y)

@spec translate_group(t() | [t()], number(), number()) :: t()

Wraps element(s) in a group with a translation transform.

tspan(content, attrs)

@spec tspan(String.t(), map()) :: t()

One line of a :text (spec/02 §2.1): a :tspan with its content and attrs, x and dy among them. A :text whose children are tspans and whose content is nil is a text of several lines (spec/14 §7.1).