D3 Tree Layout Separation Between Nodes using NodeSize
UPDATE 05/04/2018: It is my understanding d3 has changed a lot (for the better) to be a lot more modular. For those who are looking towards this answer, this was using a much older version of d3 (specifically v3).
A lot of the findings are still relevant for the d3-hierarchy
package under cluster.size()
and cluster.nodeSize()
and I am planning to potentially update my example to use that. For historical reference though, I'm leaving the bottom untouched.
Here is a jsFiddle: http://jsfiddle.net/augburto/YMa2y/
EDIT: Updated and move the example to Codepen. The example still exists on jsFiddle but Codepen seems to have a nicer editor and allows you to easily fork. I'll also try to add the example directly to this answer once I've reduced the amount of content in it.
http://codepen.io/augbog/pen/LEXZKK
Updating this answer. I talked with my friend and we looked at the source for size
and nodeSize
tree.size = function(x) {
if (!arguments.length) return nodeSize ? null : size;
nodeSize = (size = x) == null;
return tree;
};
tree.nodeSize = function(x) {
if (!arguments.length) return nodeSize ? size : null;
nodeSize = (size = x) != null;
return tree;
};
When you set a size
for the tree, you are setting a fixed size so that the tree has to conform to that width and height. When you set a nodeSize
, the tree has to be dynamic so it resets the size of the tree.
When I specified size
after nodeSize
, I was pretty much overriding what I wanted haha...
Bottom line: If you want nodeSize
to work, you can't have a fixed tree size. It will set the size to null
. Do not declare a size
if you are declaring a nodeSize
.
EDIT: D3.js actually updated the documentation. Thanks to whoever did that because it is way clearer now!
The nodeSize property is exclusive with tree.size; setting tree.nodeSize sets tree.size to null.
This is what my tree looks like now. I have also added zoom functionality as well as how to center text within the rectangle.
I didn't quite understand the accepted answer until I did some digging of my own, so I thought I'd share what I found as well...
If you are using .size()
and your nodes are overlapping, use .nodeSize()
instead
As explained in the accepted answer, .size()
sets the tree's available size, and so depending on the spacing between cousin nodes, second cousins, etc. they may get squished together and overlap. Using .nodeSize()
simply says each node should get this much space, so they will never overlap!
The code that ended up working for me was
var nodeWidth = 300;
var nodeHeight = 75;
var horizontalSeparationBetweenNodes = 16;
var verticalSeparationBetweenNodes = 128;
var tree = d3.layout.tree()
.nodeSize([nodeWidth + horizontalSeparationBetweenNodes, nodeHeight + verticalSeparationBetweenNodes])
.separation(function(a, b) {
return a.parent == b.parent ? 1 : 1.25;
});
Without horizontalSeparationBetweenNodes
and verticalSeparationBetweenNodes
the nodes edges were touching each other. I also added this .separation()
to decrease the amount of space between cousin nodes, as my nodes are pretty wide and lots of space was getting wasted.
Note: This is for d3 v3, not v4