Expresso.Element.Hierarchy (expresso v0.1.0)

Copy Markdown View Source

A tree: a hierarchy of nodes as boxes and lines, such as an org chart or the use of a disk

The tree entity holds one node entity, the root, and each node holds the nodes under it. The name of a node is its identity, and the default text of its box. The detail option of a node gives a second line, such as a role. A box can also show an image or an icon, and a line for each field.

The color of a box comes from the color option of the node or of the nearest node above it, then from the color option of the tree, which takes the colors of the palette for each branch or for each value of a field. colors/1 returns the color of each node.

Expresso.Element.Hierarchy.Layout places each box, and the drawing is one SVG with the viewBox of the layout, so it scales to the box of the element. The lines are paths in the SVG. Each box is a foreignObject that holds the HTML of the box, so its text ends with an ellipsis as HTML does. The SVG is hidden from a screen reader. A nested list with the same tree holds the text for a screen reader, and the eye does not see it.

The element module is Hierarchy, because Expresso.Element.Tree holds the functions that walk the elements of a slide. docs/tree.md gives the plan, and docs/reference/tree-element.md gives the rules for the author.

Summary

Types

t()

The struct of a tree

Functions

Make sure that a box option gives the size of each level

Return the item of the highlight option for a node and each node under it

Read the CSV file of a tree with src, and make its nodes

Make sure that a tree has one root, and that each node is a node of a tree

Make sure that a color option of a tree is :branch or a field

Return the color of each node, by its name, and the values of the legend

Return the color of each node and the values of a legend that holds the values of more than one tree, such as the frames of a tree

Make the assigns of the render function from the struct

Make sure that a highlight option is a list of groups

Change each node of each frame of a tree, and stop at the first error

Return the tree after the options of the values

Make the HTML of a tree

Return the rules of the moves and of the groups of a tree

Make sure that a stack_from option is a level under the root

Types

t()

@type t() :: %Expresso.Element.Hierarchy{
  __spark_metadata__: term(),
  at: term(),
  bar: term(),
  box: term(),
  class: term(),
  color: term(),
  delimiter: term(),
  depth: term(),
  dim: term(),
  easing: term(),
  effect: term(),
  el: term(),
  elements: term(),
  fields: term(),
  focus: term(),
  frames: term(),
  highlight: term(),
  layout: term(),
  limit: term(),
  morph: term(),
  on: term(),
  reflow: term(),
  reveal: term(),
  separator: term(),
  signature: term(),
  sort: term(),
  speed: term(),
  src: term(),
  stack_from: term(),
  steps: term(),
  sum: term(),
  timeline: term(),
  title: term(),
  value_format: term(),
  whole_first: term(),
  width: term()
}

The struct of a tree

Functions

box(size)

@spec box(term()) ::
  {:ok, [Expresso.Element.Hierarchy.Layout.size()]} | {:error, String.t()}

Make sure that a box option gives the size of each level

This function is the custom type of the option. The value is a list of sizes, one for each level from the root down, or one size for each level. A size is a keyword list with a positive integer for width and for height.

iex> Expresso.Element.Hierarchy.box(width: 200, height: 80)
{:ok, [%{width: 200, height: 80}]}

iex> Expresso.Element.Hierarchy.box([[width: 280, height: 120], [width: 220, height: 96]])
{:ok, [%{width: 280, height: 120}, %{width: 220, height: 96}]}

iex> {:error, _message} = Expresso.Element.Hierarchy.box(width: 0, height: 80)

branch(name)

@spec branch(String.t()) :: {:branch, String.t()}

Return the item of the highlight option for a node and each node under it

use Expresso imports this function, so a deck can write highlight ["Ben", branch("Ben")].

iex> Expresso.Element.Hierarchy.branch("Ben")
{:branch, "Ben"}

build(tree)

@spec build(t()) :: {:ok, t()} | {:error, String.t()}

Read the CSV file of a tree with src, and make its nodes

Expresso.PathTransformer calls this function after it joins the path to the root of the deck. Expresso.Element.Hierarchy.Data tells the two forms of a file. The function reads the file through Expresso.DeckFile, so the watch mode renders the deck again after a change to the file.

check(tree)

@spec check(t()) :: {:ok, t()} | {:error, String.t()}

Make sure that a tree has one root, and that each node is a node of a tree

Expresso.Extension calls this function when it builds the entity, so the DSL and Expresso.Builder give the same errors. A tree with src has no nodes yet, so the function checks only its options, and build/1 checks the tree after it reads the file. Nodes with the parent option become a nested tree first.

color(arg1)

@spec color(term()) :: {:ok, :branch | {:field, String.t()}} | {:error, String.t()}

Make sure that a color option of a tree is :branch or a field

This function is the custom type of the option. The name of a field can be an atom or a string, and the function returns it as a string.

