Dynamic visualization of network-graphs II

In the first part i’ve introduced a way of aligning interconnected nodes in an optimal way. The methods used had some flaws that i discussed in the last article about dynamic network-graphs. In this article i would like to expand and improve the previous script.

What are you talking about??

First, here is the demo as it stands to date:
buildnetwork.svg

Usage

Starting off, you will be presented a cleared area of 500×500 px2 with only one main node in it. This one is created at initialization and is pretty heavy so that it works as anker for the network later on and is marked with a star (*). To draw a new node, just click anywhere in the bordered area. Since any two objects are driven away from each other (had to do that to preserve a minimum distance between two nodes), you will immediately see the two nodes getting into opposite corners (the initial one slower). You can go on and draw other nodes. Eventually you’ll need to connect two nodes. To do that, click on the first node, hold down the mousebutton and drag the cursor to any other node. On release a connection is created between the two nodes and they start to attract each other.

Repeat the steps as long as you like (and your memory holds!). The network connections are optimized the whole time and the effect of the algorithms can be viewed immediately. That also means, that some CPU-power is allways being used.

Deployment

Right now, the code is really not easy (or nice) to deploy. The objects are way too much interdependent with the outer scripts. Global variabels, object references, callback functions and eventhandlers aren’t in a way that would allow a smooth deployment. If anybody still wants to get started, three global references are of great importance: drawg is the global reference to the container element which will contain the node objects. conng is the one for the connections and bg is the bg-container, that will hold the interactive connection line. Also the general SVGDoc (ownerDocument) has to be referenced.

After that, simply creating a netfield-object (o = new netfield();) and adding some nodes (o.addnode("*",250,250,100);) does the trick. o.draw() gets the svg representation of the nodes and connections in the field o.getforces(); calculates the forces between them and o.domoves(); moves the nodes accordingly.

What’s this all for?

I’m planning on using netfield for two purposes (at least). First i’d like to test some navigation usage. If it is possible to cache nodes and show them only on mouseover of their parent node (or some connected node), then a dynamic tree navigation can be achieved. The main advantage of this sort of navigation is that it can adjust to any sort of space given to it.

The second usage case is the visualization of website statistics. Theoretically it is possible to track any user (or ip) from the beginning with the referrer through all the websites he visited including pages he went back to and visited other pages from (fork). The problem is that this information can’t be easily displayed. A list isn’t appropiate for two reasons: 1. You can’t display a fork-like route, 2. if you want to display more than one user’s way through a website, you’d really need that extra dimension. With this approach it would be a color for each user showing his trails. This way one can easily see which page is linking to which other page most frequently.. Mind you, i didn’t finish the digging-code to get those information (specially following the path of one user) out of the database, but i will worry about that, when the time comes..

What’s missing yet?

In the next version i’d like to be able to simply put a netfield-element inside the svg-document and let the code worry about the rest (creating the node, connection and temporary-layers and all the eventhandlers). Also, i’d need to create a namespace for the netfield-element. What would be really nice, is a structure that would allow the creation of nodes with svg-elements. It would look something like this:

<net:field x="0" y="0" height="500px" width="500px" connectivity="true">
<net:node id="someid" x="30" y="50" mass="2" />
<net:node id="someid2" x="50" y="74" mass="1" />
<net:connection id="somecon" node1="someid" node2="someid2" length="100"
minlength="5" />
</net:field>

Wouldn’t that be cool?? To get things really going, the netfield()-object would also create a buttons-layer containing some navigational and editorial buttons. For example one should be able to zoom in and out or delete nodes or connections or even change the size of the field interactively. Looking forward to that..

What is behind the curtains?

