Reputation: 273
I am using a D3 force layout and trying to collapse child nodes whilst keeping the graph fixed, e.g. by simply changing them and their links' opacity. However, I am not trying to just collapse all nodes at once - I actually have an attribute in each node called "group", which can be 1,2 or 3.
When I click on a node, a tooltip appears with 3 buttons for each of these groups - upon clicking on the correct button, I would like the child node of that type to collapse, but all of its children (of all 3 groups) to collapse as well.
Here is the fiddle.
I have so far tried to create arrays of the node group ids and corresponding link IDs, and then use JQuery to hide those DOM objects but this didn't work:
function collapseNodes(node, collapseType, isCollapsed) {
var collapseData = minimise(node, collapseType);
var cNodes = collapseData.nodes,
cLinks = collapseData.links;
console.log(collapseData);
var newClass = isCollapsed ? "uncollapsed" : "collapsed";
cNodes.forEach(function(n) {
d3.select(n).style("opacity", 0);
});
cLinks.forEach(function(l) {
d3.select(l).style("opacity", 0);
});
}
function minimise(node, assetMinType = "") {
// Function to minimise a node
var minNodes = [];
var minLinks = [];
if (node.group == 'asset') {
node.children.forEach(function(child) {
if (child.group == assetMinType)
minimiseRec(child, node.id);
});
}
else {
minimiseRec(node, "");
// We want to keep the top node and link
minNodes.shift();
minLinks.shift();
}
function minimiseRec(node, parentID) {
minNodes.push("#" + node.id);
minLinks.push("#parent_" + parentID + "_child_" + node.address);
node.children.map(function(child) {
minimise(child, node.id);
});
}
return { nodes: minNodes, links: minLinks };
}
Does anyone know how best to do this?
Thanks.
Upvotes: 0
Views: 731
Reputation: 10612
If its only the opacity you wish to change this is fairly simple. I guess if you hide a nodes children you want to hide their childrens children and so on ?
First I set a variable d.hiddenNode
. This is so I can toggle the opacity. I set it to false. And then on click function :
.on('click', function(d) {
console.log(d);
if(d.hiddenNode){
hideChildren(d, false);
d.hiddenNode = false;
} else {
hideChildren(d, true);
d.hiddenNode = true;
}
})
Now because you want the childrens children etc to be hidden you need a recursive function like so. One that hides links and nodes ( I have commented to explain) :
function hideChildren(node, hide) {
for (var i = 0; i < node.children.length; i++) {
recurseChildren(node.children[i]); //loop through children to hide
}
function recurseChildren(node) {
nodeEnter.each(function(d) { //go through all nodes to check for children
if (d.index == node.index) { //if child is found
d3.select(this).style('opacity', function(){
return hide ? 0 : 1; //toggle opacity depending on d.hiddenNode value
}) //.remove();
}
})
link.each(function(d) { //same with links
if (d.source.index == node.index || d.target.index == node.index ) { //if source or target are hidden hide the link
d3.select(this).style('opacity', function(){
return hide ? 0 : 1;
}) //.remove();
}
})
if (node.children) { //if this node has children, call again but with their children
for (var i = 0; i < node.children.length; i++) {
recurseChildren(node.children[i]);
}
}
}
}
Here is the updated fiddle : http://jsfiddle.net/thatOneGuy/3g4fqfa8/2/
EDIT
For the pop up i just created a div that contains the 3 groups, 1,2,3 :
<div id='groupChoice'>
<div id='group1' class = 'group' onclick='hideGroup(1)'>1</div>
<div id='group2' class = 'group' onclick='hideGroup(2)'>2</div>
<div id='group3' class = 'group' onclick='hideGroup(3)'>3</div>
</div>
Set this to hidden in CSS :
.group{
width: 50px;
height:50px;
border : 1px solid black;
}
#groupChoice{
visibility:hidden;
}
I have changed the logic slightly but this is the updated fiddle with commentary : http://jsfiddle.net/thatOneGuy/3g4fqfa8/3/
Theres some work that needs to be done with the links. I havent got enough time atm to finish it off, im sorry. But that should get you started.
Basically, when you click a node, pop up comes up, you chose a group to hide, they get hidden. Hit the same node again, chose a node to show. This was done super quick, so there's a lot wrong with it, but the basics are the so it should help :)
Upvotes: 1