Tag Archives: network diagram

D3 Network (Force Directed) Render with Node Margin

I had to build the network (massive relation) diagram to (potentially) replace the regular javascript drawing module due to the data to render getting bigger everyday. Instead of enhance the existing library to support more data, I rather decided to find the replacement of drawing library for the long term solution. D3 seems to be the best candidate with a bunch of incredible examples.

This example http://bl.ocks.org/mbostock/4062045 was the good start to customize to cover all requirements that the old render library does. Although it had many features and customizations to add and one of them was adding margin between link line and node.

There are a couple of reasons you would need margin to add margin between endpoint of line and node.

    1. Display node with various shape using d3.svg.symbol(), margin would make the the node shape (diamond, rectangle, circle, etc.) not to be overlapped by the line.
    2. If you have many line link to a single node, especially if you add arrow to the end of line, margin would make its display much cleaner.

Give some free space for node’s label.

Below is a sample of render; without margin we wouldn’t be able to indicate it’s shape.

Image

In tick event of d3.layout.force(), I replace (if any) “link.attr(“d”, function(d) { });” with following:


link.attr("d", function(d) {
 // calculate new link endpoint for both source and target
 // with specified margin
 var sourceX = d.source.x,
     sourceY = d.source.y,
     targetX = d.target.x,
     targetY = d.target.y;

 var X = Math.abs(targetX - sourceX);
 var Y = Math.abs(targetY - sourceY);
 var R = Math.sqrt(X*X + Y*Y);
 var xMargin = X * nodeMargin / R;
 var yMargin = Y * nodeMargin / R;

 if (sourceX > targetX) {
 sourceX = sourceX - xMargin,
 targetX = targetX + xMargin;
 }
 else {
 sourceX = sourceX + xMargin,
 targetX = targetX - xMargin;
 }

 if (sourceY > targetY) {
 sourceY = sourceY - yMargin,
 targetY = targetY + yMargin;
 }
 else {
 sourceY = sourceY + yMargin,
 targetY = targetY - yMargin;
 }
 d.x1 = sourceX;
 d.y1 = sourceY;
 d.x2 = targetX;
 d.y2 = targetY;
})
.attr("x1", function(d) { return d.x1; })
.attr("y1", function(d) { return d.y1; })
.attr("x2", function(d) { return d.x2; })
.attr("y2", function(d) { return d.y2; });

See a sample here – http://jsfiddle.net/iamarther/gZG5x/2/ (extended fromĀ http://bl.ocks.org/mbostock/4062045)

d3_mess_sample

Tagged , ,