Reputation: 695
I've made a collapsible tree diagram in d3 (v5), a simplified version of which can be found here: https://jsfiddle.net/philipnye/cwj9nkhr/.
Each node has a label, but labels are only displayed where there is enough space for them not to overlap each other or get too close to the edge of the SVG. In the linked example, on first load labels only appear for the first two depths of the tree diagram.
requiredSpacing
is used to approximate how much space is needed, while minSpacing
checks the minimum spacing that exists between nodes at each depth.
The following lines position the nodes and labels, with a transition effect:
var nodeUpdate=nodeEnter.merge(node)
.transition()
.duration(function() {
if (loaded==0) {
return 0;
}
else {
return duration;
}
})
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
nodeUpdate.select("circle")
.attr("r", function(d) {
return radiuses[d.depth];
})
.attr("class", function(d) {
if (d._children) {
return "filled";
} else {
return "unfilled";
}
});
nodeUpdate.select("text")
.style("fill-opacity", function(d) {
if (minSpacing[d.depth]<requiredSpacing[d.depth]*2 || (d.data.position=='left' && Math.ceil(d.x/5)*5-radiuses[d.depth]-requiredSpacing[d.depth]<margin.left) || (d.data.position=='right' && Math.ceil(d.x/5)*5+radiuses[d.depth]+requiredSpacing[d.depth]>width)) {
return 1e-6;
}
else {
return 1;
}
})
.attr("class", function(d) {
if (minSpacing[d.depth]<requiredSpacing[d.depth]*2 || (d.data.position=='left' && Math.ceil(d.x/5)*5-radiuses[d.depth]-requiredSpacing[d.depth]<margin.left) || (d.data.position=='right' && Math.ceil(d.x/5)*5+radiuses[d.depth]+requiredSpacing[d.depth]>width)) {
return "nodeLabel nonselectable";
}
else {
return "nodeLabel";
}
})
I set the opacity of labels which there isn't space to show to 1e-6 (to enable a transition) and give them a class of nonselectable
, which means the labels can't be selected. But I don't actually remove them - and I then have the problem that in some cases they overlap nodes and mean the nodes can't be clicked on to expand/collapse the tree below that point. Look at the nodes two or three levels deeper than those labelled Male and Female - only somewhere between a third and a half of the nodes can be clicked on. (Note, nodes in the bottom layer aren't expandable/collapsible, as they have no children nodes.)
How am I best removing these labels, or at least stopping them preventing you from clicking on the nodes?
Things I've considered:
nonselectable
class, but this doesn't feel the most efficient approach, and I've
had some trouble trying to implement itfont-size
of close to zero. I've tried
tacking something like the code below onto my nodeUpdate
code, but it seemed to cause problems with the transition.attr("font-size", function(d) {
if (minSpacing[d.depth]<requiredSpacing[d.depth]*2 || (d.data.position=='left' && Math.ceil(d.x/5)*5-radiuses[d.depth]-requiredSpacing[d.depth]<margin.left) || (d.data.position=='right' && Math.ceil(d.x/5)*5+radiuses[d.depth]+requiredSpacing[d.depth]>width)) {
return '0.1em';
}
})
Or there may be another, better way of solving this.
How should I do it?
Upvotes: 1
Views: 763
Reputation: 102218
Just set a pointer-events: none;
to those labels:
.nonselectable {
pointer-events: none;
etc...
}
Actually, since I'm seeing that the labels are not clickable, you could set pointer-events: none;
to all of them.
Here is the updated JSFidle: https://jsfiddle.net/e3j7ta4y/
Upvotes: 1