documentationfor yFiles for HTML 2.6

Hierarchical Layout

The hierarchical layout style aims to highlight the main direction or flow within a directed graph. The nodes of a graph are placed in hierarchically arranged layers such that the (majority of) edges of the graph show the same overall orientation, for example, top-to-bottom. Additionally, the ordering of the nodes within each layer is chosen in such a way that the number of edge crossings is small.

Samples of the hierarchical layout style
Polyline Edge Routing
Orthogonal Edge Routing
Curved Edge Routing
Grouped Graph

Note that in an acyclic graph, it is always possible that all edges have the same overall orientation. In a graph that contains cyclic dependencies between nodes, they are automatically detected and resolved.

Samples of the hierarchical layout style shows several hierarchical layouts with top-to-bottom orientation. Note that the hierarchical layout style can be combined with polyline, orthogonal, octilinear, and curved edge routing. Also, layout of grouped graphs is naturally covered by the hierarchical layout style, too.

The layout algorithm provided by the yFiles diagramming library for the hierarchical layout style facilitates convenient automatic generation of high-quality layouts. It supports a variety of features that influence many aspects in the layout process, assists with different predefined behaviors to combine and choose from, and enables flexible customization of the layout process if needed.

Terminology

The hierarchically arranged layers that are typical for this layout style (hence its name) are illustrated in Layers in the hierarchical layout style. With top-to-bottom main direction, layers stretch horizontally and are ordered from top to bottom. Within each layer, the nodes are placed vertically and are ordered from left to right.

Layers in the hierarchical layout style
hierarchical layers explanation

The node order within a layer is also called their sequence. The layer ordering in a diagram is also referred to as the layering. Generally, the overall orientation of the edges is the same as the main direction of the layout, and is also the direction of the layering. In other words, if the main direction of the layout is right-to-left, for example, then also the layering is from right to left.

The terms layering and sequence directly stem from the technical operation of a hierarchical layout algorithm where the layout is generated in a three-phase process, basically:

  1. Determine the layering for the nodes of the graph.
  2. Find a node order (sequence) within each layer.
  3. Assign actual coordinates to the nodes and route the edges. This phase is commonly referred to as the drawing phase.

Application Areas

The hierarchical layout style is ideal for many application areas where it is crucial that dependency relations between entities are clearly visualized. In particular, if such relations form a chain of dependencies between entities, this layout style nicely exhibits them. Generally, whenever the direction of information flow matters, the hierarchical layout style is an invaluable tool.

Application areas that this layout style is suited for include, for example:

  • Workflow visualization
  • Software engineering (e.g., call graph visualization or activity diagrams)
  • Process modeling
  • Database modeling (e.g., Entity-Relationship diagrams)
  • Bioinformatics (e.g., biochemical pathways)
  • Network management
  • Decision diagrams

The following figures show sample diagrams from different application areas.

Samples of the hierarchical layout style
Entity-Relationship diagram
Displays pathways of the brain, layered by stages of visual processing
Decision diagram

Relevant Classes

Relevant classes for this style lists the relevant classes for the hierarchical layout style.

Relevant classes for this style
Phase Class Name Description
HierarchicLayoutMain algorithm that also provides Basic Options.
NodeLayoutDescriptorProvides node-related as well as layer-related layout options. For example, preferred minimum distances between adjacent nodes within a layer. See Related Classes.
EdgeLayoutDescriptorProvides edge-related layout options. For example, different edge routing styles for different edge types. See Related Classes.
IIncrementalHintsFactoryCreates so-called hint objects which are essential for incremental hierarchical layout. See Incremental Layout.
LayeringILayererAn implementation of this interface is responsible for assigning the nodes of a graph to layers in a hierarchical layout. In Layer Assignment Options available layering strategies for non-incremental layout calculation are presented.
ILayerConstraintFactoryEnables convenient customization of the layering process where the nodes of a graph are assigned to layers in a hierarchical layout. See Constrained Layer Assignment.
SequenceDefaultLayerSequencerUsed to determine the order of nodes within a layer.
ISequenceConstraintFactoryEnables custom node order assignment within layers. See Node Order Options.
DrawingSimplexNodePlacerThis node placer is responsible for assigning each node within a layer its coordinate with respect to the node sequence. See also the description of SimplexNodePlacer.
DefaultDrawingDistanceCalculatorIs used by the NodePlacer to determine distances between graph elements within a layer.

The classes that are used in the layering phase provide many predefined so-called layering strategies that enable a variety of different layout results. Instead of letting the algorithm compute the layering, some strategies also support prescribing the layering completely. Additionally, in cases where only some nodes need to fulfill specific layering requirements, the LayerConstraintFactory class can be used.

Similarly, in the sequence phase, the node orders within the layers, which are computed by DefaultLayerSequencer, can be customized via the services provided by the SequenceConstraintFactory class.

Basic Options

The layoutMode property determines the general layout mode of HierarchicLayout. It uses one of the following constants from the LayoutMode enum type:

FROM_SCRATCH
Sets the layout algorithm to re-compute the entire layout from scratch, i.e., a complete re-layout is started. Layout from scratch is the default setting for the Layout Mode feature. See Non-incremental Layout.
INCREMENTAL
Sets the layout algorithm to incremental mode, i.e., elements that are marked for incremental processing will be inserted into the already calculated layout of the remaining part of the graph in an optimal manner. See Incremental Layout.

Layout Orientation
layoutOrientation
Determines the main direction or flow, i.e., the overall orientation for the edges in a hierarchical layout. This property is inherited from MultiStageLayout, the direct superclass of HierarchicLayout. The layout algorithm tries to arrange nodes in such a way that all edges point in the main direction.By default, the overall orientation for the edges will be from top to bottom. The other three layout directions can be set using the constants from the LayoutOrientation enum type. Setting a layout orientation for the hierarchical layout style shows how to set the layout direction.

The documentation for the other layout options assumes that this default orientation is being used.

Setting a layout orientation for the hierarchical layout style
const hl = new HierarchicLayout()
// Use left-to-right main layout direction.
hl.layoutOrientation = LayoutOrientation.LEFT_TO_RIGHT

Layout orientation sample shows one of the sample layouts for the hierarchical layout style with layout orientation left to right.

Layout orientation sample
Hierarchical layout with layout orientation left to right.

Maximal Duration
maximumDuration
Sets a (soft) time limit for HierarchicLayout.

HierarchicLayout allows to control general drawing options like, e.g., edge routing styles or minimum distances between graph elements.

Options which affect edge routing:

Orthogonal Edge Routing
orthogonalRouting
Enables/Disables orthogonal edge routing (default is disabled)
Backloop Routing
backLoopRouting
Enables/Disables backloop routing (default is disabled)

HierarchicLayout supports four edge routing styles:

  • polyline (the default)
  • orthogonal
  • octilinear (a variation of the orthogonal routing style)
  • curved

The following figure shows the different routing styles side by side. Note that using the above property, only the former two styles can be configured. Octilinear and curved edge routing can be enabled using a corresponding EdgeLayoutDescriptor, see also Related Classes.

Edge routing styles determined by the EdgeLayoutDescriptor
Polyline edge routing
Orthogonal edge routing
Octilinear edge routing
Curved edge routing
Enabling orthogonal edge routing
const hl = getMyHierarchicLayout()

// Switching HierarchicLayout to orthogonal edge routing.
hl.orthogonalRouting = true

HierarchicLayout places the nodes in a way that reflects the main flow of a diagram, i.e. in a top-to-bottom layout most edges will connect to targets which are placed below their source nodes. However, it is not always possible to achieve this for all edges in a diagram. Edges which connect to targets which are located above their source nodes are referred to as backloop edges. By default these edges exit their source nodes at the top border and enter their targets at the bottom to keep the paths short. This may reduce the readability of a hierarchical layout as shown in the left diagram of Backloop Routing.

Setting backloop routing enabled will force backloop edges to exit at the bottom and enter at the top of their source and target, respectively, emphasizing the main direction of the diagram. Backloop routing is enabled in the right diagram of Backloop Routing.

Backloop Routing
Backloop Routing disabled
Backloop Routing enabled

Options which affect node placement:

Minimum Layer Distance
minimumLayerDistance
The minimum distance between adjacent layers
Node to Node Distance
nodeToNodeDistance
The minimum distance between two nodes in the same layer
Edge to Edge Distance
edgeToEdgeDistance
The minimum distance between two edges in the same layer
Node to Edge Distance
nodeToEdgeDistance
The minimum distance between a node and a non-adjacent edge in the same layer

Distance settings in a hierarchical layout illustrates where the settings for the drawing options take effect in a diagram.

Distance settings in a hierarchical layout
hierarchical distances

Note that the distance settings between edges and also between edges and nodes only take effect on edges that span at least one layer in the diagram. Also, keep in mind that all distances are only minimum distances, i.e., the layout algorithm may use larger distances than specified in order to achieve an aesthetic result.

HierarchicLayout provides additional support to fine-tune distances between graph elements that takes into account the thickness of edges. This is especially useful for Sankey diagrams, for example. To specify each edge’s thickness, configure an appropriate layout data instance. Alternatively, a data provider key for this property is also available.

Further drawing style options can be specified by means of the layout descriptor classes for nodes and edges. One instance of each class is held by HierarchicLayout to store and retrieve default values for drawing style options, like, e.g., preferred minimum distances between graph elements.

HierarchicLayout provides access to the default NodeLayoutDescriptor and EdgeLayoutDescriptor instances:

nodeLayoutDescriptor
Node-related layout options
edgeLayoutDescriptor
Edge-related layout options

In addition to the instances held directly by HierarchicLayout, layout descriptors can also be associated with single graph elements in order to specify individual settings for them. Setting individual descriptors for nodes or edges is done through layout data instances for the layout algorithm. See Related Classes.

Labeling

Integrated labeling is one of the two scenarios for placing the labels of a graph. It means the support provided by HierarchicLayout for finding optimal placements for edge labels such that there are no overlaps of edge labels with each other or with graph elements.