Three objects stand at the core of the script:

  1. node():

    The code representation of any given node. In the svg-code, the node-group has an attribute “nodeindex”, that references the actual node-object. Similarly, the node-object has a property called .svgObject that references the svg-code of a node.

    methods

    • .draw() - builds the svg-code and draws the actual node-representation. If you want to change the representation (e.g. box rather than circle), then this is the place. The method creates an g-element that contains the whole representation. The g-element is translated to the place, where the node has to be, so every element inside it has to be centered around 0,0. Also at the time being, the method draws the force-vector, which is stored inside the object .forcesvgObject. At the time being, this method needs a globally declared variable drawg which is a reference to a container-element in which the nodes are drawn.
    • .toString() - standard method to print object-type. Simply returns “[NetNode Object]“. This method is used, when doing something like this:
      mynode=new node();
      alert(mynode); //alerts [NetNode Object]
      

    properties

    • .id - some id for the node. This can be shown in .draw(). The initial id can be set with the first argument of node().
    • .parent - reference to parent element. Should be a netfield()-object, but this isn’t being checked right now.
    • .svgObject - contains reference to the actual svg-group representing the node.
    • .forcesvgObject - contains reference to the svg-group representing the force vector
    • .mass - Mass of the node. This influences the velocity of the node. Can be set with the fourth argument of node()

    objects

    • .pos - contains the position information. .pos.x and .pos.y are the actual coordinates at which the node is located. This information can be defined when creating the node-object by setting the second (x) and third (y) argument.
    • .force - The force-object contains the x- and y-components of the calculated force-vector.
  2. connection():

    The connections between nodes are modeled as an object each. This object is pretty straight forward:

    methods

    • .draw() - Draws the connection. Needs a globally declared reference to a container-element (conng). This container-element should be behind the drawg-element!
    • .toString() - again the standard method to print object-type. Simply returns “[NetConnection Object]”.

    properties

    • .parent - Reference to parent element.
    • .svgObject - Reference to svg object
    • .nodes - Array containing the references to the two nodes that are connected via this connection.
    • .weight - not used right now, but this should be similar to the force of the spring holding the two connected nodes together.
    • .clength - nominal length of the connection.
    • .minlength - minimal length of the connection. Not implemented yet!
  3. netfield():

    This is the actual field that contains all the calculations. In a more advanced version, this object will isa be able to create all the needed svg-objects to begin with. Right now it contains the following:

    methods

    • .toString() - yet again the standard method to print object-type. Simply returns “[Network Object]”.
    • .addnode - add a node-element to the field. This creates a node-element and places a reference in the object .nodes. (Propably better to place it under .nodes.add()..) It takes the same arguments as the node()-object and returns a reference.
    • .addconnection - creates a connection between two nodes with a specified weight and nominal length (arguments in that order). The method checks to see if the two nodes are connected first and returns a reference to the connection when created.
    • .draw() - calls all the draw-methods of every node()- and connection()-subelements.
    • .getforces - calculates the forces on all the nodes and stores it inside the node().force-objects.
    • .domoves - moves all the nodes according to the forces that are saved in the .force-objects. Returns a movement-value, to determine the amount of movement in the whole field.
    • .getforcedet - Returns the sum of all forces inside the field.
    • .getNodeById - As the name suggests, this method searches for the (first) node with the specified id. Returns false, if nothing found.
    • .setconnectivity - Little Tricky: The connectivity is the ability of the nodes inside a field to accept new and interactive connections (using the mouse as described above). If the supplied argument is true then on each node-object an eventhandler for mousedown is registered. At the time being, the eventhandler had to be an absolute reference (o.startconn), i’m trying to find out, how to get the name of the fieldobject-reference (wip)
    • .startconn, .drawnewconn, .stopconn and .clearnewconn - eventhandlers for the interactive connecting-process.

    properties

    • .mindistance - Minimal distance of any two nodes in the field. Not implemented yet.

    objects

    • .nodes - collection of node()-objects.
    • .connections - collection of connection()-objects.

Comments

  • By Romain, 5. April 2007 @ 00:46

    Hi,

    Seems very interesting but…
    - All SVG files are dead links (which lead to 404 errors).
    - Where can we have a look at the JavaScript code?

    Regards

  • By Omar Abo-Namous, 5. April 2007 @ 05:38

    @Romain: Hi, i updated the links.. sorry for the delay..

Other Links to this Post

RSS-Feed für Kommentare zu diesem Beitrag. TrackBack URI

Einen Kommentar schreiben