Invoking a Layout Algorithm Using Buffered Layout

With the yFiles layout algorithms it is possible to have a graph layout calculated using two different approaches, namely "unbuffered" layout or "buffered" layout. Unbuffered layout means to directly invoke a layout algorithm's doLayout() method. Choosing this approach, the layout calculation is performed on the given graph, and is also immediately assigned. Buffered layout, in contrast, utilizes class BufferedLayouter, which creates a copy of the original graph that is then used for layout calculation.

Important

In effect, the IGraph-related adapter mechanisms use the same copying scheme when running a layout algorithm and thus provide the same conceptual benefits as buffered layout. See also the section called “Using yFiles Layout Functionality”.

Unbuffered layout has some severe drawbacks that should be observed:

With these drawbacks in mind, it is almost always a good idea to choose buffered layout instead. It facilitates many sophisticated features, like, e.g., layout morphing, and at the same time increases an application's robustness.

Class BufferedLayouter

The main purpose of class BufferedLayouter is to create a copy of the input graph before calling its core layouter. The graph structure that is used for the copied graph is optimized for layout calculation.

Important

Class BufferedLayouter is not necessary when using the IGraph-related adapter mechanisms to run a layout algorithm. See also the section called “Using yFiles Layout Functionality”.

The core layouter subsequently executes on the copy and calculates a new layout, which is then transferred to the original graph. There are several beneficial aspects of this functionality:

  • The structure of the input graph is guaranteed to not change at all. Usually, layout providers (i.e., Layouter implementations) make no guarantees on leaving the sequence of nodes or edges unchanged, which may result in unexpected side effects. One such side effect is, for example, that a layouter may assign completely different layouts to a graph when being invoked twice on the same graph. The reason for such behavior is that a layout provider's output in general depends on the sequence of elements in the graph, but this sequence has changed with the first layout invocation.
  • Instead of immediately writing back the calculated layout to the given input graph, class BufferedLayouter provides the possibility to return the result as a GraphLayout object, leaving the original graph's layout unmodified. The GraphLayout object then allows to defer coordinate assignment to a later point in time, for example, using class LayoutTool's applyGraphLayout() method.
  • Calculating a layout on a copy instead of the original graph proves to be more robust. Even if there should occur an unrecoverable error in the layout process, class BufferedLayouter guarantees that the structure of the input graph remains consistent.

Wrapping a layout algorithm with a BufferedLayouter layout stage is as easy as shown in Example 8.2, “Using buffered layout (LayoutGraph API)”.

Example 8.2. Using buffered layout (LayoutGraph API)

// 'graph' is of type com.yworks.yfiles.layout.LayoutGraph.

// Run organic layout by implicitly wrapping its invocation using the services
// of class BufferedLayouter.
BufferedLayouter.newBufferedLayouter2(
    new SmartOrganicLayouter()).doLayout(graph);

Alternatively, class BufferedLayouter allows to get the calculated graph layout as a separate object. This is demonstrated in Example 8.3, “Buffered layout with deferred coordinate assignment (LayoutGraph API)”.

Example 8.3. Buffered layout with deferred coordinate assignment (LayoutGraph API)

// 'graph' is of type com.yworks.yfiles.layout.LayoutGraph.

// Run organic layout by implicitly wrapping its invocation using the services
// of class BufferedLayouter.
// The result of the layout is returned separately as a GraphLayout object,
// i.e., the original graph's layout information is not changed.
var gl:GraphLayout = BufferedLayouter.newBufferedLayouter2(
    new SmartOrganicLayouter()).calcLayout(graph);