Integrated labeling can be enabled or disabled using the following property:

integratedEdgeLabeling
Determines whether integrated labeling is enabled.

The before/after pair in Integrated edge labeling shows the result of a hierarchical layout with integrated edge labeling enabled.

Integrated edge labeling
Original graph with edge labels
Resulting hierarchical layout where the edge labels have been placed optimally

Optimal label placement with integrated labeling can be achieved using FreeEdgeLabelModel as the label model for the edges. As explained in Label Models, this edge label model is ideally suited in combination with integrated labeling and yields the best match for a label location that is computed by HierarchicLayout.

HierarchicLayout provides support for node label-aware hierarchical layout. Node labels do not need to be placed, but instead their size needs to be considered for the placement, respectively the routing, of adjacent graph elements. Taking node labels into consideration during layout calculation guarantees that they will not overlap nodes in the diagram.

Consider Node Labels
considerNodeLabels
Enables node label-aware layout calculation.

See also the description of the NodeLayoutDescriptor class in Related Classes which provides the support for node label handling.

Grouped Graphs

HierarchicLayout supports different layer assignment policies for graphs with grouped nodes. The layering for both incremental as well as non-incremental layout can be determined in either of two ways:

  • flat, i.e., nodes are assigned to layers regardless of nesting level within group nodes
  • recursively, i.e., layer assignment is computed from the most nested group up to the nodes in the root graph

Flat vs. recursive layer assignment compares the layer assignment policies. When layer assignment is done flat, the group nodes of a graph and their adjacent edges are ignored. In particular, this means that the layering of grouped nodes can be influenced by nodes outside of the group node. In constrast, when using recursive layer assignment, grouped nodes are processed without interference from nodes outside of their group node.

Flat vs. recursive layer assignment
Flat layer assignment policy where group nodes and their adjacent edges are ignored
Recursive layer assignment policy
Recursive layer assignment policy with compaction enabled

Recursive processing of the grouped nodes is the default behavior. Setting up flat layer assignment shows how to set up flat layer assignment with HierarchicLayout.

Setting up flat layer assignment
// Set up HierarchicLayout for grouped graphs.
const hl = new HierarchicLayout()
hl.recursiveGroupLayering = false

Recursive layer assignment optionally uses a compaction step where empty layers next to group nodes are filled with nodes from layers below these group nodes. When compaction is disabled, an alignment policy is used to specify where “ordinary” nodes that are in a layer with group nodes are placed relative to these group nodes. These options can be configured using the following properties:

compactGroups
Layer compaction
groupAlignmentPolicy
Group node-relative alignment policy

When calculating a layout for a grouped graph, HierarchicLayout also supports minimum size constraints for group nodes. A minimum size constraint can be conveniently used in order for the group node to accommodate for the size of its label. If a data provider is registered with the graph using the look-up key MINIMUM_NODE_SIZE_DP_KEY, any minimum size constraints for group nodes held by this data provider are respected by default.

HierarchicLayout’s support for grouped graphs currently does not include the following features for edge ends that directly connect to group nodes: strong port constraints, strong (fixed) port candidates, and edge/port grouping (bus-style edge routing).

HierarchicLayout’s support for incrementally calculating layouts of grouped graphs enables smooth transitions when realizing collapsing and expanding of group nodes. Incremental hierarchical layout when group nodes are collapsed and expanded presents the results of both these operations. The resulting folder node and group node, respectively, is incrementally inserted into the existing layout.

Incremental hierarchical layout when group nodes are collapsed and expanded
Original hierarchical layout with group nodes
Collapsed group node incrementally inserted into the layout
Previously collapsed group node expanded and incrementally inserted

Incremental hierarchical layout of graphs with grouped nodes is demonstrated in the tutorial demo application Hierarchic Nesting.

Recursive Edges Routing

To obtain more stable results when collapsing and expanding group nodes in interactive scenarios with incremental mode enabled, HierarchicLayout supports different routing styles for so-called recursive edges.

Recursive edges are considered those that connect nodes which belong to different group nodes. These edges are allowed to leave/enter the group nodes only at the top side or bottom side.

The recursiveEdgeStyle property in class EdgeLayoutDescriptor sets the routing style for a given recursive edge. The following routing styles are available:

DIRECTED
At their source end, recursive edges leave the containing group node(s) at the bottom side; at their target end, they enter the containing group node(s) at the top side
UNDIRECTED
At both ends, recursive edges leave/enter the containing group node(s) at the bottom side or top side.
OFF
Recursive edges aren’t routed specifically. At both ends, they can leave/enter the containing group node(s) at the left side or right side in order to connect as directly as possible.

The following figure illustrates the different routing styles for recursive edges:

Recursive edges routing styles
Recursive edges routing style directed, …​
... undirected, …​
... and off.

Recursive edges provide more stable results when collapsing/expanding group nodes in incremental mode since their leaving/entering sides in group nodes remain unchanged.

To further improve the results and preserve as much as possible from the existing drawing, the following can be applied in combination with recursive edges:

  • Recursive group layering should be enabled.
  • When expanding/collapsing a group node, the original size of the group (before expanding/collapsing) should be assigned using layout data.
  • The alternative path of specific edges should be assigned to layout data as follows:
    • Collapsing: For edges that are incident to the group node itself and edges for which one of source or target is inside the group node, the path before collapsing the group node has to be assigned as the alternative path. If source and target are either both inside or both outside the group node, no alternative path is required.
    • Expanding: For edges that are incident to the collapsed group node, the path before expanding the group node has to be assigned as the alternative path.
  • Folder nodes, i.e., collapsed group nodes, should also be marked using layout data.

Note that the following features are not supported for recursive edges:

Setup of a grouped graph’s hierarchy of nodes (using GROUP_DPKEY, NODE_ID_DPKEY, and PARENT_NODE_ID_DPKEY) is done transparently by the IGraph-related adapter mechanisms. See also Layout of Grouped Graphs and Applying an Automatic Layout.

Non-incremental Layout

Upon creation, HierarchicLayout is in non-incremental layout mode by default, i.e., it re-computes the entire layout of a given graph. This is in accordance with the behavior of the other yFiles for HTML major layout algorithms. Note that the non-incremental hierarchical layout is also referred to as layout from scratch. Switching to complete re-layout shows how to explicitly switch HierarchicLayout to non-incremental layout mode.

Switching to complete re-layout
const hl = getMyHierarchicLayout()

// Switching HierarchicLayout to do a complete re-layout of a graph.
hl.layoutMode = LayoutMode.FROM_SCRATCH

In the general three-phase process to generate a hierarchical layout, the first phase, that assigns the nodes of a graph to different layers, …​

The second phase, which is responsible for finding a good ordering of the nodes in each layer, …​

  • knows of a similar scheme to achieve custom sequencing requirements that are not covered by the default behavior.

Layer Assignment Options

HierarchicLayout assigns the nodes of a graph to separate layers using a ILayerer implementation. Layers are ordered and, assuming a top-to-bottom orientation for the main flow, are arranged vertically from top to bottom (see also Layers in the hierarchical layout style).

The layer order is a 1-based index for the layers that at the same time denotes the so-called rank of all nodes assigned to a layer. Note that the rank of a node is important in conjunction with some of the Layerer implementations.

From Scratch Layering Strategy

The layering strategy in non-incremental layout mode can be set using the fromScratchLayeringStrategy property. According to the layering strategy constant from the LayeringStrategy enum type, the actual ILayerer implementation is chosen. Internally, HierarchicLayout also sets up any specific configuration of the ILayerer if necessary.

The following layering strategy constants are available:

HIERARCHICAL_TOPMOST
A simple hierarchical layering variant. All nodes without incoming edges (indegree zero) will be assigned to the topmost layer of the layout. The number of separate layers will be as small as possible. Uses TopologicalLayerer with ranking policy NO_RERANKING.
HIERARCHICAL_OPTIMAL
An optimal hierarchical layering strategy. The layer distance of an edge is the absolute difference between the layer numbers (ranks) of its source and target node. Layer assignment will be done in such a way that the overall sum of the layer distances of all edges in the layout is minimal. Uses WeightedLayerer.
HIERARCHICAL_TIGHT_TREE
A good heuristic that approximates the layering done by Hierarchical — Optimal. Uses TopologicalLayerer with ranking policy TIGHT_TREE.
HIERARCHICAL_DOWNSHIFT
An even faster heuristic that approximates the ranking done by Hierarchical — Optimal by down-shifting some nodes in the layering. The quality is usually worse than the one produced by Tight Tree Heuristic. Uses TopologicalLayerer with ranking policy DOWN_SHIFT.
BFS
Layering based on a breadth-first search (BFS). All edges will span at most one layer in the resulting drawing. Edges between nodes that belong to the same layer are possible. To specify nodes that should be placed into the first layer, specify supplemental layout data accordingly. Note that in the absence of such data all nodes that have no incoming edges (indegree zero) are placed into the first layer. Uses BFSLayerer.
FROM_SKETCH
Layer assignment strategy that uses the initial y coordinates of the nodes to determine a layering. It tries to find a layering that is similar to the one in the input graph. When this layering strategy is used, the layout algorithm may place nodes in the same layer, even though they are connected by an edge. These inner layer edges are always routed in an orthogonal style. Uses AsIsLayerer.
USER_DEFINED
The ranks of the nodes will be given by the user. To specify the ranks, configure supplemental layout data accordingly. Uses GivenLayersLayerer.

Except when using one of the latter three layering strategies, the nodes of a graph are assigned to layers such that as much as possible edges of the graph will have the same overall orientation. With the From Sketch and User-defined Layering strategies (last and second-to-last strategy constants), the layering is prescribed by some external means and there cannot be much said about the direction of the edges.

Using either the From Sketch or User-defined Layering strategies, it is possible to specify the exact layering for all nodes of a graph. In cases where only a few nodes need to fulfill specific layering requirements, the constrained layer assignment scheme is ideally suited.

When undirected edges need to be taken into account during layer assignment, then any layering strategy specified as outlined above is ignored and instead the constrained layer assignment scheme is used.

