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 GraphCanvasComponent 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 section called “Label Support” so-called label models are presented.

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 available styles.

Figure 2.6. Hierarchy of style types

Hierarchy of style types.

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 a part of the type hierarchy of 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 package com.yworks.graph.drawing.

Table 2.3. Predefined node style implementations

Type Name Description
ShapeNodeStyle Provides a variety of predefined shapes for the visual appearance of a node. Class ShapeNodeShape defines constants for the available shapes.
ImageNodeStyle Enables using a bitmap or vector image to create the visual representation for a node. The image can be either set directly using an embedded image, or it can be loaded from an URL. This style supports the vector-based FXG, SVG, and SWF formats, as well as GIF, JPEG and PNG bitmap images.
BitmapNodeStyle Enables using a bitmap image to create the visual representation of a node. In contrast to the ImageNodeStyle, the default serialization mechanism of this style uses Base64-encoded bitmap data for writing the image.
ComponentNodeStyle An INodeStyle implementation that enables using arbitrary Flex UIComponents for the visual representation of nodes. This style has been deprecated. Please use TemplateNodeStyle instead.
TemplateNodeStyle An INodeStyle implementation that enables using arbitrary Flex UIComponents for the visual representation of nodes. In contrast to the ComponentNodeStyle, these components are aware of their context, i.e. the nodes they represent and the data associated with the nodes. For details see the section called “Node Representation Using Flex Components”.
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.
ShinyPlateNodeStyle Can be used to create rectangular nodes with rounded corners and a 'shiny plate' interior.
Node Representation Using Flex Components

The node style TemplateNodeStyle allows to use Flex components for the representation of nodes in an IGraph. Typically, the components are created as MXML components. The components need to define properties for user data (an arbitrary object, e.g. an object which represents the "data behind" the graph item) and the context which is of type TemplateStyleDataContext. Both properties can have an arbitrary name which has to be set to the style instance. Their values will be set by the renderer during the rendering process.

The user data is retrieved by an IUserTagProvider which can be specified in the TemplateNodeStyle's userTagProvider property. By default, a TagOwnerUserTagProvider is used. This provider retrieves the user data from the item's tag owner (see the section called “User Tags”).

In addition to the item related user data it is possible to use the TemplateNodeStyle's styleTag property to set a style related user object.

The following example demonstrates how to create a TemplateNodeStyle together with a matching template component:

As user data, a class Person is used which represents data related to a person:

Example 2.14. The class Person which represents the data behind the nodes.

public class Person
{
    public var name:String; // the person's name
    public var id:String;   // the person's id
    public var vip:Boolean; // whether the person is a VIP
}

The node which corresponds to a person is rendered as a Canvas with a background color which is defined by the style. The name and ID are displayed as labels. The name is displayed with a red font if the person is a VIP, otherwise with a black font. Such a component is shown in Example 2.15, “Creating a custom component to be used with the TemplateNodeStyle”.

Example 2.15. Creating a custom component to be used with the TemplateNodeStyle

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" 
  width="{INode(context.modelItem).layout.width}"
  height="{INode(context.modelItem).layout.height}"
  backgroundColor="{SolidColor(context.styleTag).color}"
  horizontalScrollPolicy="off"
  verticalScrollPolicy="off">
<!-- width and height are the node's width and height. -->
<!-- The node is retrieved from the context's modelItem property. -->
<!-- The backgroundColor is taken from the style's styleTag. -->
<!-- The scrollbars are disabled. -->

  <mx:Script>
    <![CDATA[
      // the property for the user data
      [Bindable]
      public var person:Person;

      // the property for the context
      [Bindable]
      public var context:TemplateStyleDataContext;
    ]]>
  </mx:Script>

  <mx:VBox width="100%" height="100%">
    <mx:HBox width="100%" height="100%">
      <mx:Label text="Name:"/>
      <!-- the label text is set to the person's name property -->
      <!-- the text color according to the person's vip property -->
      <mx:Label text="{person.name}"
                color="{person.vip?0xFF0000:0x000000}"/>
    </mx:HBox>
    <mx:HBox width="100%" height="100%">
      <mx:Label text="ID:"/>
      <!-- // the label text is set to the person's id property -->
      <mx:Label text="{person.id}" />
    </mx:HBox>
  </mx:VBox>
</mx:Canvas>

