Hide and Show Child Nodes on Node Tap Cytoscape
Asked Answered
A

2

9

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...

Annalee answered 6/1, 2017 at 13:20 Comment(1)
This question has nothing to do with d3.js and the tag should probably be removed. If you are interested in d3, though, cytoscape looks like it produces what d3 would call a force tree.Snowfall
C
6

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

Clark answered 17/7, 2017 at 17:14 Comment(0)
P
5

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.

Poser answered 25/5, 2017 at 13:22 Comment(2)
I spent a lot of time with the solution provided by l-boken - which works well on included data but not imported data (latter: .cyjs file exported from Cytoscape, then loaded into Cytoscape.js). While the imported data looked, programmed similarly to the example provided, I could not resolve this line (and downstream dependents): var curNode = cy.$("#" + nodes[x].data.id);. The code provided in the question + this answer provided a simple solution.Pastiness
Thanks! This is working for me but how do I make it hide in the beginning? Right now, when it renders, it is first visible and hides only when I click it.Evelinevelina

© 2022 - 2024 — McMap. All rights reserved.