Show Buttons
Share On Facebook
Share On Twitter
Share On Google Plus
Share On Linkdin
Share On Reddit
Share On Stumbleupon
Contact us
Hide Buttons

Render a d3 tree with a minimum distance between the tree nodes

I was going through the reingold-tilford-tree at the exam­ple — Since its just an exam­ple, I believe it was con­ve­nient to cre­ate an svg thats wide and tall enough to ren­der your entire tree.

But what if you dont have that lux­ury. What if all the real estate that you can afford is a 500px by 500px square on your page in which you want to ren­der this tree.

Unfor­tu­nately, set­ting the width and height of the svg to 500px and 500px does not help. D3 will just squish together all the nodes and almost noth­ing of your tree will be read­able, let alone presentable.

The only solu­tion that I could come up with for this was by com­put­ing the width and height of the svg based upon the depth of the tree and the max num­ber of nodes at any level in the tree.

Keep­ing that in mind, I did a lit­tle refac­tor of the code and made pretty much every­thing as a con­fig­urable variable.

All the source code for this tuto­r­ial is avail­able in github at in this par­tic­u­lar com­mit. If you want to run the project locally, you will have to install npm, then run the com­mand npm install, and then fire up a node server using npm run start. I just used a server since my data is kept in a file in the data direc­tory. And d3 need to load the file on the fly. The HTML page where all the magic hap­pens is large_tree_small_viewport.html. So just fire up a browser and go to the page

Now, lets jump into the code.

Load­ing the data

The first task is to load the data and define the con­fig­u­ra­tion for our lay­out. Lets do that.

In the above code, after we load our data, we cre­ate a con­fig object that acts as the pay­load to the func­tion that will ren­der the tree for us. We also selected a DOM ele­ment on the page — an svg ele­ment to be spe­cific. This is the DOM node in which our tree will be rendered.

We com­pute the width and height of the svg’s par­ent node and send this in the con­fig. This gives us the flex­i­bil­ity to use a con­tainer of any size. Make sure that the con­tainer has a overflow: auto in its CSS since we want to see scroll­bars when the svg size is larger than the container’s dimentions.

I will dis­cuss the ren­derTree func­tion a bit later, but first lets see the func­tion that com­putes the svg dimentions.

The aim of this func­tion is to deter­mine the minu­mum size of the SVG such that there is a cer­tain min­i­mum dis­tance between the nodes of the tree.

Get­ting the depth is pretty straigh­for­ward. But you gotta be care­ful when get­ting the height. Also keep in mind that this tree is laid out hor­i­zon­tally. We want to deter­mine which level of the tree has the max­i­mum height. This is irre­spec­tive of which par­ent a node belongs to. e.g. Lets say root has 2 nodes — A and B. A has 3 chil­dren, B has 5. The total num­ber of nodes at the dif­fer­ent lev­els is the following

  • root: 1
  • level 1: 2 = (A and B)
  • level 2: 8 = 3(children of A) + 5(children of B).

Once we com­pute the tree­Height and treeWidth, we then com­pute the min­i­mum size required to ren­der this tree with some spac­ing between the nodes. The spac­ing I have cho­sen is 100 and 80 for the width and height respectively.

The other impor­tant thing to notice is that I also make sure that the svg is at least as big as the view­port so that even if the amount of data is small, we dont have any dead space on the viewport.

With that out of the way, the next task is to actu­ally write our ren­derTree func­tion. Its not too dif­fer­ent from the orig­i­nal exam­ple on the web­site apart from the fact that I call the com­puteSvg­Size­From­Data before I cal­cu­late the total width and height of the svg.

In the code that fol­lows , I just make sure that I refer the con­fig object when­ever I need to deter­mine dimen­tions. Instead of spit­ting out the code here, I’d rather have you see the source file on github. Its a lit­tle more struc­tured and there­fore a bit more re-usable as well.

I hope this helps you in your mis­ery, if you were in one. If not, well good for you.