In the last article in this series I covered the basics of link routing and showed how the setPoints() API for a link could be used to create a non-straight line path between two nodes, as shown here:
In this article I want to look at some of the more advanced ways of managing links, covering:
- Label rotation
- Curved links
In the layout above, one nice enhancement would be to have the label for the Gamma link rotated to follow the direction of the link, thus:
To do this we have a new API to play with; setLabelRotationAngle() (note that a node has these same APIs as well) . This API takes a rotation angle in radians. The rotation itself will take place around the point defined by another API: setLabelRotationPoint(). This takes an x,y coordinate in the form of a DvtDiagramPoint object and defines the rotation point in the context of the label boundaries, so 0,0 for example is the top left corner of the label. Therefore you use setLabelPosition() API to define the gross position of the label on the diagram and then the other 2 APIs to control the angle and point of rotation.
Here's the sample code used to position the Gamma label and rotate it. Note that if you are rotating from the top-left corner of the label as I am doing here, there is no need to explicitly set the label rotation point as that defaults to 0,0.
Refer back to the code sample
from the previous article for the context in which you will find this fragment:
linkLabelXPos = turn3.x - (link.getLabelBounds().h + 5);
linkLabelYPos = linkStartPos.y + ((linkEndPos.y - linkStartPos.y) / 2)
+ (link.getLabelBounds().w / 2);
// rotate to 270 degrees
link.setLabelRotationAngle(270 * (Math.PI / 180));
link.setLabelPosition(new DvtDiagramPoint(linkLabelXPos, linkLabelYPos));
Curved and Complex Links
Sharp angles aren't for everyone, in some layouts you may want to have nice curves (or a mix). For example, we might want to change the sample to look like this:
In this case the "M" and the "C" mark the start of the line [M] and a cubic Bezier curve [C] definition respectively. The M element is followed by the x and y values for the start position of the path. The C element takes 3 pairs of coordinates, the first two are the control points for the Bezier curve and the final pair is the termination point:
Link paths themselves can be simple like this single cubic curve, or they can be constructed from multiple elements appended together. The core elements that you can use to create these more complex paths are:
|Prefix ||Arguments ||Purpose |
|M ||A single pair of coordinates. e.g |
|Defines the start point of a complex curve, in this case at position x=0,y=0 |
|L ||A single pair of coordinates. e.g |
|Draws a straight line from the current location (x=0, y=0) to the supplied coordinates, in this case x=10,y=20 |
|Q ||Takes one pair of coordinates for a control point, one pair of coordinates as an end point. e.g |
|Draws a quadratic Bezier curve from the current location (x=0, y=0) to the second pair coordinates, in this case x=10,y=20, using the control point x=40,y=40 to shape the curve |
|C ||Takes two pairs of coordinates for control points, one pair of coordinates as an end point. e.g |
|Draws a cubic Bezier curve from the current location (x=0, y=0) to the third pair coordinates, in this case x=150,y=50, using two control points x=72,y=80 & x=125,y=20 to shape the curve |
Note that the SVG arc element (A) is not currently supported.
More elements and variations on the elements are available, however, these are the ones you will use most of all.
Using these we can build up something a little more extreme like this. Notice have I've used a cubic Bezier curve in the path to "hop" over the "Alpha" link:
In this case the link path is made up of a mix of 8 elements defining various line segments and cubic Bezier curves, so although it looks complicated it's still composed of only the elements described above. Logically, the array reads like this:
["M", x, y, // Start point
"L", x, y, // Straight line down for a bit
"C", c1x, c1y, c2x, c2y, x, y, // Curve out towards Gamma
"L", x, y, // Straight line horizontally towards the midpoint
"C" , c1x, c1y, c2x, c2y, x, y, //The "hop"
"L", x, y, // Straight line horizontally away from the midpoint
"C" , c1x, c1y, c2x, c2y, x, y, //return curve
"L", x, y] // Straight line to the arrow endpoint
A Final Note about Calculated Positions
You will note from the example above that some of the numbers are negative, and indeed, if you have been following through with the example, and debugging to examine the actual values, you'll have noticed that many of the positions end up with negative values. Don't worry about this! Everything, as they say, is relative, and the diagram layout will resolve itself correctly. You can imagine that after you have positioned everything relative to an arbitary 0,0 origin, the diagram layout will re-base itself anyway and handle that.
In the Next Article
Now that we've completed coverage of the basics of layouts we spend some time in the next article exploring how you can incorporate flexibility into your diagram layout through configuration.