Build an Adjustable Network Diagram with Code

This simple diagram is implemented by the following code:



pj.require('/diagram/graph.js','/shape/circle.js','/shape/arcArrow.js',function (graphP,circlePP,arrowPP) {
  var geom = pj.geom,svg = pj.svg,ui = pj.ui;
  var item = svg.Element.mk('');// the root of the diagram we are assembling
  var graph = item.set('graph',graphP.instantiate());
  var circleP = graph.installAsVertexPrototype(circlePP);
  var arrowP = graph.installAsEdgePrototype(arrowPP);
  circleP.r = 12;
  circleP.fill = 'blue';
  var circle1 = graph.addVertex();
  var circle2 = graph.addVertex();
  circle1.__moveto(geom.Point.mk(-50,0));
  circle2.__moveto(geom.Point.mk(50,0));
  // set the parameters of the edge prototype
  arrowP.stroke = 'orange';
  arrowP.radius = 1; // radius of the arc as a multiple of arrow length
  arrowP.tailGap = 7; // gap between tail of arrow and its designated start point
  arrowP.headGap = 7; // gap between head of arrow and its designated end
  arrowP.solidHead = false;
  graph.connectVertices(circle1,circle2);
  graph.connectVertices(circle2,circle1);
  return item;
});

Here is the diagram in the drawing UI, in which it can be adjusted and extended, and in the code editor, where you can experiment with the code.

Note: Browser debuggers (eg Chrome's DevTools) work well with the code editor.

This example illustrates building a diagram using operations defined by its diagram type. Diagram types are external components, rather than anything built into the PrototypeJungle platform itself. The platform allows adding as many diagram types as as you like, each with its own API. In this case the diagram type is a network - a collection of nodes connected by arrows or lines, defined in /diagram/graph.js. Such a structure is referred to as a graph in mathematical terminology. In this terminology the nodes are called "vertices" and the connectors "edges" - a terminology adopted in the API.

Now, lets walk through the code.


    pj.require('/diagram/graph.js','/shape/circle.js','/shape/arcArrow.js',function (graphP,circlePP,arrowPP) {

pj: The PrototypeJungle implementation is installed under one global variable, prototypeJungle. A shorter synonym for that global, pj, is also available. If you need pj for other purposes, it can be freed by calling prototypeJungle.noConflict() (this is analogous to jQuery.noConflict(), which frees up $).

To continue:


    pj.require('/diagram/graph.js','/shape/circle.js','/shape/arcArrow.js',function (graphP,circlePP,arrowPP) { ...

 
binds the variables graphP, circlePP and arrowPP to the components defined in '/diagram/graph.js', '/shape/circle.js', and '/shape/arcArrow.js', respectively. Moving on:


    var item = svg.Element.mk('<g/>');// the root of the diagram we are assembling

pj.svg.Element.mk creates a prototype tree from SVG markup.


    var graph = item.set('graph',graphP.instantiate());

installs an instantiation of the graph component under the root. Instantiation, a fundamental operation in PrototypeJungle, is explained here.

item.set('name',ch) has the effect of item.name = ch, but also assigns item as the parent of ch (PrototypeJungle items are trees, as explained here).


    var circleP = graph.installAsVertexPrototype(circlePP);

This defines the prototype that will be used for vertices in this graph as a circle. Note that installAsVertexPrototype is a method of the graph component, defined externally to the PrototypeJungle platform.


    var arrowP = graph.installAsEdgePrototype(arrowPP);

has similar effect.


    var circle1 = graph.addVertex();

instantiates the vertex prototype assigned by installAsVertexPrototype.


  circle1.__moveto(geom.Point.mk(-50,0));

moves the resulting circle to the given position. __moveto and geom.Point.mk are operations defined by the platform.

circle2 is created and moved analogously.


 graph.connectVertices(circle1,circle2);

instantiates the edge prototype (in this case an arrow), and connects its ends to circle1 and circle2 respectively. graph.connectVertices(circle2,circle1); runs an arrow in the other direction.

The diagram can also be constructed without use of the graph component, but then the arrows won't be automatically updated with dragging of the circles - the graph component handles that. This more direct approach is presented here to give a better feeling for how to build things outside of the context of particular diagrams. The approach involves these alternative snippets of code for introducing the circles and arrows:


  var circleP = item.set('circleP',circlePP.instantiate()).__hide();
  item.set('circle1',circleP.instantiate()).__show();
  item.set('circle2',circleP.instantiate()).__show();
  
and

  var arrowP = item.set('arrowP',arrowPP.instantiate()).__hide();
  item.set('arrow1',arrowP.instantiate()).__show();
  item.set('arrow2',arrowP.instantiate()).__show();
  

Since there is no autopositioning of the arrows, we also need:


   var p1 = geom.Point.mk(-50,0);
   var p2 = geom.Point.mk(50,0)
   item.arrow1.setEnds(p1,p2); //set start and end points of the arrow
   item.arrow2.setEnds(p2,p1);
   

This variant of the code can be found here.

For a full explanation of coding in PrototypeJungle, which will enable you to define your own visual elements and diagram types, see the coding guide.