Example 2.16, “Creating a new TemplateNodeStyle instance” shows how to create a new style instance which uses the above class, TemplateComponent, as component. The person property identifier is set as the style's dataPropertyName and the context property identifier is set as contextPropertyName. Also, the style's styleTag is set to a SolidColor instance to yield a light gray background.

Example 2.16. Creating a new TemplateNodeStyle instance

// create a new TemplateNodeStyle
var style:TemplateNodeStyle = new TemplateNodeStyle(TemplateComponent, "person", "context");
style.styleTag = new SolidColor(0xEEEEEE);

As no custom userTagProvider is set, the user data (i.e. the Person instances) will be retrieved from the node's ITagOwner. In other words, each node has to have its Person instance mapped to its ITagOwner's tag.

The TemplateStyleDemo demonstrates how to use the TemplateNodeStyle.

Node Style Customization

Custom node styles need to implement the styleRenderer property defined in interface INodeStyle and the install() method from interface IVisualStyle. See also the section called “Creating Custom Styles”.

Figure 2.8, “Sample renderings of BevelNodeStyle, PanelNodeStyle, and ShapeNodeStyle” shows examples of nodes using BevelNodeStyle, PanelNodeStyle, and ShapeNodeStyle respectively. Note that PanelNodeStyle renders a drop shadow by itself.

Figure 2.8. Sample renderings of BevelNodeStyle, PanelNodeStyle, and ShapeNodeStyle

BevelNodeStyle
PanelNodeStyle
ShapeNodeStyle
yFiles Java Compatibility Node Styles

yFiles FLEX includes specialized style implementations for compatibility with yFiles Java. For details about working with yFiles FLEX and yFiles Java, please see the section called “Communicating with yFiles Java on the Server”.

Table 2.4. yFiles Java compatibility node styles

Type Name Description
JavaShapeNodeStyle A node style implementation that corresponds to the yFiles Java ShapeNodeRealizer
JavaImageNodeStyle A node style implementation that corresponds to the yFiles Java ImageNodeRealizer
JavaGroupNodeStyle A node style implementation that corresponds to the yFiles Java GroupNodeRealizer

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.9, “Hierarchy of edge style types” shows the type hierarchy of edge style implementations.

Figure 2.9. Hierarchy of edge style types

Hierarchy of edge style types.

Table 2.5, “Predefined edge style implementations” lists the predefined edge style implementations present in package com.yworks.graph.drawing.

Table 2.5. Predefined edge style implementations

Type Name Description
PolylineEdgeStyle An edge representation where straight line segments are used to connect the bends.
Edge Style Customization

Abstract class AbstractEdgeStyle serves as a convenient basis for actual edge styles. Custom edge styles still need to implement the install() method from interface IVisualStyle. 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.10, “Hierarchy of port style types” shows the type hierarchy of port style implementations.

Figure 2.10. Hierarchy of port style types

Hierarchy of port style types.

Table 2.6, “Predefined port style implementations” lists the predefined port style implementations present in package com.yworks.graph.drawing.

Table 2.6. Predefined port style implementations

Type Name Description
SimplePortStyle Provides a simple representation for ports.
Port Style Customization

Custom port styles need to implement the styleRenderer property defined in interface IPortStyle and the install() method from interface 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.11, “Predefined label style types” shows the type hierarchy of label style implementations.

Figure 2.11. Predefined label style types

Predefined label style types.

Table 2.7, “Predefined label style implementations” lists the predefined label style implementations present in package com.yworks.graph.drawing.

Table 2.7. Predefined label style implementations

Type Name Description
SimpleLabelStyle Enables rendering of a label's text.
TLFLabelStyle A simple label style which uses the Flash Text Engine and the Text Layout Framework (TLF) to render the label text. This style supports CFF fonts, bidirectional text and different text converters. The Text Layout Framework is part of Flex 4.
CSSLabelStyle A simple label style which uses style sheets instead of TextFormat for formatting texts.
IconLabelStyle Builds on the functionality that SimpleLabelStyle provides and additionally allows to place an icon at several positions relative to the label's text.
IconLabelStyleDecorator Allows to place an icon at several positions relative to the label's text on a label which is rendered by an arbitrary ILabelStyle.
NodeStyleLabelStyleAdapter Allows to add the rendering of a given node style as the background for the visual representation of the wrapped label style.
TemplateLabelStyle An ILabelStyle implementation that enables using arbitrary Flex UIComponents for the visual representation of nodes.These components are aware of their context, i.e. the labels they represent and the data associated with the labels. The TemplateLabelStyle is used like the TemplateNodeStyle whose usage is explained in the section called “Node Representation Using Flex Components”.
Label Style Customization

