HTMLGraph

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

  
NameTypeDescriptionRequiredDefault
layerWidthnumberWidth of a single layerNo300
layerSpacenumberMinimum space between nodes within a single layerNo300
nextLayerNodesResolverNextLayerNodesResolverDetermines which nodes move to the next layer during layout calculationNo"adjacent"
transformTransformation | Transformation[] | undefinedSingle transformation or array of transformations to apply to node positionsNoundefined

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 object
  • currentNodeId - 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.

  1. Shift
    
const canvas = new CanvasBuilder(element)
  .enableLayout({
    algorithm: {
      type: "hierarchical",
      transform: {
        shift: { x: 100, y: 200 },
      },
    },
  })
  .build();

  
  1. Scale
    
const canvas = new CanvasBuilder(element)
  .enableLayout({
    algorithm: {
      type: "hierarchical",
      transform: {
        scale: 2,
        origin: { x: 0, y: 0 },
      },
    },
  })
  .build();

  

The origin parameter is optional.

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

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

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

( x 1 y 1 1 ) = ( a b c d e f 0 0 1 ) * ( x y 1 )