Hierarchical Layout
Configure hierarchical layout by setting type: "hierarchical" in the enableLayout method of a CanvasBuilder instance.
const element = document.getElementById("canvas");
const canvas = new CanvasBuilder(element)
.enableLayout({
algorithm: {
type: "hierarchical",
},
})
.build();
Hierarchical layout supports optional configuration parameters:
const canvas = new CanvasBuilder(element)
.enableLayout({
algorithm: {
type: "hierarchical",
layerWidth: 300,
layerSpace: 300,
nextLayerNodesResolver: "outgoing",
transform: { mirror: Math.PI / 2 },
},
})
.build();
| Name | Type | Description | Required | Default |
|---|---|---|---|---|
layerWidth | number | Width of a single layer | No | 300 |
layerSpace | number | Minimum space between nodes within a single layer | No | 300 |
nextLayerNodesResolver | NextLayerNodesResolver | Determines which nodes move to the next layer during layout calculation | No | "adjacent" |
transform | Transformation | Transformation[] | undefined | Single transformation or array of transformations to apply to node positions | No | undefined |
NextLayerNodesResolver
Hierarchical layout algorithm uses breadth-first graph traversal to generate a graph spanning tree.
The nextLayerNodesResolver is a function that allows you to specify which nodes
should be candidates for placement in the next layer relative to the current node.
It receives a single argument object with the following properties:
graph- a Graph objectcurrentNodeId- the identifier of the current node in the layer
For example, here is a function that resolves only outgoing nodes:
const outgoingNextLayerNodesResolver = (params) => {
const { graph, currentNodeId } = params;
const outgoingNodeIds = graph
.getNodeOutgoingEdgeIds(currentNodeId)
.map((edgeId) => {
const edge = graph.getEdge(edgeId);
const port = graph.getPort(edge.to);
return port.nodeId;
});
return new Set(outgoingNodeIds);
};
You can pass a string value instead of a function if your use case matches one of these predefined options:
"outgoing"- resolves only outgoing nodes (nodes that receive connections from the current node)"incoming"- resolves only incoming nodes (nodes that connect to the current node)"adjacent"- resolves both outgoing and incoming nodes (default)
Transformation
The transform parameter can be either a single transformation or an array of sequential transformations.
In general, a transformation is represented by a function that modifies the coordinates of a node.
const canvas = new CanvasBuilder(element)
.enableLayout({
algorithm: {
type: "hierarchical",
transform: (point) => {
return { x: point.x, y: point.y };
},
},
})
.build();
Additionally, there are several built-in implementations of these functions for common scenarios to simplify setup.
- Shift
const canvas = new CanvasBuilder(element)
.enableLayout({
algorithm: {
type: "hierarchical",
transform: {
shift: { x: 100, y: 200 },
},
},
})
.build();
- Scale
const canvas = new CanvasBuilder(element)
.enableLayout({
algorithm: {
type: "hierarchical",
transform: {
scale: 2,
origin: { x: 0, y: 0 },
},
},
})
.build();
The origin parameter is optional.
- Rotate
const canvas = new CanvasBuilder(element)
.enableLayout({
algorithm: {
type: "hierarchical",
transform: {
rotate: Math.PI / 2,
origin: { x: 0, y: 0 },
},
},
})
.build();
The origin parameter is optional.
- Mirror
const canvas = new CanvasBuilder(element)
.enableLayout({
algorithm: {
type: "hierarchical",
transform: {
mirror: Math.PI / 2,
origin: { x: 0, y: 0 },
},
},
})
.build();
The mirror parameter specifies the angle of the mirror axis. The origin parameter is optional.
- Matrix
const canvas = new CanvasBuilder(element)
.enableLayout({
algorithm: {
type: "hierarchical",
transform: {
a: 1,
b: 0,
c: 10,
d: 0,
e: 1,
f: 20,
},
},
})
.build();
This is how transformation works on a point with (x, y) coordinates.