Hierarchy Layout
The Hierarchy layout positions vertices in a hierarchy, oriented either vertically or horizontally, following a slightly modified version of the 'Sugiyama' method.
import { newInstance,
HierarchyLayout } from "@jsplumbtoolkit/browser-ui"
const toolkit = newInstance()
const surface = toolkit.render(someElement, {
"layout": {
"type": HierarchyLayout.type
}
});
Parameters
Interface HierarchyLayoutParameters
Name | Type | Description |
---|---|---|
absoluteBacked? | boolean | Defaults to false. If true, then the layout will use any position values found in the data for a given vertex. |
alignment? | Optional, defaults to HierarchyLayoutAlignmentValues.center . Instructs the layout how to place child nodes with
respect to their parent nodes. By default, a group of child nodes is centered on its parent. The layout also supports "start" and "end" for
this value, which work in much the same way as "flex-start" and "flex-end" do in CSS: for a layout
with the root at the top of the tree and the child nodes underneath, a value of "start" for align would cause the
first child of the root to be placed immediately under the root, with its first child immediately underneath, etc.
The remainder of the content would fan out to the right. This option also works in conjunction with invert and
axis:HierarchyLayoutAxisValues.vertical. | |
axis? | Either horizontal (the default, groups of child vertices are laid out in rows) or vertical (groups of child vertices are
laid out in columns) | |
edgeFilter? | Optional filter for edges. If provided, this function will be used to filter the edges that identify links between vertices. All filtered edges are gathered | |
gatherUnattachedRoots? | boolean | If true root nodes that do not have children will be positioned adjacent to the last root node that does have children. When false (which is the default), unattached roots are spaced apart so that they do not overlap any child trees. |
generateRouting? | boolean | Defaults to false. If true, the layout generates routing information for the channels between layers and edge nodes, and for edge routing. |
getRootNode? | Optional function you can provide that will dynamically be invoked to get the root node to use. | |
height? | number | Optional fixed height for the layout. |
invert? | boolean | If true, the layout will be inverted in its perpendicular axis. For instance, if axis is "horizontal" and invert is
true, the root nodes of the layout will be placed at the bottom of the layout, and their children will be placed above them. |
locationFunction? | LocationFunction | Optional function that, given some vertex, can provide the x/y location of the vertex on the canvas |
maxIterations? | number | Maximum number of iterations to run. Defaults to 24. |
maxIterationsWithoutImprovement? | number | Number of iterations to try rearranging the graph without an improvement in legibility before accepting the current state. Defaults to 2. |
padding? | PointXY | Optional padding to put around the elements. |
placementStrategy? | The strategy to use when placing vertices. Default is 'center', meaning every row is centered around the axis orthogonal to the axis in which the vertices are laid out. | |
respectEdgeDirection? | boolean | If true, the layout will take into account 'directed' edges, and attempt to place the source of any given edge in a higher layer than the edge's target. This flag also has the effect of positioning any nodes that act only as the source of one or more edges on the root layer of the layout. It isn't always possible to place the source of some edge in a higher layer than the edge's target, due to the graph's topology, but this flag will ensure the layout makes every effort to do so. |
rootNode? | any | Optional node to use as the root. If this is not provided the layout calculates the best candidate based upon incoming and outgoing edges for each vertex. |
width? | number | Optional fixed width for the layout. |
Orientation
The layout at the top of this page shows the horizontal
. Here we show the same dataset in the vertical
orientation:
import { newInstance,
HierarchyLayout } from "@jsplumbtoolkit/browser-ui"
const toolkit = newInstance()
const surface = toolkit.render(someElement, {
"layout": {
"type": HierarchyLayout.type,
"options": {
"axis": "vertical"
}
}
});
Placement Strategy
You can use a few different "placement strategies" with the Hierarchy layout. By default, the child elements of some parent are positioned with respect to the center of their parent element (you can see this in the layouts above). This behaviour corresponds to a placementStrategy
of parent
.
You can, instead, instruct the layout to position elements with respect to the layout's main axis, should you wish to, using a placementStrategy
of center
, start
or end
.
Here we see placementStrategy:'center'
in operation - each layer is positioned such that its center point lies on the main axis of the layout:
Hierarchy layout with placementStrategy:center
In the next two examples we use start
and end
. Note how these roughly correlate to the way flex-start
and flex-end
function in a flex layout.
Hierarchy layout with placementStrategy:start
Hierarchy layout with placementStrategy:end
Alignment
A separate, but related, concept to the placementStrategy
is that of alignment
, which instructs the layout how to place child elements with respect to their parent element, and is only used when placementStrategy
is set to parent
. Here's the first layout from above, but with alignment:'start'
set:
import { newInstance,
HierarchyLayout } from "@jsplumbtoolkit/browser-ui"
const toolkit = newInstance()
const surface = toolkit.render(someElement, {
"layout": {
"type": HierarchyLayout.type,
"options": {
"alignment": "start"
}
}
});
Determining the root node(s)
In the Hierarchy layout there are always one or more "root" vertices, which are vertices that are to be placed at the root of the hierarchy. The layout calculates these by looking for vertices that are not the target of any edges. If it finds none, an arbitrary vertex will be used as the initial root. From each root, edges are followed and connected vertices are placed, until there are no more edges to follow. There may be more than one root in a given dataset.
You can specify a root node by setting it as the rootNode
:
import { newInstance,
HierarchyLayout } from "@jsplumbtoolkit/browser-ui"
const toolkit = newInstance()
const surface = toolkit.render(someElement, {
"layout": {
"type": HierarchyLayout.type,
"options": {
"rootNode": rootNode,
"axis": "horizontal"
}
}
});
Note that we said "a" root node, and not "the" root node, as after placing every node connected to your nominated root, the layout will continue to place other root nodes that it has found.
Edge routing
From version 6.9.0 onwards, the Hierarchy layout can generate routing information for edges, via the generateRouting
flag:
This is the first step towards general support for edge routing in JsPlumb, and we're very interested in hearing any feedback you may have on what we have so far and what direction to take this in (particularly if you are a licensee!).
To setup edge routing you need 3 things:
-
You must be using a
Hierarchy
layout and you need to havegenerateRouting:true
in the layout options: -
You must be using the Straight connector type. This is actually now the default connector type used by JsPlumb so if you haven't specifically set a connector anywhere you'll be using this.
-
You must not be using Continuous or Dynamic anchors. Neither of these anchor types allow anchor locations to be overridden at the point level. As with the note about connectors above, if you have not specifically set an anchor type you'll be using the default, in this case a static anchor, whose location can be overridden.
-
You need to enable the edgeRouting plugin
import { newInstance,
HierarchyLayout,
EdgeRoutingPlugin } from "@jsplumbtoolkit/browser-ui"
const toolkit = newInstance()
const surface = toolkit.render(someElement, {
"plugins": [
{
"type": EdgeRoutingPlugin.type
}
]
});
A deeper discussion of edge routing can be on the edge routing plugin page, but to whet your appetite, here's the Hierarchy layout configured to use orthogonal routing: