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.


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)


Tagged , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: