skip to main content
Programmer's documentation > Using graph layout algorithms > Using advanced features > Defining your own type of layout
 
Defining your own type of layout
Describes how to develop a custom graph layout algorithm if you need one.
*A sample custom layout algorithm
*Describes the features of a custom layout algorithm and shows an example.
*Implementing the layout method
*Explains how to implement a layout method.
A sample custom layout algorithm
If the layout algorithms provided with Rogue Wave®  JViews Diagrammer do not meet your needs, you can develop your own layout algorithms by subclassing IlvGraphLayout.
When a subclass of IlvGraphLayout is created, it automatically fits into the generic Rogue Wave  JViews Diagrammer layout framework and benefits from its infrastructure:
*Generic parameters: see Base class parameters and features
*Notification of progress: see Using event listeners
*Capability to lay out any graph object using the generic graph model: see Using the graph model
*Capability to apply the layout separately for the connected components of a disconnected graph: see Laying out connected components of a disconnected graph
*Capability to lay out nested graphs (see Nested layouts), and so on.
Example
To illustrate the basic ideas for defining a new layout, the following simple example shows a possible implementation of the simplest layout algorithm, the Random Layout. The new layout class is called MyRandomLayout.
The following code shows the skeleton of the class:
 
 
public class MyRandomLayout
  extends IlvGraphLayout
{
  public MyRandomLayout()
  {
  }
 
  public MyRandomLayout(MyRandomLayout source)
  {
    super.source(source);
  }
 
  public IlvGraphLayout copy()
  {
    return new MyRandomLayout(this);
  }
 
  protected void layout(boolean redraw)
  {
    ...
  }
}
The constructor with no arguments is empty.
The copy constructor and the copy method are implemented, because they are used when laying out a nested graph (see Nested layouts).
Then, the abstract method layout(boolean) of the base class is implemented as follows:
 
 protected void layout(boolean redraw)
  {
    // obtain the graph model
    IlvGraphModel graphModel = getGraphModel();
 
    // obtain the layout report
    IlvGraphLayoutReport layoutReport = getLayoutReport();
 
    // obtain the layout region
    IlvRect rect = getCalcLayoutRegion();
    float xMin = rect.x;
    float yMin = rect.y;
    float xMax = rect.x + rect.width;
    float yMax = rect.y + rect.height;
 
    // initialize the random generator
    Random random = (isUseSeedValueForRandomGenerator()) ?
        new Random(getSeedValueForRandomGenerator()):
        new Random();
 
    // browse the objects in the grapher
    Enumeration nodes = graphModel.getNodes();
    while (nodes.hasMoreElements()) {
        Object node = nodes.nextElement();
 
        // skip fixed nodes
        if (isPreserveFixedNodes() && isFixed(node)))
            continue;
 
        // compute coordinates
        float x = xMin + (xMax - xMin) * random.nextFloat();
        float y = yMin + (yMax - yMin) * random.nextFloat();
 
        // move the node to the computed position
        graphModel.moveNode(node, x, y, redraw);
 
        // notify listeners on layout events
        callLayoutStepPerformedIfNeeded();
    }
 
    // set the layout report code
    layoutReport.setCode(IlvGraphLayoutReport.LAYOUT_DONE);
}
...
The layout method is protected, which is the access type of the method in the base class. This does not prevent a user outside the package that contains the class from performing the layout, because it is started by using the public method performLayout.
Implementing the layout method
Depending on the characteristics of the layout algorithm, some of the steps required can be different or unnecessary, or other steps can be required.
Depending on the particular implementation of your layout algorithm, other methods of the base graph layout class must be overridden. For instance, if your subclass supports some of the generic parameters of the base class, you must override the supports[ParameterName] method (see Base class parameters and features).
For further information about the class IlvGraphLayout, refer to the API reference documentation.
NOTE If you want to save the layout parameters of your new layout algorithm in .ivl files, you should override the methods createLayoutGrapherProperty, createLayoutNodeProperty, createLayoutLinkProperty, and subclass IlvGraphLayoutGrapherProperty, IlvGraphLayoutNodeProperty, and IlvGraphLayoutLinkProperty. See Saving layout parameters and preferred layouts for more explanation.
To implement the layout method in the sample custom layout algorithm:
1. Obtain the graph model ( getGraphModel() on the layout instance).
 
IlvGraphModel graphModel = getGraphModel();
2. Obtain the instance of the layout report that is automatically created when the performLayout method from the superclass is called ( getLayoutReport() on the layout instance, see Using a graph layout report.
 
IlvGraphLayoutReport layoutReport = getLayoutReport();
3. Obtain the layout region parameter to compute the area where the nodes are placed.
 
IlvRect rect = getCalcLayoutRegion();
4. Initialize the random generator.
 
Random random = (isUseSeedValueForRandomGenerator()) ?
        new Random(getSeedValueForRandomGenerator()):
        new Random();
(For information on the seed value parameter, see Random generator seed value.)
5. Get an enumeration of the nodes ( getNodes() on the graph model instance).
 
Enumeration nodes = graphModel.getNodes();
6. Browse the nodes, skipping fixed nodes ( isFixed(node) on the layout instance) if asked by the user ( isPreserveFixedNodes() on the layout instance).
 
while (nodes.hasMoreElements()) {
   Object node = nodes.nextElement();
...
(For details on fixed nodes, see Preserve fixed nodes).
7. Move each node to the newly computed coordinates inside the layout region ( graphModel.moveNode ).
 
graphModel.moveNode(node, x, y, redraw);
8. Notify the listeners on layout events that a new node was positioned ( callLayoutStepPerformedIfNeeded() on the layout instance). It allows the user to implement, for example, a progress bar if a layout event listener was registered on the layout instance.
 
callLayoutStepPerformedIfNeeded();
(For details on event listeners, see Using event listeners.)
9. Finally, set the code in the layout report.
 
layoutReport.setCode(IlvGraphLayoutReport.LAYOUT_DONE);
Once you have implemented your own layout algorithm MyRandomLayout, you can add it to a CSS file to use it in a diagram component. Since your new layout algorithm is not one of the predefined graph layout algorithms, you need to specify it as fully qualified in CSS:
 
SMD {
    GraphLayout: true;
}
GraphLayout {
    graphLayout: "mypackage.MyRandomLayout";
    // ... additionally, any bean property of MyRandomLayout can
    // be specified here ...
}

Copyright © 2018, Rogue Wave Software, Inc. All Rights Reserved.