iex> Expresso.Element.Hierarchy.color(:branch)
{:ok, :branch}

iex> Expresso.Element.Hierarchy.color({:field, :team})
{:ok, {:field, "team"}}

iex> {:error, _message} = Expresso.Element.Hierarchy.color(:leaf)

colors(tree)

@spec colors(t()) :: {%{required(String.t()) => color}, [{String.t(), pos_integer()}]}
when color: {:role, atom()} | {:palette, pos_integer()} | nil

Return the color of each node, by its name, and the values of the legend

A color is {:role, role} for the color option of a node or of a node above it, {:palette, n} for a color of the palette from 1 to 8, or nil. The legend holds each value of the field of color {:field, name} and its color of the palette, in the order of the first node with the value.

iex> alias Expresso.Element.{Hierarchy, Node}
iex> root = %Node{name: "A", elements: [%Node{name: "B", elements: [%Node{name: "C"}]}, %Node{name: "D", color: :danger}]}
iex> Hierarchy.colors(%Hierarchy{color: :branch, elements: [root]})
{%{"A" => nil, "B" => {:palette, 1}, "C" => {:palette, 1}, "D" => {:role, :danger}}, []}

colors(hierarchy, legend)

@spec colors(t(), [{String.t(), pos_integer()}]) ::
  {%{required(String.t()) => color}, [{String.t(), pos_integer()}]}
when color: {:role, atom()} | {:palette, pos_integer()} | nil

Return the color of each node and the values of a legend that holds the values of more than one tree, such as the frames of a tree

The colors of a field come from the legend, so a value has one color in each frame.

get_assigns(tree)

@spec get_assigns(t()) :: map()

Make the assigns of the render function from the struct

The key boxes holds each box with its overlay attributes and its cards, one card for each content of the box. The key lines holds the path and the attributes of each line. The key lists holds the root of each list for a screen reader, and the key copies holds the small trees of the handout view. A tree without frames has one card for each box, one list and no copy.

highlight(groups)

@spec highlight(term()) ::
  {:ok, [[String.t() | {:branch, String.t()}]]} | {:error, String.t()}

Make sure that a highlight option is a list of groups

This function is the custom type of the option. A group is the name of a node, {:branch, name}, or a list of those. The function returns each group as a list.

iex> Expresso.Element.Hierarchy.highlight(["Ben", {:branch, "Eve"}, ["Cy", "Di"]])
{:ok, [["Ben"], [{:branch, "Eve"}], ["Cy", "Di"]]}

iex> {:error, _message} = Expresso.Element.Hierarchy.highlight([[]])

map_frames(tree, fun)

@spec map_frames(t(), (map() -> {:ok, map()} | {:error, reason})) ::
  {:ok, t()} | {:error, reason}
when reason: term()

Change each node of each frame of a tree, and stop at the first error

Expresso.Element.Tree.map_ok/2 walks the key :elements only, so a transformer calls this function for the nodes of the frames.

prepared(tree)

@spec prepared(t()) :: t()

Return the tree after the options of the values

Expresso.Element.Hierarchy.Values.prepare/2 applies depth, sum, sort and limit to the root. The layout, the colors and the HTML read this tree, so each one shows the same nodes.

render(assigns)

@spec render(map()) :: Phoenix.HTML.safe()

Make the HTML of a tree

The figure holds the SVG of the drawing, which a screen reader does not read, and a nested list of the nodes, which the eye does not see. The legend is in the SVG under the tree, and each field of a node is in the list, so a screen reader reads the value that gives a color.

rules(tree)

@spec rules(t()) :: [String.t()]

Return the rules of the moves and of the groups of a tree

With frames, each box is at its place in the first frame that holds it. At each step of a later frame, a box at a different place gets the custom properties --tree-dx and --tree-dy, as with reflow.

With reflow, at each step, a box that is not in its place of the full layout gets the custom properties --tree-dx and --tree-dy, and the style sheet moves it with a transition.

A group of the highlight option gives one rule at its step. The rule sets --dimmed: 1 on each box and each line whose node is not in the group, so the line to a box in focus keeps its color. A branch holds the node and each node under it in the tree after the options of the values, also the node of the rest of a limit. A node that depth or limit removes has no box, so the rule leaves it out.

Expresso.Overlay.Render.style/1 adds the rules to the style block of the deck. A tree without reflow and without highlight has no rules.

stack_from(level)

@spec stack_from(term()) :: {:ok, pos_integer()} | {:error, String.t()}

Make sure that a stack_from option is a level under the root

This function is the custom type of the option. The root is level 1, and it has no node above it to stack under, so the first level is 2.

iex> Expresso.Element.Hierarchy.stack_from(3)
{:ok, 3}

iex> {:error, _message} = Expresso.Element.Hierarchy.stack_from(1)