Skip to main content

Hierarchical Layout

The Hierarchical layout positions vertices in a hierarchy, oriented either vertically or horizontally. The classic use cases for this layout are such things as a family tree or an org chart.

caution

As of version 6.1.0 this layout is deprecated. The Hierarchy layout now offers all of the functionality this layout offers and more. In 7.x versions of the Toolkit this layout will no longer be available.

Hierarchical layout

Note This layout does not, by default, refresh when edges are added/removed, for performance reasons (as it has to visit the entire dataset). You can set refreshLayoutOnEdgeConnect on a render call to get the layout to refresh when edges are added/removed:

var surface = toolkit.render(someElement, {
layout:{
type:"Hierarchical",
options:{

}
},
refreshLayoutOnEdgeConnect:true
});

Parameters

Home > @jsplumbtoolkit/browser-ui > HierarchicalLayoutParameters

HierarchicalLayoutParameters interface

Warning: This API is now obsolete.

From 6.1.0 use the Hierarchy layout instead

Parameters for the Hierarchical Layout.

Signature:

export interface HierarchicalLayoutParameters extends AbstractHierarchicalLayoutParameters<Vertex> 

Extends: AbstractHierarchicalLayoutParameters<Vertex>

Properties

PropertyModifiersTypeDescription
align?HierarchicalLayoutAlignment(Optional) Optional, defaults to "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 hierarchical 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 orientation:"vertical"
invert?boolean(Optional) Optional, defaults to false. If true, the layout will be inverted, ie. the root node will be at the bottom for horizontal layouts, and to the right for vertical layouts
orientation?HierarchicalLayoutOrientation(Optional) Optional, defaults to "vertical". Valid values are "vertical" and "horizontal".
spacing?HierarchicalLayoutSpacing(Optional) Optional, defaults to "auto". Valid values are: "auto" (Spacing.auto) Spaces each node and its parent according to the size of the biggest node in the given node's level. "compress" (Spacing.compress) Uses a regular spacing between each node and its parent

Home > @jsplumbtoolkit/browser-ui > AbstractHierarchicalLayoutParameters

AbstractHierarchicalLayoutParameters interface

Signature:

export interface AbstractHierarchicalLayoutParameters<T extends HasId> extends AbsoluteBackedLayoutParameters 

Extends: AbsoluteBackedLayoutParameters

Properties

PropertyModifiersTypeDescription
getChildVertices?HierarchicalLayoutChildVerticesFunction<T>(Optional) Optional function used to determine the edges to traverse to find children from some node
getRootNode?(toolkit: JsPlumbToolkit) => Array<Vertex>(Optional) Optional. A function that is given the Toolkit instance as argument and is expected to return either a single node/group, or an array of nodes/groups, to use as the root(s) for the layout
ignoreLoops?boolean(Optional) Defaults to true. If a loop is found during the layout it is usually ignored, unless this is set to true.
ignorePorts?boolean(Optional) Defaults to false, meaning that ports are taken into account when figuring the list of edges from some vertex. If you set this to true, ports will be ignored and the layout will only consider edges connected directly to each vertex.
multipleRoots?boolean(Optional) Optional, defaults to true. If false, multiple roots are not supported, and assuming you have not overridden getRootNode, the layout uses the first node found in the dataset (otherwise it still uses the result of your getRootNode function)
rootNode?Array<Vertex>(Optional) Optional. Defines the node/group to use as the root of the tree. This may be provided either as a node/group id or as a node/group object. If this parameter is not specified and multipleRoots is not false then the layout uses the result(s) of the getRootNode function; otherwise it uses the first node/group found in the dataset.

Home > @jsplumbtoolkit/browser-ui > AbsoluteBackedLayoutParameters

AbsoluteBackedLayoutParameters interface

Parameters for a layout that extends AbsoluteBackedLayout

Signature:

export interface AbsoluteBackedLayoutParameters extends LayoutParameters 

Extends: LayoutParameters

Properties

PropertyModifiersTypeDescription
absoluteBacked?boolean(Optional) Defaults to false. If true, then the layout will use any position values found in the data for a given vertex.

Home > @jsplumbtoolkit/browser-ui > LayoutParameters

LayoutParameters interface

Base interface for layout parameters. All layout parameter interfaces extend this.

Signature:

export interface LayoutParameters extends Record<string, any> 

Extends: Record<string, any>

Properties

PropertyModifiersTypeDescription
height?number(Optional) Optional fixed height for the layout.
locationFunction?LocationFunction(Optional) Optional function that, given some vertex, can provide the x/y location of the vertex on the canvas
padding?PointXY(Optional) Optional padding to put around the elements.
width?number(Optional) Optional fixed width for the layout.

