Hide and Show Child Nodes on Node Tap Cytoscape

5.6k views Asked by At

I am trying to create a collapsible tree structure in Cytoscape using breadthfirst layout, to replicate the D3 collapsible tree.

I am trying to replicate this type of click action on nodes, but adding restore functionality in addition - Images & breadthfirst layout

The reason I chose Cytoscape is because I had a scenario where the tree would have nodes with more than 1 parent.

I have tried to add a tap event using the following code:

cy.on('tap', 'node', function() {
    if (this.scratch().restData == null) {
       // Save node data and remove
       this.scratch({
            restData: this.connectedEdges().targets().remove()
       });
    } else {
       // Restore the removed nodes from saved data
       this.scratch().restData.restore();
       this.scratch({
            restData: null
       });
    }
}

But, this is successful only to collapse and expand its immediate child nodes (rest of the nodes are still visible) and also causes problem when I tap on leaf nodes.

If anyone knows a way to expand and collapse a node, please help.

Edit: Guys, if anyone knows the solution for a simple multilevel tree also, that would also be a good start...

2

There are 2 answers

2
nensimons On

I replaced this line of code:

 restData: this.connectedEdges().targets().remove()

with this one:

restData: this.successors().targets().remove()

and this code now collapses children and grandchildren nodes (only tested on 3 levels) and leaf nodes no longer collapse into their parent when clicked.

0
L Bokun On

I have found a few options to achieve this effect.

  1. Using remove and restore. When the tree is loaded, the nodes' children are stored.

    var childrenData = new Map(); //holds nodes' children info for restoration
    var nodes = elems.nodes
    for(var x = 0; x < nodes.length; x++){
      var curNode = cy.$("#" + nodes[x].data.id);
      var id = curNode.data('id');
      //get its connectedEdges and connectedNodes
      var connectedEdges = curNode.connectedEdges(function(){
        //filter on connectedEdges
        return !curNode.target().anySame( curNode );
      });
      var connectedNodes = connectedEdges.targets();
      //and store that in childrenData
      //removed is true because all children are removed at the start of the graph
      childrenData.set(id, {data:connectedNodes.union(connectedEdges), removed: true}); 
    }  
    

    This data can then be removed and restored on a node click, similar to your original code. I used Cytoscape's Images collapsing tree demo as the base for my example: jsfiddle

  2. Using the display attribute of a node. Because the nodes are hidden and not removed, their connected edges and nodes are still accessible, so you don't have to store the data beforehand.

    cy.on('tap', 'node', function(){
      //if the node's children have been hidden
      //getting the element at 1 because the element at 0 is the node itself
      //want to check if its children are hidden
      if (this.connectedEdges().targets()[1].style("display") == "none"){
        //show the nodes and edges
        this.connectedEdges().targets().style("display", "element");
      } else {
        //hide the children nodes and edges recursively
        this.successors().targets().style("display", "none");
      }
    }); 
    

    (jsfiddle)

  3. There is also a Cytoscape expansion on GitHub with the name cytoscape.js-expand-collapse. I have not personally used it, but its description matches the functionality you describe:

    A Cytsocape.js extension to expand/collapse nodes for better management of complexity of compound graphs