Model items used in an
IGraph
(i.e., items of type
INode, IEdge, IPort, and ILabel) by themselves do not provide any visual
representation.
Instead, the functionality to render model items in the GraphControl is
encapsulated by so-called "styles."
Along with their complementing counterparts, the so-called "style renderers,"
they hold all necessary state and provide all logic needed to create the visual
appearance of graph elements.
The following sections cover:
Additionally, in the Port Support and Label Support sections, the so-called port location models and label models are presented. Although they do not directly influence the styling of the graph, they are used for determining the geometry of ports and labels and thus influence the overall visual appearance.
For either type of graph element there is a specialized style type available:
interfaces INodeStyle
and
IEdgeStyle
for nodes and
edges, and interfaces
IPortStyle
and
ILabelStyle
for ports and
labels, respectively.
Figure 2.6, “Hierarchy of style types” shows the type hierarchy of the base style interfaces.
yFiles WPF Viewer leverages the native WPF styling mechanism by providing specialized
ContentControl-based style types for the visual representation of graph elements.
INodeControlNodeStyle
, ILabelControlLabelStyle
,
IEdgeSegmentControlEdgeStyle
,
and IPortControlPortStyle
are
the corresponding style type interfaces for nodes, labels, edges, and ports, respectively.
Figure 2.7, “Hierarchy of style types that support WPF styling of ContentControls” shows the type hierarchy of ContentControl-based
styles.
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 directly 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 ContentControl style types extend generic interface ITaggedStyleBase<TModelItem>
,
a sub-interface of IVisualStyle, and appropriately bind its type parameter TModelItem
in a similar manner.
ContentControl style type interfaces also inherit from the respective interface
for their kind of model item, i.e., an INodeControlNodeStyle is also a true INodeStyle,
for example.
(See also in the sections below.)
Abstract generic class ControlStyleBase<TModelItem> is the base implementation for all actual ContentControl style type classes. Each ContentControl-based style is accompanied by a specialized ContentControl subclass which can be styled using WPF styling techniques. A style instance basically determines which WPF style to apply to the ContentControl. The WPF style can conveniently be created and designed in any WPF-enabled XAML designer application.
The following sections cover the predefined style implementations for the model item types:
Using styles along with class DefaultGraph, the default IGraph implementation, is described in the section called “Working with Styles”.
Node styles are responsible for the graphical rendering of nodes in the canvas.
Interface INodeStyle
is
the common base type for actual implementations.
Figure 2.8, “Hierarchy of node style types” shows part of the type hierarchy of the node
style implementations.
Table 2.3, “Predefined node style implementations” lists the predefined node style
implementations present in the
yWorks.yFiles.UI.Drawing
namespace.
Table 2.3. Predefined node style implementations
| Type Name | Description |
|---|---|
| NodeControlNodeStyle |
Enables using WPF-styled ContentControls for the visual representation of a node. (See below for a description on using NodeControlNodeStyle.) |
| UIElementNodeStyle |
Enables using DataTemplates for the visual representation of a node. The DataTemplate can be retrieved from a XAML resource, for example. Note that the NodeControlNodeStyle supersedes this implementation. |
| SimpleAbstractNodeStyle<TVisual> |
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 |
| ImageNodeStyle |
Enables using an image to create the visual representation for a node. |
| 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. |
| GeneralPathNodeStyle |
Allows arbitrary
GeneralPath |
| PanelNodeStyle |
An implementation of interface
IPanelNodeStyle |
| BevelNodeStyle |
An implementation of interface
IBevelNodeStyle |
| ShinyPlateNodeStyle |
Can be used to create rectangular nodes with rounded corners and a 'shiny plate' interior. By default, this style renders a drop shadow by itself. |
| ShadowNodeStyleDecorator |
A node style decorator to add a drop shadow to the visual representation of the wrapped node style. See below. |
Figure 2.9, “Node style representations” shows examples of nodes using predefined node style implementations.
Figure 2.9. Node style representations
![]() |
![]() |
![]() |
![]() |
| Some of the predefined shapes of ShapeNodeStyle | ImageNodeStyle showing the yWorks logo | ||
![]() |
![]() |
![]() |
Node style type NodeControlNodeStyle allows to use the ContentControl-based WPF styling mechanism to create the visual representation of nodes in an IGraph. This enables using the XAML control templating scheme to define the appearance of nodes, including the support of triggers, visual states, and transitions.
The control style and its control template is applied to class NodeControl
,
a specialized ContentControl subclass.
Example 2.13, “XAML ControlTemplate definition excerpt for the appearance of nodes” shows part of a control template definition
for nodes taken from the ControlStylesDemo
demo application.
Note how the target type of the template is specified to be of type NodeControl.
Example 2.13. XAML ControlTemplate definition excerpt for the appearance of nodes
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:y="http://www.yworks.com/xml/yfiles-wpf/2.0/xaml"
xmlns:ControlStyles="clr-namespace:Demo.yFiles.Graph.ControlStyles"
...
>
<Style x:Key="CustomerNodeTemplate" TargetType="y:NodeControl">
<Setter Property="MinHeight" Value="80"/>
<Setter Property="MinWidth" Value="150"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type ControlStyles:Customer}">
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Id: "/>
<TextBlock Text="{Binding Id}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>
<!-- Background Gradient -->
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="#FFCCFFFF" />
<GradientStop Offset="1" Color="#FF249ae7" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="y:NodeControl">
<Border x:Name="border" CornerRadius="5"
Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}">
<StackPanel>
<!-- Name -->
<Border>
<Border.Background>
<SolidColorBrush x:Name="ShineBrush" Opacity="0.25"
Color="White"/>
</Border.Background>
<TextBlock Margin="1,10,1,5" x:Name="NameTextBlock" FontSize="13"
Text="{Binding
RelativeSource={RelativeSource TemplatedParent},
Path=Content.Name}"
TextAlignment="Center" HorizontalAlignment="Center"/>
</Border>
<!-- Other Properties -->
<ContentPresenter Margin="10,10,0,0"/>
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="ItemSelected" Value="true">
<Setter TargetName="NameTextBlock" Property="FontWeight"
Value="Bold"/>
</Trigger>
<Trigger Property="ItemFocused" Value="true">
<Setter Property="BorderBrush" Value="Black"/>
</Trigger>
<Trigger Property="ItemHighlighted" Value="true">
<Setter TargetName="border" Property="Effect">
<Setter.Value>
<DropShadowEffect Color="Red" Opacity="1" BlurRadius="20"
ShadowDepth="0" RenderingBias="Performance"/>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Style for customer nodes. -->
<y:NodeControlNodeStyle x:Key="DetailNodeStyle"
StyleResourceKey="CustomerNodeTemplate"/>
</ResourceDictionary>
Further examples of ControlTemplate definitions for the appearance of nodes can be found in tutorial demo application VSMDemo.
Abstract generic class
SimpleAbstractNodeStyle<TVisual>
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.
The following methods from class SimpleAbstractNodeStyle are called to create, respectively update, the visual representation for a given node. Being abstract, the former method needs to be overridden by subclasses. The latter method is recommended to override as well in order to improve the rendering performance in an application.
protected abstract TVisual CreateVisual(INode node, IRenderContext renderContext) |
|
| Description | Abstract method to create the visual representation for the given INode. |
protected virtual TVisual UpdateVisual(INode node, IRenderContext renderContext, TVisual oldVisual) |
|
| Description | Optional, but recommended override to update the given INode's visual representation. |
The MySimpleNodeStyle class in the SimpleCustomStyleWindow demo application presents a node style implementation that subclasses SimpleAbstractNodeStyle. How to subclass SimpleAbstractNodeStyle is also shown in the Custom Styles tutorial; see especially the steps 01 and 03 on how to override the CreateVisual and UpdateVisual methods.
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.
Note that this class uses WPF's effects engine to dynamically create the drop shadow
which may affect performance adversely.
How to implement a better performing drop shadow is shown in the
Custom Styles tutorial;
see especially step 07.
Example 2.14. 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(Colors.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.10, “ShapeNodeStyle decorated using ShadowNodeStyleDecorator” shows a node using ShapeNodeStyle that is decorated by means of ShadowNodeStyleDecorator to also have a drop shadow.
Edge styles are responsible for the graphical rendering of edges in the canvas.
Interface IEdgeStyle
is the common base type for actual implementations, and abstract class
AbstractEdgeStyle
provides
default implementations for the methods of interface IEdgeStyle.
Figure 2.11, “Hierarchy of edge style types” shows a part of the type hierarchy of edge style
implementations.
Table 2.4, “Predefined edge style implementations” lists the predefined edge style
implementations present in the
yWorks.yFiles.UI.Drawing
namespace.
Table 2.4. Predefined edge style implementations
| Type Name | Description |
|---|---|
| EdgeSegmentControlEdgeStyle |
Enables using WPF-styled ContentControls for the visual representation of the segments of an edge. (See below for a description on using EdgeSegmentControlEdgeStyle.) |
| UIElementEdgeStyle |
Enables using DataTemplates for the visual representation of an edge. The DataTemplate can be retrieved from a XAML resource, for example. Note that the EdgeSegmentControlEdgeStyle supersedes this implementation. |
| SimpleAbstractEdgeStyle<TVisual> |
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.12, “Edge style representations” shows examples of edges using predefined edge style implementations.
Edge style type EdgeSegmentControlEdgeStyle allows to use the ContentControl-based WPF styling mechanism to create the visual representation of edges in an IGraph. This enables using the XAML control templating scheme to define the appearance of edges, including the support of triggers, visual states, and transitions.
The control style and its control template is applied to class EdgeSegmentControl
,
a specialized ContentControl subclass.
Example 2.15, “XAML ControlTemplate definition excerpt for the appearance of edge segments” shows part of a control template definition
for edge segments taken from the ControlStylesDemo
demo application.
Note how the target type of the template is specified to be of type EdgeSegmentControl.
Example 2.15. XAML ControlTemplate definition excerpt for the appearance of edge segments
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:y="http://www.yworks.com/xml/yfiles-wpf/2.0/xaml"
>
<Style x:Key="EdgeSegmentTemplate" TargetType="y:EdgeSegmentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="y:EdgeSegmentControl">
<Grid>
<Rectangle x:Name="rectangle" Fill="OrangeRed"
RadiusX="2.5" RadiusY="2.5" Margin="-2.5,0,-2.5,0">
</Rectangle>
<Polygon x:Name="targetArrow" Points="10,2.5,0,0,0,5"
Fill="{Binding ElementName=rectangle, Path=Fill}"
VerticalAlignment="Stretch" HorizontalAlignment="Right"
Visibility="Collapsed"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsLast" Value="true">
<Setter TargetName="rectangle"
Property="Margin" Value="-2.5,0,7.5,0"/>
<Setter TargetName="targetArrow"
Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Further examples of ControlTemplate definitions for the appearance of edge segments can be found in tutorial demo application VSMDemo.
Abstract generic class
SimpleAbstractEdgeStyle<TVisual>
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.
The following methods from class SimpleAbstractEdgeStyle are called to create, respectively update, the visual representation for a given edge. Being abstract, the former method needs to be overridden by subclasses. The latter method is recommended to override as well in order to improve the rendering performance in an application.
protected abstract TVisual CreateVisual(IEdge edge, IRenderContext renderContext) |
|
| Description | Abstract method to create the visual representation for the given IEdge. |
protected virtual TVisual UpdateVisual(IEdge edge, IRenderContext renderContext, TVisual oldVisual) |
|
| Description | Optional, but recommended override to update the given IEdge's visual representation. |
The MySimpleEdgeStyle class in the SimpleCustomStyleWindow 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 16.
Abstract class
AbstractEdgeStyle
serves
as a convenient basis for actual edge styles that need more custom rendering
support than SimpleAbstractEdgeStyle provides, for example.
Custom edge styles that base on AbstractEdgeStyle still need to implement the
Install
method, which is repeated from the superinterface of generic base type
IVisualStyle, however adapted to use IEdge as the type for the original type
parameter TModelItem.
See also the section called “Creating Custom Styles”.
Because bends are an integral part of an edge, they are rendered by the edge style, too.
Port styles are responsible for the graphical rendering of ports in the canvas.
Interface IPortStyle
is the common base type for actual implementations.
Figure 2.13, “Hierarchy of port style types” shows a part of the type hierarchy of port style
implementations.
Table 2.5, “Predefined port style implementations” lists the predefined port style
implementations present in the
yWorks.yFiles.UI.Drawing
namespace.
Table 2.5. Predefined port style implementations
| Type Name | Description |
|---|---|
| PortControlPortStyle |
Enables using WPF-styled ContentControls for the visual representation of a port. (See below for a description on using PortControlPortStyle.) |
| UIElementPortStyle |
Enables using DataTemplates for the visual representation of a port. The DataTemplate can be retrieved from a XAML resource, for example. Note that the PortControlPortStyle supersedes this implementation. |
| SimpleAbstractPortStyle<TVisual> |
Greatly simplifies port style customization using subclassing. (See below for a description of SimpleAbstractPortStyle.) |
| SimplePortStyle |
Provides a very simple representation for ports. |
Port style type PortControlPortStyle allows to use the ContentControl-based WPF styling mechanism to create the visual representation of ports in an IGraph. This enables using the XAML control templating scheme to define the appearance of ports, including the support of triggers, visual states, and transitions.
The control style and its control template is applied to class PortControl
,
a specialized ContentControl subclass.
Example 2.16, “XAML ControlTemplate definition for the appearance of ports” shows a control template definition for ports
taken from the ControlStylesDemo
demo application.
Note how the target type of the template is specified to be of type PortControl.
Example 2.16. XAML ControlTemplate definition for the appearance of ports
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:y="http://www.yworks.com/xml/yfiles-wpf/2.0/xaml"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="PortTemplate" TargetType="y:PortControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="y:PortControl">
<Border x:Name="border" CornerRadius="5">
<Border.Background>
<!-- Background gradient -->
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="#FFFFFFBB"/>
<GradientStop Offset="1" Color="#FFFFEE77"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="Color2"
Storyboard.TargetProperty="Color" To="Black"
Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="Color2"
Storyboard.TargetProperty="Color"
Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Further examples of ControlTemplate definitions for the appearance of ports can be found in tutorial demo application VSMDemo.
Abstract generic class
SimpleAbstractPortStyle<TVisual>
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.
The following methods from class SimpleAbstractPortStyle are called to create the visual representation for a given port and that return the port's bounds. The method to update the port's visual representation is also included. Being abstract, the former methods need to be overridden by subclasses. The latter method is recommended to override as well in order to improve the rendering performance in an application.
protected abstract TVisual CreateVisual(IPort port, IRenderContext renderContext) |
|
| Description | Abstract method to create the visual representation for the given IPort. |
protected abstract RectD GetBounds(IPort port, ICanvasContext canvasContext) |
|
| Description | Abstract method to get the bounds of the given IPort's visual. |
protected virtual TVisual UpdateVisual(IPort port, IRenderContext renderContext, TVisual oldVisual) |
|
| Description | Optional, but recommended override to update the given IPort's visual representation. |
The MySimplePortStyle class in the SimpleCustomStyleWindow 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 22.
Custom port styles that do not base on SimpleAbstractPortStyle need to
implement the
Renderer
property defined in interface IPortStyle and the
Install
method defined in the superinterface of generic base type IVisualStyle.
See also the section called “Creating Custom Styles”.
Label styles are responsible for the graphical rendering of labels in the
canvas.
Interface ILabelStyle
is the common base type for actual implementations.
Figure 2.14, “Predefined label style types” shows a part of the type hierarchy of label style
implementations.
Table 2.6, “Predefined label style implementations” lists the predefined label style
implementations present in the
yWorks.yFiles.UI.Drawing
namespace.
Table 2.6. Predefined label style implementations
| Type Name | Description |
|---|---|
| LabelControlLabelStyle |
Enables using WPF-styled ContentControls for the visual representation of a label. (See below for a description on using LabelControlLabelStyle.) |
| UIElementLabelStyle |
Enables using DataTemplates for the visual representation of a label. The DataTemplate can be retrieved from a XAML resource, for example. Note that the LabelControlLabelStyle supersedes this implementation. |
| SimpleAbstractLabelStyle<TVisual> |
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 style type LabelControlLabelStyle allows to use the ContentControl-based WPF styling mechanism to create the visual representation of labels in an IGraph. This enables using the XAML control templating scheme to define the appearance of labels, including the support of triggers, visual states, and transitions.
The control style and its control template is applied to class LabelControl
,
a specialized ContentControl subclass.
Example 2.17, “XAML ControlTemplate definition excerpt for the appearance of labels” shows part of a control template definition
for labels taken from the ControlStylesDemo
demo application.
Note how the target type of the template is specified to be of type LabelControl.
Example 2.17. XAML ControlTemplate definition excerpt for the appearance of labels
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:y="http://www.yworks.com/xml/yfiles-wpf/2.0/xaml"
xmlns:ControlStyles="clr-namespace:Demo.yFiles.Graph.ControlStyles"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="LabelTemplate" TargetType="y:LabelControl" >
<Setter Property="Background">
<Setter.Value>
<!-- Background Gradient -->
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="#FFFFFFBB" />
<GradientStop Offset="1" Color="#FFFFEE77" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type ControlStyles:Relation}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Product.Name}" FontSize="6"/>
<TextBlock Text=" <- " FontSize="6"/>
<TextBlock Text="{Binding Path=Customer.Name}" FontSize="6"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="y:LabelControl">
<Border CornerRadius="5" Background="{TemplateBinding Background}"
MinWidth="100">
<StackPanel Orientation="Vertical" Margin="5">
<TextBlock x:Name="LabelTextBlock" TextAlignment="Center"
Text="{TemplateBinding LabelText}" FontSize="12"
Margin="3"/>
<ContentPresenter x:Name="contentPresenter"/>
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="ItemSelected" Value="true">
<Setter TargetName="LabelTextBlock" Property="FontWeight"
Value="Bold"/>
</Trigger>
<Trigger Property="IsFlipped" Value="true">
<Setter TargetName="contentPresenter" Property="FlowDirection"
Value="RightToLeft"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Further examples of ControlTemplate definitions for the appearance of labels can be found in tutorial demo application VSMDemo.
Abstract generic class
SimpleAbstractLabelStyle<TVisual>
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.
The following methods from class SimpleAbstractLabelStyle are called to create the visual representation for a given label and that return the label's preferred size. The method to update the label's visual representation is also included. Being abstract, the former methods need to be overridden by subclasses. The latter method is recommended to override as well in order to improve the rendering performance in an application.
protected abstract TVisual CreateVisual(ILabel label, IRenderContext renderContext) |
|
| Description | Abstract method to create the visual representation for the given ILabel. |
protected abstract SizeD GetPreferredSize(ILabel label) |
|
| Description | Abstract method to get the given ILabel's preferred size. |
protected virtual TVisual UpdateVisual(ILabel label, IRenderContext renderContext, TVisual oldVisual) |
|
| Description | Optional, but recommended override to update the given ILabel's visual representation. |
The MySimpleLabelStyle class in the SimpleCustomStyleWindow demo application presents a label style implementation that subclasses SimpleAbstractLabelStyle. How to subclass SimpleAbstractLabelStyle is also shown in the Custom Styles tutorial; see especially the steps 10 and 12 on how to override the CreateVisual and UpdateVisual methods.
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.15, “Edge label that uses NodeStyleLabelStyleAdapter” shows an edge label where a
BevelNodeStyle is used to render the background.
Setting up different node styles and associating them with nodes of a graph is presented in Example 2.18, “Creating a graph”. The resulting graph is depicted in Figure 2.16, “Shape node style and image node style”.
Example 2.18. 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.
ImageNodeStyle ins = new ImageNodeStyle();
ins.Image =
new BitmapImage(new Uri("PathToSomeImage.png", UriKind.RelativeOrAbsolute));
graph.NodeDefaults.Style = ins;
graph.NodeDefaults.Size = new SizeD(ins.Image.Width * 2.0, ins.Image.Height);
// Create some nodes.
INode[] nodes = new INode[6];
for (int i = 0; i < nodes.Length - 1; i += 2) {
nodes[i] = graph.CreateNode(new PointD(i * 50, 100));
graph.SetStyle(nodes[i], sns);
graph.SetBounds(nodes[i],
new RectD(nodes[i].Layout.X, nodes[i].Layout.Y, 40, 40));
nodes[i + 1] = graph.CreateNode(new PointD(i * 50, 200));
}
Styles can be associated with model items using different schemes: an IVisualStyle instance for a specific kind of model item can be both
Style sharing can be easily achieved whenever a single style instance is associated with a model item by reference. Example 2.19, “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.19. 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.20, “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.20. Changing the color of a node
// 'graph' is of type yWorks.yFiles.UI.Model.IGraph.
// 'node' is of type yWorks.yFiles.UI.Model.INode.
IShapeNodeStyle shapeNS = node.Style as IShapeNodeStyle;
if (shapeNS != null) {
shapeNS.Brush = Brushes.AliceBlue;
}
// Tell the engine to update the displays (the style instance cannot know itself
// which display it appears in).
graph.InvalidateDisplays();
Generally, style types team up with a corresponding style renderer type, separating duties as follows: the actual style implementation ideally only holds the state that is needed for rendering an item, while the style renderer provides the logic that performs the real work using the style's state. This separation enables sharing of style renderer instances among an arbitrary number of style objects and is also known as the Flyweight pattern.
As a consequence, creating a custom style is mainly the task of creating a proper style renderer. Most conveniently, a custom style type can be created using the appropriate generic abstract class listed in the following table:
Table 2.7. Base types for custom style type implementations
| Base Type | Description |
|---|---|
| SimpleAbstractNodeStyle<TVisual> |
Simplifies node style customization using subclassing. |
| SimpleAbstractEdgeStyle<TVisual> |
Simplifies edge style customization using subclassing. |
| SimpleAbstractLabelStyle<TVisual> |
Simplifies label style customization using subclassing. |
| SimpleAbstractPortStyle<TVisual> |
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.21, “Custom node style implementation” presents a sample node style type based on generic abstract class SimpleAbstractNodeStyle that provides custom implementations for the callback methods.
Example 2.21. Custom node style implementation
public class MyCirclesNodeStyle : SimpleAbstractNodeStyle<Canvas> {
private double percentage = 0.25d;
private Color backColor = Colors.Blue;
private Color foreColor = Colors.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 Canvas CreateVisual(INode node, IRenderContext rc) {
var canvas = new Canvas();
Brush brush = new SolidColorBrush(style.BackColor);
canvas.Children.Add(new Ellipse() { Fill = brush, Width = node.Layout.Width,
Height = node.Layout.Height, Stroke = brush, StrokeThickness = 1.0
});
brush = new SolidColorBrush(style.ForeColor);
var innerEllipse = new Ellipse() { Fill = brush, Stroke = brush,
StrokeThickness = 1.0
};
innerEllipse.Width = node.Layout.Width * style.Percentage;
innerEllipse.Height = node.Layout.Height * style.Percentage;
Canvas.SetTop(innerEllipse,
(node.Layout.Height * (1.0 - style.Percentage)) / 2.0);
Canvas.SetLeft(innerEllipse,
(node.Layout.Width * (1.0 - style.Percentage)) / 2.0);
canvas.Children.Add(innerEllipse);
// Tell the CanvasControl where to place the Canvas containing the rendering.
canvas.SetCanvasArrangeRect(
new Rect(node.Layout.X, node.Layout.Y,
node.Layout.Width, node.Layout.Height));
return canvas;
}
// For performance reasons, we implement the update method.
protected override Canvas UpdateVisual(INode node, IRenderContext rc,
Canvas oldVisual) {
var canvas = oldVisual as Canvas;
if (canvas != null && canvas.Children.Count == 2) {
// Adjust the data for the outer ellipse.
Ellipse ellipse1 = (Ellipse) canvas.Children[0];
ellipse1.Width = node.Layout.Width;
ellipse1.Height = node.Layout.Height;
// Adjust the data for inner ellipse.
Ellipse ellipse2 = (Ellipse) canvas.Children[1];
ellipse2.Width = node.Layout.Width * style.Percentage;
ellipse2.Height = node.Layout.Height * style.Percentage;;
// Tell the CanvasControl where to place the Canvas containing the
// rendering.
canvas.SetCanvasArrangeRect(
new Rect(node.Layout.X, node.Layout.Y,
node.Layout.Width, node.Layout.Height));
return canvas;
}
return CreateVisual(rc);
}
// The abstract base class calls this method when hit tests should be
// performed.
protected override bool IsHit(INode node, PointD point, ICanvasContext ctx) {
return GeomSupport.EllipseContains(node.Layout.ToRectD(), point,
ctx.HitTestRadius);
}
// Finds an intersection for the current node.
protected override PointD? GetIntersection(INode node,
PointD inner, PointD outer) {
return GeomSupport.FindEllipseLineIntersection(node.Layout.ToRectD(),
inner, outer);
}
// Checks whether the given coordinates lie within the circle.
protected override bool IsInside(INode node, PointD point) {
return GeomSupport.EllipseContains(node.Layout.ToRectD(), point, 0);
}
}
The Custom Styles tutorial presents step by step how to create custom node, edge, port, and label styles on the basis of the respective SimpleAbstractStyle class.
The available style renderer implementations either directly or indirectly
inherit from abstract generic class
AbstractStyleRenderer<TModelItem, TModelStyle, TStyle>
,
which combines all necessary functionality that relates to the visual
appearance of graph elements.
In particular, it implements interface
IVisualCreator
, which defines
the methods for creating and updating the Visual for a model item.
Figure 2.17, “Common style renderer base type AbstractStyleRenderer” depicts the inheritance structure
of AbstractStyleRenderer.
Node style renderers are the complementary counterparts to the node styles.
They provide the actual logic that is invoked by the canvas for rendering an
item.
Interface
INodeStyleRenderer
is the
common base type for actual implementations.
The predefined node style renderer implementations together with the respective styles they correspond to are listed in Table 2.8, “Predefined node style renderer implementations”.
Table 2.8. Predefined node style renderer implementations
| Style Type | Complementing Renderer Type | Description |
|---|---|---|
| INodeControlNodeStyle |
NodeControlNodeStyleRenderer |
The renderer uses the styled NodeControl instance of the node's associated INodeControlNodeStyle object to render the node and its tag. |
| IUIElementNodeStyle |
UIElementNodeStyleRenderer |
Uses a DataTemplate from the style to render the node and its tag. |
| 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 only need to implement the CreateVisual method (see below) 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.
abstract Visual CreateVisual(IRenderContext ctx) |
|
| Description | Abstract method in class AbstractNodeStyleRenderer for creating the Visual for a node. |
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 |
|---|---|---|
| IEdgeSegmentControlEdgeStyle |
EdgeSegmentControlEdgeStyleRenderer |
The renderer uses the styled EdgeSegmentControl instance of the node's associated IEdgeSegmentControlEdgeStyle object to render the segments of the edge and the edge's tag. |
| IUIElementEdgeStyle |
UIElementEdgeStyleRenderer |
Uses a DataTemplate from the style to render the edge and its tag. |
| 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. |
Abstract generic class
PathBasedEdgeStyleRenderer<TStyle>
provides default implementations for most of the methods from its base types,
which in particular include AbstractStyleRenderer.
The remaining methods that need to be implemented by inheriting types are listed
below.
Also, the type parameter, which is constrained to be of type IEdgeStyle, needs
to be bound to the style type that this renderer type is actually
complementing.
protected abstract GeneralPath CreatePath() |
|
| Description | Abstract methods from class PathBasedEdgeStyleRenderer. |
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 |
|---|---|---|
| IPortControlPortStyle |
PortControlPortStyleRenderer |
The renderer uses the styled PortControl instance of the node's associated IPortControlPortStyle object to render the port and its tag. |
| IUIElementPortStyle |
UIElementPortStyleRenderer |
Uses a DataTemplate from the style to render the port and its tag. |
| ISimplePortStyle |
SimplePortStyleRenderer |
Renders a port as a circle using the Brush property of the port's associated ISimplePortStyle. |
Note that the port style renderers directly inherit from abstract generic class AbstractStyleRenderer. The type parameters are bound to the IPort and IPortStyle types, and to the IUIElementPortStyle, IPortControlPortStyle, and ISimplePortStyle type, respectively.
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 |
|---|---|---|
| ILabelControlLabelStyle |
LabelControlLabelStyleRenderer |
The renderer uses the styled LabelControl instance of the node's associated ILabelControlLabelStyle object to render the label and its tag. |
| IUIElementLabelStyle |
UIElementLabelStyleRenderer |
Uses a DataTemplate from the style to render the label and its tag. |
| 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 UIElementLabelStyleRenderer and IconLabelStyleRenderer directly inherit from abstract generic class AbstractStyleRenderer. The type parameters are bound to the ILabel and ILabelStyle types, and to the IUIElementLabelStyle and IIconLabelStyle type, respectively.
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
below.
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.
protected abstract SizeD GetPreferredSize() |
|
abstract Visual CreateVisual(IRenderContext ctx) |
|
| Description | Abstract methods from class AbstractLabelStyleRenderer. |
The location of a port at a node, in both static as well as dynamic scenarios, is determined by a so-called port location model. It is responsible for finding the proper location for a port with respect to a port location model parameter. The port location model parameter is associated with a port and encodes its desired position. It is created by a port location model and is valid only in the context of this port location model.
In a dynamic scenario, where a user resizes or moves a node, or moves a port, port location models are queried to determine the proper location of the port(s).
Although a port location model determines the position of a port, it cannot be
associated with one.
Instead, a
port location model parameter
that is created by a port location model instance is associated with a given
port.
Then, to determine the port's position, this port location model instance is
found via the model parameter's
Model
property.
Interface IPortLocationModel
provides the basis for port location model implementations.
Table 2.12, “Predefined port location model implementations” lists the predefined port
location model implementations.
Table 2.12. Predefined port location model implementations
| Model Type | Description |
|---|---|
| AnchoredPortLocationModel |
Specifies the location of a port in world coordinates. |
| NodeScaledPortLocationModel |
The location of a port is specified relative to the center of the node and in relation to its geometry. See the description below. |
Class NodeScaledPortLocationModel defines a port location model where the location of a port is specified relative to the center of the node and in relation to the geometry of the node's bounding rectangle.
The center of the node is interpreted as the origin of a "coordinate system" where going up/to the left means negative sign and going down/to the right means positive sign. The distances to the borders of the node are interpreted relative to the node's width and height, respectively, so that the distance to the left (right) border, for example, is always half the width. Thus, the top left corner of the node corresponds to the relative location (-0.5, -0.5), the bottom right corner to (0.5, 0.5).
When the width or height of a node changes, the location of a port is appropriately updated according to the node's new geometry. In effect, this means that the distances to the center of the node are scaled using the same factor that the width/height have changed.
NodeScaledPortLocationModel provides convenient support for nine predefined port locations. Example 2.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 yWorks.yFiles.UI.Model.INode
NodeScaledPortLocationModel nsplm = NodeScaledPortLocationModel.Instance;
IPortLocationModelParameter plmp =
nsplm.CreateOffsetParameter(node, new PointD(0.25, 0.0));
When the node is resized, this custom port location will be scaled accordingly so that the port is always located right of the node's center, half way to the node's border.
A port location model parameter is an implementation of interface
IPortLocationModelParameter
that is created by a port location model.
It encodes a possible port position that is valid in the context of its
corresponding port location model.
To create a model parameter, IPortLocationModel defines the 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.
IPortLocationModelParameter CreateParameter(IPortOwner portOwner, PointD location) |
|
| Description | Method for creating the default port location model parameter. |
The following methods provided by interface IGraph can be used to specify the port location model parameter for a port.
When a port is added to a model item of the graph using the AddPort method that
lacks the port location model parameter, class DefaultGraph associates the port
location model parameter that it finds as part of the default settings for the
model item's kind.
Technically, this means that DefaultGraph queries the
LocationModelParameter
property of the IPortDefaults implementation which is part of the default
settings of either nodes or edges.
IPort AddPort(IPortOwner owner, IPortLocationModelParameter locationModelParameter, IPortStyle portStyle, object tag) |
|
| Description | Port location model parameter (extension) methods from interface IGraph for setting the port location model parameter when adding a new port to the graph model. |
void SetLocationModelParameter(IPort port, IPortLocationModelParameter locationParameter) |
|
| Description | ... for setting the port location model parameter for an existing port. |
The geometry of both node labels and edge labels is determined by so-called label models. Specifically, a label model is responsible for finding the proper location for a label with respect to a "label model parameter." The label model parameter is associated with a label and encodes its desired position. It is created by a label model and is valid only in the context of this label model.
Although a label model determines the position of a label, it cannot be
associated with one.
Instead, a
label model parameter
that is created by a label model instance is associated with a given label.
Then, to determine the label's position, this label model instance is found via
the model parameter's
Model
property.
Interface ILabelModel
provides the basis for both
node label model and
edge label model implementations
described below.
In addition to these label models that determine the location of a label
relative to its respective owner, class
FreeLabelModel
can be used to place labels freely in world coordinate space.
ILabelModel is also the basis for class
GenericLabelModel
q
which can be used to
create user-defined node label and edge label models.
A label model parameter is an implementation of interface
ILabelModelParameter
that is
created by a label model.
It encodes a possible label position that is valid in the context of its
corresponding label model.
Most often, the position that a model parameter encodes is a predefined
position that is defined relative to the owner of the label.
For example, the node label model
ExteriorLabelModel
uses model parameters that encode eight distinct logical positions around a
node, named North, NorthEast, East,
SouthEast, etc., which define positions outside the bounds of a
node.
To create a model parameter, ILabelModel defines the following method 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.
ILabelModelParameter CreateDefaultParameter() |
|
| 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.
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.
ILabel AddLabel(ILabeledItem item, ILabelModelParameter labelModelParameter, SizeD preferredSize, ILabelStyle style, string text, object tag) |
|
| Description | Label model parameter (extension) methods from interface IGraph for setting the label model parameter when adding a new label to the graph model. |
void SetLabelModelParameter(ILabel label, ILabelModelParameter parameter) |
|
| Description | ... for setting the label model parameter for an existing label. |
Node label models are responsible for determining the geometry of labels where the actual owner is an INode. Figure 2.20, “Hierarchy of node label model types” depicts the type hierarchy of available node label models.
Label model type
FreeNodeLabelModel
allows to freely define a node label's position relative to its owner.
The predefined node label positions used with all other node label models are
depicted in Figure 2.21, “Possible node label positions” and
Figure 2.22, “Possible node label positions with InteriorStretchLabelModel”.
The latter figure illustrates the predefined label positions of label model
type
InteriorStretchLabelModel
.
It is important to note that the set of valid positions varies with the model types, i.e., not all possible positions are valid for each node label model. Table 2.13, “Valid node label positions for each model type” lists the sets of valid positions for each node label model.
Table 2.13. Valid node label positions for each model type
| Model Type | Valid Positions |
|---|---|
| InteriorLabelModel |
NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast |
| ExteriorLabelModel |
NorthWest, North, NorthEast, West, East, SouthWest, South, SouthEast |
| SandwichLabelModel |
North, South |
The predefined node label positions of InteriorStretchLabelModel consist of the following five positions: North, East, South, West, and Center as shown in Figure 2.22, “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.22. Possible node label positions with InteriorStretchLabelModel
![]() |
![]() |
| Non-Center label positions. Note the label orientation at East and West positions. | Labels at Center position are stretched to use the entire geometry of the node. |
Example 2.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 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 GraphEditorWindow.
Edge label models are responsible for determining the geometry of labels where the actual owner is an IEdge. Figure 2.23, “Hierarchy of edge label model types” depicts the type hierarchy of available edge label models.
The following example code demonstrates how to set an edge label model parameter that describes a position valid in the context of RotatedSliderEdgeLabelModel:
Example 2.24. 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 GraphEditorWindow and EdgeLabelingWindow.
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.24. Candidates for a specific edge label model using side slider edge label model
![]() |
![]() |
| Possible label candidates along the edge's path as found by RotatedSideSliderEdgeLabelModel for an auto-rotated edge label. | ...the same, but for a non-auto-rotated edge label. |
![]() |
| ...the same, but for a non-auto-rotated edge label that has a preset rotation angle (of 315 degrees counterclockwise). |
With RotatedSliderEdgeLabelModel
or RotatedSideSliderEdgeLabelModel
the label placement can be controlled by a number of properties:
bool AutoRotationEnabled { get; set; } |
|
| Description | Specifies whether or not edge labels are automatically rotated according to the angle of the corresponding reference edge segment. By default, this feature is enabled. |
double Angle { get; set; } |
|
| Description | The angle of the label. If auto-rotation is enabled, the angle is measured counterclockwise relative to the edge. If not, it is relative to the x-axis. The default angle is 0.0. |
double Distance { get; set; } |
|
| Description | The distance between the label's box and the edge's path. A distance of 0.0, which is the default value, means label placement on the edge's path. In conjunction with the DistanceRelativeToEdge property, positive and negative values can be used to place labels to the sides of the edge path or above/below the edge path. |
bool DistanceRelativeToEdge { get; set; } |
|
| Description | Determines whether the value of the Distance property is interpreted to mean label placement to the sides of the edge path or above/below the edge path. |
The parameters for both label models place the label on a specific segment of the
edge with a given ratio where 0.0 places the label at the start of
the segment and 1.0 at the end.
For RotatingSliderEdgeLabelModel, the
CreateParameterFromSource
and
CreateParameterFromTarget
methods create a parameter with a segment index and ratio counting from the source
or the target node of the edge, respectively.
For RotatedSideSliderEdgeLabelModel, the corresponding
CreateParameterFromSource
and
CreateParameterFromTarget
methods additionally allow to determine whether the label should be placed to the
left or to the right of the edge.
The following example demonstrates how to place labels using the RotatedSliderEdgeLabelModel and the RotatedSideSliderEdgeLabelModel:
Example 2.25. Using the Rotated(Side)SliderEdgeLabelModel
// 'graph' is of type yWorks.yFiles.UI.Model.IGraph.
// 'edge1' and 'edge2' are of type yWorks.yFiles.UI.Model.IEdge.
// Create a label model which auto-rotates and places the label on the edge path.
RotatedSliderEdgeLabelModel centerModel =
new RotatedSliderEdgeLabelModel();
centerModel.Distance = 0;
centerModel.AutoRotationEnabled = true;
// Create a parameter for this model which places the label in the middle
// (ratio 0.5) of the second (0-based index 1) segment counting from the source
// node.
ILabelModelParameter centerParam =
centerModel.CreateParameterFromSource(1, 0.5);
// Add the label.
graph.AddLabel(edge1, "Center", centerParam);
////////////////////////////////////////////////////////////////////////////////
// Create a label model which places the labels at either side of the edge.
RotatedSideSliderEdgeLabelModel sideModel =
new RotatedSideSliderEdgeLabelModel();
sideModel.Distance = 10; // 10 units away from the edge
sideModel.AutoRotationEnabled = false; // auto rotation disabled
sideModel.Angle = 0; // parallel to the x-axis
// Create a parameter which places the label at the beginning of the first edge
// segment seen from the target node.
ILabelModelParameter sideParam =
sideModel.CreateParameterFromTarget(0, 0.0, true);
// Add the label.
graph.AddLabel(edge2, "Side", sideParam);
Class
GenericLabelModel
provides a generic means to create user-defined label models for either node
labels or edge labels.
It allows to compose a custom blend of arbitrary label positions that are
available with the predefined label models using the methods below:
API Excerpt 2.1. 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.26, “Composing a node label model”.
|
Copyright ©2008-2011, yWorks GmbH. All rights reserved. |