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 example – http://bl.ocks.org/mbostock/4339184. Since its just an example, I believe it was convenient to create an svg thats wide and tall enough to render your entire tree.

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

Unfortunately, setting the width and height of the svg to 500px and 500px does not help. D3 will just squish together all the nodes and almost nothing of your tree will be readable, let alone presentable.

The only solution that I could come up with for this was by computing the width and height of the svg based upon the depth of the tree and the max number of nodes at any level in the tree.

Keeping that in mind, I did a little refactor of the code and made pretty much everything as a configurable variable.

All the source code for this tutorial is available in github at in this particular commit. If you want to run the project locally, you will have to install npm, then run the command 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 directory. And d3 need to load the file on the fly. The HTML page where all the magic happens is large_tree_small_viewport.html. So just fire up a browser and go to the page http://127.0.0.1:3000/large_tree_small_viewport.html.

Now, lets jump into the code.


Loading the data

The first task is to load the data and define the configuration for our layout. Lets do that.

In the above code, after we load our data, we create a config object that acts as the payload to the function that will render the tree for us. We also selected a DOM element on the page – an svg element to be specific. This is the DOM node in which our tree will be rendered.

We compute the width and height of the svg’s parent node and send this in the config. This gives us the flexibility to use a container of any size. Make sure that the container has a overflow: auto in its CSS since we want to see scrollbars when the svg size is larger than the container’s dimentions.

I will discuss the renderTree function a bit later, but first lets see the function that computes the svg dimentions.

The aim of this function is to determine the minumum size of the SVG such that there is a certain minimum distance between the nodes of the tree.

Getting the depth is pretty straighforward. But you gotta be careful when getting the height. Also keep in mind that this tree is laid out horizontally. We want to determine which level of the tree has the maximum height. This is irrespective of which parent a node belongs to. e.g. Lets say root has 2 nodes – A and B. A has 3 children, B has 5. The total number of nodes at the different levels is the following

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

Once we compute the treeHeight and treeWidth, we then compute the minimum size required to render this tree with some spacing between the nodes. The spacing I have chosen is 100 and 80 for the width and height respectively.

The other important thing to notice is that I also make sure that the svg is at least as big as the viewport 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 actually write our renderTree function. Its not too different from the original example on the bl.ocks.org website apart from the fact that I call the computeSvgSizeFromData before I calculate the total width and height of the svg.

In the code that follows , I just make sure that I refer the config object whenever I need to determine dimentions. Instead of spitting out the code here, I’d rather have you see the source file on github. Its a little more structured and therefore a bit more re-usable as well.

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


Ryan Sukale

Ryan is just a regular guy next door trying to manage his life and finances.