The layout at the top of this page shows the horizontal. Here we show the same dataset in the vertical orientation:

Hierarchical layout with `orientation:vertical`
Hierarchical layout with align:start
Hierarchical layout with align:start
Hierarchical layout with align:end
Hierarchical layout

Determining children of a vertex

The getChildEdges function, which is an optional parameter on the Hierarchical layout, forms the core of how the Hierarchical layout traverses the dataset. It is defined as:

getChildEdges = function(vertex:Vertex, toolkit:JsPlumbToolkit):Array<Edge>;

Its purpose is to return a list of Edge objects for the given node/group, where the edges define the connections from this node/group to what should be considered its children. The default implementation of this is:

function(vertex:Vertex, toolkit:JsPlumbToolkit) {
return toolkit.getAllEdgesFor(vertex, (e:Edge) => {
const target = isPort(e.target) ? e.target.getParent() : e.target
return ( e.source === vertex || (this._ignorePorts !== true && isPort(e.source) && e.source.getParent() === vertex) ) &&
this.adapter.filter(target)
})
}

Which basically says, get all the edges for which this node/group (or port, if connecting via ports is enabled) is the source.

Custom implementations of this function can, for example, test the type of edges, to exclude certain types from determining the structure of the hierarchy:

function(vertex:Vertex, toolkit:JsPlumbToolkit) {
return toolkit.getAllEdgesFor(vertex, function(e) {
return e.data.type !== "FLOATING" && e.source === vertex || (this._ignorePorts !== true && isPort(e.source) && e.source.getParent() === vertex)
});
}

Here we test each edge to see if it is of type FLOATING, and if so, we do not return it. The result would be that the hierarchical layout would be determined by the other edges; any edges of this type would still be drawn, of course. They would simply be painted to/from wherever in the hierarchy the two end nodes/groups were located.


Determining the root node(s)

In the Hierarchical layout there are always one or more "root" vertices, which are vertices that are to be placed at the root of the hierarchy. The Hierarchical layout uses the optional getRootNode function to determine the root node/group (s), the default implementation of which is as follows:

function(toolkit:JsPlumbToolkit) {
if (params.options.multipleRoots !== false) {
return toolkit.filter((o:any) => {
if (isNodeVertex(o)) {
const targetEdges = o.getTargetEdges()
// a node/group can be root if it has no target edges, or if it has only loopback edges, and it is not excluded by the filter.
return (targetEdges.length === 0 || _allTargetEdgesLoopback(targetEdges, o)) && this.adapter.filter(o)
} else {
return false
}
}).getAll()
}
else {
return this._vertices.length > 0 ? [ this._vertices[0] ]: null
}
}

When multipleRoots is enabled (which it is by default) then this function searches for all nodes/groups that are not targets of any edges. When multipleRoots is set to false, the function returns the first node in the dataset. You should keep this default behaviour in mind when using this layout - be sure that the first node in your dataset is your root (or provide your own getRootNode function).


Padding between elements

You can control the amount of whitespace between elements via the padding parameter. In the demonstration below we use a value of 150 pixels for both axes:

layout:{
type:"Hierarchical",
options:{
padding:{
x:150, y:150
}
}
}
Element padding

Compare the above with the default value of 60 pixels:

Default element padding

Note that the node elements are not smaller in the first of these two previous examples - the surface has been told to automatically adjust its zoom level to fit all the content in the viewport.


Examples

Simple Example

Here we tell the Surface what the ID of the node to use as the root is, and we specify some padding and a horizontal orientation.

toolkit.render(someElement, {
layout:{
type:"Hierarchical",
options:{
rootNode:"rootNodeId",
padding:[ 50, 50 ],
orientation:"horizontal"
}
}
});

Edge Filter example

Taken from the discussion above: only edges that are not of type FLOATING will determine the structure of the hierarchy.

toolkit.render(someElement, {
layout:{
type:"Hierarchical",
options:{
getChildEdges:(v:Vertex, toolkit:JsPlumbToolkit) => {
return toolkit.getAllEdgesFor(vertex, (e:Edge) => {
return e.data.type !== "FLOATING" && e.source === nodeOrGroup || (params.ignorePorts !== true && isPort(e.source) && e.source.getParent() === vertex)
})
}
}
}
})

Root Nodes example

Return all Node vertices whose type is ROOT to use as the roots of the hierarchy.

toolkit.render(someElement, {
layout:{
type:"Hierarchical",
options:{
getRootNodes:(toolkit:JsPlumbToolkit) => {
return toolkit.filter((o:Base) => {
return (isNode(o) && o.type === "ROOT")
}).getAll()
}
}
}
})