在 Cytoscape.js 中动画构建图表
Animate building a graph in Cytoscape.js
您好,我想学习如何在 Cytoscape.js 中制作图表动画。对我来说,这意味着,用户会选择一种布局算法,然后从根节点开始,一条边会从该节点开始生长,最终指向图中下一个节点的方向,然后该节点将从一个小节点开始生长点,这个过程会重复。这最终将最终为正在构建的整个图形设置动画。我认为这与Images and Breadthfirst Layout Demo正好相反。
谁能帮我想出一个策略来做到这一点?我在想我需要用我的节点列表布置一个无头图,并使用这些位置来显示 html 容器中显示的主图中的动画。
感谢您的帮助
如果你在初始化时拥有所有元素,只需将它们全部放入图中即可。您可以让它们最初隐藏在您的样式表中,您可以用动画一个一个地显示它们。
我会使用 .animation()
而不是 .animate()
,因为您随后可以使用返回的 animation
对象及其播放承诺。您可以创建一个承诺链作为您的时间线。
这是我最终使用的方法,按照 maxkfranz 的建议使用 play promise,而不是延迟会更好。
/****************************************************************************************************
* 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
};
您好,我想学习如何在 Cytoscape.js 中制作图表动画。对我来说,这意味着,用户会选择一种布局算法,然后从根节点开始,一条边会从该节点开始生长,最终指向图中下一个节点的方向,然后该节点将从一个小节点开始生长点,这个过程会重复。这最终将最终为正在构建的整个图形设置动画。我认为这与Images and Breadthfirst Layout Demo正好相反。
谁能帮我想出一个策略来做到这一点?我在想我需要用我的节点列表布置一个无头图,并使用这些位置来显示 html 容器中显示的主图中的动画。
感谢您的帮助
如果你在初始化时拥有所有元素,只需将它们全部放入图中即可。您可以让它们最初隐藏在您的样式表中,您可以用动画一个一个地显示它们。
我会使用 .animation()
而不是 .animate()
,因为您随后可以使用返回的 animation
对象及其播放承诺。您可以创建一个承诺链作为您的时间线。
这是我最终使用的方法,按照 maxkfranz 的建议使用 play promise,而不是延迟会更好。
/****************************************************************************************************
* 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
};