Concepts

The task of a layout algorithm is a major undertaking that involves arbitrarily complex logic. However, there can be identified a number of well-defined (sub-)tasks that even completely different algorithms do in a similar manner. Factoring out such tasks so that they can be reused in varying contexts, greatly reduces the complexity of any layout algorithm.

The yFiles library allows to formulate complex layout processes by plugging together so-called "layout stages" that, among other things, can be used to handle such well-defined (sub-)tasks.

The Layout Stages Concept

A layout stage serves as a kind of container that encapsulates arbitrary layout functionality, and provides a general means to string together multiple stages into a compound layout process. Interface LayoutStage defines the basis for a layout stage. It is a specialization of interface Layouter, and thus can be used as a stand-alone layout provider as well as a part of a larger layout process.

Figure 5.2. LayoutStage

LayoutStage.

The methods of interface LayoutStage are used to establish a relationship to another Layouter implementation, the so-called "core layouter." The core layouter's invocation is entirely bracketed by the layout stage's logic.

When used in the context of a larger layout process, the layout stage can easily be used to simplify the core layouter's task. It performs preprocessing steps on the input graph before the core layouter's invocation, and postprocessing steps thereafter.

Table 5.1, “Predefined layout stages” lists some of the predefined LayoutStage implementations, most of them being part of the default compound layout process as described below. Further layout stages are described in the section called “Layout Stages”.

Table 5.1. Predefined layout stages

Classname Description
SelfLoopLayouter Calculates orthogonal edge paths for a graph's self-loops (reflexive edges).
ParallelEdgeLayouter Calculates edge paths for all edges with identical source node and target node. (Self-loops are not processed.)
OrientationLayouter Changes the orientation of a computed layout.
SubgraphLayouter Reduces the original graph to the subgraph that is induced by selected nodes.

Figure 5.3, “Layout stages complex” shows the class hierarchy for the layout stages.

Figure 5.3. Layout stages complex

Layout stages complex.

Default Compound Layout Process

The most prominent example for a complex layout process can be observed with abstract class CanonicMultiStageLayouter. It is the superclass for the yFiles major layout algorithms, and provides a conveniently configurable layout pipeline for performing preprocessing steps on the input graph before the core layouter's invocation, and postprocessing steps thereafter. The central role of CanonicMultiStageLayouter can also be seen in Figure 5.10, “The yFiles layout algorithms”.

All layout stages from Table 5.1, “Predefined layout stages” are part of the compound layout process defined by CanonicMultiStageLayouter. The following methods and properties of class CanonicMultiStageLayouter can be used for configuring the layout process:

appendStage(stage:LayoutStage):void
prependStage(stage:LayoutStage):void
removeStage(stage:LayoutStage):void
Description Methods to add and remove individual layout stages.
enableOnlyCore():void
componentLayouterEnabled:Boolean
selfLoopLayouterEnabled:Boolean
Description Methods and properties for enabling and disabling the predefined layout stages, and also for controlling their enabled state. (Excerpt.)
componentLayouter:LayoutStage
selfLoopLayouter:LayoutStage
Description Properties for predefined layout stages. (Excerpt.)

Providing Supplemental Layout Data

The yFiles layout algorithms support advanced functionality that can take into account even individual information for single graph elements. However, individual setup like, e.g., attaching a preferred edge length to each edge, is beyond the means a graph structure provides. Instead, a data provision scheme is used to provide the individual setup as supplemental information to a layout algorithm.

The supplemental data for the graph elements is bound to the graph using a so-called "data provider key." During layout calculation, the algorithm then retrieves the data provider that contains the data from the graph by using the same key.

Depending on the data provider key, the algorithm expects the returned data provider to hold values of specific type for either nodes or edges of the graph. Example 5.3, “Binding supplemental data (IGraph API)” shows the use of an IMapper as the data provider for an IGraph-based graph. The mapper returns an integral value for each edge indicating the edge's preferred length to the organic layout algorithm.

Example 5.3. Binding supplemental data (IGraph API)

public class MyIMapper implements IMapper {

    private var _myGetLength:Function;

    public function MyIMapper( myGetLength:Function ) {
        this._myGetLength = myGetLength;
    }

    public function lookupValue(key:Object):Object {
        return int(200 * this._myGetLength(IEdge(key)));
    }

