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
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
@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
@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)
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"}
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.
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.
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)
@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}}, []}
@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.
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.
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([[]])
@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.
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.
@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.
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.
@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)