Custom label styles need to implement the styleRenderer property defined in interface ILabelStyle and the install() method from interface 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.12, “Edge label that uses NodeStyleLabelStyleAdapter” shows an edge label where a BevelNodeStyle is used to render the background.

Figure 2.12. 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.17, “Creating a graph”. The resulting graph is depicted in Figure 2.13, “Shape node style and image node style”.

Figure 2.13. Shape node style and image node style

Shape node style and image node style.

Example 2.17. Creating a graph

[Embed(source="resources/image.png")]
private static var imageClass:Class;

private function createGraph():IGraph {
  var graph:IGraph = new DefaultGraph();

  // Set up a node style that uses a circle.
  var sns:ShapeNodeStyle = ShapeNodeStyle( graph.defaultNodeStyle );
  sns.shapeNodeShape = ShapeNodeShape.ELLIPSE;
  
  // Set up a node style that uses an image to represent nodes.
  var ins:ImageNodeStyle = new ImageNodeStyle();
  ins.imageClass = imageClass;
  graph.defaultNodeStyle = ins;
  graph.defaultNodeSize = 
    com.yworks.canvas.geom.Size.create(ins.image.width, ins.image.height);
  
  // Create some nodes.
  var nodes:Array = new Array(6);
  for (var i:int = 0; i < nodes.length - 1; i += 2) {
    nodes[i] = graph.createNodeAt(i * 50, 100);
    graph.setNodeStyle(nodes[i], sns);
    graph.setBounds(nodes[i], nodes[i].layout.x, nodes[i].layout.y, 40, 40);
    nodes[i + 1] = graph.createNodeAt(i * 50, 200);
  }
  
  return graph;
}

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.18, “Style sharing” presents this scheme using the setNodeStyle 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.18. Style sharing

// 'graph' is of type com.yworks.graph.model.IGraph.

var shapeNS:MyShapeNodeStyle = new MyShapeNodeStyle();
for (var it:Iterator = myNodeList.iterator(); it.hasNext(); ) {
  graph.setNodeStyle(INode( it.next() ), shapeNS);
}

In contrast, when a node is associated with a style via the default style mechanism provided by class DefaultGraph, a copy of the style instance that is returned by the defaultNodeStyle property is used.

Example 2.19, “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.19. Changing the color of a node

// 'graph' is of type com.yworks.graph.model.IGraph.
// 'node' is of type com.yworks.graph.model.INode.

var shapeNS:IShapeNodeStyle = node.style as IShapeNodeStyle;
if (shapeNS != null) {
  shapeNS.fill = Fills.BLUE;
}

Creating Custom Styles

Each style type teams 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.

Framework requirements for an actual custom style type are minimal: the style's styleRenderer property is expected to return an instance of the style's complementing renderer type. The instance is then used for the rendering of corresponding model items. Also needed is an implementation for the install() method defined in interface IVisualStyle. In almost all cases, however, this can be safely realized as a lean implementation that just forwards all invocations to the renderer's install method.

Additionally, a style type needs to provide a clone method that can be used to create copies of an instance.

Example 2.20, “Custom node style implementation” presents a sample implementation of a node style type that fulfills the framework requirements as described above.

Example 2.20. Custom node style implementation

public class CustomStyle implements INodeStyle {
  private var _styleRenderer:CustomStyleRenderer;
  private var _stroke:IStroke;
  private var _percentage:Number = 0.5;
  private var _fill:IFill;

  /**
   * Create a new style instance.
   * @param styleRenderer Custom renderer instance for this style. 
   *                      If <code>null</code>, a default style renderer 
   *                      is used.
   * @param stroke The initial stroke for this style. 
   *               If <code>null</code>, a default stroke is used.
   * @param fill The initial fill for this style. 
   *             If <code>null</code>, a default fill is used.
   */
  public function CustomStyle( styleRenderer:CustomStyleRenderer = null, 
                               stroke:IStroke = null, fill:IFill = null ) {
    if( null != styleRenderer ) {
      this._styleRenderer =  styleRenderer;
    } else {
      this._styleRenderer = new CustomStyleRenderer();
    }

    if( null != stroke ) {
      this._stroke = stroke;
    } else {
      this._stroke = new Stroke( 0x000000, 1.0, 1.0 );
    }

    if( null != fill ) {
      this._fill = fill;
    } else {
      this._fill = new SolidColor( 0xFFCC00, 1.0 );
    }
  }