Node Order Options

In a hierarchical layout, the ordering of the nodes within a layer determines the number of edge crossings in the resulting layout. By default, HierarchicLayout uses class DefaultLayerSequencer for determining this node order.

The sequencing that DefaultLayerSequencer generates can be conveniently customized using the support for constrained node sequencing.

Incremental Layout

Upon creation, HierarchicLayout is in non-incremental layout mode by default, i.e., it recomputes the entire layout of a given graph. The other layout mode, namely incremental layout, needs to be turned on explicitly.

Incremental layout is closely related to layout from sketch, where a given arrangement of nodes is taken as the starting point for a layout calculation and also as a specification for the calculation’s desired outcome. Compared to a complete re-layout of a graph, the main advantage of incremental layout is that distinct parts of a graph can be rearranged while the remainder of the graph, which defines the sketch, is not, or only slightly, changed.

Carefully note that the layout algorithm may move graph elements that are part of the sketch in order to optimally insert any incremental graph elements. In other words, incremental layout does not guarantee that any non-incremental parts of a graph stay exactly as they were. However, they will keep their relative position.

Switching to incremental layout shows how to switch HierarchicLayout to incremental layout mode.

Switching to incremental layout
const hl = getMyHierarchicLayout()

// Switching HierarchicLayout to do incremental layout of a graph.
hl.layoutMode = LayoutMode.INCREMENTAL

Additionally, any graph elements that shall be processed using incremental semantics need to be annotated appropriately so that the algorithm is able to discern them correctly from the parts that define the sketch. Annotation of the incremental parts of a graph is achieved by means of a data provider. See Specifying Hints.

Use Cases

Incremental layout has two major use cases, which both involve layout from sketch:

  • Interactive creation of a graph structure where the layout calculation is performed dynamically with each newly inserted graph element.
  • Subsequent improvement of distinct parts from an already existing graph layout, where the remainder of the layout stays mainly unchanged.

Both these use cases are illustrated below.

Sequence of incremental layouts shows a sequence of incremental layouts generated by class HierarchicLayout. Starting with a given graph, new graph elements are inserted optimally into the existing drawing from the step before (which defines the sketch). Note the emphasis for newly added elements.

Sequence of incremental layouts

The second major use case for incremental layout, the optimization of distinct parts from an existing hierarchical layout is shown in Incremental layout used for optimization. There, an entire subgraph is calculated anew and optimally placed into the given drawing that defines the sketch.

Incremental layout used for optimization

Both use cases are handled by annotating the “new” graph elements by means of so-called hint objects which are used by the algorithm during layout calculation in incremental mode. The hint object for a graph element that shall be processed using incremental semantics can be provided via supplemental layout data objects.

Specifying Hints

Using layout data you can easily specify hints for the most common use cases:

  • insert nodes into specified layers of the existing drawing
  • place nodes into suitable layers of the existing drawing

Class IncrementalHintItemMapping, which can be assigned to HierarchicLayoutData.incrementalHints, provides two properties for this:

IncrementalHintItemMapping.incrementalSequencingItems
The layout algorithm places the specified node on an already existing layer.
IncrementalHintItemMapping.incrementalLayeringNodes
The layout algorithm places the specified node in a suitable layer, possibly creating new layers.

The following example defines a set of nodes that should be laid out incrementally:

Setting incremental hints for nodes using layout data
const graph = getMyGraph()

const hl = new HierarchicLayout()

// Get a collection of those nodes that should be processed using incremental
// layout semantics.
const incrementalNodes = myGetIncrementalNodes()

// Create the layout data and set the incremental hints on it.
const layoutData = new HierarchicLayoutData({
  // Set the incremental nodes item collection on it.
  // There are other ways to define the incremental hints for nodes, not
  // using a collection. For example, you could specify a function that creates
  // the incremental hints for each node on the fly. But in this example we
  // simply use a collection.
  incrementalHints: {
    incrementalLayeringNodes: incrementalNodes
  }
})

// Now, set incremental mode and invoke layout calculation with the previously
// defined layout data.
hl.layoutMode = LayoutMode.INCREMENTAL
graph.applyLayout(hl, layoutData)

There are more specific hints for other use cases available, such as:

  • place nodes into suitable layers of the existing drawing with respect to their exact coordinates (either both directions, or confined to only one direction)
  • place groups incrementally but keep their content as it is
  • route edges

In these use cases, you need to use a so-called hint factory which can create such special hints:

createIncrementalGroupHint(forItemId: Object): Object
The group will be placed on a suitable position. All hints of the descendants of a group are interpreted relative to the group node. Descendants without hints maintain their relative order within the group node (but not with elements outside the group).
createUseExactCoordinatesHint(forNodeId: Object): Object
The node will be placed in an already existing layer that is suitable for its location. The position within its layer will be determined by its current location. While for nodes without hints the algorithm only keeps the relative positions, for nodes with an exact coordinate hint the algorithm should also preserve the exact coordinates. Note that using exact coordinate hints may lead to drawing artifacts like node overlaps and node-edge intersections.
createUseExactLayerCoordinatesHint(forNodeId: Object): Object
The node will be placed in an already existing layer that is suitable for its location. The position within its layer is not dependent on the location of the item.
createUseExactSequenceCoordinatesHint(forNodeId: Object): Object
The position within the sequence of its layer will be determined by its current coordinates.

When inserting nodes or routing edges according to their hint, nodes and edges from the graph that have no hint object associated retain their original relative order both within layers as well as from layer to layer.

Class HierarchicLayout has a property holding a hint factory object of type IIncrementalHintsFactory. Code that shows the usage of a hint factory is presented in the following example:

Using a hint factory
const graph = getMyGraph()

const hl = new HierarchicLayout()

// Get a collection of those nodes that should be processed using incremental
// layout semantics.
const incrementalNodes = myGetIncrementalNodes()

// Create the layout data and set the incremental hints on it.
const layoutData = new HierarchicLayoutData({
  incrementalHints: (item, factory) =>
    item instanceof INode && incrementalNodes.includes(item) ? factory.createUseExactCoordinatesHint(item) : null
})

// Now, set incremental mode and invoke layout calculation with the previously
// defined layout data.
hl.layoutMode = LayoutMode.INCREMENTAL
graph.applyLayout(hl, layoutData)
const graph = getMyGraph()

const hl = new HierarchicLayout()

// Get a collection of those nodes that should be processed using incremental
// layout semantics.
const incrementalNodes = myGetIncrementalNodes()

// Create the layout data and set the incremental hints on it.
const layoutData = new HierarchicLayoutData({
  incrementalHints: (item: IModelItem, factory: IIncrementalHintsFactory) =>
    item instanceof INode && incrementalNodes.includes(item) ? factory.createUseExactCoordinatesHint(item) : null
})

// Now, set incremental mode and invoke layout calculation with the previously
// defined layout data.
hl.layoutMode = LayoutMode.INCREMENTAL
graph.applyLayout(hl, layoutData)

The layout algorithm queries hints from the layout data for both nodes and edges. Because of this, the layout data requires this information as an object of type IncrementalHintItemMapping.If you are using a data provider instead of layout data, the data provider that is registered using the look-up key INCREMENTAL_HINTS_DP_KEY also holds data for both nodes and edges. Hence, neither INodeMap nor IEdgeMap implementations can be used as the basis for this data provider.An alternative basis for the data provider would be, e.g., an IDataMap as returned by method createHashedDataMap, or any custom IDataProvider implementation that is not restricted to one type of graph element.

The demo Interactive Hierarchic Layout shows how to use the incremental layout capabilities.

Constrained Layer Assignment

HierarchicLayout supports user-defined constrained layer assignment for from-scratch layout mode as well as for incrementally inserted graph elements in incremental layout mode. Nodes can be restricted to be placed either

  • absolute, i.e., into the first or last layer of the layout, or
  • relative to a given reference node into the same layer, a layer preceding that of the reference node, or a layer following that of the reference node.

The remaining nodes, that have no constraints defined, are processed using the layerer that is set with HierarchicLayout.

Note that relative layer constraints in incremental layout mode can also be specified between nodes that belong to the sketch and nodes that shall be processed using incremental semantics. Relative constraints between nodes that both belong to the sketch are ignored.

Constrained hierarchical layering shows a resulting hierarchical layout where nodes with an absolute constraint specified for them are placed in the topmost layer (note the emphasis on these nodes). Normally, i.e., when no constraints are specified, these nodes are placed in the very center of the graph as can be observed in the original hierarchical layout.

Constrained hierarchical layering
Usual hierarchical layout (i.e. without taking constraints into account)
Resulting hierarchical layout where the constrained nodes are placed in the topmost layer.

HierarchicLayoutData.layerConstraints returns an instance of LayerConstraintData which provides the following methods to define both absolute and relative layer constraints for nodes.

placeAtTop(node: INode): void
placeAtBottom(node: INode): void
Absolute constraints.
placeInSameLayer(referenceNode: INode, sameLayerNode: INode): void
placeAbove(referenceNode: INode, aboveNode: INode, minDistance: number, weight: number): void
placeBelow(referenceNode: INode, belowNode: INode, minDistance: number, weight: number): void
Constraints relative to a given reference node from the same graph instance.

Specifying layer constraints shows how to specify layer constraints for two nodes.

Specifying layer constraints
const hierarchicLayoutData = new HierarchicLayoutData()
const layerData = hierarchicLayoutData.layerConstraints
// place node1 in the top layer
layerData.placeAtTop(node1)
// place node2 in a layer below node1
layerData.placeBelow(node1, node2)

The methods for defining relative constraints optionally support specifying a minimum distance to the relative node as well as a priority value of the constraint. A constraint’s priority is a positive integral value that is used to resolve conflicting constraint definitions by not considering low-priority constraints.

Constrained Node Sequencing

Constrained node sequencing enables user-defined ordering of nodes within a given layer. Nodes can be restricted to be placed either

  • absolute, i.e., at the beginning or at the end of their layer, or
  • relative to a given reference node before it or after it.

