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.

NOTE: this layout is delivered in its own package - @jsplumbtoolkit/layout-hierarchical.

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/layout-hierarchical > HierarchicalLayoutParameters

HierarchicalLayoutParameters interface#

Parameters for the Hierarchical Layout.

Signature:

export interface HierarchicalLayoutParameters extends AbstractHierarchicalLayoutParameters 

Extends: AbstractHierarchicalLayoutParameters

Properties#

PropertyTypeDescription
align?string(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?"compress" | "auto"(Optional) Optional, defaults to "auto". Valid values are: "auto" Spaces each node and its parent according to the size of the biggest node in the given node's level "compress" Uses a regular spacing between each node and its parent

Home > @jsplumbtoolkit/layout-hierarchical > AbstractHierarchicalLayoutParameters

AbstractHierarchicalLayoutParameters interface#

Parameters for layouts that extends AbstractHierarchicalLayout.

Signature:

export interface AbstractHierarchicalLayoutParameters extends AbsoluteBackedLayoutParameters 

Extends: AbsoluteBackedLayoutParameters

Properties#

PropertyTypeDescription
getChildEdges?(node: Vertex, toolkit: JsPlumbToolkit) => Array<Edge>(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.

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).


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()      }    }  }})