The graph model found in package
com.yworks.graph.model
centers around interface
IGraph
.
It serves as a visually rich representation of the mathematical notion of a
directed graph and provides geometry as well as rendering support for the items
it contains.
A directed graph is defined as consisting of two sets, a node set and an edge set. A node represents any kind of entity and an edge represents a relation between any two nodes.
Directed graph means that all edges from the edge set have direction, i.e., a distinct source node and a distinct target node. The mathematical notation for an edge is a pair where the first component denotes source and the second component denotes target node: edge e = (source, target).
The yFiles FLEX graph model adds further elements to this concept: so-called ports serve as linking elements between nodes and edges. So-called bends, which are part of an edge, present a means to define a geometry for edges. Also, label elements can be used with nodes and edges and add to their visual appearance.
Nodes and edges of a graph are modeled by interfaces
INode
and
IEdge
.
The ports that link nodes and edges are defined by interface
IPort
, the bends that an
edge can contain are defined by interface
IBend
.
Finally, interface ILabel
defines generic labels for both nodes and edges.
Figure 2.2, “Graph structure” depicts the central graph structure types
in yFiles FLEX.
Through a set of convenient properties, IGraph makes available collection views
of the model items it contains.
For example, the
nodes
and
edges
properties can
be used to obtain a view of all nodes and all edges, respectively.
The types surrounding IGraph consistently provide read-only views of their data, and to change a graph element's properties, methods defined in IGraph need to be used. In other words, IGraph holds responsibility for all changes to the graph model, be it of structural nature, changes of geometry, or regarding the visual appearance of graph elements.
Figure 2.3, “Type hierarchy of model items” shows the type hierarchy of the model items in a yFiles FLEX graph model.
All graph structure interfaces either directly or indirectly have interface
ILookup
as their base type.
Consequently, the powerful look-up mechanism as discussed in
the section called “Look-up Mechanism” can be used to query dynamic sets of associated types
that handle specific aspects of even single instances of such interface
implementations.
Figure 2.4, “Relationships between graph structure types” depicts the interrelations of graph structure elements. Nodes and edges connect to each other using ports, which logically belong to the nodes (i.e., the owner of an IPort is an INode). Edges, more precisely their paths, are defined by the ports at their ends and a sequence of zero or more bends in-between these (where each of the IBend will indicate the IEdge as its owner).
The INode, IEdge, IPort, and IBend interfaces allow to obtain a graph element's geometry as well as the style object that manages visual appearance. While node geometry can be obtained directly from INode, edge geometry is available via an edge's IPort and IBend objects.
In addition to the immediate graph structure elements, there is also support for an arbitrary number of labels at both nodes and edges. The actual INode or IEdge a label belongs to, is indicated as the ILabel's owner. Figure 2.5, “ILabeledItem and ILabel” presents ILabel's relationship to other model items.
Besides geometry and style, interface ILabel also grants access to label-specific data like the label's text. Label geometry is special since actual location is calculated by a so-called label model, which uses a label model parameter that is associated with the label. Label models and also the creation of valid label model parameters is explained in the section called “Label Support”.
Interface IGraph defines fundamental graph structure-related functionality including creation and deletion of graph elements, or querying of structural aspects, like, e.g., adjacency lists. Provided is also support for modifying the geometry of graph elements, i.e., their location and size, and for modifications to the visual appearance of model items.
API Excerpt 2.1, “Graph model-related methods from interface IGraph” shows IGraph's methods that deal with the creation of graph elements and modification of the graph structure.
API Excerpt 2.1. Graph model-related methods from interface IGraph
// Creation of graph elements.
createNode():INode
createEdge(sourcePort:IPort, targetPort:IPort, style:IEdgeStyle = null):IEdge
// INode is also IPortOwner.
addPort(portOwner:IPortOwner, x:Number, y:Number):IPort
addBend(edge:IEdge, index:int, x:Number, y:Number):IBend
// INode and IEdge are also ILabeledItem.
addLabel(item:ILabeledItem, text:String,
labelModelParameter:ILabelModelParameter = null,
style:ILabelStyle = null):ILabel
Methods that handle the deletion of graph elements are listed in API Excerpt 2.2, “Graph model-related deletion methods from interface IGraph”.
API Excerpt 2.2. Graph model-related deletion methods from interface IGraph
// Deletion of graph elements. clear():void clearBends(edge:IEdge):void // Single graph elements. removeNode(node:INode):void removeEdge(edge:IEdge):void removePort(port:IPort):void removeBend(bend:IBend):void removeLabel(label:ILabel):void
IGraph methods that allow to query structural aspects of a graph, for example, the set of edges adjacent at a given node, are listed in API Excerpt 2.3, “Further graph structure-related methods”.
API Excerpt 2.3. Further graph structure-related methods
// Querying structural aspects of a graph. contains(item:IModelItem):Boolean edgesAtPort(port:IPort):Iterable // INode is also IPortOwner. edgesAtPortOwner(portOwner:IPortOwner):Iterable
The geometry of graph elements can be altered by means of the methods listed in API Excerpt 2.4, “Geometry-related methods”. They allow to directly change the sizes of nodes and labels, and the locations of nodes, ports, and bends.
Note that IGraph provides the
defaultNodeSize
property, which holds a default size for nodes that is automatically used at
creation time when no explicit size is specified.
API Excerpt 2.4. Geometry-related methods
// Convenience methods for changing the geometry/location of nodes, bends, // ports, and labels. setBounds(node:INode, x:Number, y:Number, width:Number, height:Number):void setBendLocation(bend:IBend, x:Number, y:Number):void setPortLocation(port:IPort, x:Number, y:Number):void setPreferredSize(label:ILabel, width:Number, height:Number):void
Modifying the visual appearance of model items is supported by the IGraph methods presented in API Excerpt 2.5, “Styles-related methods from interface IGraph”. They can be used to conveniently handle styles, which are responsible for providing the visual presentation of graph elements (see also the section called “Visual Representation of Graph Elements”).
API Excerpt 2.5. Styles-related methods from interface IGraph
// Style setters. setNodeStyle(node:INode, style:INodeStyle):void setEdgeStyle(edge:IEdge, style:IEdgeStyle):void setLabelStyle(label:ILabel, style:ILabelStyle):void setPortStyle(port:IPort, style:IPortStyle):void
However, IGraph also provides the necessary support for a so-called "default
style" mechanism that automatically binds styles to newly created graph
elements.
This is achieved with the help of the
defaultNodeStyle
,
defaultEdgeStyle
, etc.
set of properties, which allow both read and write access.
Class DefaultGraph
is the
default IGraph (see above) implementation used
in yFiles FLEX.
It holds the central graph structure that is displayed by the canvas, i.e.,
class GraphCanvasComponent.
Class DefaultGraph allows to conveniently create a graph model consisting of nodes, edges, ports, etc., connect them appropriately, or again remove any element from the graph. Querying structural aspects of the graph model or changing the geometry of model items is easily achieved. Also, the visual appearance for each kind of graph element or each individual model item can be set using styles.
For example, the methods listed in API Excerpt 2.6, “Graph structure-related methods”, which add to the graph structure methods already defined in IGraph, can be used to obtain all incoming and outgoing edges at a given node.
API Excerpt 2.6. Graph structure-related methods
inEdgesAtPort(port:IPort):Iterable // INode is also IPortOwner. inEdgesAtPortOwner(portOwner:IPortOwner):Iterable outEdgesAtPort(port:IPort):Iterable // INode is also IPortOwner. outEdgesAtPortOwner(portOwner:IPortOwner):Iterable
DefaultGraph fully supports the notion of default styles as laid out in interface IGraph. Any created graph element is automatically associated with a fresh instance of its respective style type. The actual default node style, default edge style, etc. instances that are used for this mechanism can be set in advance.
As an option, DefaultGraph can also be configured to apply style sharing
semantics when automatically associating default style instances with model
items.
When either of the
shareDefaultNodeStyleInstance
,
shareDefaultEdgeStyleInstance
,
etc. properties is set to true, the respective default style
instance is associated with a model item by reference instead of being cloned.
Initially, classes
ShapeNodeStyle
and
PolylineEdgeStyle
are used
as the default node and edge styles for the default style support of class
DefaultGraph.
Similarly,
SimpleLabelStyle
is used
as the default node label and default edge label style.
Node styles and edge styles are described in the section called “Visual Representation of Graph Elements”.
Class DefaultGraph supports the look-up mechanism as described in the section called “Look-up Mechanism” by means of a look-up chain (see the section called “Look-up Chaining”) that is maintained by an actual instance. The look-up chain can be easily customized using the methods listed in API Excerpt 2.7, “Methods for modifying the look-up chain of class DefaultGraph”.
API Excerpt 2.7. Methods for modifying the look-up chain of class DefaultGraph
addLookup(lookup:IContextLookupChainLink):void {}
removeLookup(lookup:IContextLookupChainLink):void {}
Table 2.1, “Supported type requests with Lookup method” presents a sample of types that are supported with look-up operations initiated on a DefaultGraph instance.
Table 2.1. Supported type requests with Lookup method
| Requested Type | Description |
|---|---|
| ILookupDecorator |
The returned ILookupDecorator enables convenient manipulation of look-up chains maintained for the graph elements of the queried DefaultGraph, i.e., for all its nodes, edges, labels, etc. As a convenience, manipulation of the graph's own look-up chain is also supported. (See below for a description on using ILookupDecorator.) |
The ILookupDecorator that is returned when requesting this type in an invocation of DefaultGraph's Lookup method makes available further look-up chains for decoration. These look-up facilities are maintained for the model items in the DefaultGraph, i.e., specifically look-up operations initiated on the following types can be decorated: INode, IEdge, IPort, IBend, and ILabel. Example 2.1, “Modifying the look-up chain for the nodes of a DefaultGraph” shows the typical pattern that is used to modify the look-up chain for the items of a DefaultGraph.
Example 2.1. Modifying the look-up chain for the nodes of a DefaultGraph
function prependMyCustomLookupBehavior( graph:IGraph ):void {
// Get the graph's ILookupDecorator that enables manipulation of all look-up
// operations for the contained graph elements.
var decorator:ILookupDecorator =
graph.lookup( ILookupDecorator ) as ILookupDecorator;
if( null != decorator ) {
// Test whether decoration of look-up operations initiated on type INode is
// supported.
if( decorator.canDecorate( INode ) ) {
// Prepend a custom look-up provider.
decorator.addLookup( INode, new MySelectionPaintableChainLink() );
}
}
}
The CustomStyle demo application shows how selection painting of all nodes can be customized using the lookup decorator mechanism.
Example 2.2, “Creating a graph” shows how to create a graph and how to populate it with newly created graph elements. The example also demonstrates how to add labels to both nodes and edges.
Example 2.2. Creating a graph
var graph:IGraph = new DefaultGraph();
// Create 10 nodes.
var nodes:Array = new Array[10];
for (var i:int = 0; i < nodes.length; i++) {
nodes[i] = graph.createNode();
graph.addLabel(nodes[i], "Node #" + i.toString());
}
// Create 5 edges. Each edge has "even" source node and "odd" target node.
var edges:Array = new Array[5];
for (var i:int = 0, j:int = 0; i < nodes.length - 1; i += 2, j++) {
edges[j] = graph.createEdge(nodes[i], nodes[i + 1]);
graph.addLabel(edges[j], "Edge #" + j.toString());
}
Connecting edges to the ports of some nodes and also adding bends to edges is presented in Example 2.3, “Creating a graph”.
Example 2.3. Creating a graph
var graph:IGraph = new DefaultGraph();
// Node style configuration.
((ShapeNodeStyle)graph.defaultNodeStyle).shapeNodeShape =
ShapeNodeShape.ROUND_RECT;
graph.defaultNodeSize = com.yworks.canvas.geom.Size.create(80, 40);
// Create two nodes.
var fst:INode = graph.createNodeAt(100, 200),
snd:INode = graph.createNodeAt(300, 200);
// Add a port to each node.
var fstSouth:IPort = graph.addPort(fst, 120, 220),
sndNorth:IPort = graph.addPort(snd, 280, 180);
// Create two edges connecting the ports.
var back:IEdge = graph.createEdge(sndNorth, fstSouth),
forth:IEdge = graph.createEdge(fstSouth, sndNorth);
// Add some bends to each edge.
graph.addBend(back, 0, 240, 100);
graph.addBend(back, 1, 160, 300);
graph.addBend(forth, 0, 120, 300);
graph.addBend(forth, 1, 200, 300);
graph.addBend(forth, 2, 200, 100);
graph.addBend(forth, 3, 280, 100);
Iterating over the elements of a graph is supported in a number of ways. Example 2.4, “Iterating over graph elements”, for example, presents iteration over the nodes of a graph and iteration over the edges adjacent at a node.
Example 2.4. Iterating over graph elements
// 'graph' is of type com.yworks.model.IGraph.
// Iterate over all nodes in the graph.
for (var it:Iterator = graph.nodes; it.hasNext(); ) {
var node:INode = it.next();
if (!fulfillsSomeCondition(node)) {
continue;
}
// Iterate over all adjacent edges at nodes that fulfill some condition.
// (Technically, the edges are adjacent to an IPortOwner.)
var jt:Iterator = graph.edgesAtPortOwner(node).iterator()
for (; jt.hasNext(); ) {
var edge:IEdge = jt.next();
// If the edge is outgoing at the current node, then reverse it.
if (edge.sourcePort.owner == node) {
var tmpPort:IPort = edge.sourcePort;
edge.sourcePort = edge.targetPort;
edge.targetPort = tmpPort;
}
}
}
Getting all edges that connect to some ports from a given set of nodes is shown in Example 2.5, “Iterating over graph elements (cont.)”.
Example 2.5. Iterating over graph elements (cont.)
// 'graph' is of type com.yworks.graph.model.IGraph.
for (var it:Iterator = myNodeList.iterator(); it.hasNext(); ) {
var node:INode = it.next();
for (var jt:Iterator = node.ports.iterator(); jt.hasNext(); ) {
var port:IPort = jt.next();
if (!fulfillsSomeCondition(port)) {
continue;
}
// Iterate over all adjacent edges at ports that fulfill some condition.
for (var kt:Iterator = graph.edgesAtPort(port).iterator(); kt.hasNext(); ) {
doSomethingWithThisEdge(kt.next());
}
}
Example 2.6, “Iterating over graph elements (cont.)” shows iteration over all bends of a set of edges.
Example 2.6. Iterating over graph elements (cont.)
for (var it:Iterator = myEdgeList.iterator(); it.hasNext(); ) {
var edge:IEdge = it.next();
// Iterate over all bends of the current edge.
for (var jt:Iterator = edge.bends.iterator(); jt.hasNext(); ) {
var bend:IBend = jt.next();
trace("bend location: x=" + bend.x + " y=" + bend.y);
}
}
The code snippet in Example 2.7, “Iterating over graph elements (cont.)” iterates over all node labels in the graph and prints out their content.
Example 2.7. Iterating over graph elements (cont.)
// 'graph' is of type com.yworks.graph.model.IGraph.
// Iterating over all node labels from the graph.
for (var it:Iterator = graph.nodeLabels.iterator(); it.hasNext(); ) {
var nodeLabel:ILabel = it.next();
trace(nodeLabel.owner.toString() + ": '" + nodeLabel.text + "'");
}
|
Copyright ©2007-2008, yWorks GmbH. All rights reserved. |