Interactive Organic Layout

Class InteractiveOrganicLayouter provides organic layout for use in interactive environments. Its strength is its capability to generate continuous updates to the layout of a graph during calculation. Furthermore, it also allows a user to seemingly simultaneously perform arbitrary modifications to a graph, which are subsequently accounted for in the layout calculation.

In contrast to the majority of yFiles layout algorithms, class InteractiveOrganicLayouter does not inherit from CanonicMultiStageLayouter, but is instead provided as an implementation of interface Layouter as depicted in Figure 5.59, “Interactive organic layout implementation”.

Figure 5.59. Interactive organic layout implementation

Interactive organic layout implementation.

Among other things, this means that there is no special support for routing of either self-loops or parallel edges, for example. In particular, when a graph contains parallel edges, they will be routed using overlapping edge paths.

General Usage

In the single-threaded Flash Player/ActionScript execution environment, InteractiveOrganicLayouter is designed to be used in a cooperative setup where the layout algorithm does its calculations in defined time slices after which it yields back control to the application. This enables an application that presents a graphical user interface (GUI) to the user to remain nearly fully interactive while the layout algorithm, at least perceived simultaneously, performs its calculations. This setup also enables modifications to the graph seemingly simultaneous to the layout calculation.

Setup

The setup for using interactive organic layout in a single-threaded execution environment needs an implementation of interface InteractiveOrganicLayouter_SingleThreadContext. This so-called context object is used to control the layout calculation. When starting the algorithm, class InteractiveOrganicLayouter returns an appropriate implementation:

startLayoutSingleThreaded(graph:LayoutGraph):InteractiveOrganicLayouter_SingleThreadContext
Description Starts the layout algorithm and creates the context object to control layout calculation.

Interface SingleThreadContext in particular defines the following method that can be used in an application to yield time to the layout algorithm:

doLayout(duration:uint):void
Description Triggers layout calculation lasting the specified amount of time.

If the graph that is to be processed by InteractiveOrganicLayouter is intended to allow structural modifications by a user, then it is strongly recommended to use an instance of CopiedLayoutGraph instead of a simple LayoutGraph. Doing so helps avoiding synchronization problems that occur when nodes and/or edges can be added to or removed from the graph while the layout algorithm performs its calculations.

Starting the layout algorithm using a copy of the original graph is shown in the following code snippet:

Example 5.25. Starting the layout algorithm

// create a copy of the graph for the layout algorithm
var adapter:LayoutGraphAdapter = new LayoutGraphAdapter(graph);
_copiedLayoutGraph = CopiedLayoutGraph.newCopiedLayoutGraph2(adapter, adapter);

// create the layouter
var organicLayouter:InteractiveOrganicLayouter = new InteractiveOrganicLayouter();
organicLayouter.maxTime = 2000;
// start the layouter for a single thread (see note 1) and retrieve the context
// to handle the layouter.
// (note 1): Flash is single threaded, so we don't have a choice here.
_layoutContext = organicLayouter.startLayoutSingleThreaded(_copiedLayoutGraph);

State

Interactive organic layout algorithm can be in either of three states: running, sleeping, or stopped. When running, the algorithm lives on the allowed maximal runtime and continuously calculates "intermediate" layouts for the given graph. When sleeping, the algorithm does nothing, but is still "alive." In contrast, when stopped, the algorithm is terminated. Figure 5.60, “State diagram for InteractiveOrganicLayouter” depicts the states and the possible state transitions of InteractiveOrganicLayouter.

Figure 5.60. State diagram for InteractiveOrganicLayouter

State diagram for InteractiveOrganicLayouter.

The following properties and methods can be used to query the current state of an InteractiveOrganicLayouter instance, change its state, and set the maximal runtime. Note that when an instance is changed from "sleeping" to "running" state, the maximal runtime is again fully available.

running:Boolean
sleeping:Boolean
stopped:Boolean
Description Properties to query the algorithm's current state.
wakeUp():void
stop():void
stopAndWait():void
Description Methods to change the current state.
maxTime:uint
Description Determines the maximal runtime when in "running" state.

