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.
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.
Using styles along with class DefaultGraph, the default IGraph implementation, is described in the section called “Working with Styles”.
Node styles are responsible for the graphical rendering of nodes in the canvas.
Interface INodeStyle
is
the common base type for actual implementations.
Figure 2.7, “Hierarchy of node style types” shows a part of the type hierarchy of node
style implementations.
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 |
| 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 existing display object, or it can be loaded from an URL. |
| 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. |
| GeneralPathNodeStyle |
Allows arbitrary
GeneralPath |
| PanelNodeStyle |
An implementation of interface
IPanelNodeStyle |
| BevelNodeStyle |
An implementation of interface
IBevelNodeStyle |
| SWFNodeStyle |
A node style that allows to use SWF movies as node visualizations. |
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.
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 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.
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. |
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”.
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.10, “Hierarchy of port style types” shows the type hierarchy of port style
implementations.
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. |
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 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.
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. |
| IconLabelStyle |
Builds on the functionality that SimpleLabelStyle provides and additionally allows to place an icon at several positions relative to the label's text. |
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.
Setting up different node styles and associating them with nodes of a graph is presented in Example 2.8, “Creating a graph”. The resulting graph is depicted in Figure 2.13, “Shape node style and image node style”.
Example 2.8. 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
Style sharing can be easily achieved whenever a single style instance is associated with a model item by reference. Example 2.9, “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.9. 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.10, “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.
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.11, “Custom node style implementation” presents a sample implementation of a node style type that fulfills the framework requirements as described above.
Example 2.11. 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.12, “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.12. Custom node style renderer implementation
public class CustomStyleRenderer extends AbstractNodeStyleRenderer {
override public function paint( g:YGraphics, ctx:IPaintContext ):void {
var nodeBounds:IRectangle = this.layout;
var x:Number = nodeBounds.x;
var y:Number = nodeBounds.y;
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( x, y, width, height );
if( null != fill ) {
g.endFill( fill );
}
g.applyStroke(Strokes.NO_STROKE);
g.applyFill(new SolidColor(0xFF0000, 0.8));
g.drawRect(x+1, y+1, (width-2)*percentage, height-2);
g.endFill();
}
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.
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
IPaintable
, which defines the
method that is invoked for providing the actual rendering for an item.
Figure 2.14, “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.
Figure 2.15, “Hierarchy of node style renderer types” shows part of the type hierarchy of
node style renderer 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 |
ComponentNodeStyle |
Renders a node using the UIComponent returned by the component property of the node's associated ComponentNodeStyle 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. |
| SWFNodeStyle |
SWFNodeStyleRenderer |
Renders a node using the SWF movie of the node's associated SWFNodeStyle object. |
Abstract class
AbstractNodeStyleRenderer
provides default implementations for most of the abstract methods from its base
type AbstractStyleRenderer.
Inheriting types still need to implement the
paint
method appropriately.
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.
Figure 2.16, “Hierarchy of edge style renderer types” shows the type hierarchy of edge
style renderer 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 in API Excerpt 2.9, “Abstract methods from class AbstractEdgeStyleRenderer”.
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.
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.
Figure 2.17, “Hierarchy of port style renderer types” shows the type hierarchy of port
style renderer 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 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.
Figure 2.18, “Hierarchy of label style renderer types” shows the type hierarchy of label
style renderer 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. |
Note that SimpleLabelStyleRenderer directly inherits from abstract class AbstractStyleRenderer.
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.
ILabelModel is also the basis for class
GenericLabelModel
which can
be used to
create user-defined node label and edge label models.
A label model parameter is an implementation of interface
ILabelModelParameter
that is
created by a label model.
It encodes a possible label position that is valid in the context of its
corresponding label model.
Most often, the position that a model parameter encodes is a predefined
position that is defined relative to the owner of the label.
For example, the node label model
ExteriorLabelModel
uses
model parameters that encode eight distinct logical positions around a node,
named north, northEast, east,
southEast, etc., which define positions outside the bounds of a
node.
To create a model parameter, ILabelModel defines the method shown in API Excerpt 2.10, “Default label model parameter creation method” that can be used to obtain the so-called "default model parameter" for a given label model. The available node label models and edge label models provide further model-specific methods to create valid model parameters.
API Excerpt 2.10. Default label model parameter creation method
createDefaultParameter():ILabelModelParameter
API Excerpt 2.11, “Label model parameter methods from interface IGraph” lists the methods provided by interface IGraph that can be used to specify the label model parameter for a label.
When a label is added to 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.
API Excerpt 2.11. Label model parameter methods from interface IGraph
// Setting the label model parameter when adding a new label to the graph model.
addLabel(item:ILabeledItem, text:String,
labelModelParameter:ILabelModelParameter = null,
style:ILabelStyle = null):ILabel
// Setting the label model parameter for an existing label.
setLabelModelParameter(label:ILabel, parameter:ILabelModelParameter):void
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.
The predefined node label positions of the node label models are depicted in Figure 2.21, “Possible node label positions”.
It is important to note that the set of valid positions varies with the model types, i.e., not all possible positions are valid for each node label model. Table 2.13, “Valid node label positions for each model type” lists the sets of valid positions for each node label model.
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.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 |
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, south, and center positions).
Example 2.13, “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.
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.
Example 2.14, “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 SliderEdgeLabelModel.
Example 2.14. Sharing a label model parameter instance among a set of edge labels
// 'graph' is of type com.yworks.graph.model.IGraph.
var selm:SliderEdgeLabelModel = new SliderEdgeLabelModel();
selm.distance = 10;
// The label will be placed at the side of the edge near the first bend.
var selmp:ILabelModelParameter = selm.createParameterFromSource(0, 1.0);
for (var it:Iterator = myEdgeList.iterator(); it.hasNext(); ) {
graph.setLabelModelParameter(it.next(), selmp);
}
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 shown in
API Excerpt 2.12, “Methods for creating user-defined label models”.
API Excerpt 2.12. Methods for creating user-defined label models
// Determines the default label model parameter.
GenericLabelModel( defaultParameter:ILabelModelParameter ) {}
addParameter( parameter:ILabelModelParameter ):ILabelModelParameter {}
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.15, “Composing a node label model”.
|
Copyright ©2007-2008, yWorks GmbH. All rights reserved. |