  public function set fill( fill:IFill ):void {
    this._fill = fill;
  }

  public function get fill():IFill {
    return this._fill;
  }

  public function set stroke( stroke:IStroke ):void {
    this._stroke = stroke;
  }

  public function get stroke():IStroke {
    return this._stroke;
  }

  public function set percentage( percentage:Number):void {
    this._percentage = percentage;
  }

  public function get percentage():Number {
    return this._percentage;
  }

  public function get styleRenderer():IStyleRenderer {
    return this._styleRenderer;
  }

  public function install( canvas:CanvasComponent, group:ICanvasObjectGroup, 
                           modelItem:IModelItem ):Array {
    return this._styleRenderer.install( canvas, group, modelItem );
  }

  public function clone():Object {
    var clone:CustomStyle = 
      new CustomStyle( this._styleRenderer, this._stroke, this._fill );
    clone.percentage = percentage;
    return clone;
  }
}

To create a custom style renderer type one of the abstract classes provided by the framework can be conveniently used as the base type. Table 2.8, “Base types for custom style renderer implementations” lists the available style renderer base types.

Table 2.8. Base types for custom style renderer implementations

Base Type Description
AbstractNodeStyleRenderer Abstract base type for node style renderer types.
PathBasedEdgeStyleRenderer Abstract base type for edge style renderer types.
AbstractLabelStyleRenderer Abstract base type for label style renderer types.
AbstractStyleRenderer Abstract base type for port style renderer types.

Example 2.21, “Custom node style renderer implementation” presents a sample implementation for a node style renderer that complements the above node style type and provides the actual rendering logic.

Example 2.21. Custom node style renderer implementation

public class CustomStyleRenderer extends AbstractNodeStyleRenderer {

  override public function createDisplayObject(context:IDisplayObjectContext):DisplayObject {
    var displayObject:YDisplayObject = new YDisplayObject();
    paint(displayObject.yGraphics,context);
    updateLayout(displayObject, context);
    return displayObject;
  }

  protected function paint( g:YGraphics, ctx:IPaintContext ):void {
    var nodeBounds:IRectangle = this.layout;

    var width:Number = nodeBounds.width;
    var height:Number = nodeBounds.height;

    var stroke:IStroke = this.stroke;
    var fill:IFill = this.fill;
    var percentage:Number = this.percentage;

    if( null != fill ) {
        g.applyFill( fill );
    }
    if( null != stroke ) {
        g.applyStroke( stroke );
    }
    g.drawRect( 0, 0, width, height );

    if( null != fill ) {
        g.endFill( fill );
    }

    g.applyStroke(Strokes.NO_STROKE);
    g.applyFill(new SolidColor(0xFF0000, 0.8));
    g.drawRect(1, 1, (width-2)*percentage, height-2);
    g.endFill();
  }

  protected function updateLayout(obj:DisplayObject, context:IDisplayObjectContext):void {
    var layout:IRectangle = this.layout;
    obj.x = layout.x;
    obj.y = layout.y;
  }

  protected function get fill():IFill {
    return CustomStyle( this._style ).fill;
  }
    
  protected function get percentage():Number {
    return CustomStyle( this._style ).percentage;
  }

  protected function get stroke():IStroke {
    return CustomStyle( this._style ).stroke;
  }

  override public function lookup( type:Class ):Object {
    if( type == ISerializer ) {
      return CustomStyleSerializer.instance;
    }
    return super.lookup( type );
  }
}

The methods that need to be implemented to realize the actual rendering of either kind of model item naturally differ for each style renderer type. Below, the respective sections on the node, edge, port, and label style renderers describe these methods.

Common to all available abstract base types is a convenient implementation for the install method that is used by the framework to actually install canvas objects into the scene graph and establish the connection to the logic within the renderer. This default implementation suffices for almost all cases and can be used to delegate the calls to the style's install method to.

As an option, a custom style renderer can also implement the configure() method defined in abstract class AbstractStyleRenderer. This method is called by most of the methods defined in interface IStyleRenderer and enables configuration of the renderer instance relating to these method invocations.