Polling for Results

The cooperative setup as used with InteractiveOrganicLayouter means that the layout process does not return a single result by itself, but instead, in each calculation time slice and as long as it is in "running" state, continuously generates "intermediate" results. These results are in the layout algorithm's data structures only, but can be polled by the application and be used as continuous updates to the layout of a graph.

The following methods allow to easily poll either the current coordinates of single nodes or commit all current positions of nodes to the original graph at once:

getCenterX(node:Node):Number
getCenterY(node:Node):Number
getCenter(node:Node):YPoint
Description Retrieve the current center coordinate(s) of a single node from InteractiveOrganicLayouter's data structures.
commitPositions():void
commitPositionsSmoothly(maxMovement:Number, percentage:Number):Number
Description Updates all node locations with the coordinates from InteractiveOrganicLayouter's data structures.

In tutorial demo application InteractiveOrganicLayouterDemo.mxml the "intermediate" results are repeatedly calculated and assigned to the original graph in a contiuous fashion by means of a callback function in an animation:

Example 5.26. Callback setup to repeatedly calculate and assign node positions

// Create a Tween animation to continuously update the layout
var tween:Tween = new Tween(new Object(), 0, 1, Number.MAX_VALUE, -1, 
                            function(value:Object):void {
  // on each tween update: re-calculate the layout
  _layoutContext.doLayout(100);
  // update the visible graph with the changes
  if (_layouter.commitPositionsSmoothly(50, 0.1) > 0) {
    // if anything changed: invalidate the display
    graphCanvas.updateContentRect();
    graphCanvas.invalidateDisplayList();
  }
});

Interaction

The interactive organic layout algorithm allows a user to seemingly simultaneously modify node positions and also node-related parameters while layout calculation takes place. The following methods can be used to update InteractiveOrganicLayouter's data structures with new node positions, and also to specify further node-related parameters that determine, e.g., the size of a node or its inertia:

setCenterX(node:Node, x:Number):void
setCenterY(node:Node, y:Number):void
setCenter(node:Node, x:Number, y:Number):void
Description Set the current center coordinate(s) of a single node in InteractiveOrganicLayouter's data structures.
setInertia(node:Node, inertia:Number):void
setRadius(node:Node, radius:Number):void
Description Further node-related parameters used by InteractiveOrganicLayouter.

In addition, InteractiveOrganicLayouter optionally also supports modifications to the original graph's structure, i.e., nodes and/or edges can be added to or removed from the graph and the layout calculation subsequently properly accounts for these changes. The following property has to be used to enable support for structural modifications.

Important

To avoid synchronization problems when structural changes to the graph are allowed, it is strongly recommended to provide InteractiveOrganicLayouter a copy of the original graph using an instance of CopiedLayoutGraph. See also the section called “Setup”.

automaticStructureUpdateEnabled:Boolean
Description Enables/disables automatic updates for structural changes in the original graph.

To support structural modifications to the original graph, interactive organic layout relies on proper notification by means of graph events. Graph listeners registered with the original graph inform InteractiveOrganicLayouter of any structural changes that occur. See also the description of graph listeners in the section called “Events and Listeners”.

As an alternative to using automatic structure updates, the structure of the original graph can also be synchronized explicitly using code similar to that shown in Example 5.27, “Performing explicit structure updates”.

Example 5.27. Performing explicit structure updates

Tutorial demo application InteractiveOrganicLayouterDemo.mxml uses a graph listener and explicit synchronization to support structural modifications to the original graph:

Example 5.28. Support for structural changes through graph listeners

/**
 * Initializes the default style, creates a sample graph and starts the 
 * interactive layouter.
 */  
private function initializeGraph():void {
  var graph:IGraph = graphCanvas.graph;
  ...
  
  // register a listener so that structure updates are handled automatically
  graph.addEventListener(GraphEvent.GRAPH_CHANGED, onStructureChanged);
}

/**
 * Commit graph structure changes to the copied layout graph.
 */ 
