There are at least four ways to control node visibility:
* the "visibility" style
* the "display" attribute
* the "opacity" style
* the "fill-opacity" and "stroke-opacity" style
There's a good summary in this thread:
http://groups.google.com/group/d3-js/browse_thread/thread/6021c3bfa8a215ae
If you have circles, you could also transition the radius to or from
0, which is aesthetically pleasing.
> var link = vis.selectAll("line.link")
> .style("display", function(d) {if (d.target.level > dl &&
> d.target.group == gr){return "";}});
This isn't doing what you expect, because the style operator will
remove the property if the return value from your function is null or
undefined. So this is actually making all of the nodes visible, rather
than only affecting the ones you intend. A better way to do this is to
filter the selection, so that you only toggle the style property on
some of the nodes. For example, to clear the display property and make
some nodes visible:
vis.selectAll("line.link")
.filter(function(d) { return d.target.level > dl &&
d.target.group == gr; })
.style("display", null);
Similarly, to hide some nodes:
vis.selectAll("line.link")
.filter(function(d) { return d.target.level > dl &&
d.target.group == gr; })
.style("display", "none");
Mike
"""
A null value will remove the style property.
"""
https://github.com/mbostock/d3/wiki/Selections#style
Also, note that null == undefined in JavaScript!
Mike
If you really want to select all descendants of a given element, you can selectAll("*"), but this is rarely needed.
Mike
Here's how you might select descendant nodes by traversing the tree structure:
node.on("click", function(p) {
// remove links that are connected to descendants
link.filter(function(d) {
for (d = d.source; d; d = d.parent) {
if (d === p) return true;
}
}).remove();
// remove all descendants
node.filter(function(d) {
while (d = d.parent) {
if (d === p) return true;
}
}).remove();
});
Of course, this isn't the best implementation for a few reasons:
1. The layout should adjust when the child nodes are removed.
2. You may want to show hidden child nodes again (i.e., undo the hide).
And why not add animated transitions to smoothly expand and collapse
the tree? :)
Mike
Untrue. You don't need to use recursion to traverse a tree. Look
closely at the filter:
function(d) {
while (d = d.parent) {
if (d === p) return true;
}
}
The while loop causes the code to walk up the parent chain, starting
at the current node (d). If, while traversing ancestors, the toggle
node (p) is found, then we know that the current node (d) is a
descendant of the toggle node. If I wanted to only detect direct
children instead, I would say:
function (d) {
return d.parent === p;
}
> I tried to modify your function to work recursively, but I always get either
> an undefined 'd' or 'p'.
This is a JavaScript error. Without posting your code, it's difficult
to say what the problem will be. In my example, there are two nested
functions:
1. The `on` operator registers a "click" event listener. This defines
the node `p` ,which represents the node that was clicked on.
2. Within the event listener, the `filter` operator is applied to the
nodes. This invokes another function on each node, defining a node
`d`, which represents every other node.
There's a concept in JavaScript called closure which is what allows
the function passed to the `filter` operator to access not just it's
direct arguments (d, i) but also the arguments and variables in
enclosing functions (p).
Mike
Mike