Defining your own type of layout
Describes how to develop a custom graph layout algorithm if you need one.
Describes the features of a custom layout algorithm and shows an example.
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:
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.
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();
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();
...
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();
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.