The yFiles label capabilities cover a variety of standard features common with today's word processing systems. A label can have multiple lines, the label's text can be aligned in several ways, and font attributes like type, size, and color can be controlled. Also, using an instance of type java.awt.Insets, a label's text can be placed with custom margins within its bounding box. Other graphical attributes, including background and border color, can be set, too.
Look and feel of both node labels and edge labels are defined by so-called
"configurations," i.e., sets of interface implementations that cover all
aspects of label functionality.
Classes NodeLabel and EdgeLabel each make available two predefined
configurations, the default label configuration, which is encapsulated in class
DefaultLabelConfiguration
, and a second
configuration that provides automatic line-wrapping of a label's text.
The latter one is accessible with these classes using the name
"CroppingLabel".
In addition to text alignment and font attributes, the default label configuration provides further useful features. On the basis of the used font the label's size is automatically determined each time a new text is set, respectively one of the label's properties changes. Instead of text, or in addition to its text, a label can also show an icon, and for complete freedom in design it can even render HTML code. Furthermore, the entire label can be rotated about its center. Figure 6.17, “Some features of the default label configuration” depicts some label variations.
HTML rendering is enabled by default and is triggered as soon as the label's text starts with <html>. Note that the rendering capabilities are constrained to the basic HTML support provided by Swing. Example 6.2, “Creating some labels” shows code to generate various kinds of labels.
Example 6.2. Creating some labels
// 'nr1' to 'nr3' are of type y.view.NodeRealizer. NodeLabel nl; // First node. nl = nr1.createNodeLabel(); nr1.setLabel(nl); // Set the label model and position. nl.setModel(NodeLabel.CORNERS); nl.setPosition(NodeLabel.NW); // Note the line breaks. nl.setText("Label with \nbackground \nand border \ncolor."); nl.setBackgroundColor(new Color(204, 255, 204)); nl.setLineColor(new Color(51, 153, 102)); // Second node. nl = nr2.createNodeLabel(); nr2.setLabel(nl); nl.setText("Rotated label."); nl.setRotationAngle(310); // Third node. nl = nr3.createNodeLabel(); nr3.setLabel(nl); // Set the label model and position. nl.setModel(NodeLabel.SANDWICH); nl.setPosition(NodeLabel.S); // HTML rendering is on by default. nl.setText("<html><hr>" + "<em><b>HTML</b> label</em><br>" + "with multiple lines<br>" + "and rules." + "<hr></html>");
Figure 6.18, “Label with icon instead of text” is created by the code shown in Example 6.3, “Creating a label with an icon”.
Example 6.3. Creating a label with an icon
// 'nr' is of type y.view.NodeRealizer. NodeLabel nl = nr.createNodeLabel(); nr.setLabel(nl); // Set the label model and position. nl.setModel(NodeLabel.SANDWICH); nl.setPosition(NodeLabel.N); // Well-known icon that comes in handy as an example... nl.setIcon(MetalIconFactory.getFileChooserHomeFolderIcon());
Using an image icon as the content of a node label permits a node that is
rendered by a ShapeNodeRealizer
to show
both shape and image.
In contrast to using an
ImageNodeRealizer
, however, the image
will retain its size, i.e., it will not scale with the node.
Using the additional line of code from Example 6.4, “Setting custom margins”, the label's bounding box is effectively enlarged to create the specified margins around the text. See Figure 6.19, “Label text with custom margins” for the result.
Example 6.4. Setting custom margins
// Increase the left margin. nl.setInsets(new Insets(10, 70, 10, 10));
Using the "CroppingLabel" configuration, which enables a label's text to be automatically line-wrapped, it is easily possible to have a label's visual presentation truncated to fit into the node's size, for example. Figure 6.20, “Label text line-wrapping and cropping” shows both the default behavior when a node label has a long text, and the results when the text is automatically line-wrapped to fit either the width or the width and height of its node. In the latter case, when the line-wrapped label text does not fit, the displayed text is truncated and an ellipsis character replaces the part that is not shown.
Example 6.5, “Different sizing policies for the label text” shows the code that sets up the auto-sizing policies depicted in Figure 6.20, “Label text line-wrapping and cropping”.
The CroppingLabel configuration currently has no support for HTML rendering or setting an icon with a label.
Example 6.5. Different sizing policies for the label text
// 'graph' is of type y.view.Graph2D. Set configurations = NodeLabel.getFactory().getAvailableConfigurations(); for (int i = 0; i < 3; i++) { Node n = graph.createNode(200 * (i + 1), 100); NodeLabel nl = graph.getRealizer(n).getLabel(); nl.setFontName("Tahoma"); nl.setFontSize(14); nl.setAlignment(YLabel.ALIGN_LEFT); nl.setText("The quick brown fox jumps over the lazy dog."); switch (i) { case 1: if (configurations.contains("CroppingLabel")) { nl.setConfiguration("CroppingLabel"); nl.setAutoSizePolicy(NodeLabel.AUTOSIZE_NODE_WIDTH); } break; case 2: if (configurations.contains("CroppingLabel")) { nl.setConfiguration("CroppingLabel"); nl.setAutoSizePolicy(YLabel.AUTOSIZE_NONE); nl.setContentSize(60, 60); } break; default: nl.setAutoSizePolicy(YLabel.AUTOSIZE_CONTENT); } }
Abstract class YLabel defines a set of inner interfaces which allow fine-grained control over all aspects of a label's visual representation and behavior. Custom label logic can be conveniently expressed by providing implementations for only a selection or for all of these interfaces:
Together, a set of actual implementations for these interfaces forms a so-called "configuration" that defines the look and feel of a label. Different configurations can be used to define a variety of label types.
Management of label configurations is done by static inner class
YLabel.Factory
.
A reference to this class can be get using the NodeLabel and EdgeLabel class
method shown in API Excerpt 6.23, “Static method to get the factory for configuration management”.
API Excerpt 6.23. Static method to get the factory for configuration management
// Getter method in classes NodeLabel and EdgeLabel. static YLabel.Factory getFactory()
To handle user-defined data, YLabel defines the
YLabel.UserDataHandler
inner interface.
This interface is used to delegate all work that relates to copying or
(de)serializing of all user-defined data of a label.
Class SimpleUserDataHandler
can be used
as a default implementation for this interface.
It is capable of dealing with arbitrary user-defined data objects that
implement interfaces java.lang.Cloneable (for copying)
and java.io.Serializable (for serialization and
deserialization).
Class DefaultLabelConfiguration
serves as
a default implementation for all YLabel interfaces.
It provides the default label behavior and can be used as a convenient base for
customized configurations.
Example 6.6, “Customizing the default node label configuration” shows how to create a
specialized node label configuration using another YLabel.Painter
implementation.
Example 6.6. Customizing the default node label configuration
// Get the factory to register custom styles/configurations. YLabel.Factory factory = NodeLabel.getFactory(); // Retrieve a map that holds the default NodeLabel configuration. // The implementations contained therein can be replaced one by one in order to // create custom configurations... Map implementationsMap = factory.createDefaultConfigurationMap(); // Customize the painting with a custom YLabel.Painter implementation. implementationsMap.put(YLabel.Painter.class, new MyPainter()); // Add this configuration to the factory. factory.addConfiguration("Bubble", implementationsMap);
Tutorial demo application YLabelConfigurationDemo.java presents in detail how a custom node label configuration is created.
The aforementioned general features are offered by abstract class
YLabel
.
Classes NodeLabel and EdgeLabel provide further label functionality that is
specific to the respective type of graph element.
Figure 6.21, “Label classes hierarchy” presents the class hierarchy for the label
functionality from package y.view.
A label naturally belongs to a specific graph element, and accordingly should be presented near this element. To control the label's position relative to its element, so-called "label models" are used.
Class NodeLabel
provides a number of
label models with predefined positions and additionally a "free" model, where
the label's position is solely defined by an offset.
Figure 6.22, “Possible node label positions” depicts all predefined positions for a node
label.
It is important to note that the set of valid positions varies with the chosen model, i.e., not all possible positions are valid for each model. Table 6.4, “Valid label positions for each model” lists the sets of valid positions for each node label model.
Table 6.4. Valid label positions for each model
| Model Name | Valid Positions |
|---|---|
| INTERNAL | TOP_LEFT, TOP, TOP_RIGHT, LEFT, CENTER, RIGHT, BOTTOM_LEFT, BOTTOM, BOTTOM_RIGHT |
| CORNERS | NW, NE, SW, SE |
| SIDES | N, W, E, S |
| EIGHT_POS | All positions from CORNERS and also all from SIDES. |
| SANDWICH | N, S |
| FREE | ANYWHERE |
The offset with the "free" label model is the distance vector between the upper left corners of node and label. Setting a label model and choosing one of the predefined label positions is demonstrated in Example 6.7, “Setting a node label model”. If the chosen position is not in the set of valid positions for a label model, then a default position is taken instead.
Example 6.7. Setting a node label model
// 'nr' is of type y.view.NodeRealizer. // Create the label and add it to the node realizer. NodeLabel nl = nr.createNodeLabel(); nr.setLabel(nl); // Set a node label model and choose one of the predefined label positions. // 'CORNERS' has four positions at the corners of a node, outside its bounds. nl.setModel(NodeLabel.CORNERS); // 'SE' means the lower right corner. nl.setPosition(NodeLabel.SE);
Observe that the sets of valid positions with label models CORNERS, SANDWICH, and SIDES are proper subsets of those allowed with label model EIGHT_POS. Choosing one of these subsets explicitly restricts the number of available label positions, i.e., for the most flexibility EIGHT_POS is the best choice.
Class EdgeLabel
provides several label
models with predefined positions, and some "slider" models where the set of
valid positions is dynamic and varies with the length of the edge path.
Additionally, there is also a "free" model available, where the label's
position is defined by an offset.
Table 6.5, “Edge label models” lists all edge label models and shows the
predefined label positions, the dynamic positions of the "slider" models, and
also examples for offset positions with the "free" model.
Table 6.5. Edge label models
| Model Name | Valid Positions |
|---|---|
| CENTERED |
CENTER
![]() |
| TWO_POS |
HEAD, TAIL
![]() |
| THREE_CENTER |
SCENTR, CENTER, TCENTR
![]() |
| SIX_POS |
SHEAD, HEAD, THEAD, STAIL, TAIL, TTAIL
![]() |
| CENTER_SLIDER |
DYNAMIC
![]() |
| SIDE_SLIDER |
DYNAMIC
![]() |
| FREE |
ANYWHERE
![]() |
The dynamic positions of the "slider" models are specified by a ratio value that ranges from 0.0 to 1.0. It determines the label's placement along the edge path, with increasing value meaning positions farther from the source node. The offset with the "free" label model is the distance vector between the intersection point of the first edge segment with the source node and the upper left corner of the label. Setting a label model and choosing a label position is demonstrated in Example 6.8, “Setting an edge label model”. If the chosen position is not in the set of valid positions for a label model, then a default position is taken instead.
Example 6.8. Setting an edge label model
// 'er' is of type y.view.EdgeRealizer. // Create the label and add it to the edge realizer. EdgeLabel el = er.createEdgeLabel(); er.addLabel(el); // Set an edge label model. 'CENTER_SLIDER' has a dynamic number of label // positions that lie on the edge's path. el.setModel(EdgeLabel.CENTER_SLIDER); el.setPosition(EdgeLabel.DYNAMIC); // Choose a label position near the source node. el.setRatio(0.3);
In addition to the EdgeRealizer object associated there are further classes involved in rendering an edge's visual representation. For each of the edge's bends the EdgeRealizer object holds a corresponding object of type Bend. The special graphical decoration that can be placed at either end of an edge is governed by class Arrow. And the line graphic of the edge itself can be controlled using class LineType.
API Excerpt 6.24, “Arrow-related methods from class EdgeRealizer” shows the methods provided by class EdgeRealizer to handle arrows.
API Excerpt 6.24. Arrow-related methods from class EdgeRealizer
// Getter methods. Arrow getArrow() Arrow getSourceArrow() Arrow getTargetArrow() // Setter methods. void setArrow(Arrow arrow) void setSourceArrow(Arrow arrow) void setTargetArrow(Arrow arrow)
Class Arrow
renders the graphical
decorations that can be placed at an edge's ends.
Normally, this decoration is some kind of arrowhead that is used to indicate
the edge's direction.
Table 6.6, “Arrow shapes of class Arrow” depicts the predefined arrow shapes.
Note that omitting the decoration is done using another arrow shape. Arrow type NONE, which is not shown below, "renders" an empty arrow shape.
Table 6.6. Arrow shapes of class Arrow
| Arrow Type | Arrow Shape |
|---|---|
| DELTA |
![]() |
| DIAMOND |
![]() |
| SHORT |
![]() |
| STANDARD |
![]() |
| WHITE_DELTA |
![]() |
| WHITE_DIAMOND |
![]() |
Class Arrow supports fine-grained control of arrowhead rendering. It is possible to specify an arrowhead's distance to the border of a node, and also the position of the edge path's end relative to an arrowhead's tip.
In addition to the predefined arrow shapes it is also possible to register
custom ones using the methods listed in API Excerpt 6.25, “Support for custom arrow shapes”.
The most freedom defining a customized arrow(head) is provided when using
graphical objects that implement interface
Drawable
.
API Excerpt 6.25. Support for custom arrow shapes
// Getter and setter methods for custom arrow shapes. static Arrow addCustomArrow(String name, Drawable drawable) static Arrow addCustomArrow(String name, Shape shape, Color fillColor) static Arrow addCustomArrow(String name, Shape shape, Color fillColor, Stroke lineStroke, Color lineColor) static Arrow getCustomArrow(String name) // Arrow shapes using customized distance and arrow length. static Arrow addCustomArrow(String name, Drawable drawable, double arrowLength, double clipLength) static Arrow addCustomArrow(String name, Shape shape, Color fillColor, Stroke lineStroke, Color lineColor, double arrowLength, double clipLength) String getCustomName()
Class Bend
is to bends (also known as
control points) what classes NodeRealizer and EdgeRealizer are to nodes and
edges.
It handles all user interface (UI)-related aspects, i.e., it renders a bend's
graphical representation, and also provides a number of features including,
e.g., control of the selection state and support for hit tests.
Note that bends, i.e., control points, determine the path of an edge, but are not necessarily part of the path itself. Especially the classes BezierEdgeRealizer and SplineEdgeRealizer exhibit this difference.
The most defining characteristic of a bend is its location. API Excerpt 6.26, “Positional methods from class Bend” lists the methods that can be used to control it.
Class LineType
is responsible for
rendering the line graphic of an edge.
It is used for both poly-line edges as well as curves.
Table 6.7, “Line types of class LineType” shows the predefined line types.
Note that the line types are available in different widths.
Table 6.7. Line types of class LineType
| Constant Name | Line Type |
|---|---|
| DASHED_STYLE |
![]() |
| DOTTED_STYLE |
![]() |
| LINE_STYLE |
![]() |
Different line types can be get directly using their respective names, e.g., DASHED_1, DOTTED_2, LINE_4, etc. Alternatively, LineType also offers the static methods from API Excerpt 6.27, “Static getter methods from class LineType” to get (one of) the available line types.
API Excerpt 6.27. Static getter methods from class LineType
static Vector availableLineTypes() static LineType getLineType(int width, byte style)
In addition to the predefined line types it is also possible to create custom ones using the method from API Excerpt 6.28, “Support for creation of custom line types”.
The indication whether a graph element is selected or not contributes a great deal to the user experience and is of central importance to the notion of a user interacting with the graph structure by means of a graphical user interface.
The predefined NodeRealizer and EdgeRealizer implementations define special rendering logic for the selection indication of its associated graph elements. A selected node, e.g., also shows eight small knobs around its outline that can be used to change the node's width and height. Figure 6.24, “Selection indication for nodes, edges, and bends” shows the default results for selected nodes, a selected edge, and selected bends. Note that bends have different appearance depending on the context.
Figure 6.24. Selection indication for nodes, edges, and bends
![]() |
![]() |
![]() |
| Selected nodes. | Selected edge. | Selected control points (bends). |
Both realizer types offer getter and setter methods to control the selection
state of their associated graph element.
Likewise, similar methods in class Bend can be used to control the selection
state of an edge's control points.
Class Graph2D has a variety of additional convenience methods to change,
respectively query, the selection state of arbitrary collections of graph
elements.
Figure 6.25, “Methods for modifying the selection state” presents an overview of the classes and their
methods dealing with selection state.
Further, more sophisticated methods to alter the selection state are offered
by abstract class Selections
.
Changes in the selection state of graph elements can easily be listened to
using the familiar events and listener concept.
Interface Graph2DSelectionListener
conveys an event of type
Graph2DSelectionEvent
which can be
queried for specific details.
See the section called “Events and Listeners” for further description.
|
Copyright ©2004-2008, yWorks GmbH. All rights reserved. |