default_input : Input
A single node with no children. Replace by record update.
:= []
Tree layouts for input already known to be a hierarchy. Two readings of
the same input: the level-by-level one (the default layout), and the
radial one (layout_radial), which puts the root at the center and each
generation on its own ring. A caller with a hierarchy provides it
directly as a Spec, the root node of the tree; every other node is a
descendant.
layout is the usual entry point. For repeated layouts of unchanged
input, call prepare once and pass the result to layout_prepared.
default_input : Input
A single node with no children. Replace by record update.
default_settings : Settings
Settings that produce a readable top-to-bottom tree in common cases.
default_radial_settings : RadialSettings
Radial settings that produce a readable drawing in common cases: the first subtree starts at twelve o'clock and siblings follow clockwise.
Check the input and settings, then cache the layout it determines.
layout_prepared : Prepared -> Result
Return the previously computed layout. This operation cannot fail.
Check and lay out input in one call. This is the usual entry point.
prepare_radial : Input, RadialSettings -> [Ok(RadialPrepared), Err(List(Problem))]
Check the input and radial settings, then cache the layout they determine.
layout_radial_prepared : RadialPrepared -> Result
Return the previously computed radial layout. This operation cannot fail.
layout_radial : Input, RadialSettings -> [Ok(Result), Err(List(Problem))]
Check and lay out input in one call, read radially: the root at the center, each generation on its own ring, subtrees in nested wedges in sibling order.
:= { width : F64, height : F64, children : List(Spec) }
A hierarchy given as one: the spec is its own root node, and every value of this type is a tree by construction — there is no separate "is it a tree" check. Nodes are numbered in depth-first order (this root is 0), and every other output list aligns to that order.
Input : Spec
Tidy input for the current exemplar: the root of the hierarchy.
Settings : { sibling_gap : F64, subtree_gap : F64, level_gap : F64, direction : [Down, Up, Left, Right] }
Space between adjacent siblings, between adjacent subtrees that do not share a parent, and between levels; the axis the tree grows along.
RadialSettings : {
sibling_gap : F64,
subtree_gap : F64,
ring_gap : F64,
start_angle : F64,
winding : [Clockwise, CounterClockwise],
}
Spacing for the radial reading. sibling_gap and subtree_gap keep
the same meaning as in Settings and set each node's share of its
ring; ring_gap separates consecutive rings; start_angle (radians)
is where the first subtree begins, with Clockwise or
CounterClockwise deciding which way around the rings siblings
follow.
Problem : [
InvalidWidth(U64),
InvalidHeight(U64),
InvalidSiblingGap,
InvalidSubtreeGap,
InvalidLevelGap,
InvalidRingGap,
InvalidStartAngle,
]
Invalid sizes or settings found while checking input, indexed by each node's depth-first position.
Result : {
layout : {
positions : List({ x : F64, y : F64 }),
bounds : { x : F64, y : F64, width : F64, height : F64 },
routes : List(Route),
},
depths : List(U64),
}
Geometry plus each node's depth, both in depth-first order.
positions are node centers; route endpoints lie on the connected
nodes' bounding rectangles (a zero-size node's endpoint is its
center), so an arrowhead drawn at a route's end lands on the box.