    public function mapValue(key:Object, value:Object):void {}

    public function unMapValue(key:Object):void {}
}

// 'graph' is of type com.yworks.graph.model.IGraph.

// Create an implicit IMapper and add it to the mapper registry of the graph
// using a so-called data provider look-up key as its tag.
// The key is then used by the layout algorithm to retrieve the supplemental
// data.
graph.mapperRegistry.addMapper(SmartOrganicLayouter.PREFERRED_EDGE_LENGTH_DATA,
                               // getLength: a Function that takes an IEdge and
                               // returns an int
                               new MyIMapper( getLength ));

            // Invoke organic layout on the graph.
var sol:SmartOrganicLayouter = new SmartOrganicLayouter();
CopiedLayoutIGraph.applyLayout(graph, sol);

Abort Mechanism for Layout Calculations

Class AbortHandler provides an abort mechanism for layout calculations. In a single-threaded execution environment, the abort handler can be used to specify a runtime threshold after which this mechanism will early terminate or instantly terminate a layout calculation.

The abort handler for a graph is specified through a data provider that is bound to the graph. The data provider is expected to be registered with the graph using key ABORT_HANDLER_DPKEY. Once an abort handler is attached to a graph, any layout algorithm with support for the abort mechanism working on this graph can be stopped or canceled via the abort handler.

createForGraph(graph:LayoutGraph):AbortHandler
Description Returns a graph's attached abort handler or creates a new one and attaches it.
stopDuration:uint
cancelDuration:uint
Description Properties to specify runtime thresholds (in milliseconds) before terminating a layout calculation. A value of 0 means no premature termination.

Specifying a stop duration for a layout calculation results in early, but not immediate, termination of the layout run after the given runtime has elapsed. The layout algorithm will still deliver a consistent result.

Specifying a cancel duration for a layout calculation, in contrast, will end layout calculation instantly after the given runtime has elapsed. The layout algorithm will throw an AlgorithmAbortedException and all work done so far by the algorithm will be discarded. This may lead to an inconsistent state of the graph. It is thus recommended to only cancel layout algorithms that work on a copy of the graph to avoid corrupting the original graph.

Furthermore, when layout calculation is ended instantly, the state of the ILayouter instance may become corrupted. Hence, a new instance has to be created after each cancelation.

In a single-threaded execution environment, it is important to reset the AbortHandler before each new layout calculation in order to update the handler's internal start time:

reset():void
Description Resets the abort handler's internal start time.

Automatic layout calculation for a diagram in conjunction with an abort handler that has a runtime threshold configured can be conveniently invoked using class LayoutExecutor as outlined in the following code snippet. LayoutExecutor uses the given AbortHandler object and performs all necessary setup prior to the layout calculation. It registers a data provider holding the abort handler with the proper graph and also resets the abort handler's state.

Example 5.4. Using an abort handler in conjunction with class LayoutExecutor

// 'graphCanvas' is of type com.yworks.ui.GraphCanvasComponent.

// Create a layout algorithm.
var ihl:IncrementalHierarchicLayouter = new IncrementalHierarchicLayouter();

// Create an abort handler.
var handler:AbortHandler = new AbortHandler();

// Specify a runtime threshold before the layout algorithm is stopped...
handler.stopDuration = 30000;

// ... OR specify a runtime threshold before it is canceled.
handler.cancelDuration = 30000;

try {
  var layoutExecutor:LayoutExecutor = new LayoutExecutor(graphCanvas, ihl);
  // Use the abort handler created before.
  layoutExecutor.abortHandler = handler;
  
  layoutExecutor.duration = 500;
  layoutExecutor.updateContentRect = true;
  
  // Start layout.
  layoutExecutor.start();
}
catch (exception:Error) {
  trace(exception);
}

The following layout algorithms and routing algorithms of the yFiles FLEX library have built-in support for the abort mechanism:

Table 5.2. Support for abort mechanism in yFiles algorithms

  Classname
Layout algorithms IncrementalHierarchicLayouter
CircularLayouter
SmartOrganicLayouter
OrthogonalLayouter, OrthogonalGroupLayouter, DirectedOrthogonalLayouter, and CompactOrthogonalLayouter
Layout stages ComponentLayouter
ParallelEdgeLayouter
Routing algorithms EdgeRouter