Reputation:
I'm trying to do this thing in D3.js but unable to find a way to do it.
What I want to do is, when a person clicks on the root node (level 0), it should show the child elements (level 1). When a person clicks on one of the child nodes (level 1) it should show its childrens (level 2) and the parent and parent-of-parent (level 1, this what the user clicked), but hide all the unrelated parents (from level 1).
Let me explain you this with pictures.
Upvotes: 3
Views: 3781
Reputation: 1976
You could do something like http://bl.ocks.org/benlyall/4fea200ebebb273aa4df
I forked http://bl.ocks.org/mbostock/4339083 and made a few changes:
Added a new property to each node .all_children
which keeps track of all children. We need this, or something similar since .children
contains the child nodes currently displayed, and ._children
is used by the existing code to determine if a node contains children or not (and sets the style accordingly).
Also added a .hidden
property that helps to determine whether or not the node should be displayed.
These are added after loading the data:
d3.json("flare.json", function(error, flare) {
root = flare;
root.x0 = height / 2;
root.y0 = 0;
function collapse(d) {
if (d.children) {
d.all_children = d.children;
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
d.hidden = true;
}
}
root.all_children = root.children;
root.children.forEach(collapse);
root.children.forEach(function(d) { d.hidden = false; });
root.hidden = false;
update(root);
});
Updated the update
function to reflect the new changes and only draw the nodes that are supposed to be drawn:
function update(source) {
// Compute the new tree layout.
var nodes = tree.nodes(root).filter(function(d) { return !d.hidden; }).reverse(),
links = tree.links(nodes);
The nodes
variable is set to only contain nodes that are NOT hidden.
Updated the click
handler to correctly set the state of the nodes in the display:
// Toggle children on click.
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
if (d._children) {
d._children.forEach(function(n) { n.hidden = true; });
if (d.parent) {
d.parent.children = d.parent.all_children;
d.parent.children.forEach(function(n) {
n.hidden = false;
});
}
}
} else {
d.children = d._children;
d._children = null;
if (d.children) {
d.children.forEach(function(n) { n.hidden = false; });
if (d.parent) {
d.parent.children = [d,];
d.parent.children.filter(function(n) { return n !== d; }).forEach(function(n) {
n.hidden = true;
});
}
}
}
update(d);
}
The first part of the if
statement is called when we're collapsing a node, in which case, we need to display all of the siblings of the clicked node by setting d.parent.children
to d.parent.all_children
and setting each of those nodes to .hidden = false
. And we need to hide all the children of the clicked node by setting d.children = null
and then setting each node in d._children
to hidden.
The second part of the if
statement is called when we're expanding a node, in which case, we need to hide its siblings (set .hidden
to true
) and update the .children
property of the clicked node's .parent
node so that only the clicked node is listed as a child.
Upvotes: 6