The CustomStyle demo application shows how to create and use a custom style and a custom renderer implementation.

A special kind of abstract style and renderer are the delegating styles DelegatingNodeStyle, DelegatingEdgeStyle, DelegatingLabelStyle and DelegatingPortStyle. These styles can wrap an existing style and delegate the rendering to the wrapped style's renderer. Subclasses can use this to decorate the wrapped styles, e.g. by adding a flex effect or filter to them. The DelegatingStyleDemo shows how to create delegating styles and wrap existing styles with them.

Style Renderers

The available style renderer implementations either directly or indirectly inherit from abstract class AbstractStyleRenderer, which combines all necessary functionality that relates to the visual appearance of graph elements. In particular, it implements interface IDisplayObjectCreator, which defines the methods for creating and updating the DisplayObject for a model item. Figure 2.14, “Common style renderer base type AbstractStyleRenderer” depicts the inheritance structure of AbstractStyleRenderer.

Figure 2.14. 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.9, “Predefined node style renderer implementations”.

Table 2.9. Predefined node style renderer implementations

Style Type Complementing Renderer Type Description
IShapeNodeStyle ShapeNodeStyleRenderer Renders a node using the shape that is defined by the shapeNodeShape property of the node's associated IShapeNodeStyle object.
ImageNodeStyle ImageNodeStyleRenderer Renders a node using the vector or bitmap image returned by the image property of the node's associated ImageNodeStyle object.
BitmapNodeStyle BitmapNodeStyleRenderer Renders a node using the bitmap image returned by the image property of the node's associated BitmapNodeStyle object.
ComponentNodeStyle ComponentNodeStyleRenderer Renders a node using the UIComponent returned by the component property of the node's associated ComponentNodeStyle object.
TemplateNodeStyle TemplateNodeStyleRenderer Renders a node using the UIComponent returned by the templateClass property of the node's associated TemplatetNodeStyle object. Passes associated data and the context to that component.
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.

Abstract class AbstractNodeStyleRenderer provides default implementations for most of the abstract methods from its base type AbstractStyleRenderer. Inheriting types only need to implement the createDisplayObject method (see below) appropriately.

createDisplayObject(ctx:IDisplayObjectContext):DisplayObject
Description Abstract method in class AbstractNodeStyleRenderer for creating the DisplayObject for a node.

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.10, “Predefined edge style renderer implementations”.

Table 2.10. Predefined edge style renderer implementations

Style Type Complementing Renderer Type Description
IPolylineEdgeStyle PolylineEdgeStyleRenderer Renders an edge as a poly-line path using the properties of the edge's associated IPolylineEdgeStyle object.

Abstract class AbstractEdgeStyleRenderer provides default implementations for most of the methods from its base type AbstractStyleRenderer. The remaining methods that need to be implemented by inheriting types are listed below.

getPath():GeneralPath
Description Abstract method from class AbstractEdgeStyleRenderer.

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.11, “Predefined port style renderer implementations”.

Table 2.11. Predefined port style renderer implementations

Style Type Complementing Renderer Type Description
SimplePortStyle SimplePortStyleRenderer Renders a port as a circle using the stroke and radius properties of the port's associated SimplePortStyle.

Note that SimplePortStyleRenderer directly inherits from abstract class AbstractStyleRenderer.

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.12, “Predefined label style renderer implementations”.

Table 2.12. Predefined label style renderer implementations

Style Type Complementing Renderer Type Description
ISimpleLabelStyle SimpleLabelStyleRenderer Renders a label's text. The renderer uses the properties of the label's associated ISimpleLabelStyle object.
TLFLabelStyle TLFLabelStyleRenderer Renders a label's text within the oriented rectangle that describes the label's layout. Uses the Flash Text Engine and the Text Layout Framework for rendering.
CSSLabelStyle CSSLabelStyleRenderer Renders a label's text within the oriented rectangle that describes the label's layout. Uses a style sheet instead of a TextFormat for text formatting.
IIconLabelStyle IconLabelStyleRenderer Renders a label's text (see description of SimpleLabelStyleRenderer) and the icon that the label's associated IIconLabelStyle object returns.
IIconLabelStyleDecorator IconLabelStyleRenderer Renders a label's text using the ILabelStyle and the icon that the label's associated IIconLabelStyleDecorator object returns. Note that this renderer can handle both IIconLabelStyle and IIconLabelStyleDecorator.
TemplateLabelStyle TemplateLabelStyleRenderer Renders a node using the UIComponent returned by the templateClass property of the node's associated TemplatetLabelStyle object. Passes associated data and the context to that component.

