Boo
Boo

Reputation: 377

Animate building a graph in Cytoscape.js

Hi I would like to learn how to animate building a graph in Cytoscape.js. To me this means, the user would choose a layout algorithm, then starting with the root node an edge would grow from the node and eventually end up pointing in the direction of the next node in the graph, then that node would grow from a small dot, and the process would repeat. This would eventually end up animating the entire graph being built. I think this is just the opposite of the Images and Breadthfirst Layout Demo.

Can anyone help me figure out a strategy to do this? I'm thinking I need to layout a headless graph with my list of nodes and use those positions to display the animations in the main graph displayed in the html container.

thanks for any help

Upvotes: 2

Views: 1566

Answers (2)

Boo
Boo

Reputation: 377

Here's what I ended up using, it would work better using the play promise as maxkfranz suggests, instead of the delay.

/****************************************************************************************************    
 * https://gist.github.com/maxkfranz/aedff159b0df05ccfaa5
 * method will animate the graph building, from parent to child
 * 
 */
animateGraphBuilding = function(nodes){

    var delay = 0;      
    var size = nodes.length;
    var duration = (200000 / size);
    mod = $('#animationSpeed').val()/2;
    if(mod < 1){ 
        mod = 1; 
        $('#animationSpeed').val(mod);
    }else if(mod > 100){
        mod = 100;
        $('#animationSpeed').val(mod);

    }

    duration /= mod;

    var visitedMap = {};//used to ensure nodes are only animated once

    for(var index = 0; index < size; ++index){
        visitedMap[nodes[index].data('id')] = 0;
    }
    var nodesCopy = nodes.clone();//store original rendered positions

    //loop through the list of nodes and then,
    //Find connected nodes and then,
    //loop through connected nodes and animated from parent to original position
    for( var i = 0; i < nodes.length; ++i ){ 
        var cNode = nodes[i];                   
        var nextNodes = cNode.connectedEdges(
                function(){
                    return this.source().same(cNode);
                }
            ).targets();                                                                        

        for (var index = 0; index < nextNodes.length; ++index){
            var nNode = nextNodes[index];

            (function(currentNode, x, copyNode, nextNode){          

                if(nextNode != null && x != 0 && visitedMap[nextNode.data('id')] < 1){
                    ++visitedMap[nextNode.data('id')];
                    //console.log('currentNode: ' + currentNode.data('id')+ ', x: ' + x + ', nextNode: ' + nextNode.data('id') );

                    var position = nextNode.renderedPosition();                 
                    nextNode.renderedPosition(copyNode.renderedPosition());         

                    nextNode.delay( delay, function(){
                        nextNode.style("visibility", "visible");                        
                    } ).animate(    {                   
                            renderedPosition: position //to this position                               
                        }, {
                            duration: duration,
                            complete: function(){/*do nothiing*/}
                        }                                                                   
                    );                  
                }else if (nextNode != null && visitedMap[nextNode.data('id')] < 1){ 

                    ++visitedMap[nextNode.data('id')];
                    var position = nextNode.renderedPosition();                 
                    nextNode.renderedPosition(copyNode.renderedPosition());         

                    nextNode.delay( delay, function(){
                        currentNode.style("visibility", "visible"); //show the root node
                        nextNode.style('visibility', 'visible');                    
                    } ).animate(    {                   
                            renderedPosition: position,//to this position                               
                        }, {
                            duration: duration,
                            complete: function(){/*do nothing*/}                    
                        }                                       
                    );                                          
                }           

                delay += duration;

            })(cNode, i, nodesCopy[i], nNode);                      
        } //end inner for, iterates through children nodes
    } // end of outter for, iterates through all nodes                  
};  

Upvotes: 1

maxkfranz
maxkfranz

Reputation: 12250

If you have all the elements at init, just put them all in the graph. You can have them initially hidden with your stylesheet, and you can show them one-by-one with animations.

I would use .animation() rather than .animate(), because you can then use the returned animation object and its play promise. You can just create a chain of promises as your timeline.

Upvotes: 2

Related Questions