Visual Representation of Graph Elements

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.

Styles

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.

Figure 2.6. Hierarchy of style types

Hierarchy of style types.

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

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.

Figure 2.7. Hierarchy of node style types

Hierarchy of node style types.

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 defines enumerators for the available shapes.
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 objects to create the visual representation for a node.
PanelNodeStyle An implementation of interface IPanelNodeStyle that can be used to create the visual representation for group nodes, for example. By default, this style renders a drop shadow by itself.
BevelNodeStyle An implementation of interface IBevelNodeStyle that can be used to create rectangular nodes with rounded corners, a bevel border, and a shining background. Optionally, this style renders a drop shadow by itself.
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

ShapeNodeStyle: Rectangle
ShapeNodeStyle: RoundRectangle
ShapeNodeStyle: Ellipse
UriImageNodeStyle
Some of the predefined shapes of ShapeNodeStyle UriImageNodeStyle showing the yWorks logo
PanelNodeStyle
BevelNodeStyle
ShinyPlateNodeStyle
Node Representation Using SimpleAbstractNodeStyle

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.

Node Style Customization

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.

Figure 2.9. ShapeNodeStyle decorated using ShadowNodeStyleDecorator

ShapeNodeStyle decorated using ShadowNodeStyleDecorator

Edge Styles

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.

Figure 2.10. Hierarchy of edge style types

Hierarchy of edge style types.

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.

Figure 2.11. Edge style representations

ArcEdgeStyle
PolylineEdgeStyle
ArcEdgeStyle PolylineEdgeStyle
Edge Representation Using SimpleAbstractEdgeStyle

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.

Edge Style Customization

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”.

Note

Because bends are an integral part of an edge, they are rendered by the edge style, too.

Port Styles

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.

Figure 2.12. Hierarchy of port style types

Hierarchy of port style types.

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.
Port Representation Using SimpleAbstractPortStyle

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.

Port Style Customization

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

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.

Figure 2.13. Predefined label style types

Predefined label style types.

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.
Label Representation Using SimpleAbstractLabelStyle

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.

Label Style Customization

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.

Figure 2.14. Edge label that uses NodeStyleLabelStyleAdapter

NodeStyleLabelStyleAdapter

Working with Styles

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”.

Figure 2.15. Shape node style and image node style

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

  • shared among a set of like items or be
  • used exclusively with a single item.

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();

Creating Custom Styles

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.

Style Renderers

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.

Figure 2.16. Common style renderer base type AbstractStyleRenderer

Common style renderer base type AbstractStyleRenderer.

Node Style Renderers

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.

API Excerpt 2.13. Abstract paint method in class AbstractNodeStyleRenderer

// Paints the node.
abstract void Paint(Graphics g, IPaintContext ctx)

Edge Style Renderers

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.

API Excerpt 2.14. Abstract methods from class PathBasedEdgeStyleRenderer

// The edge's actual path.
protected abstract GeneralPath CreatePath()
// The Pen that is used by the Paint method to render the edge path.
protected abstract Pen GetPen()

Port Style Renderers

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

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.

API Excerpt 2.15. Abstract methods from class AbstractLabelStyleRenderer

// Returns the label's preferred size.
protected abstract SizeD GetPreferredSize()

// Paints the label's content.
protected abstract void PaintContent(Graphics g, IRenderContext ctx,
                                     double width, double height)

Port Support

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).

Figure 2.17. IPortLocationModel

IPortLocationModel.

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.

Port Location Model Parameter

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.

Note

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)

Label Support

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.

Figure 2.18. ILabelModel

ILabelModel.

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.

Label Model Parameter

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.

Note

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

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.

Figure 2.19. Hierarchy of node label model types

Hierarchy of node label model types.

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 .

Figure 2.20. Possible node label positions

Possible node label positions.

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

Possible node label positions with InteriorStretchLabelModel.
Center node label position of 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

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.

Figure 2.22. Hierarchy of edge label model types

Hierarchy of edge label model types.

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.

Rotated Edge Label Models

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

Edge label candidates by RotatedSideSliderEdgeLabelModel.
Edge label candidates by RotatedSideSliderEdgeLabelModel.
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.
Edge label candidates by RotatedSideSliderEdgeLabelModel.
...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);

Generic Label Model

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”.

Example 2.22. Composing a node label model

GenericLabelModel glm = new GenericLabelModel(InteriorLabelModel.Center);
glm.AddParameter(InteriorLabelModel.NorthEast);
glm.AddParameter(ExteriorLabelModel.NorthEast);