A Guide to Diagram – Part 1 – Data for Nodes and Links

I guess the first thing to get your head around with diagram is the core data structures that are required. Fortunately this is not a very complex area although it does differ in one small respect from that for other components that you might be worth dealing with.
Fundamentally the diagram represents two sets of separate, but related, data objects.  A set of nodes, and a set of links that join those nodes. The important thing here is that these are supplied as two separate collections of data rather than say a single recursive hierarchy. 
So in order to build a diagram you will need a collection of node objects and a collection of link objects.  Note that when I say "collection" here I mean that these sets of objects can be provided either in the form of something that implements the List interface (e.g. java.util.ArrayList) or a CollectionModel (org.apache.myfaces.trinidad.model.CollectionModel). The latter of these two categories includes data provided by the ADF binding layer in the form of a table or hierarchical binding (the same type of binding that you would use for an ADF table), so mapping data in from your model layer should be a snap. 

So what's a Node? 

A node collection can be a collection of anything, diagram does not impose any particular data structure or naming on you. All you need is an attribute (exposed through a public getter) that can act as the unique ID for the node.  This attribute can be of any type although generally you'll want to keep it to something simple such as a String, int, or long for example.  What does matter, is that each row in the collection needs to have a unique one.  If you use an object type of your own for this node ID be sure to implement the equals() method of that object.
You map the collection of nodes through a <dvt:diagramNodes> tag using the value attribute as the way to pass it in. The diagramNodes tag acts like many other iterating components used in ADF Faces. It has a second attribute called var that we use as the way to reference each row from the value collection as we stamp it out.  By convention var is usually set to "node". 
As each node is stamped out, we use a <dvt:diagramNode> component to represent it.  I'll talk more about what can actually be represented within a node in the next article. 

A Basic Example

Just to give you a chance to try this out yourself, here is a super simple example that we'll build up as we go along. 
To start off with, here's a really basic definition for a node object :
public class SampleNode {
  private int _uniqueNodeId;
  private String _nodeLabel;

  public SampleNode(int id, String label){
    _uniqueNodeId = id;
    _nodeLabel = label;
  }

  public int getUniqueNodeId() {
    return _uniqueNodeId;
  }

  public String getNodeLabel() {
    return _nodeLabel;
  }
}

And then let's create a collection of those in a managed bean so that we can access it from diagram:

/** Mapped as a managed Bean called "diagramModel"
  * SessionScoped */
public class DiagramDataModel {
  private List<SampleNode> _nodes;

  public DiagramDataModel(){
    //Seed the diagram with three nodes
    _nodes = new ArrayList<SampleNode>(3);
    _nodes.add(new SampleNode(0,"First Node"));
    _nodes.add(new SampleNode(1,"Second Node"));
    _nodes.add(new SampleNode(2,"Third Node"));
  }

  public List<SampleNode> getNodes() {
    return _nodes;
  }
}

And map that into the UI

<dvt:diagram id="d1" summary="Example Diagram">
  <dvt:diagramNodes id="dns1" value="#{diagramModel.nodes}" var="node">
    <dvt:diagramNode id="dn1" nodeId="#{node.uniqueNodeId}" label="#{node.nodeLabel}"/>
  </dvt:diagramNodes>
</dvt:diagram>
OK, now if you've followed along and run the page, something will happen although all you'll actually see is a mess of overlapping text in the top left hand corner of the diagram component. Not very useful yet, but stick with me here.

On to Links

So we have nodes, what about the links (or edges) that may join them together? As I mentioned these have to be supplied as a separate collection from the nodes. This allows for maximum flexibility as a node can be linked to as many other nodes as required, or to zero other nodes or even several times to the same partner node.
Just like the data structure required for a node, the basic data structure for a link is very simple and flexible.  This time though, it needs two specific attributes; a source node and a destination node. As you may of guessed, these need to correspond to the unique node identifiers that we defined on our node objects and passed to the nodeId attribute of the diagramNode tag. Needless to say, any nodeId referenced by a link has to exist on the diagram otherwise the link will not display. The source and destination nodes are mapped using the startNode and endNode attributes respectively in the <dvt:diagramLink> tag.

Our Basic Example Continued…