Note that SimpleLabelStyleRenderer directly inherits from abstract class AbstractStyleRenderer.

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.15. 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.13, “Predefined port location model implementations” lists the predefined port location model implementations.

Table 2.13. Predefined port location model implementations

Model Type Description
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.22, “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.22. Creating a model parameter for a custom port location

// 'node' is of type com.yworks.canvas.model.INode

var nsplm:NodeScaledPortLocationModel = NodeScaledPortLocationModel.instance;
var plmp:IPortLocationModelParameter =
    nsplm.createOffsetParameter(node, YPoint.create(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 following 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.

function createParameter(portOwner:IPortOwner,
                         location:IPoint):IPortLocationModelParameter
Description Default port location model parameter creation method

The following methods provided by interface IGraph 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 addPort(), class DefaultGraph creates an appropriate parameter of the NodeScaledPortLocationModel.

function addPortWithParameter( portOwner:IPortOwner,
                    modelParameter:IPortLocationModelParameter ):IPort
Description Setting the port location model parameter when adding a new port to the graph model.
function setPortLocationModelParameter( port:IPort,
                      modelParameter:IPortLocationModelParameter ):void
Description Setting the port location model parameter for an existing port.

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

ILabelModel is also the basis for class GenericLabelModel 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, the following method defined in interface ILabelModel 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.

createDefaultParameter():ILabelModelParameter
Description Method for creating the default label model parameter.

The following methods provided by interface IGraph can be used to specify the label model parameter for a label.

Note

When a label is added to the graph using the addLabel method lacking the label model parameter, class DefaultGraph associates the default label model parameter that is returned by the createDefaultParameter method of the label model returned by either of the defaultNodeLabelModelParameter or defaultEdgeLabelModelParameter properties.

addLabel(item:ILabeledItem, text:String,
         labelModelParameter:ILabelModelParameter = null,
         style:ILabelStyle = null):ILabel
Description Sets the label model parameter when adding a new label to the graph model.
setLabelModelParameter(label:ILabel, parameter:ILabelModelParameter):void
Description Sets the label model parameter for an existing label.

Node Label Models

Node label models are responsible for determining the geometry of labels where the actual owner is an INode. Figure 2.17, “Hierarchy of node label model types” depicts the type hierarchy of available node label models.

Note

When working with a yFiles Java server component, only the ExteriorNodeLabelModel and InteriorNodeLabelModels can be mapped to the yFiles Java node label models automatically. See the section called “Working with Labels on the Server” for details about transferring label positions between yFiles FLEX and yFiles Java.

Figure 2.17. Hierarchy of node label model types

Hierarchy of node label model types.

The predefined node label positions of the node label models are depicted in Figure 2.18, “Possible node label positions”.

Figure 2.18. 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.14, “Valid node label positions for each model type” lists the sets of valid positions for each node label model.

The default node label model classes provide static constants that define both the position strings of all available label positions and predefined shareable model instances provided by the corresponding model.

Table 2.14. 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

The predefined node label positions of InteriorStretchLabelModel consist of the following five positions: north, east, south, west, and center as shown in Figure 2.19, “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.

Note

For east and west positions, the font that is used by the label needs to be embedded in the application's SWF file. Otherwise, the displayed text will not reflect the rotated nature of the label, but will instead have default (horizontal) orientation.

Figure 2.19. 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.23, “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.23. Adding a node label using a specific label model parameter

// 'graph' is of type com.yworks.graph.model.IGraph.
// 'node' is of type com.yworks.graph.model.INode.

graph.addLabel(node, "I am NorthEast.", ExteriorLabelModel.northEast);

Edge Label Models

Edge label models are responsible for determining the geometry of labels where the actual owner is an IEdge. Figure 2.20, “Hierarchy of edge label model types” depicts the type hierarchy of available edge label models.

Note

When working with a yFiles Java server component, only the FreeEdgeLabelModel, RotatedSliderEdgeLabelModel, and RotatedSideSliderEdgeLabelModel can be mapped to the yFiles Java node label models automatically. See the section called “Working with Labels on the Server” for details about transferring label positions between yFiles FLEX and yFiles Java.

Figure 2.20. Hierarchy of edge label model types

Hierarchy of edge label model types.

Example 2.24, “Sharing a label model parameter instance among a set of edge labels” demonstrates how to set an edge label model parameter that describes a position valid in the context of RotatedSliderEdgeLabelModel.

Example 2.24. Sharing a label model parameter instance among a set of edge labels

// 'graph' is of type com.yworks.graph.model.IGraph.

var model:RotatedSliderEdgeLabelModel = new RotatedSliderEdgeLabelModel();
// The label will be placed at the side of the edge near the first bend.
model.distance = 10;
var param:ILabelModelParameter = model.createParameterFromSource(0, 1.0);

for (var it:Iterator = myEdgeList.iterator(); it.hasNext(); ) {
  graph.setLabelModelParameter(it.next(), param);
}

Setting up and using edge label models is extensively presented in tutorial demo application EdgeLabelingDemo.

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.

Note

In order to render the rotated label text properly it is necessary to embed the label font. See the knowledge base article Fonts are not displayed correctly for details.

Figure 2.21. Candidates for the different rotated (side) slider label models

Auto rotation enabled
Fixed angle at 0 degrees.
Auto rotation enabled, distance set to 10
Possible label candidates along the edge's path as found by RotatedSliderEdgeLabelModel for an auto-rotated edge label. ...the same, but for a non-auto-rotated edge label... ...auto rotated again, but with a distance > 0.
Auto rotation enabled
Fixed angle at 0 degrees.
Auto rotation enabled, distance set to 10
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 135 degrees counterclockwise).
With RotatedSliderEdgeLabelModel or RotatedSideSliderEdgeLabelModel the label placement can be controlled by a number of properties:
autoRotationEnabled:Boolean
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.
angle:Number
Description The angle of the label in radians. If autorotation is enabled the angle is measured counterclockwise relative to the edge, if not it is relative to the x-axis. The default is 0.
distance:Number
Description The distance of the label's box to the edge. The distance is measured from the corner which is nearest to the edge. A distance of 0 places the label centered on the edge. To place the label at the side of the edge without a distance use Number.MIN_VALUE. The interpretation of positive/negative values depends on property distanceRelativeToEdge. The default is 0.
distanceRelativeToEdge:Boolean
Description A value indicating whether the distance to the edge is interpreted relative to the edge's path: If this property is set to true, the label is placed to the left of the edge segment (relative to the segment direction) if distance is less than 0 and to the right of the edge segment if distance is greater than 0. This property is only available for the RotatedSliderEdgeLabelModel.

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. The methods createParameterFromSource and createParameterFromTarget create a parameter with a segment index and ratio counting from the source or the target node of the edge, respectively, for a RotatingSliderEdgeLabelModel. In addition, the corresponding methods for a RotatedSideSliderEdgeLabelModel allow to determine whether the label should be placed left or right to the edge.

The following example demonstrates how to place labels using the RotatedSliderEdgeLabelModel and the RotatedSideSliderEdgeLabelModel.

Example 2.25. Using the Rotated(Side)SliderEdgeLabelModel

// graph is of type IGraph
// edge1 and edge2 are of type IEdge

// create a label model which places the label along the edge
var centerModel:RotatedSliderEdgeLabelModel =
                                    new RotatedSliderEdgeLabelModel();
centerModel.distance = 0;					// centered on the edge
centerModel.autoRotationEnabled = true; 	// with auto rotation enabled

// 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
var centerParam:ILabelModelParameter =
                          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
var sideModel:RotatedSideSliderEdgeLabelModel =
                                    new RotatedSideSliderEdgeLabelModel();
sideModel.distance = 10;				// 10 units away from the edge
sideModel.autoRotationEnabled = false;	// with auto rotation disabled
sideModel.angle = 0;					// and 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
var sideParam:ILabelModelParameter =
                        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:

GenericLabelModel(defaultParameter:ILabelModelParameter)
Description Determines the default label model parameter.
addParameter( parameter:ILabelModelParameter ):ILabelModelParameter
Description Adds a new 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.26, “Composing a node label model”.

Example 2.26. Composing a node label model

var glm:GenericLabelModel = new GenericLabelModel( InteriorLabelModel.center );
glm.addParameter( InteriorLabelModel.northEast );
glm.addParameter( ExteriorLabelModel.northEast );