private function onStructureChanged(event:GraphEvent):void {
  if (event.kind == GraphEventKind.NODE_CREATED) {
    // a new node was created:
    var node:INode = INode(event.item);
    var layout:IRectangle = node.layout;
    // update the layout graph
    _layouter.syncStructure();
    _layoutContext.doLayout(10);
    // we nail down all newly created nodes
    var copiedNode:Node = _copiedLayoutGraph.getCopiedNode(node);
    _layouter.setCenter(copiedNode, layout.x + layout.width/2, 
                                    layout.y + layout.height/2);
    _layouter.setInertia(copiedNode, 1);
    _layouter.setStress(copiedNode, 0);
  }
  else {
    // anything else has changed: update the layout graph
    if (_layouter != null) {
      _layouter.syncStructure();
      _layoutContext.doLayout(10);
    }
  }                
}

Supplemental Layout Data

Class InteractiveOrganicLayouter knows a number of data provider keys which are used to retrieve supplemental layout data for a graph's elements. The data is bound to the graph by means of a data provider, which is registered using a given look-up key. Table 5.41, “Data provider look-up keys” lists all look-up keys for InteractiveOrganicLayouter.

Binding supplemental layout data to a graph is described in the section called “Providing Supplemental Layout Data”.

Table 5.41. Data provider look-up keys

Key Element Type Value Type Description
PREFERRED_EDGE_LENGTH_DATA edge Number For each edge a double value that indicates its preferred length.

Layout Options

Interactive organic layout provides a set of options that affect its behavior. These options can be set using the properties and setter methods of class InteractiveOrganicLayouter.

Maximal Runtime
API
maxTime:uint
Description Sets the maximal duration of the layout process in milliseconds.

After the layout process has finished or the time specified using Maximal Runtime is spent, InteractiveOrganicLayouter will sleep, i.e., it has to be awakened before another layout process can be invoked (see also the description of running/sleeping state of InteractiveOrganicLayouter).

If this upper bound is hit during the layout process, the quality of the layout may not be optimal. Increasing the value increases the likeliness of an optimal layout.

Preferred Node Distance
API
preferredNodeDistance:Number
Description The preferred node distance which will be used to calculate the layout. The layout algorithm tries to arrange the nodes in such a way that the desired distance is complied with.

The following property and setter method allow to specify the general preferred length for all edges, respectively individual preferred edge length. The layout algorithm tries to arrange the nodes in such a way that the edges have the desired edge length. Note that the edge length is measured from node border to node border.

Preferred Edge Length
API
preferredEdgeLength:Number
setPreferredEdgeLength(edge:Edge, newEdgeLength:Number):void
Description Property and setter method to specify general preferred edge length, respectively individual preferred edge length.

Alternatively, to specify the preferred edge length for each edge individually, 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 PREFERRED_EDGE_LENGTH_DATA. Note that in the absence of an individual preferred edge length the general preferred edge length will be used.

Important

Although the data provider look-up key defined in class OrganicLayouter is used to specify individual preferred edge lengths, the actual type of data provided are double values.

Quality
API
quality:Number
Description This setting can be used to adjust the quality of the layout calculated by the layout algorithm. Small values lead to short running times, while greater values result in better quality. For large graph structures (hundreds and thousands of nodes) it is advisable to begin with smaller values and to gradually increase them.

Output Restrictions

Class InteractiveOrganicLayouter allows to impose so-called "output restrictions" on the result of the layout calculcation. More precisely, the layout result can be determined to fit into a specified region, e.g., a rectangle or a circle. Also, the layout result can be restricted to a specified aspect ratio, too.

outputRestriction:OutputRestriction
Description Class OutputRestriction serves as a factory to create predefined output restrictions that can be used in conjunction with this property.

Tutorial Demo Code

Tutorial demo application InteractiveOrganicLayouterDemo.mxml shows how to use the layout functionality of class InteractiveOrganicLayouter in an interactive environment where the user can "live"-drag nodes and freely modify the graph structure.