user1934426 user1934426 - 1 year ago 136
jQuery Question

D3 Force Layout: Collapse Subset of Child Nodes (Opacity Change)

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;
var newClass = isCollapsed ? "uncollapsed" : "collapsed";

cNodes.forEach(function(n) {"opacity", 0);

cLinks.forEach(function(l) {"opacity", 0);

function minimise(node, assetMinType = "") {
// Function to minimise a node
var minNodes = [];
var minLinks = [];

if ( == 'asset') {
node.children.forEach(function(child) {
if ( == assetMinType)
else {
minimiseRec(node, "");

// We want to keep the top node and link


function minimiseRec(node, parentID) {
minNodes.push("#" +;
minLinks.push("#parent_" + parentID + "_child_" + node.address); {

return { nodes: minNodes, links: minLinks };

Does anyone know how best to do this?


Answer Source

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) {
        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'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 || == node.index ) { //if source or target are hidden hide the link'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++) {

Here is the updated fiddle :


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>

Set this to hidden in CSS :

  width: 50px;
  border : 1px solid black;


I have changed the logic slightly but this is the updated fiddle with commentary :

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 :)

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download