Class HierarchicLayouter
is
a layout algorithm that portraits the precedence relation of directed graphs.
It is ideal for many application areas, including, e.g.:
The hierarchical layout algorithm aims to highlight the main direction or flow within a directed graph. Cyclic dependencies of nodes will be automatically detected and resolved. Nodes will be placed in hierarchically arranged layers. Additionally, the ordering of the nodes within each layer is chosen in such a way that the number of line (or edge) crossings is small. Edge routing can be polyline, orthogonal, or in a curved style.
Figure 5.20. Sample layouts produced by class HierarchicLayouter
|
|
|
|
| Problem solving at yWorks (just kidding ;-) | Entity-Relationship Diagram. | Displays pathways of the brain, layered by stages of visual processing. |
Class HierarchicLayouter implements interface
PortConstraintKeys
and uses the data
provider keys which are defined therein to retrieve supplemental layout data
for a graph's elements.
Also used are further data provider keys defined by a number of classes from
package
y.layout.hierarchic
.
The data is bound to the graph by means of a data provider, which is registered
using a given look-up key.
Table 5.17, “Data provider look-up keys” lists all look-up keys for
HierarchicLayouter.
Binding supplemental layout data to a graph is described in the section called “Providing Supplemental Layout Data”.
Table 5.17. Data provider look-up keys
| Key | Element Type | Value Type | Description |
|---|---|---|---|
| SOURCE_GROUPID_KEY |
Edge | Object | For each edge an arbitrary Object indicating the group its source end is affiliated with. |
| TARGET_GROUPID_KEY |
Edge | Object | For each edge an arbitrary Object indicating the group its target end is affiliated with. |
| SOURCE_PORT_CONSTRAINT_KEY |
Edge | PortConstraint | For each edge a PortConstraint object encoding its source end's port constraint. |
| TARGET_PORT_CONSTRAINT_KEY |
Edge | PortConstraint | For each edge a PortConstraint object encoding its target end's port constraint. |
| CORE_NODES |
Node | boolean | For each node a boolean value indicating whether it should be placed into the first layer. |
| LAYER_ID_KEY |
Node | int | For each node an integral value indicating the layer number it should be placed into. |
| EDGE_LABEL_LAYOUT_KEY |
Edge | LabelLayoutData[] | For each edge an array of LabelLayoutData objects that encode size and preferred placement for all labels of the edge. |
| GROUP_KEY |
Node | Number | For each node a Number object encapsulating an integral value that indicates the packed block the node is affiliated with. |
HierarchicLayouter can be configured and extended in diverse ways. This section highlights some of the configuration options available for this layouter.
Determines the minimal distance between nodes that reside in adjacent layers.
Determines the minimal distance between adjacent nodes that reside in the same layer.
Determines the distance between adjacent pairs of horizontal edge segments, and between horizontal edge segments and nodes.
Determines the minimal length of the first segment in an orthogonal edge routing. This applies to the routing of self-loops, same-layer edges, and orthogonal inter-layer edge routing.
Sets the maximal duration of the layout process in milliseconds. The maximal duration is a soft bound, which may be exceeded in case essential parts of the layout calculation are still missing. Most likely the layout quality will increase with a longer calculation period. In most cases the layouter will consume the complete time assigned to it.
Determines the main layout orientation. The layouter tries to arrange nodes in such a way that all edges point in the main layout direction.
Influences the horizontal spacing between nodes, the number of bends of the edges, and the overall balance of the layout.
Figure 5.21, “Different hierarchic layout styles” displays the effect of using different layout styles. There is a tradeoff involved between the straightness of edge paths and the compactness of the diagram.
Determines the edge routing style.
Figure 5.22, “Different routing styles and different edge path realizers” below shows the effect of different routing styles available for class HierarchicLayouter.
The visual representation of an edge (path) is defined by edge realizers, i.e.,
objects of type EdgeRealizer
from the
yFiles library package
y.view
.
Both type and configuration of a realizer object determine how to draw an edge
given its control points.
See also the section called “Edge Realizers” for descriptions of the yFiles predefined EdgeRealizer implementations.
Figure 5.22. Different routing styles and different edge path realizers
|
|
|
| ROUTE_ORTHOGONAL |
ROUTE_ORTHOGONAL |
If enabled, all edges that do not point in the main layout direction will be routed as back-loops. Back-loops start at the bottom side of their source node, then turn around 180 degrees, go upward, then turn around 180 degrees again and finally connect to the upper side of their target node.
HierarchicLayouter assigns the nodes to separate layers. The nodes within each layer will be placed on the same horizontal line. The layers will be numbered from 1 to maxLayer and arranged vertically starting with the small-numbered layers. The rank of a node is the number of the layer it belongs to.
An important layering strategy for the hierarchic layout style is called Hierarchical Layering. A hierarchical layering tries to assign nodes to layers in a way that as much as possible edges of the graph will point to the main layout direction, i.e., the start nodes of the edges will have a smaller rank than the corresponding end nodes. Also, a hierarchical layering will never put two connected nodes in the same layer.
To specify the ranks, a data provider holding such supplemental layout data
must be bound to the graph.
The data provider is expected to be registered with the graph using key
LAYER_ID_KEY
.
To specify nodes that should be place into the first layer, a data provider
holding such supplemental layout data can be bound to the graph.
The data provider is expected to be registered with the graph using key
CORE_NODES
.
Note that in the absence of such a data provider all nodes that have no
incoming edges are placed into the first layer.
Class ConstraintLayerer
is
an implementation of the Layerer interface that enables user-defined
constrained layering.
Nodes can be restricted to be placed either
The remaining nodes, that have no constraints defined, are processed by the core layerer that is set with ConstraintLayerer. By default, the core layerer uses the Tight Tree heuristic.
Figure 5.23, “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.
Figure 5.23. Constrained hierarchical layering
![]() |
![]() |
| Original hierarchical layout. | Resulting hierarchical layout where the constrained nodes are placed in the topmost layer. |
Example 5.19, “Setting the core layerer for ConstraintLayerer” presents how hierarchical layout is set up for constrained layer assignment where the previously configured Layerer implementation is used as ConstraintLayerer's core layerer. Nodes that have no constraints defined will be placed according to the layering strategy of this Layerer.
Example 5.19. Setting the core layerer for ConstraintLayerer
// Instantiate hierarchical layout and, in particular, configure the layerer. HierarchicLayouter hl = new HierarchicLayouter(); hl.setLayeringStrategy(HierarchicLayouter.LAYERING_HIERARCHICAL_DOWNSHIFT); // Instantiate a ConstraintLayerer. ConstraintLayerer cl = new ConstraintLayerer(); // Set the previously configured layerer as ConstraintLayerer's core layerer. cl.setCoreLayerer(hl.getLayerer()); // Set the ConstraintLayerer as the new layerer for hierarchical layout. hl.setLayerer(cl);
To express both absolute and relative constraints, ConstraintLayerer offers a so-called "constraint factory" which provides the methods for specifying constraints for the nodes of a graph. API Excerpt 5.6, “Getter method for ConstraintFactory” shows the static getter method for the constraint factory.
API Excerpt 5.6. Getter method for ConstraintFactory
// Getter for the constraint factory. static ConstraintFactory createConstraintFactory(Graph graph)
The returned constraint factory is specific for the graph given at instantiation. API Excerpt 5.7, “ConstraintFactory methods for specifying constraints” lists the methods that allow to define both absolute and relative constraints for nodes.
API Excerpt 5.7. ConstraintFactory methods for specifying constraints
// Absolute constraints. void addPlaceNodeAtTopConstraint(Node n) void addPlaceNodeAtBottomConstraint(Node n) // Constraints relative to a given reference node. void addPlaceNodeInSameLayerConstraint(Node reference, Node sameLayer) void addPlaceNodeAboveConstraint(Node reference, Node above) void addPlaceNodeBelowConstraint(Node reference, Node below)
Using class ConstraintLayerer in a hierarchical layout and defining constraints for the nodes of a graph is demonstrated in the tutorial demo application ConstraintLayererDemo.java.
This section describes options that influence the ordering of the nodes within a layer and thus the number of edge crossings of the resulting layout.
Within class HierarchicLayouter an implementation of the interface
LayerSequencer
is
responsible for determining the order of nodes within a layer.
The default implementation of this interface is
ClassicLayerSequencer
.
The options below describe some settings of this class.
Determines the strategy used to find a better node ordering within a layer.
If enabled, a postprocessing further reduces the number of edge crossings. The postprocessing step can be rather time consuming. This feature is disabled by default. It is advisable to activate this processing step for high quality layout results.
If enabled, a postprocessing step tries to eliminate all false edge crossings. A false edge crossing is an edge crossing between two edges that share a common terminal node.
The hierarchic layout algorithm can be configured to obey port constraints. Using port constraints for both ends of each edge in the graph it is possible to specify at which side of the source and target node an edge path must connect. This feature is supported for all different kinds of edges: ordinary edges, self-loops, and same layer edges.
The algorithm can be instructed to place each port at either the North, East, South, or West side of the node, or to choose the most appropriate side itself.
Opposed to "Weak Port Constraints," using "Strong Port Constraints" it is possible to not only specify the side of the node at which an edge must connect to it, but also the exact port position.
Both strong and weak port constraints can be mixed easily in the drawing. Strong port constraints are supported by all three types of edges.
Figure 5.25, “Constraint at which exact points edges should connect to nodes” demonstrates strong port constraints (the rather "odd" port positions have been set to be "strong").
A special feature of the hierarchical layout algorithm is its ability to group multiple ports (edge end points) together to be anchored at the same location. This can be specified for both source ports and target ports.
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 the same layer and belong to the same group, even if they do not share the same node at that end point, they will be merged together in a bus structure in that layer.
This highly versatile configuration policy can be used to specify different interesting edge routing behaviors. Some of them are shown in Figure 5.26, “Multiple different edge group configurations resulting in bus style edge routings”.
The hierarchical layout algorithm allows to bundle nodes within a layer to a so-called "packed block" of nodes. A packed block will always be placed as an inseparable unit on the layer. Note that this will only influence nodes that lie in the same layer. Figure 5.27, “Packed blocks” shows three packed blocks on different layers of the graph. In the figure, the blocks are emphasized both by an enclosing rectangle and also by different node colors.
To specify the packed block a node should be put into, a data provider holding
such supplemental layout data can be bound to the graph.
The data provider is expected to be registered with the graph using key
GROUP_KEY
.
Note that in the absence of the data provider no packed blocks are created.
Besides the general labeling support as described in the section called “General Labeling”, which is available with all yFiles layout algorithms, the hierarchical layout algorithm additionally features integrated labeling. Integrated labeling is available for edge labels, they are taken into consideration when determining both node placement and edge path generation. With this strategy it is guaranteed that no edge label will overlap other objects in the diagram.
Figure 5.28. Automatic edge labeling methods
![]() |
![]() |
| General edge labeling as a postprocessing step. Labels may overlap other objects. | Edge labeling as part of main layout procedure. Labels only overlap their associated edges. |
To specify size and preferred placement of edge labels when using integrated
labeling, a data provider holding such supplemental layout data must be bound
to the graph.
The data provider is expected to be registered with the graph using key
EDGE_LABEL_LAYOUT_KEY
.
Enabling integrated labeling with HierarchicLayouter and using the services of class LabelLayoutTranslator to conveniently have such a data provider created and bound to the graph is described in the section called “Integrated Labeling”.
Package
y.layout.hierarchic
contains all classes that constitute hierarchical layout.
The main layouter is encapsulated in the class
HierarchicLayouter
.
A variant of this class, that is capable of laying out hierarchically organized
graphs, is
HierarchicGroupLayouter.
The structure of the hierarchical layout implementation follows the Strategy
design pattern.
It is composed of implementations of the interface classes
Layerer
,
LayerSequencer
, and
Drawer
.
Each of which is responsible for a certain phase within the layout process.
Programmers can provide their specialized implementations of layout phases and
can thus customize and extend layout behavior in a very powerful way.
The following yFiles tutorial demo programs demonstrate how to use class HierarchicLayouter in an application context.
|
Copyright ©2004-2008, yWorks GmbH. All rights reserved. |