So let's extend our working sample to add links. First of all define a Java type for an individual link:
public class SampleLink {
  private int _sourceNodeId;
  private int _destinationNodeId;
  public SampleLink(int source, int destination){
    _sourceNodeId = source;
    _destinationNodeId = destination;
  }

  public int getSourceNodeId() {
    return _sourceNodeId;
  }
  public int getDestinationNodeId() {
    return _destinationNodeId;
  }
}

Then we can amend the model class we created earliet to include some of these links as well to join the existing nodes:

/** Mapped as a managed Bean called "diagramModel"
  * SessionScoped */
public class DiagramDataModel {
  private List<SampleNode> _nodes;
  private List<SampleLink> _links;
  public DiagramDataModel(){    
    //Seed the diagram with three nodes
    _nodes = new ArrayList<SampleNode>(3);
    _nodes.add(new SampleNode(0,"First Node"));
    _nodes.add(new SampleNode(1,"Second Node"));
    _nodes.add(new SampleNode(2,"Third Node"));
    //And links to join each to the next
    _links = new ArrayList<SampleLink>(3);
    _links.add(new SampleLink(0,1));
    _links.add(new SampleLink(1,2));
    _links.add(new SampleLink(2,0));  
  }

  public List<SampleNode> getNodes() {
    return _nodes;
  }

  public List<SampleLink> getLinks() {
    return _links;
  }
}

Just like the nodes, the links are expressed through a duet of tags:  <dvt:diagramLinks> which stamps out the collection of links using the standard value and var combo, and <dvt:diagramLink> which is responsible for stamping out each link instance:
Just as in the case of the nodes, the actual amount of information actually required is minimal, just the source and destination unique node ids:
<dvt:diagram id="d1" summary="Example Diagram">
  <dvt:diagramNodes id="dns1" value="#{ diagramModel.nodes}" var="node">
    <dvt:diagramNode id="dn1" nodeId="#{node.uniqueNodeId}" label="#{node.nodeLabel}"/>
  </dvt:diagramNodes>
  <dvt:diagramLinks id="dls1" value="#{diagramModel.links}" var="link">
    <dvt:diagramLink id="dl1" 
                     startNode="#{link.sourceNodeId}"
                     endNode="#{link.destinationNodeId}"/>
  </dvt:diagramLinks>
</dvt:diagram>
Now again, if you run, this you'll just get a mess of overlapping text in the top left corner of the diagram, so we need to make one small addition to help it all make sense – a layout. Don't worry about the mechanics of creating or using a layout at this stage I'll cover that in a lot of detail in a later article, instead just do the following:
  1. Download the ADF Faces demo .war file from the OTN ADF download page
  2. From within the .war file extract the dvt-demo-javascript.jar file (use your favorite zip tool to unpack the .war and look in the WEB-INF/lib directory for this file.
  3. Drop the jar into the public_htmlWEB-INF/lib directory of your project (you may have to create this) 
Then amend the page slightly to reference one of the layouts.  In this case I'm using the circle layout:

<dvt:diagram id="d1" summary="Example Diagram" 
             layout="circleLayout">
  <dvt:clientLayout name="circleLayout" 
                    method="DemoCircleLayout.circleLayout"
                    featureName="DemoCircleLayout"/>
The <dvt:clientLayout> tag is responsible for identifying exactly what JavaScript needs to be run to layout the node and it defines an alias (in this case circleLayout) that the diagram will refer to using the layout attribute.  As we will see in later articles when I explain layouts in more detail, an individual diagram may actually use multiple clientLayouts.

Now when the page is run, here's the result.  It's still rather plain, however, a semblance of structure is beginning to emerge as the nodes are now distributed in a circle and joined with links, we're on the right track!

Our first diagram

In the Next Article

Next time I'll be exploring what you can do with the node contents in a little more detail, which in turn, will help to transform our starter diagram into something a little more attractive.


Comments:

Post a Comment:
  • HTML Syntax: NOT allowed
About

Oracle Data Visualizations provide a broad range of beautiful, interactive components for viewing and understanding data. This blog covers topics on the new features in Oracle Data Visualization components and how-to articles on advanced functionality.

Search

Categories
Archives
« March 2015
SunMonTueWedThuFriSat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
20
21
22
23
24
25
26
27
28
29
30
31
    
       
Today