Any remaining nodes that have no constraints defined are placed by the algorithm at optimal positions within their respective layer. In particular, this means that for a set of nodes {A, B, C} within a layer where relative constraints specify a sequence like so: {A before B, B before C}, other nodes from the layer might still intermit the sequence in the resulting layout.

Constrained node sequencing shows resulting hierarchical layouts where nodes are placed according to different sequence constraints.

The first before/after pair shows a result where nodes with an absolute constraint specified for them are placed at the beginning of their respective layers (note the emphasis on these nodes). Normally, i.e., when no constraints are specified, these nodes are placed in the very center of the graph as can be observed in the original hierarchical layout.

The other pair depicts the result of using relative constraints to achieve a specified sequence for some nodes within their layer.

Constrained node sequencing
Usual hierarchical layout (i.e. without taking constraints into account)
Resulting hierarchical layout where the constrained nodes are placed at the beginning of their respective layers.
Usual hierarchical layout (i.e. without taking constraints into account).
Resulting hierarchical layout where the constrained nodes are placed lexicographically ordered within their layer.

HierarchicLayoutData.sequenceConstraints allows to conveniently define both absolute and relative node order constraints. It returns an instance of SequenceConstraintData which provides provides the following methods to specify node order constraints:

placeAtHead(item: IModelItem): void
placeAtTail(item: IModelItem): void
Absolute constraints
placeBefore(item: IModelItem, beforeItem: IModelItem): void
placeAfter(item: IModelItem, afterItem: IModelItem): void
Constraints relative to a given reference item

Specifying sequence constraints shows how the sequence constraints can be specified for given nodes

Specifying sequence constraints
const hierarchicLayoutData = new HierarchicLayoutData()
const sequenceData = hierarchicLayoutData.sequenceConstraints
// place node1 first
sequenceData.placeAtHead(node1)
// place node2 after node1
sequenceData.placeAfter(node1, node2)

Layer Assignment with Undirected Edges

To determine the layering for the nodes of a graph, the layer assignment phase by default takes into account the directedness of all edges of the graph. From the very nature of the hierarchical layout style this means that the nodes of a graph are arranged such that the (majority of) edges show the same overall orientation in the resulting diagram, for example, top-to-bottom.

With the support for undirected edges, HierarchicLayout provides a means to specify that in the resulting diagram a given edge should neither be oriented with nor against the main direction, but that instead its nodes should preferably be placed into the same layer. Note that due to further optimization criteria it cannot be guaranteed that they are always placed into the same layer (see also the tip below).

Generally, this feature allows to specify that a subset of edges should be considered irrelevant for the actual hierarchical structure of a diagram. It is especially suited to achieve aesthetic layouts for diagrams where nodes have an attached non-structural element that is exclusively connected to them, like it is often the case in UML diagrams with 'note' or 'description' nodes, for example.

Layer assignment with undirected edges
Usual hierarchical layout.
Resulting hierarchical layout where nodes connected by undirected edges (note the emphasis) are placed into the same layer (ideally).

Edges can be marked as being undirected by means of properly configured supplemental layout data.

The layout data’s edgeDirectedness property holds a floating point value per edge to specify the edge’s directedness. An edge can be marked using one of the following directedness values:

  • 0 denotes an undirected edge; the algorithm tries to place the nodes connected by this edge into the same layer, if possible
  • 1 denotes a regular edge that should be oriented with the main direction of the resulting hierarchical layout
  • -1 denotes an edge that should be oriented against the main direction of the resulting hierarchical layout

By default, all edges are assumed to have a directedness value of 1.

To only achieve that a specific subset of edges points against the main direction in the resulting diagram, it can be faster to explicitly revert these edges before the layout invocation and afterwards restore their original direction. This can be conveniently done with the help of layout stage ReverseEdgesStage, for example.Relative layer constraints can be used to fix an edge so that its nodes are always placed into the same layer.

Custom Subcomponents

HierarchicLayout allows to easily define subcomponents (i.e. a subset of nodes of the input graph) which are arranged by a specified, individual ILayoutAlgorithm instance. Therefore, different components of the same graph can be handled by different layout algorithms while the components on the top level are arranged in the usual hierarchical way. Note that components can not be nested.

Example

In Layout with three subcomponents a possible use case is illustrated. The example graph contains three different subcomponents indicated by node labels. Nodes that do not belong to any component are not labeled. The main hierarchical layout has top-to-bottom orientation and features orthogonal edge routes. The first subcomponent ('HL' labels) is also arranged by a hierarchical layout algorithm, but with left-to-right orientation and polyline edge routes. The 'Tree' component is arranged by a tree layout algorithm and, finally, the last component is handled by the organic layout algorithm ('O' labels).

Layout with three subcomponents
The graph contains three different subcomponents, each arranged using another layout algorithm.

Usage

The behavior of subcomponents is defined by their associated subcomponent descriptor HierarchicLayoutSubcomponentDescriptor. Set the layout algorithm that should be applied to the associated subcomponent, using the property layoutAlgorithm. Additionally, some components can be integrated into the surrounding hierarchical layout for a better fit. The policy whether to integrate a subcomponent in this way can be specified with the property placementPolicy.

To define subcomponents use the layout data property subcomponents. The Add method of the property takes the subcomponent descriptor as parameter to create a new component that should be arranged according to the specifications in the descriptor. The returned item collection allows to conveniently define which nodes should belong to the newly added subcomponent. See the following code example that shows how to define a subcomponent that should be arranged by an organic layout algorithm.

Definition of a subcomponent arranged by OrganicLayout
const graph = getMyGraph()
const data = new HierarchicLayoutData()

// Create a subcomponent descriptor which specifies how the subcomponent is handled
// In this case, the subcomponent will be arranged by the provided OrganicLayout instance
const descriptor = new HierarchicLayoutSubcomponentDescriptor(new OrganicLayout())

// Associate nodes with the subcomponent descriptor
data.subcomponents.add(descriptor).items = getMySubComponentNodes()

// Apply the hierarchic layout with the defined subcomponents
graph.applyLayout(new HierarchicLayout(), data)

Inter-Edges

There can be edges that connect nodes of different subcomponents or nodes of a subcomponent with top-level nodes. These edges are referred to as inter-edges. With respect to inter-edges, there are some minor restrictions. Their style might slightly differ from other, normal hierarchical edges. Also, the minimum first/last segment length setting can not always be satisfied for inter-edges.

Grouped Graphs

Subcomponents can be defined for grouped graphs, however, there are some restrictions: All subcomponent nodes must be on the same hierarchy level if the group node itself is not part of the subcomponent. If a group is assigned to a subcomponent, then all its descendants (including other group nodes) must be in the same component, too.

Subcomponent Placement

Subcomponents are generally handled by the hierarchical layout as if they were one single large node. For subcomponents that are only connected to the remaining graph by a single node outside the component, also called a connector node, it is possible to integrate the component layout into the hierarchical layout. If the placementPolicy allows for integrated placement of the component, the connector node and all inter-edges are included in the layout calculation for the component. This way, subcomponents that are associated with a unique connector node will be placed in direct proximity of the node by the hierarchical layout. The available placement policies are:

Isolated component placement
ISOLATED
If this placement policy is selected for a subcomponent, it is handled as a large, independent node by the hierarchical layout, even if there is a connector node at which the component could be integrated.
Hierarchical layout with isolated subcomponent.<para class="dguide-para"></para>

Forced integrated component placement
ALWAYS_INTEGRATED
If this placement policy is selected, the subcomponent will always be integrated into the hierarchic layout, unless there is no connector node at which to integrate it. The algorithm will allow overlaps with the rest of the graph, or deviations from the specified edge routing behavior to integrate the component. This policy is therefore most effective, when the resulting component layout is predictable and unlikely to cause such problems.
Hierarchical layout with isolated subcomponent.<para class="dguide-para"></para>

