Model items used in an
IGraph
(i.e., items of type
INode, IEdge, IPort, and ILabel) by themselves do not provide any visual
representation.
Instead, the functionality to render model items in the GraphControl is
encapsulated by so-called "styles."
Along with their complementing counterparts, the so-called "style renderers,"
they hold all necessary state and provide all logic needed to create the visual
appearance of graph elements.
The following sections cover:
Additionally, in the Port Support and Label Support sections, the so-called port location models and label models are presented. Although they do not directly influence the styling of the graph, they are used for determining the geometry of ports and labels and thus influence the overall visual appearance.
For either type of graph element there is a specialized style type available:
interfaces INodeStyle
and
IEdgeStyle
for nodes and
edges, and interfaces
IPortStyle
and
ILabelStyle
for ports and
labels, respectively.
Figure 2.6, “Hierarchy of style types” shows the type hierarchy of the base style interfaces.
Generic interface IVisualStyle is the base type for all styles.
Its type parameter is constrained to
IModelItem
, which is the base
type for all graph structure interfaces used by interface IGraph (see also
the section called “Graph Structure”).
The style types that extend
IVisualStyle<TModelItem>
appropriately bind the type parameter TModelItem.
For example, INodeStyle uses INode, IEdgeStyle uses IEdge, etc. to specify the
style's specific kind of IModelItem.
The following sections cover the predefined style implementations for the model item types:
Using styles along with class DefaultGraph, the default IGraph implementation, is described in the section called “Working with Styles”.
Node styles are responsible for the graphical rendering of nodes in the canvas.
Interface INodeStyle
is
the common base type for actual implementations.
Figure 2.7, “Hierarchy of node style types” shows part of the type hierarchy of the node
style implementations.
Table 2.3, “Predefined node style implementations” lists the predefined node style
implementations present in the
yWorks.yFiles.UI.Drawing
namespace.
Table 2.3. Predefined node style implementations
| Type Name | Description |
|---|---|
| SimpleAbstractNodeStyle |
Greatly simplifies node style customization using subclassing. (See below for a description of SimpleAbstractNodeStyle.) |
| ShapeNodeStyle |
Provides a variety of predefined shapes for the visual appearance of a node.
The enumeration type
ShapeNodeShape |
| MemoryImageNodeStyle |
Enables using a bitmap image to create the visual representation of a node. The serialization mechanism of this style uses Base64-encoded bitmap data when writing the image. |
| UriImageNodeStyle |
Enables using a bitmap image to create the visual representation of a node. In contrast to MemoryImageNodeStyle, the serialization mechanism uses the URI when writing the image. |
| GeneralPathNodeStyle |
Allows arbitrary
GeneralPath |
| PanelNodeStyle |
An implementation of interface
IPanelNodeStyle |
| BevelNodeStyle |
An implementation of interface
IBevelNodeStyle |
| ShinyPlateNodeStyle |
Can be used to create rectangular nodes with rounded corners and a 'shiny plate' interior. By default, this style renders a drop shadow by itself. |
| ShadowNodeStyleDecorator |
A node style decorator to add a drop shadow to the visual representation of the wrapped node style. See below. |
Figure 2.8, “Node style representations” shows examples of nodes using predefined node style implementations.
Figure 2.8. Node style representations
![]() |
![]() |
![]() |
![]() |
| Some of the predefined shapes of ShapeNodeStyle | UriImageNodeStyle showing the yWorks logo | ||
![]() |
![]() |
![]() |
Abstract class
SimpleAbstractNodeStyle
facilitates convenient creation of custom node representations.
SimpleAbstractNodeStyle is an INodeStyle implementation that uses a fixed,
predefined renderer implementation, eliminating the need to create an explicit
renderer for node representations.
API Excerpt 2.9, “Method from SimpleAbstractNodeStyle that subclasses need to override” shows the method from class SimpleAbstractNodeStyle that is called to create and update the visual representation for a given node. Being abstract, it needs to be overridden by subclasses.
API Excerpt 2.9. Method from SimpleAbstractNodeStyle that subclasses need to override
// Abstract method to create the visual representation for the given INode.
protected abstract void Paint(INode node,
Graphics graphics, IRenderContext renderContext)
The MySimpleNodeStyle class in the SimpleCustomStyleForm demo application presents a node style implementation that subclasses SimpleAbstractNodeStyle. How to subclass SimpleAbstractNodeStyle is also shown in the Custom Styles tutorial; see especially step 01.
Custom node styles that do not base on SimpleAbstractNodeStyle need to
implement the
Renderer
property defined in interface INodeStyle and the
Install
method defined in the superinterface of generic base type IVisualStyle.
See also the section called “Creating Custom Styles”.
Class
ShadowNodeStyleDecorator
is a special INodeStyle implementation that allows to decorate node styles.
It can be used to add a drop shadow to the visual representation of the wrapped
node style.
Example 2.13. Decorating a drop shadow onto a node style
// 'graph' is of type yWorks.yFiles.UI.Model.IGraph. ShapeNodeStyle sns = new ShapeNodeStyle(); sns.Brush = new SolidColorBrush(Color.LightGray); sns.Shape = ShapeNodeShape.RoundRectangle; ShadowNodeStyleDecorator snsd = new ShadowNodeStyleDecorator(sns); // 'someNode' is of type yWorks.yFiles.UI.Model.INode. graph.SetStyle(someNode, snsd);
Figure 2.9, “ShapeNodeStyle decorated using ShadowNodeStyleDecorator” shows a node using ShapeNodeStyle that is decorated by means of ShadowNodeStyleDecorator to also have a drop shadow.
Edge styles are responsible for the graphical rendering of edges in the canvas.
Interface IEdgeStyle
is the common base type for actual implementations, and abstract class
AbstractEdgeStyle
provides
default implementations for the methods of interface IEdgeStyle.
Figure 2.10, “Hierarchy of edge style types” shows a part of the type hierarchy of edge style
implementations.
Table 2.4, “Predefined edge style implementations” lists the predefined edge style
implementations present in the
yWorks.yFiles.UI.Drawing
namespace.
Table 2.4. Predefined edge style implementations
| Type Name | Description |
|---|---|
| SimpleAbstractEdgeStyle |
Greatly simplifies edge style customization using subclassing. (See below for a description of SimpleAbstractEdgeStyle.) |
| ArcEdgeStyle |
Provides an arc representation for an edge. The rendering does not take into account bends of an edge, instead the arc's height is determined as a fixed ratio or fixed height. |
| PolylineEdgeStyle |
An edge representation where straight line segments are used to connect the bends. |
Figure 2.11, “Edge style representations” shows examples of edges using predefined edge style implementations.
Abstract class
SimpleAbstractEdgeStyle
facilitates convenient creation of custom edge representations.
SimpleAbstractEdgeStyle is an IEdgeStyle implementation that uses a fixed,
predefined renderer implementation, eliminating the need to create an explicit
renderer for edge representations.
API Excerpt 2.10, “Method from SimpleAbstractEdgeStyle that subclasses need to override” shows the method from class SimpleAbstractEdgeStyle that is called to create and update the visual representation for a given edge. Being abstract, it needs to be overridden by subclasses.
API Excerpt 2.10. Method from SimpleAbstractEdgeStyle that subclasses need to override
// Abstract method to create the visual representation for the given IEdge.
protected abstract void Paint(IEdge edge,
Graphics graphics, IRenderContext renderContext)
The MySimpleEdgeStyle class in the SimpleCustomStyleForm demo application presents an edge style implementation that subclasses SimpleAbstractEdgeStyle. How to subclass SimpleAbstractEdgeStyle is also shown in the Custom Styles tutorial; see especially step 14.
Abstract class
AbstractEdgeStyle
serves
as a convenient basis for actual edge styles that need more custom rendering
support than SimpleAbstractEdgeStyle provides, for example.
Custom edge styles that base on AbstractEdgeStyle still need to implement the
Install
method, which is repeated from the superinterface of generic base type
IVisualStyle, however adapted to use IEdge as the type for the original type
parameter TModelItem.
See also the section called “Creating Custom Styles”.
Because bends are an integral part of an edge, they are rendered by the edge style, too.
Port styles are responsible for the graphical rendering of ports in the canvas.
Interface IPortStyle
is the common base type for actual implementations.
Figure 2.12, “Hierarchy of port style types” shows a part of the type hierarchy of port style
implementations.
Table 2.5, “Predefined port style implementations” lists the predefined port style
implementations present in the
yWorks.yFiles.UI.Drawing
namespace.
Table 2.5. Predefined port style implementations
| Type Name | Description |
|---|---|
| SimpleAbstractPortStyle |
Greatly simplifies port style customization using subclassing. (See below for a description of SimpleAbstractPortStyle.) |
| SimplePortStyle |
Provides a very simple representation for ports. |
Abstract class
SimpleAbstractPortStyle
facilitates convenient creation of custom port representations.
SimpleAbstractPortStyle is an IPortStyle implementation that uses a fixed,
predefined renderer implementation, eliminating the need to create an explicit
renderer for port representations.
API Excerpt 2.11, “Methods from SimpleAbstractPortStyle that subclasses need to override” shows the methods from class SimpleAbstractPortStyle that are called to create the visual representation for a given port and that return the port's bounds. Being abstract, both methods need to be overridden by subclasses.
API Excerpt 2.11. Methods from SimpleAbstractPortStyle that subclasses need to override
// Abstract method to create the visual representation for the given IPort.
protected abstract void Paint(IPort port,
Graphics graphics, IRenderContext renderContext)
// Abstract method to get the bounds of the given IPort's visual.
protected abstract RectD GetBounds(IPort port, ICanvasContext canvasContext)
The MySimplePortStyle class in the SimpleCustomStyleForm demo application presents a port style implementation that subclasses SimpleAbstractPortStyle. How to subclass SimpleAbstractPortStyle is also shown in the Custom Styles tutorial; see especially step 19.
Custom port styles that do not base on SimpleAbstractPortStyle need to
implement the
Renderer
property defined in interface IPortStyle and the
Install
method defined in the superinterface of generic base type IVisualStyle.
See also the section called “Creating Custom Styles”.
Label styles are responsible for the graphical rendering of labels in the
canvas.
Interface ILabelStyle
is the common base type for actual implementations.
Figure 2.13, “Predefined label style types” shows a part of the type hierarchy of label style
implementations.
Table 2.6, “Predefined label style implementations” lists the predefined label style
implementations present in the
yWorks.yFiles.UI.Drawing
namespace.
Table 2.6. Predefined label style implementations
| Type Name | Description |
|---|---|
| SimpleAbstractLabelStyle |
Greatly simplifies label style customization using subclassing. (See below for a description of SimpleAbstractLabelStyle.) |
| SimpleLabelStyle |
Enables rendering of a label's text within an oriented rectangle. |
| IconLabelStyle |
Builds on the functionality that SimpleLabelStyle provides and additionally allows to place an icon at several positions relative to the label's text. |
| NodeStyleLabelStyleAdapter |
Allows to add the rendering of a given node style as the background for the visual representation of the wrapped label style. See below. |
Abstract class
SimpleAbstractLabelStyle
facilitates convenient creation of custom label representations.
SimpleAbstractLabelStyle is an ILabelStyle implementation that uses a fixed,
predefined renderer implementation, eliminating the need to create an explicit
renderer for label representations.
API Excerpt 2.12, “Methods from SimpleAbstractLabelStyle that subclasses need to override” shows the methods from class SimpleAbstractLabelStyle that are called to create the visual representation for a given label and that return the label's preferred size. Being abstract, both methods need to be overridden by subclasses.
API Excerpt 2.12. Methods from SimpleAbstractLabelStyle that subclasses need to override
// Abstract method to create the visual representation for the given ILabel.
protected abstract void Paint(ILabel label,
Graphics graphics, IRenderContext renderContext)
// Abstract method to get the given ILabel's preferred size.
protected abstract SizeD GetPreferredSize(ILabel label)
The MySimpleLabelStyle class in the SimpleCustomStyleForm demo application presents a label style implementation that subclasses SimpleAbstractLabelStyle. How to subclass SimpleAbstractLabelStyle is also shown in the Custom Styles tutorial; see especially step 09.
Custom label styles that do not base on SimpleAbstractLabelStyle need to
implement the
Renderer
property defined in interface ILabelStyle and the
Install
method defined in the superinterface of generic base type IVisualStyle.
See also the section called “Creating Custom Styles”.
Class
NodeStyleLabelStyleAdapter
is an ILabelStyle implementation that allows to decorate label styles.
It can be used to add the rendering of a given node style as the background for
the visual representation of the wrapped label style.
Figure 2.14, “Edge label that uses NodeStyleLabelStyleAdapter” shows an edge label where a
BevelNodeStyle is used to render the background.
Setting up different node styles and associating them with nodes of a graph is presented in Example 2.14, “Creating a graph”. The resulting graph is depicted in Figure 2.15, “Shape node style and image node style”.
Example 2.14. Creating a graph
IGraph graph = new DefaultGraph();
// Set up a node style that uses a circle.
ShapeNodeStyle sns = graph.NodeDefaults.Style;
sns.Shape = ShapeNodeShape.Ellipse;
// Set up a node style that uses an image to represent nodes.
IImageNodeStyle ins = new UriImageNodeStyle
{ Uri = new Uri("PathToSomeImage.png", UriKind.RelativeOrAbsolute) };
graph.NodeDefaults.Style = ins;
graph.NodeDefaults.Size = new SizeD(ins.Image.Width * 2.0, ins.Image.Height);
// Create some nodes.
INode[] nodes = new INode[6];
for (int i = 0; i < nodes.Length - 1; i += 2) {
nodes[i] = graph.CreateNode(new PointD(i * 50, 100));
graph.SetStyle(nodes[i], sns);
graph.SetBounds(nodes[i],
new RectD(nodes[i].Layout.X, nodes[i].Layout.Y, 40, 40));
nodes[i + 1] = graph.CreateNode(new PointD(i * 50, 200));
}
Styles can be associated with model items using different schemes: an IVisualStyle instance for a specific kind of model item can be both
Style sharing can be easily achieved whenever a single style instance is associated with a model item by reference. Example 2.15, “Style sharing” presents this scheme using the SetStyle method to associate a single custom ShapeNodeStyle instance by reference with a set of nodes. Similarly, when associating a single ShapeNodeStyle instance by reference at node creation time, the style can also be shared among multiple nodes.
Example 2.15. Style sharing
// 'graph' is of type yWorks.yFiles.UI.Model.IGraph.
MyShapeNodeStyle shapeNS = new MyShapeNodeStyle();
foreach (INode node in myNodeList) {
graph.SetStyle(node, shapeNS);
}
When a node is associated with the default style via the support for default settings
provided by IGraph, the style instance that is returned by the Style
property of the INodeDefaults implementation is also shared.
Example 2.16, “Changing the color of a node” shows how to obtain the style that is used for a specific node from its graph and changing the node's color. Styles for the other kinds of items can be obtained and modified in a similar manner.
Example 2.16. Changing the color of a node
// 'graph' is of type yWorks.yFiles.UI.Model.IGraph.
// 'node' is of type yWorks.yFiles.UI.Model.INode.
IShapeNodeStyle shapeNS = node.Style as IShapeNodeStyle;
if (shapeNS != null) {
shapeNS.Brush = Brushes.AliceBlue;
}
// Tell the engine to update the displays (the style instance cannot know itself
// which display it appears in).
graph.InvalidateDisplays();
Generally, style types team up with a corresponding style renderer type, separating duties as follows: the actual style implementation ideally only holds the state that is needed for rendering an item, while the style renderer provides the logic that performs the real work using the style's state. This separation enables sharing of style renderer instances among an arbitrary number of style objects and is also known as the Flyweight pattern.
As a consequence, creating a custom style is mainly the task of creating a proper style renderer. Most conveniently, a custom style type can be created using the appropriate abstract class listed in the following table:
Table 2.7. Base types for custom style type implementations
| Base Type | Description |
|---|---|
| SimpleAbstractNodeStyle |
Simplifies node style customization using subclassing. |
| SimpleAbstractEdgeStyle |
Simplifies edge style customization using subclassing. |
| SimpleAbstractLabelStyle |
Simplifies label style customization using subclassing. |
| SimpleAbstractPortStyle |
Simplifies port style customization using subclassing. |
Each of these base types uses a fixed, predefined renderer implementation for the representation of the respective graph element, eliminating the need to create an explicit renderer and thus simplifying the creation of a custom style type to appropriate implementations of a few callback methods. Instead the work of the renderer is delegated to methods in the subclass, of which the important ones are abstract.
Example 2.17, “Custom node style implementation” presents a sample node style type based on abstract class SimpleAbstractNodeStyle that provides a custom implementations for the callback method.
Example 2.17. Custom node style implementation
public class MyCirclesNodeStyle : SimpleAbstractNodeStyle {
private double percentage = 0.25d;
private Color backColor = Color.Blue;
private Color foreColor = Color.Orange;
public double Percentage {
get { return percentage; }
set { percentage = Math.Min(Math.Max(value, 0.0), 1.0); }
}
public Color BackColor {
get { return backColor; }
set { backColor = value; }
}
public Color ForeColor {
get { return foreColor; }
set { foreColor = value; }
}
// Paints a filled circle and on top of that another filled circle. The radius
// of the second circle is given as a percentage value relative to that of the
// first circle.
protected override void Paint(INode node, Graphics g, IRenderContext rc) {
IRectangle layout = node.Layout;
float x = (float)layout.X; float y = (float)layout.Y;
float w = (float)layout.Width; float h = (float)layout.Height;
Brush brush = new SolidBrush(style.BackColor);
g.FillEllipse(brush, x, y, w, h);
float wi = (float)(node.Layout.Width * style.Percentage);
float hi = (float)(node.Layout.Height * style.Percentage);
brush = new SolidBrush(style.ForeColor);
g.FillEllipse(brush, x + (w - wi) / 2.0, y + (h - hi) / 2.0, wi, hi);
}
// The abstract base class calls this method when hit tests should be
// performed.
protected override bool IsHit(INode node, PointD point, ICanvasContext ctx) {
return GeomSupport.EllipseContains(node.Layout.ToRectD(), point,
ctx.HitTestRadius);
}
// Finds an intersection for the current node.
protected override PointD? GetIntersection(INode node,
PointD inner, PointD outer) {
return GeomSupport.FindEllipseLineIntersection(node.Layout.ToRectD(),
inner, outer);
}
// Checks whether the given coordinates lie within the circle.
protected override bool IsInside(INode node, PointD point) {
return GeomSupport.EllipseContains(node.Layout.ToRectD(), point, 0);
}
}
The Custom Styles tutorial presents step by step how to create custom node, edge, port, and label styles on the basis of the respective SimpleAbstractStyle class.
The available style renderer implementations either directly or indirectly
inherit from abstract generic class
AbstractStyleRenderer<TModelItem, TModelStyle, TStyle>
,
which combines all necessary functionality that relates to the visual
appearance of graph elements.
In particular, it implements interface
IPaintable
, which defines the
method that is invoked for providing the actual rendering for an item.
Figure 2.16, “Common style renderer base type AbstractStyleRenderer” depicts the inheritance structure
of AbstractStyleRenderer.
Node style renderers are the complementary counterparts to the node styles.
They provide the actual logic that is invoked by the canvas for rendering an
item.
Interface
INodeStyleRenderer
is the
common base type for actual implementations.
The predefined node style renderer implementations together with the respective styles they correspond to are listed in Table 2.8, “Predefined node style renderer implementations”.
Table 2.8. Predefined node style renderer implementations
| Style Type | Complementing Renderer Type | Description |
|---|---|---|
| IShapeNodeStyle |
ShapeNodeStyleRenderer |
Renders a node using the shape that is defined by the Shape property of the node's associated IShapeNodeStyle object. |
| IImageNodeStyle |
ImageNodeStyleRenderer |
Renders a node using the image returned by the Image property of the node's associated IImageNodeStyle object. |
| IGeneralPathNodeStyle |
GeneralPathNodeStyleRenderer |
Renders a node using the GeneralPath object returned by the Path property of the node's associated IGeneralPathNodeStyle object. |
| IBevelNodeStyle |
BevelNodeStyleRenderer |
Renders a node using the properties of the node's associated IBevelNodeStyle object. |
| IPanelNodeStyle |
PanelNodeStyleRenderer |
Renders a node using the properties of the node's associated IPanelNodeStyle object. |
| IShinyPlateNodeStyle |
ShinyPlateNodeStyleRenderer |
Renders a node using the properties of the node's associated IShinyPlateNodeStyle object. |
Abstract generic class
AbstractNodeStyleRenderer<TStyle>
provides default implementations for most of the abstract methods from its base
type AbstractStyleRenderer.
Inheriting types still need to implement the
Paint
method appropriately.
Also, the type parameter, which is constrained to be of type INodeStyle, needs
to be bound to the style type that this renderer type is actually
complementing.
Edge style renderers are the complementary counterparts to the edge styles.
They provide the actual logic that is invoked by the canvas for rendering an
item.
Interface
IEdgeStyleRenderer
is the
common base type for actual implementations.
The predefined edge style renderer implementations together with the respective styles they correspond to are listed in Table 2.9, “Predefined edge style renderer implementations”.
Table 2.9. Predefined edge style renderer implementations
| Style Type | Complementing Renderer Type | Description |
|---|---|---|
| IArcEdgeStyle |
ArcEdgeStyleRenderer |
Renders an edge as an arc using the properties of the edge's associated IArcEdgeStyle object. |
| IPolylineEdgeStyle |
PolylineEdgeStyleRenderer |
Renders an edge as a poly-line path using the properties of the edge's associated IPolylineEdgeStyle object. |
Port style renderers are the complementary counterparts to the port styles.
They provide the actual logic that is invoked by the canvas for rendering an
item.
Interface
IPortStyleRenderer
is the
common base type for actual implementations.
The predefined port style renderer implementations together with the respective styles they correspond to are listed in Table 2.10, “Predefined port style renderer implementations”.
Table 2.10. Predefined port style renderer implementations
| Style Type | Complementing Renderer Type | Description |
|---|---|---|
| ISimplePortStyle |
SimplePortStyleRenderer |
Renders a port as a circle using the Brush property of the port's associated ISimplePortStyle. |
Note that SimplePortStyleRenderer directly inherits from abstract generic class AbstractStyleRenderer. The type parameters are bound to the IPort, IPortStyle, and ISimplePortStyle types.
Label style renderers are the complementary counterparts to the label styles.
They provide the actual logic that is invoked by the canvas for rendering an
item.
Interface
ILabelStyleRenderer
is the
common base type for actual implementations.
The predefined label style renderer implementations together with the respective styles they correspond to are listed in Table 2.11, “Predefined label style renderer implementations”.
Table 2.11. Predefined label style renderer implementations
| Style Type | Complementing Renderer Type | Description |
|---|---|---|
| ISimpleLabelStyle |
SimpleLabelStyleRenderer |
Renders a label's text within the oriented rectangle that describes the label's layout. The renderer uses the properties of the label's associated ISimpleLabelStyle object. |
| IIconLabelStyle |
IconLabelStyleRenderer |
Renders a label's text (see description of SimpleLabelStyleRenderer) and the icon that the label's associated IIconLabelStyle object returns. |
Note that IconLabelStyleRenderer directly inherits from abstract generic class AbstractStyleRenderer. The type parameters are bound to the ILabel, ILabelStyle, and IconLabelStyle types.
Abstract generic class AbstractLabelStyleRenderer<TStyle>
provides default implementations for most of the abstract methods from its base
type AbstractStyleRenderer.
The remaining methods that need to be implemented by inheriting types are listed
in API Excerpt 2.15, “Abstract methods from class AbstractLabelStyleRenderer”.
Also, the type parameter, which is constrained to be of type ILabelStyle, needs
to be bound to the style type that this renderer type is actually complementing.
The location of a port at a node, in both static as well as dynamic scenarios, is determined by a so-called port location model. It is responsible for finding the proper location for a port with respect to a port location model parameter. The port location model parameter is associated with a port and encodes its desired position. It is created by a port location model and is valid only in the context of this port location model.
In a dynamic scenario, where a user resizes or moves a node, or moves a port, port location models are queried to determine the proper location of the port(s).
Although a port location model determines the position of a port, it cannot be
associated with one.
Instead, a
port location model parameter
that is created by a port location model instance is associated with a given
port.
Then, to determine the port's position, this port location model instance is
found via the model parameter's
Model
property.
Interface IPortLocationModel
provides the basis for port location model implementations.
Table 2.12, “Predefined port location model implementations” lists the predefined port
location model implementations.
Table 2.12. Predefined port location model implementations
| Model Type | Description |
|---|---|
| AnchoredPortLocationModel |
Specifies the location of a port in world coordinates. |
| NodeScaledPortLocationModel |
The location of a port is specified relative to the center of the node and in relation to its geometry. See the description below. |
Class NodeScaledPortLocationModel defines a port location model where the location of a port is specified relative to the center of the node and in relation to the geometry of the node's bounding rectangle.
The center of the node is interpreted as the origin of a "coordinate system" where going up/to the left means negative sign and going down/to the right means positive sign. The distances to the borders of the node are interpreted relative to the node's width and height, respectively, so that the distance to the left (right) border, for example, is always half the width. Thus, the top left corner of the node corresponds to the relative location (-0.5, -0.5), the bottom right corner to (0.5, 0.5).
When the width or height of a node changes, the location of a port is appropriately updated according to the node's new geometry. In effect, this means that the distances to the center of the node are scaled using the same factor that the width/height have changed.
NodeScaledPortLocationModel provides convenient support for nine predefined port locations. Example 2.18, “Creating a model parameter for a custom port location” shows how a model parameter for a custom port location can be created. It uses a relative offset that defines the port to be anchored at a discrete location right of the node's center, half way to the node's border.
Example 2.18. Creating a model parameter for a custom port location
// 'node' is of type yWorks.yFiles.UI.Model.INode
NodeScaledPortLocationModel nsplm = NodeScaledPortLocationModel.Instance;
IPortLocationModelParameter plmp =
nsplm.CreateOffsetParameter(node, new PointD(0.25, 0.0));
When the node is resized, this custom port location will be scaled accordingly so that the port is always located right of the node's center, half way to the node's border.
A port location model parameter is an implementation of interface
IPortLocationModelParameter
that is created by a port location model.
It encodes a possible port position that is valid in the context of its
corresponding port location model.
To create a model parameter, IPortLocationModel defines the method shown in API Excerpt 2.16, “Default port location model parameter creation method” which can be used to obtain a model parameter that best matches a given (world coordinates) port location. The available port location models provide further model-specific methods to create valid model parameters.
API Excerpt 2.16. Default port location model parameter creation method
IPortLocationModelParameter CreateParameter(IPortOwner portOwner,
PointD location)
API Excerpt 2.17, “Port location model parameter methods from interface IGraph” lists the methods provided by interface IGraph that can be used to specify the port location model parameter for a port.
When a port is added to a model item of the graph using the AddPort method that
lacks the port location model parameter, class DefaultGraph associates the port
location model parameter that it finds as part of the default settings for the
model item's kind.
Technically, this means that DefaultGraph queries the
LocationModelParameter
property of the IPortDefaults implementation which is part of the default
settings of either nodes or edges.
API Excerpt 2.17. Port location model parameter methods from interface IGraph
// Setting the port location model parameter when adding a new port to the
// graph model.
IPort AddPort(IPortOwner owner,
IPortLocationModelParameter locationModelParameter)
IPort AddPort(IPortOwner owner,
IPortLocationModelParameter locationModelParameter,
IPortStyle portStyle)
// Setting the port location model parameter for an existing port.
void SetLocationModelParameter(IPort port,
IPortLocationModelParameter locationParameter)
The geometry of both node labels and edge labels is determined by so-called label models. Specifically, a label model is responsible for finding the proper location for a label with respect to a "label model parameter." The label model parameter is associated with a label and encodes its desired position. It is created by a label model and is valid only in the context of this label model.
Although a label model determines the position of a label, it cannot be
associated with one.
Instead, a
label model parameter
that is created by a label model instance is associated with a given label.
Then, to determine the label's position, this label model instance is found via
the model parameter's
Model
property.
Interface ILabelModel
provides the basis for both
node label model and
edge label model implementations
described below.
In addition to these label models that determine the location of a label
relative to its respective owner, class
FreeLabelModel
can be used to place labels freely in world coordinate space.
ILabelModel is also the basis for class
GenericLabelModel
q
which can be used to
create user-defined node label and edge label models.
A label model parameter is an implementation of interface
ILabelModelParameter
that is
created by a label model.
It encodes a possible label position that is valid in the context of its
corresponding label model.
Most often, the position that a model parameter encodes is a predefined
position that is defined relative to the owner of the label.
For example, the node label model
ExteriorLabelModel
uses model parameters that encode eight distinct logical positions around a
node, named North, NorthEast, East,
SouthEast, etc., which define positions outside the bounds of a
node.
To create a model parameter, ILabelModel defines the method shown in API Excerpt 2.18, “Default label model parameter creation method” that can be used to obtain the so-called "default model parameter" for a given label model. The available node label models and edge label models provide further model-specific methods to create valid model parameters.
API Excerpt 2.18. Default label model parameter creation method
ILabelModelParameter CreateDefaultParameter()
API Excerpt 2.19, “Label model parameter methods from interface IGraph” lists the methods provided by interface IGraph that can be used to specify the label model parameter for a label.
When a label is added to a model item of the graph using the AddLabel method
that lacks the label model parameter, class DefaultGraph associates the label
model parameter that it finds as part of the default settings for the model
item's kind.
Technically, this means that DefaultGraph queries the
LabelModelParameter
property of the ILabelDefaults implementation which is part of the default
settings of either nodes or edges.
API Excerpt 2.19. Label model parameter methods from interface IGraph
// Setting the label model parameter when adding a new label to the graph model.
ILabel AddLabel(ILabeledItem item, ILabelModelParameter labelModelParameter,
string text)
ILabel AddLabel(ILabeledItem item, ILabelModelParameter labelModelParameter,
ILabelStyle style, string text)
ILabel AddLabel(ILabeledItem item, ILabelModelParameter labelModelParameter,
ILabelStyle style, string text, object tag)
ILabel AddLabel(ILabeledItem item, ILabelModelParameter labelModelParameter,
ILabelStyle style, string text, SizeD preferredSize)
// Setting the label model parameter for an existing label.
void SetLabelModelParameter(ILabel label, ILabelModelParameter parameter)
Node label models are responsible for determining the geometry of labels where the actual owner is an INode. Figure 2.19, “Hierarchy of node label model types” depicts the type hierarchy of available node label models.
Label model type
FreeNodeLabelModel
allows to freely define a node label's position relative to its owner.
The predefined node label positions used with all other node label models are
depicted in Figure 2.20, “Possible node label positions” and
Figure 2.21, “Possible node label positions with InteriorStretchLabelModel”.
The latter figure illustrates the predefined label positions of label model
type
InteriorStretchLabelModel
.
It is important to note that the set of valid positions varies with the model types, i.e., not all possible positions are valid for each node label model. Table 2.13, “Valid node label positions for each model type” lists the sets of valid positions for each node label model.
Table 2.13. Valid node label positions for each model type
| Model Type | Valid Positions |
|---|---|
| InteriorLabelModel |
NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast |
| ExteriorLabelModel |
NorthWest, North, NorthEast, West, East, SouthWest, South, SouthEast |
| SandwichLabelModel |
North, South |
The predefined node label positions of InteriorStretchLabelModel consist of the following five positions: North, East, South, West, and Center as shown in Figure 2.21, “Possible node label positions with InteriorStretchLabelModel”.
When a label is at the East or West position, it is also rotated so that the base line of the label text is near the center of the node. In addition, InteriorStretchLabelModel also changes the length of the labels to match the node's height (East and West positions) or its width (North and South positions). Labels at Center position use the entire geometry of the node.
Figure 2.21. Possible node label positions with InteriorStretchLabelModel
![]() |
![]() |
| Non-Center label positions. Note the label orientation at East and West positions. | Labels at Center position are stretched to use the entire geometry of the node. |
Example 2.19, “Adding a node label using a specific label model parameter” demonstrates how to set a label model parameter that describes a position valid in the context of ExteriorLabelModel.
Example 2.19. Adding a node label using a specific label model parameter
// 'graph' is of type yWorks.yFiles.UI.Model.IGraph. // 'node' is of type yWorks.yFiles.UI.Model.INode. graph.AddLabel(node, ExteriorLabelModel.NorthEast, "I am NorthEast.");
Setting up and using node label models is extensively presented in tutorial demo application GraphEditorForm.
Edge label models are responsible for determining the geometry of labels where the actual owner is an IEdge. Figure 2.22, “Hierarchy of edge label model types” depicts the type hierarchy of available edge label models.
The following example code demonstrates how to set an edge label model parameter that describes a position valid in the context of RotatedSliderEdgeLabelModel:
Example 2.20. Sharing a label model parameter instance among a set of edge labels
// 'graph' is of type yWorks.yFiles.UI.Model.IGraph.
RotatedSliderEdgeLabelModel rselm = new SliderEdgeLabelModel();
rselm.Distance = 10;
// The label will be placed at the side of the edge near the first bend.
ILabelModelParameter rselmp = rselm.CreateParameterFromSource(0, 1.0);
foreach (ILabel edgeLabel in myEdgeList) {
graph.SetLabelModelParameter(edgeLabel, rselmp);
}
Setting up and using edge label models is extensively presented in tutorial demo applications GraphEditorForm and EdgeLabelingForm.
Edge labels also support being rotated, and using an appropriate edge label model it is possible to have the text of an edge label be in parallel to its corresponding edge segment, even in a dynamic scenario where the slope of the edge segment changes.
Figure 2.23. Candidates for a specific edge label model using side slider edge label model
![]() |
![]() |
| Possible label candidates along the edge's path as found by RotatedSideSliderEdgeLabelModel for an auto-rotated edge label. | ...the same, but for a non-auto-rotated edge label. |
![]() |
| ...the same, but for a non-auto-rotated edge label that has a preset rotation angle (of 315 degrees counterclockwise). |
With RotatedSliderEdgeLabelModel
or RotatedSideSliderEdgeLabelModel
the label placement can be controlled by a number of properties:
bool AutoRotationEnabled { get; set; } |
|
| Description | Specifies whether or not edge labels are automatically rotated according to the angle of the corresponding reference edge segment. By default, this feature is enabled. |
double Angle { get; set; } |
|
| Description | The angle of the label. If auto-rotation is enabled, the angle is measured counterclockwise relative to the edge. If not, it is relative to the x-axis. The default angle is 0.0. |
double Distance { get; set; } |
|
| Description | The distance between the label's box and the edge's path. A distance of 0.0, which is the default value, means label placement on the edge's path. In conjunction with the DistanceRelativeToEdge property, positive and negative values can be used to place labels to the sides of the edge path or above/below the edge path. |
bool DistanceRelativeToEdge { get; set; } |
|
| Description | Determines whether the value of the Distance property is interpreted to mean label placement to the sides of the edge path or above/below the edge path. |
The parameters for both label models place the label on a specific segment of the
edge with a given ratio where 0.0 places the label at the start of
the segment and 1.0 at the end.
For RotatingSliderEdgeLabelModel, the
CreateParameterFromSource
and
CreateParameterFromTarget
methods create a parameter with a segment index and ratio counting from the source
or the target node of the edge, respectively.
For RotatedSideSliderEdgeLabelModel, the corresponding
CreateParameterFromSource
and
CreateParameterFromTarget
methods additionally allow to determine whether the label should be placed to the
left or to the right of the edge.
The following example demonstrates how to place labels using the RotatedSliderEdgeLabelModel and the RotatedSideSliderEdgeLabelModel:
Example 2.21. Using the Rotated(Side)SliderEdgeLabelModel
// 'graph' is of type yWorks.yFiles.UI.Model.IGraph.
// 'edge1' and 'edge2' are of type yWorks.yFiles.UI.Model.IEdge.
// Create a label model which auto-rotates and places the label on the edge path.
RotatedSliderEdgeLabelModel centerModel =
new RotatedSliderEdgeLabelModel();
centerModel.Distance = 0;
centerModel.AutoRotationEnabled = true;
// Create a parameter for this model which places the label in the middle
// (ratio 0.5) of the second (0-based index 1) segment counting from the source
// node.
ILabelModelParameter centerParam =
centerModel.CreateParameterFromSource(1, 0.5);
// Add the label.
graph.AddLabel(edge1, "Center", centerParam);
////////////////////////////////////////////////////////////////////////////////
// Create a label model which places the labels at either side of the edge.
RotatedSideSliderEdgeLabelModel sideModel =
new RotatedSideSliderEdgeLabelModel();
sideModel.Distance = 10; // 10 units away from the edge
sideModel.AutoRotationEnabled = false; // auto rotation disabled
sideModel.Angle = 0; // parallel to the x-axis
// Create a parameter which places the label at the beginning of the first edge
// segment seen from the target node.
ILabelModelParameter sideParam =
sideModel.CreateParameterFromTarget(0, 0.0, true);
// Add the label.
graph.AddLabel(edge2, "Side", sideParam);
Class
GenericLabelModel
provides a generic means to create user-defined label models for either node
labels or edge labels.
It allows to compose a custom blend of arbitrary label positions that are
available with the predefined label models using the methods below:
API Excerpt 2.20. Methods for creating user-defined label models
// Determines the default label model parameter. GenericLabelModel(ILabelModelParameter defaultParameter) ILabelModelParameter AddParameter(ILabelModelParameter parameter)
For example, it is easily possible to create a node label model that uses the NorthEast label positions of the InteriorNodeLabelModel and the ExteriorNodeLabelModel together with a Center position as the default parameter. See Example 2.22, “Composing a node label model”.
|
Copyright ©2006-2011, yWorks GmbH. All rights reserved. |