Automatic placement
AUTOMATIC
This is the default policy. If this policy is selected for a subcomponent that has a connector node, the algorithm will check whether the integrated component layout is desirable in the context of the hierarchic layout. It ensures, that the component layout does not cause overlaps, is compatible with the specified edge routing behavior and has no constraints that directly prevent it from being placed at the connector node. Some important criteria which should be considered:
  • The sub-layout must have an orientation/direction which is orthogonal with respect to the main hierarchic layout orientation. Consider the top-to-bottom orientation as main direction: the sub-layout must be completely left or right of the owner node. The inter-edges of the owner must connect left or right.
  • If in incremental layout mode, the sketch of the component must comply with the location of the component layout in relation to the owner node.
  • Layering constraints with the connector node must allow that the connector can be in the same layer as the subcomponent.
  • Any sequencing constraint with the connector node must comply with the subcomponent layout (e.g., a place before constraint complies with a subcomponent layout where all the component nodes are placed before the connector node.
hierarchical subcomponent automatic policy<para class="dguide-para"></para>

Integrated subcomponents work especially well when the inner sub-layout algorithm has an explicit layout orientation (like e.g. HierarchicLayout or TreeLayout).

Using Placement to Improve Component Alignment

In some use-cases subcomponents may have a single node connecting to the rest of the graph that lies in the component. In such cases it often makes semantic sense to align that node with graph nodes outside the component, that are placed in the same layer by the hierarchic layout. Since the hierarchic layout considers the component as a single large node, this cannot be guaranteed implicitly, however, the integrated placement can be used to achieve the desired alignment by excluding that specific node from the subcomponent.

Layout with isolated tree subcomponent (green) and slight misalignment in top-layer
Layout with integrated tree subcomponent (green) and correct alignment in top-layer

Port Constraints

HierarchicLayout supports both weak port constraints as well as strong port constraints that are specified for the edges of a graph (more precisely, the edge ends). The setup of port constraints is presented in Port Constraints.

Using weak port constraints for the ends of an edge, it is possible to specify at which side of the source node or target node, respectively, an edge path must connect. Constraint on which side edges should connect to nodes shows the resulting hierarchical layout of a graph where some edges are set up having weak port constraints.

Constraint on which side edges should connect to nodes
Usual hierarchical layout (i.e. without taking port constraints into account)
Resulting hierarchical layout with weak port constraints

Using strong port constraints, it is possible to specify the side of the node at which an edge must connect, and additionally also the exact position of the port. Constraint at which exact points edges should connect to nodes shows the resulting hierarchical layout of a graph where some edges are set up having strong port constraints.

Constraint at which exact points edges should connect to nodes
Usual hierarchical layout (i.e. without taking port constraints into account)
Resulting hierarchical layout with strong port constraints

Carefully observe how the nodes A and B change their position in the resulting hierarchical layout from the figure above. This is due to the strong port constraints specified for the edge ends at the common target node, which would result in an edge crossing with the original node order.

Both weak port constraints and strong port constraints can be mixed easily in the drawing.

Configure supplemental layout data for source port and target port constraints to use this feature.

Port Candidates

In addition to the support provided for port constraints, HierarchicLayout also supports the concept of port candidates. Both aspects, i.e., matching port candidates as well as modeling enhanced port constraints are supported.

For the matching of port candidates, the set of allowed anchor locations for edge ends at the nodes of a graph are retrieved from supplemental layout data via the node port candidate set. The subset of desired anchor locations where the source ports and target ports of edges like to connect to are specified by the source port candidate and target port candidate sets, respectively. Note that the candidates in both sets must be the same instances if the matching should be able to detect that two candidates are equal. It does not suffice that candidates have the same parameters.

The example in Using port candidates to control connection points demonstrates the use of port candidates to distribute edges at defined connection points: one port candidate at each corner of the diamond node allows one edge to connect. Additional candidates at the top and bottom allow edges to connect at these points when all other candidates are already occupied. These additional candidates are associated with a higher cost to make sure they will be only used after all other candidates are occupied.

See Port Candidates for Nodes for a detailed description of the port candidates concept.

Using port candidates to control connection points
Incoming edges connect at the top, the first outgoing edge at the bottom…​
…​ more outgoing edges occupy the right and left corners…​
…​ when all corners are occupied

For modeling enhanced port constraints, the set of possible port candidates for the edges of a graph are retrieved from source port candidate and target port candidate sets, respectively.

Edge Grouping

Incremental hierarchical layout supports the notion of grouping together multiple edge ends to be anchored at the same location. This can be specified for both source ends and target ends. The general setup for edge groups is described in Layout with Edge Grouping.

Edges that belong to the same group at a specific end will additionally be routed in bus-style, i.e., if multiple edges start or end at nodes in the same layer and belong to the same group, even if they do not share the same node at their ends, they will be merged together in a bus structure in that layer.

HierarchicLayout supports both automatic and custom edge grouping.

Automatic Edge Grouping

Automatic edge grouping is disabled by default. It can be enabled using the following property:

automaticEdgeGrouping
Enables/Disables automatic edge grouping

Automatic edge grouping tries to group as many edges as possible, without changing the semantic of the graph. Edges are grouped either at a common source node or at a common target node. They won’t be grouped, if grouping would lead to ambiguous paths. The effect of automatic edge grouping is shown in Automatic Edge Grouping. Note that edges with a common source are grouped as well as edges with a common target. Also note that the outgoing edges at node B are not grouped, because grouping at this node would mock a connection between A and D.

Automatic Edge Grouping
Automatic edge grouping disabled
Automatic edge grouping enabled

Edges are only grouped at their source (target) node if they do not have a port constraint/port candidates at this node. Furthermore, edges cannot be grouped at a node with specified port candidates. If automatic edge grouping is enabled, user specified edge groups are ignored.

Custom Edge Grouping

If more flexibility is needed, edges can be grouped by specifying edge groups using data providers as described in Layout with Edge Grouping.

The general rule describing how bus structures are created can be summarized as follows: edge paths are merged from both sides, source and target, beginning as close to the respective edge ends as possible. From this rule, the following consequences arise:

  • edges that start at a common node and belong to the same source group are merged together such that they are anchored at the same location; the same holds similarly for edges ending at a common node that belong to the same target group
  • edges that start at nodes in different layers, but belong to the same source group are merged together in a cascading manner; the same holds similarly for edges ending at nodes in different layers, but belong to the same target group

From this rule it is also clear that edges being grouped at both ends will result in edge routings where the paths are merged to the maximum extent possible.

Edge group configurations and resulting bus-style edge routings presents some edge routing results (in the figures to the left) and describes their actual source and target group setup. Note that the figures to the right depict the edge routing that results when both the edges are reversed and the source and target groups are exchanged.

Edge group configurations and resulting bus-style edge routings
Figure Description Figure
Edges starting at A nodes are grouped at their source side using a common A ID (for example). Likewise, edges starting at B nodes are grouped at their source side using a common B ID. Additionally, at their target side the edges are grouped such that all A edges share a common ID and all B edges share a common ID.
Edges starting at the upper nodes are grouped at their target side using a common A ID (for example). Likewise, edges starting at the middle nodes are grouped at their target side using a common B ID.
All edges are grouped at their target side using a common ID.
All edges are grouped at their source side using a common ID. Additionally, at their target side the edges are also grouped such that they share a common ID.
Edges are grouped at their source side using a common ID.

To specify which edges should be grouped and how, provide supplemental layout data with properly configured source and target group ids.

Bus Structures

So-called bus structures are related to edge grouping. A bus structure consists of a root node and bus nodes that are directly connected to the root node. All edges connecting bus nodes of the same structure have the same edge direction (note that the specified edgeDirectedness is considered). Bus structures consisting of outgoing edges are placed below the root node, whereas structures consisting of incoming edges are placed above the root node (assuming that the layout orientation is top-to-bottom).

Hierarchical layout containing a bus structure
The example contains a single bus structure with 15 bus nodes.

The bus substructures are arranged using a style that results in a more compact layout. Edges to the bus nodes are routed using a shared bus segment that connects to the common root node. The bus nodes are arranged using several layers above or below the root node such that the whole substructure has a compact area. By default, each bus layer contains equally many bus nodes, bus nodes of adjacent layers are center-aligned and the bus segment is routed in the middle of the nodes.

Defining buses can make layouts much more compact in scenarios with nodes that have a large number of adjacent edges and especially if the successor/predecessor nodes are leaf nodes without further edges.

To specify a bus structure one must map edges to a BusDescriptor instance. Edges with the same descriptor instance and the same direction with respect to a common root node are grouped and form the bus. The mapping can conveniently be defined by using the layout data property buses.

The BusDescriptor allows to configure the number of nodes that should be placed before and after the common bus segment, see the properties maximumNodesBeforeBus and maximumNodesAfterBus. The terms before and after refer to the ordering in the node sequence (see Terminology). By default the bus segment is placed such that it is in the middle of the bus node sequence. For example, if a layer contains six nodes of the same bus structure, then the bus segment is inserted between the third and the fourth bus node; this example can also be observed in the layout example Hierarchical layout containing a bus structure.

If a more specific assignment of nodes to the sides of the bus segment is desired, then this can be achieved by using nodesBeforeBus. The property allows to individually state for a node if it should be placed before the bus or after it. Another more involved configuration possibility is provided by busRootOffsets. The feature enables to specify individual offsets that define in which layer a bus node is placed with respect to the root node. Thus, an individual bus node layering can be realized. By default, each bus layer contains equally many bus nodes (except for the last one if a different number of nodes is remaining).

Grid

HierarchicLayout provides support for placing nodes on grid coordinates. Grid placement is enabled by means of the following property, which at the same time also determines the spacing between grid coordinates:

gridSpacing
Setting a value strictly greater than 0.0 enables grid placement and determines the distance between grid coordinates. The value is used both in vertical and in horizontal direction.

The graph’s edges will also be routed on the grid, i.e. their bends are placed on grid coordinates, if possible. Placing bends on the grid isn’t always possible depending on other configurations, for example:

  • the configured edge routing style
  • the port coordinates of an edge end when there are strong port constraints set
  • the port assignment policy at a node, which may place edge ends on non-grid coordinates (e.g., DEFAULT, ON_SUBGRID)

The following figures show the results of grid placement with the different edge routing styles supported by HierarchicLayout. Observe how the center of each node is placed on grid coordinates and edge paths run on grid lines where possible. All figures use a grid spacing of 10.0 [pixel].

Edge routing styles with enabled grid placement
Orthogonal edge routing
Octilinear edge routing
Polyline edge routing.
Curved edge routing.

Different grid spacing values can be used to achieve an effect on a graph similar to a scaling transformation:

Resulting grid placements of the same graph with different grid spacings
Grid spacing = 10.0
Grid spacing = 30.0

By default, nodes will be placed on the grid with their center. However, it is possible to define an alternative reference point for each node with which it is placed instead. For example, if the upper left corner of a node should be on grid coordinates.

With the following property of class NodeLayoutDescriptor the reference point for a node can be set:

gridReference
Determines a node’s reference point, which shall be placed on grid coordinates. By default, a node’s center is used as its reference point.

Note that non-empty group nodes will always be placed such that their borders are on grid lines. They are not affected by reference point configuration.

When using the Layer Alignment property of the NodeLayoutDescriptor class to top-align (bottom-align) all nodes of a layer, also adjust the reference points of the nodes to their top (bottom) for best results in conjunction with grid placement.

To handle the edges of a graph, HierarchicLayout supports different port assignment policies in conjunction with grid placement. The policies determine how the edges at each side of a node will be distributed along the respective side.

The portAssignment property in class NodeLayoutDescriptor sets the port assignment policy for a given node. The following policy constants are available:

DEFAULT
Distributes the edges on each node side evenly without considering the grid. This is the default setting that is also used when no grid is specified.
ON_GRID
Distributes the edges on each node side on grid lines. If there are less grid lines than there are edges at a side, multiple edges may connect at the same location. When the node is placed on the grid with a reference point on its border, it is possible that there is no grid line available at the node’s side. In that case, all edges at that node side will be centered at the side.
ON_SUBGRID
Distributes the edges on each node side on grid lines. If there are less grid lines than there are edges at a side, the grid will be subdivided until there is at least one grid line per edge available.

The following figures show the different port assignment policies with the same graph:

Different port assignment policies with grid placement
DEFAULT
ON_GRID
ON_SUBGRID

See also the description of the NodeLayoutDescriptor class in Related Classes which provides the properties for setting individual reference points and configuring port assignment policies.

The grid placement support of HierarchicLayout does not work well with exact layer coordinate hints or exact sequence coordinate hints.

Swimlanes

HierarchicLayout provides support for so-called swimlane layout. This type of layout uses the notion of adjacent lanes into which nodes are placed. The lanes are oriented with the general layout direction, i.e., perpendicular to the layers of the hierarchical layout. Each normal node of the graph is placed into a single lane, group nodes in a grouped graph are allowed to stretch across multiple lanes such that they encompass all their contained nodes.

Swimlanes shows a resulting swimlane layout as calculated by HierarchicLayout where the layout direction is from left to right. The visual representation of the swimlanes is rendered by a group node that uses the TableNodeStyle node style.

Swimlanes
Left-to-right swimlane layout with group nodes.

Swimlane layout is a special case in the more general concept of so-called partitioned layout support. The lanes present a one-dimensional partition within which the nodes of a diagram are organized. The setup for partitioned layout is presented in Layout of Tables and Swimlanes.

Partition grid shows a resulting partitioned layout. Note the two-dimensional partition which results from the rows and columns.

Partition grid
Left-to-right partitioned layout

Setup

With the classes from the yFiles for HTML Complete package, the setup for swimlane/partitioned layout calculation of a graph with table structures can be reduced to a minimum by using the morphLayout method as shown in Swimlane/partitioned layout preparation. Internally, this method uses the services of class TableLayoutConfigurator to take care of all necessary configuration steps related to swimlane/partitioned layout.

Swimlane/partitioned layout preparation
const graph = getMyGraph()

const hl = new HierarchicLayout()
hl.componentLayoutEnabled = false
hl.layoutOrientation = LayoutOrientation.LEFT_TO_RIGHT
hl.orthogonalRouting = true
hl.recursiveGroupLayering = false
const nodePlacer = hl.nodePlacer
nodePlacer.barycenterMode = true

// Invoke layout calculation.
// Internally, morphLayout uses TableLayoutConfigurator to prepare all
// relevant information for a layout algorithm.
try {
  await graphComponent.morphLayout(hl)
} catch (error) {
  console.log(error)
}
const graph = getMyGraph()

const hl = new HierarchicLayout()
hl.componentLayoutEnabled = false
hl.layoutOrientation = LayoutOrientation.LEFT_TO_RIGHT
hl.orthogonalRouting = true
hl.recursiveGroupLayering = false
const nodePlacer = hl.nodePlacer as SimplexNodePlacer
nodePlacer.barycenterMode = true

// Invoke layout calculation.
// Internally, morphLayout uses TableLayoutConfigurator to prepare all
// relevant information for a layout algorithm.
try {
  await graphComponent.morphLayout(hl)
} catch (error) {
  console.log(error)
}

Convenience class LayoutExecutor also uses the services of class TableLayoutConfigurator, but additionally provides access to its internal TableLayoutConfigurator instance for configuration and customization.

Swimlane/partitioned layout preparation (IGraph API) demonstrates how to set up a swimlane/partitioned layout without the convenience functionality from the yFiles for HTML Complete package.

HierarchicLayout relies on the services of the PartitionGrid class, which can be used to

  • define a grid-like structure consisting of rows and columns that represents a partition,
  • create IDs for the cells of a partition, which result from the rows and columns, and
  • assign the nodes of a diagram to these partition cells by means of the cell IDs.

Partitioned layout calculation needs a PartitionGrid object and the mapping of nodes to cells provided to the layout algorithm via supplemental layout data.

Basically, the partition grid needs to be created, and the PartitionGridData that holds the necessary information about the partition grid and the mapping of nodes to cells has to be created, filled and assigned to the HierarchicLayoutData.

This process is demonstrated in the following example:

Swimlane/partitioned layout preparation (IGraph API)
const graph = getMyGraph()
// Nodes 'n1' and 'n2' to 'n6' (not shown here).
const n1 = getMyNode()

// Create a grid having three rows and four columns.
const grid = new PartitionGrid(3, 4)

// Create an IMapper to store the mapping of nodes to swimlanes, resp. partition
// grid cells.
const cellMap = new Mapper()

// Assign the nodes to the cells.
cellMap.set(n1, grid.createCellId(1, 0))
cellMap.set(n2, grid.createCellId(0, 1))
cellMap.set(n3, grid.createCellId(2, 2))
cellMap.set(n4, grid.createCellId(1, 3))
cellMap.set(n5, grid.createCellId(0, 3))
cellMap.set(n6, grid.createCellId(0, 3))

// Create the layout data for the partition grid and assign the cellMapping and the grid to it.
const partitionGridData = new PartitionGridData({
  grid: grid,
  cellIds: cellMap
})

// Create the supplemental layout data for the hierarchic layout ...
const layoutData = new HierarchicLayoutData({
  // ... and set the layout data for the partition grid accordingly.
  partitionGridData: partitionGridData
})

// Create the layout algorithm...
const hl = new HierarchicLayout()
hl.layoutOrientation = LayoutOrientation.LEFT_TO_RIGHT
// ... and start layout calculation.
graph.applyLayout(hl, layoutData)
const graph = getMyGraph()
// Nodes 'n1' and 'n2' to 'n6' (not shown here).
const n1 = getMyNode()

// Create a grid having three rows and four columns.
const grid = new PartitionGrid(3, 4)

// Create an IMapper to store the mapping of nodes to swimlanes, resp. partition
// grid cells.
const cellMap = new Mapper<INode, PartitionCellId>()

// Assign the nodes to the cells.
cellMap.set(n1, grid.createCellId(1, 0))
cellMap.set(n2, grid.createCellId(0, 1))
cellMap.set(n3, grid.createCellId(2, 2))
cellMap.set(n4, grid.createCellId(1, 3))
cellMap.set(n5, grid.createCellId(0, 3))
cellMap.set(n6, grid.createCellId(0, 3))

// Create the layout data for the partition grid and assign the cellMapping and the grid to it.
const partitionGridData = new PartitionGridData({
  grid: grid,
  cellIds: cellMap
})

// Create the supplemental layout data for the hierarchic layout ...
const layoutData = new HierarchicLayoutData({
  // ... and set the layout data for the partition grid accordingly.
  partitionGridData: partitionGridData
})

// Create the layout algorithm...
const hl = new HierarchicLayout()
hl.layoutOrientation = LayoutOrientation.LEFT_TO_RIGHT
// ... and start layout calculation.
graph.applyLayout(hl, layoutData)

Note that Swimlane/partitioned layout preparation (IGraph API) shows the basic setup of the partition grid seen in Partition grid. Observe how the layout algorithm respects the specified organization of the nodes within the partition cells.

Partition Grid

For the calculation of a swimlane/partitioned layout, HierarchicLayout uses the information in the so-called partition grid.

Class PartitionGrid encapsulates a simple grid-like structure consisting of rows and columns. In addition to the structure itself, the partition grid also holds geometric information related to both rows and columns, like, e.g. minimum heights/widths or insets.

The geometric information specific to a row or column is available through its descriptor object, which is an instance of RowDescriptor or ColumnDescriptor, respectively.

PartitionGrid creates IDs for the cells of a partition, which result from the rows and columns. Most notably, these IDs are used to assign the nodes of a diagram to the partition cells.

createCellId(rowIndex: number, columnIndex: number): PartitionCellId
Creates partition cell IDs for use with the nodes of a diagram.

Since group nodes in a swimlane diagram are allowed to stretch across multiple lanes, they can also be assigned to a (two-dimensional) range of cells.

createCellSpanId(fromRowIndex: number, fromColIndex: number, toRowIndex: number, toColIndex: number): PartitionCellId
Creates partition cell IDs for use with the group nodes of a diagram. The cell ID represents a (two-dimensional) range of cells stretching the specified rows and columns.

The PartitionGrid object enables further configuration of the layout outcome. The following properties can be used to control whether the order of rows and columns in a swimlane layout shall be automatically determined.

optimizeRowOrder
Optimize the order of rows to minimize the diagram’s overall edge lengths.
optimizeColumnOrder
Optimize the order of columns to minimize the diagram’s overall edge lengths.

To specify a swimlane/partitioned layout, provide supplemental layout data to the layout algorithm. The most convenient way is the layout data class PartitionGridData, which is a container for the partition grid and the mapping of the nodes to the cells.

HierarchicLayout’s support for partitioned layout covers the configuration options below for normal nodes and group nodes. Depending on the kind of partition cell ID that is associated with a normal node, the layout algorithm will place the normal node:

  • none in a suitable partition cell of the partition grid structure
  • Single cell in the specified partition cell of the partition grid structure
  • Range of cells into one of the partition cells of the specified range

Depending on the kind of the partition cell ID that is associated with a group node, the layout algorithm will place the group node such that:

  • none it encompasses all its contained nodes. If they are in multiple cells, the group node stretches across these cells.
  • Single cell its boundary corresponds to the bounds of the specified partition cell, independent of the cells of its contained nodes
  • Range of cells its boundary corresponds to the smallest rectangle encompassing the partition cells of the specified range, independent of the cells of its contained nodes

When using the Single cell and Range of cells partition cell ID configurations for a group node, all its contained nodes need to have corresponding partition cell ID configurations (i.e., the cell ID of the group node isn’t automatically assigned to its content).

Tabular Groups

For horizontal layout orientations, a group node may be drawn as a single-column table, with the child nodes considered to be table entries. More precisely, the child nodes are placed in a compact style within the same layer with a distance defined by tabularGroupChildDistance. Edges usually connect to the child nodes. A tabular group may contain nested groups that always behave like tabular groups as well.

Typical applications for such structures are the visualization of database schemas or uml class diagrams (see example below).

Tabular Group Node Examples
A database schema visualized using hierarchic layout with tabular groups
A UML class diagram visualized with nested tabular groups
A generic example that shows tabular groups with edge labels

As shown in the following snippet, marking a group as a tabular group is achieved via the property tabularGroups.

Mark Groups as Tabular Groups
// Mark a group node as tabular group
hierarchicLayoutData.tabularGroups = ItemCollection.from([groupNode])

Note that the general layout orientation implies the orientation of the table. A horizontal LayoutOrientation (e.g., left-to-right) leads to single-column tables, whereas a vertical orientation leads to single-row tables. In any case, the children of a tabular group node are always placed on the same layer.

Ordering of Children inside a Tabular Group

By default, the algorithm chooses an order of the children within a tabular group such that the number of implied edge crossings is low. To obtain specific orders sequence constraints may be added or, as an alternative, a custom IComparer<T> may be specified, as shown in the snippet below.

Ordering Nodes inside a Table
// Use a comparator to arrange the children alphabetically by their label
// Note that you can specify different orders for different tabular groups, if desired
hierarchicLayoutData.tabularGroupChildComparers.constant = (child1, child2) =>
  child1.labels.first().text.localeCompare(child2.labels.first().text)
// Use a comparator to arrange the children alphabetically by their label
// Note that you can specify different orders for different tabular groups, if desired
hierarchicLayoutData.tabularGroupChildComparers.constant = (child1: INode, child2: INode) =>
  child1.labels.first().text.localeCompare(child2.labels.first().text)

Note that when a custom Comparer is specified for a tabular group, it is only applied to the group’s direct children. To use a custom Comparer for all descendants, i.e., the children of nested groups as well, the Comparer needs also be attached to those nested group nodes. If all groups use the same ordering, the process can be simplified by using a constant mapping.

Further Notes on Tabular Groups

There are some setups for which a tabular group may not be tight (i.e., maximally compact):

  • If edges directly connect to a tabular group (not to its content), then it is not guaranteed that the group becomes maximally compact.
  • The same is true if there are children with self-loops. Such self-loops are always drawn within the tabular group.
  • In addition, labels of edges connecting two children of the same tabular group may intersect with other edge segments.

Besides, the groups may not be tight if there are user specified constraints like node halos, node labels that exceed the size of the associated child node, and port constraints connecting to a side orthogonal to the layout orientation.

Critical Paths

HierarchicLayout provides functionality that allows to align nodes that are part of so-called critical paths. This feature can be used to emphasize relevant edge paths in a diagram.

Alignment of nodes of a critical path
Usual hierarchical layout (i.e. without taking critical paths into account).
Resulting hierarchical layout where the nodes of a critical path are aligned.

A critical path in a graph is unambiguously defined by its edges. By means of supplemental layout data, each edge of a critical path is assigned a positive, non-zero integral value. The value denotes that an edge is part of a critical path. It also serves to define the priority of the edge, respectively the priority of the critical path itself, if edges from different critical paths connect to a common node. Then, the edge with the highest priority determines the actual nodes to align.

To further emphasize the importance of an edge, it can also get higher crossing costs, making a crossing with the edge less likely. Edges of a critical path do not automatically get higher crossing costs. See Edge Crossing Costs for more information about the crossing cost feature.

Edge Crossing Costs

Edge crossings with a certain edge can have a custom cost. This is considered by the crossing minimization phase of HierarchicLayout. During this phase, the considered cost for two crossing edges is the product of both edge’s crossing costs.

Specifying individual costs influences the sequencing of the nodes and allows to treat some edges with higher priority than others, because higher crossing costs mean that it is less likely that an edge will cross with others. Note however, that the crossing minimization is a heuristic and it can never be guaranteed that a certain edge is not crossed, no matter how high the costs are.

Crossing costs are defined by means of supplemental layout data (cf. HierarchicLayoutData.edgeCrossingCosts).

Crossing costs with group borders

Crossing costs can also be defined for edges that may cross group node borders. This applies only for vertical group node borders if the layout orientation is vertical and only for horizontal group node borders if the layout orientation is horizontal. This way, it can be specified how undesirable it is if an edge crosses through a group node where it does not start or end. By default, crossing a group node border is more expensive than crossing another edge. The costs can be customized by means of supplemental layout data (see also property groupBorderCrossingCosts).

Node Halos

HierarchicLayout by default supports node halos as soon as they are declared. During layout calculation, it takes any specified additional padding around nodes into consideration and keeps the areas clear of other graph elements. The labels of a node and its adjacent edge segments are not affected and can still be placed inside or cross the node’s halo.

Node halos are specified by means of supplemental layout data.

NodeLayoutDescriptor and EdgeLayoutDescriptor

Classes NodeLayoutDescriptor and EdgeLayoutDescriptor (together with class RoutingStyle) can be used to configure node-related and edge-related layout and drawing options. For example, the following options can be set for nodes and edges, respectively:

  • relative alignment of nodes within their layer
  • preferred minimum distance from obstacles (both nodes and edges)
  • different routing styles for edges
  • minimum length of first and last edge segment, respectively

The NodeLayoutDescriptor provides a number of options for node configuration:

Layer Alignment
layerAlignment
Determines the alignment of a node within its layer. Values can be set from 0.0 (top) to 1.0 (bottom). See also Node-related layout and drawing options.
Minimum Layer Height
minimumLayerHeight
Determines the minimum height of the layer this node is assigned to. See also Node-related layout and drawing options.
Minimum Distance from Obstacles
minimumDistance
Determines the preferred minimum distance.
Node Label Mode
nodeLabelMode
Determines the consideration of node labels during the layout. See also Node label modes.

For grid placement support in particular, these options are available:

Grid Reference Point
gridReference
Determines a node’s reference point, which shall be placed on grid coordinates. By default, a node’s center is used as its reference point.
Port Assignment Policy
portAssignment
Sets the port assignment policy for a given node. The policy determines how the edges at each side of the node will be distributed along the respective side.

A NodeLayoutDescriptor instance can be specified individually for single nodes by means of supplemental layout data, for example by setting the nodeLayoutDescriptors property on the HierarchicLayoutData. In the absence of an individual descriptor for a node, the default NodeLayoutDescriptor instance that is registered with HierarchicLayout will be used.

Node-related layout and drawing options illustrates layer-related options from NodeLayoutDescriptor. In the left figure, the second and third node are aligned topmost in their layer. In the right figure, the same nodes are still aligned topmost, however the minimum layer height has been set to a value larger than the biggest node.

Node label modes illustrates the results for different node label modes when calculating a hierarchical layout. The figures show, from left to right, a long node label and how it is considered for the layout using different settings available with NodeLayoutDescriptor. Note that the second figure shows the result with NodeLayoutDescriptor’s default setting.

Node label modes
Node labels never considered,…​
considered (the default), …​
…​ considered for self-loops also.

The edge layout can be configured using class EdgeLayoutDescriptor together with class RoutingStyle:

Routing Style
routingStyle
Configures the routing style for different edge types.
Minimum Length of First and Last Segment
minimumFirstSegmentLength
minimumLastSegmentLength
Determine the minimum length of the first (at the source) and last (at the target) edge segment.
Minimum Length and Slope (Polyline Routing)
minimumLength
minimumSlope
Determine the minimum length and the minimum slope of the edge’s mid segments in a vertical layout. Applies only to polyline routing style.
Minimum Distance to Obstacles
minimumDistance
Determines the preferred minimum distance to obstacles.
Recursive Edges Routing
recursiveEdgeStyle
Configures how edges connecting nodes that belong to different groups are routed.

An EdgeLayoutDescriptor instance can be specified individually for single edges by means of supplemental layout data, for example by setting the edgeLayoutDescriptors property on the HierarchicLayoutData. In the absence of an individual descriptor for an edge, the default EdgeLayoutDescriptor instance that is registered with HierarchicLayout will be used.

In conjunction with EdgeLayoutDescriptor, class RoutingStyle enables configuration of different edge routing styles for different edge types like backloop edges, same-layer edges, self-loops, and edges in edge groups. By default, the routing style that is given at creation time of a RoutingStyle instance is set uniformly for all edge types. The following properties can be used to set different styles:

backLoopRoutingStyle
edgeGroupRoutingStyle
sameLayerEdgeRoutingStyle
selfLoopRoutingStyle
Edge routing style configuration for different edge types.

Edge routing options illustrates routing style-related options from EdgeLayoutDescriptor. The figures show the different routing style options available.

Edge routing options
Polyline edge routing
Orthogonal edge routing
Octilinear edge routing
Curved edge routing

Edge-related layout and drawing options illustrates different minimum lengths settings for the first and last edge segments when calculating a hierarchical layout.

Edge-related layout and drawing options
First and last segment length: 0px
First and last segment length: 15px

Polyline edge routing style is the default setting that is used by the default EdgeLayoutDescriptor for all edge types.

To specify individual layout settings for nodes and edges, provide supplemental layout data for node layout descriptors and edge layout descriptors.

SimplexNodePlacer

Class SimplexNodePlacer is the default INodePlacer implementation that is used by HierarchicLayout during the drawing phase. It can be retrieved via the nodePlacer property.

Most notably, SimplexNodePlacer provides support for symmetric placement of nodes where possible.

barycenterMode
Enables drawing phase support for symmetric placement of nodes.

SimplexNodePlacer also provides an optional post-processing step that tries to remove bends from edges in order to straighten their paths.

straightenEdges
Enables drawing phase support for optimized edge paths.

Additionally, it makes available drawing phase options that can be used in conjunction with grouped graphs.

groupCompactionStrategy
Allows to control whether the horizontal space occupied by group node content should be compacted.

The following setter can be used to place adjacent edge labels in a compact, stacked style:

labelCompaction
Determines whether adjacent edge labels shall be placed in a compact manner.

Applicable Layout Stages

Layout Stages lists layout stages that can be used to enhance the layout process of class HierarchicLayout.

Layout Stages
Class Name Description
TopLevelGroupToSwimlaneStageEnables convenient swimlane setup using plain group nodes instead of a partition grid.

TopLevelGroupToSwimlaneStage is an alternative to explicitly setting up swimlanes using a partition grid as described in Swimlanes. It presents a convenient means for specifying the setup for a swimlane layout using plain group nodes.

Each top-level group node is interpreted as holding the contents for one swimlane, i.e., all nodes within such a group node are assigned to the same lane when calculating the swimlane layout. Naturally, this approach supports only swimlane setups where neither group nodes nor folder nodes stretch across multiple lanes.

Tutorial Demo Code

Using both the incremental as well as the non-incremental layout functionality of class HierarchicLayout is presented in detail in the following tutorial demo applications:

Layout setup for a diagram with swimlane nodes can be observed in tutorial demo application Table Editor.

Layout Data

When using class HierarchicLayout, supplemental layout data for a graph’s elements can be specified either by using class HierarchicLayoutData or by registering data providers with the graph using given look-up keys. Supplemental layout data lists all properties of HierarchicLayoutData and the corresponding look-up keys that HierarchicLayout tests during the layout process in order to query supplemental data.

Providing supplemental layout data is described in detail in Layout Data.

Supplemental layout data

incrementalHints
For each incrementally added node or edge a hint object that marks the respective graph element to be inserted into the hierarchical layout in an optimal manner. The hint object is created by a hint factory, like, e.g., the hint factory that is returned by method createIncrementalHintsFactory.
Data Provider Key: INCREMENTAL_HINTS_DP_KEY
Maps from node, edge to Object
nodeLayoutDescriptors
For each node a NodeLayoutDescriptor object that configures a number of node-related options.
Maps from node to NodeLayoutDescriptor
edgeLayoutDescriptors
For each edge an EdgeLayoutDescriptor object that configures a number of edge-related options.
Maps from edge to EdgeLayoutDescriptor
sourceGroupIds
For each edge an arbitrary Object indicating the group its source end is affiliated with.
Data Provider Key: SOURCE_GROUP_ID_DP_KEY
Maps from edge to Object
targetGroupIds
For each edge an arbitrary Object indicating the group its target end is affiliated with.
Data Provider Key: TARGET_GROUP_ID_DP_KEY
Maps from edge to Object
sourcePortGroupIds
For each edge an arbitrary Object indicating the port group its source end is affiliated with.
Data Provider Key: SOURCE_PORT_GROUP_ID_DP_KEY
Maps from edge to Object
targetPortGroupIds
For each edge an arbitrary Object indicating the port group its target end is affiliated with.
Data Provider Key: TARGET_PORT_GROUP_ID_DP_KEY
Maps from edge to Object
buses
For each edge a bus descriptor indicating the bus structure this edge belongs to.
Data Provider Key: BUS_DESCRIPTOR_DP_KEY
Maps from edge to BusDescriptor
busRootOffsets
For a bus structure node the layer offset with respect to the layer of the root node of the bus that the node belongs to.
Data Provider Key: ROOT_OFFSET_DP_KEY
Maps from node to Integer
nodesBeforeBus
For marking the bus structure nodes that should be placed before the common bus segment.
Data Provider Key: PLACE_BEFORE_BUS_DP_KEY
Maps from node to boolean
tabularGroups
For marking the group nodes which are handled as tabular groups.
Data Provider Key: TABULAR_GROUPS_DP_KEY
Maps from node to boolean
tabularGroupChildComparers
For each tabular group node a IComparer<T> that is used to sort children of the table group node.
Maps from node to Comparer
sourcePortConstraints
For each edge a PortConstraint object encoding its source end’s port constraint.
Maps from edge to PortConstraint
targetPortConstraints
For each edge a PortConstraint object encoding its target end’s port constraint.
Maps from edge to PortConstraint
nodePortCandidateSets
For each node a PortCandidateSet object encoding the set of allowed anchor locations for edges.
Maps from node to PortCandidateSet
sourcePortCandidates
For each edge a ICollection<T> of PortCandidate objects that encode the subset of desired anchor locations where the source port likes to connect to.
Maps from edge to Collection
targetPortCandidates
For each edge a ICollection<T> of PortCandidate objects that encode the subset of desired anchor locations where the target port likes to connect to.
Maps from edge to Collection
layerConstraintFactory
For the graph a token that allows to bind a constraint factory.
Maps from graph to Object
sequenceConstraintFactory
For the graph a token that allows to bind a constraint factory.
Maps from graph to Object
nodeTypes
For each node an arbitrary Object indicating the node’s type, see Layout with Custom Node Types for more details.
Data Provider Key: NODE_TYPE_DP_KEY
Maps from node to Object
GROUP_DP_KEY
For each node a boolean value indicating whether it is a group node or not.
Data Provider Key: GROUP_DP_KEY
Maps from node to boolean
folderNodes
For marking folder nodes.
Data Provider Key: FOLDER_NODES_DP_KEY
Maps from node to boolean
NODE_ID_DP_KEY
For each node an Object that serves as a unique ID.
Data Provider Key: NODE_ID_DP_KEY
Maps from node to Object
PARENT_NODE_ID_DP_KEY
For each node an Object indicating the group node it belongs to. The Object matches the unique ID of a group node that is in the same graph.
Data Provider Key: PARENT_NODE_ID_DP_KEY
Maps from node to Object
MINIMUM_NODE_SIZE_DP_KEY
For each group node a YDimension object that specifies the group node’s minimum size constraint.
Data Provider Key: MINIMUM_NODE_SIZE_DP_KEY
Maps from node to YDimension
layerIndices
The layout algorithm writes an integer value for each node. The value represents the index of the actual layer a node has been assigned to.
Data Provider Key: LAYER_INDEX_DP_KEY
Maps from node to Integer
sequenceIndices
The layout algorithm writes an integer value for each node. The value represents the index of the node inside the sequence of the according layer a node has been assigned to.
Data Provider Key: SEQUENCE_INDEX_DP_KEY
Maps from node to Integer
givenLayersLayererIds
For each node a non-negative integer value representing the layer ID of each node.
Data Provider Key: LAYER_ID_DP_KEY
Maps from node to Integer
criticalEdgePriorities
For each edge of a critical path a positive, non-zero integral value that indicates the priority of the edge/the critical path.
Maps from edge to int
edgeCrossingCosts
For each edge a positive floating point value defining the cost for crossing the edge or zero if crossing the edge should not be punished during the edge crossing minimization phase.
Data Provider Key: EDGE_CROSSING_COST_DP_KEY
Maps from edge to double
groupBorderCrossingCosts
For each group node a positive floating point value defining the cost for an edge crossing through the group node border.
Maps from node to double
nodeHalos
A NodeHalo object that specifies the halo sizes at each side of a node.
Data Provider Key: NODE_HALO_DP_KEY
Maps from node to NodeHalo
abortHandler
An AbortHandler instance that will be queried by the layout algorithm to determine whether layout calculation shall be terminated.
Data Provider Key: ABORT_HANDLER_DP_KEY
Maps from graph to AbortHandler
edgeThickness
For each edge a non-negative floating point value that indicates the edge’s thickness.
Data Provider Key: EDGE_THICKNESS_DP_KEY
Maps from edge to number
edgeDirectedness
For each edge a floating point value that indicates the directedness of the edge.
Data Provider Key: EDGE_DIRECTEDNESS_DP_KEY
Maps from edge to number
subcomponents
For each subcomponent (a collection of nodes) a subcomponent descriptor that should be applied to it.
Maps from collection of nodes to HierarchicLayoutSubcomponentDescriptor
bfsLayererCoreNodes
For identifying the core nodes of the BFS layering.
Data Provider Key: CORE_NODES_DP_KEY
Maps from node to boolean
alternativeEdgePaths
For each edge an alternative path connecting to the content of the expanded/collapsed group.
Data Provider Key: ALTERNATIVE_EDGE_PATH_DP_KEY
Maps from node to YPointPath
alternativeGroupBounds
For each group node, the original size of the group (before expanding/collapsing).
Maps from node to YRectangle
partitionGridData
Specifies a PartitionGrid for the hierarchic layout.
PartitionGridData.grid
Specifies the partition grid structure for the graph. Can also be defined using the rowIndices and columnIndices properties.
Data Provider Key: PARTITION_GRID_DP_KEY
Maps from graph to PartitionGrid
PartitionGridData.cellIds
Specifies the partition cell id for a node. Alternatively, cell indices for a node can be specified using the rowIndices and columnIndices properties.
Data Provider Key: PARTITION_CELL_ID_DP_KEY
Maps from node to PartitionCellId
selfLoopCalculatorData
Specifies settings for routing self-loops (i.e. edges that have the same source and target node).
SelfLoopCalculatorData.octilinearEdges
For specifying which self-loops should be octilinear.
Data Provider Key: OCTILINEAR_EDGES_DP_KEY
Maps from edge to Collection
SelfLoopCalculatorData.minimumOctilinearSegmentLengths
For each octilinear self-loop a double value that specifies the minimum length of its octilinear segments.
Maps from edge to double
SelfLoopCalculatorData.minimumNodeDistances
For each node a double value that specifies the minimum distance to the self-loop edges.
Data Provider Key: MINIMUM_NODE_DISTANCE_DP_KEY
Maps from node to double
SelfLoopCalculatorData.minimumEdgeDistances
For each edge a double value that specifies the minimum distance to the next edge or node side.
Data Provider Key: MINIMUM_EDGE_DISTANCE_DP_KEY
Maps from edge to double
SelfLoopCalculatorData.minimumFirstSegmentLengths
For each self-loop a double value that specifies the minimum length of its first segment.
Maps from edge to double
SelfLoopCalculatorData.minimumLastSegmentLengths
For each self-loop a double value that specifies the minimum length of its last segment.
Maps from edge to double

Setup of a grouped graph’s hierarchy of nodes (using GROUP_DP_KEY, NODE_ID_DP_KEY, and PARENT_NODE_ID_DP_KEY) is done transparently by the IGraph-related adapter mechanisms. See also Layout of Grouped Graphs and Applying an Automatic Layout.