2011-11-23 64 views
5

修订问题 我已经更新了这一点更简洁..:到〜3000拉斐尔对象一次顺利动画属性发生变化

在这种提琴:http://jsfiddle.net/pX2Xb/4/我有借鉴一些3000拉斐尔代码圈到页面。然后尝试在10秒内一次对所有圆圈进行动画处理(更改填充颜色),这会产生笨重的视觉动画。将圆圈数量更改为20以查看比较平滑的动画。

我的问题是(a)是否有可能对3000个元素进行更新,并且(b)如果是,那么代码的做法是什么?

一些注意事项:

  • 我愿意拿小定时打,如果有一些方法来解决这个优化,但是,例如,我想所有界至少已经更新无论动画时间设置为1.5倍。所以,如果动画是10秒,所有圈子应该已经改变了15.
  • 3000个元素大致是我目前的限制,所以我会很高兴它为此工作:)在说,如果解决方案可以有效地处理更多的事情,对于一般情况来说,这真的很棒。

旧的细节,在情况下,它可以帮助

我创建一个大图美县,其中有超过3000的;我使用this Wikipedia svg file来获取相关的SVG路径来创建地图,并使用RaphaelJs来渲染地图。

因此,我结束了类似下面的3000语句:

var cc_02130 = rsr.path("M 140.66674,.... 320.11635"); // county path 
    cc_02130.attr({id: '02130',.. .."marker-start": 'none'}); // init attrs 

我也创造了Paper.set()对象来保存所有这些元素:

var myset = paper.set([cc_56039, cc_56040, cc_56041 ...]) 

忘记了在这里实际生成的文件非常大,我非常感谢的建议,我可以如何将更改应用到上面详述的对象的体积,这既快又合理确定CPU聪明 (可能是一个很大的问题)。

我绝对会改变我的代码/对象的结构,只要我可以单独更改特定县的属性。 例如,我希望能够在一秒或两次(全部3000+)中为每个路径内容应用不同的颜色。

我面临的挑战不是如何应用颜色变化,动画等,而是如何快速高效地完成这一任务。现在,如果我循环并对3000多个对象应用更改,我的机器就会尖叫我;作为替代方案,我使用setTimeout将更改分解为更小的块(也许10个一次,延迟40 ms)。超过3000个项目,这变得很慢,并仍然使用大量的CPU。

感谢, OLI

+1

我的猜测是,你的延迟来自你更新对象触发的大量重绘,而不是从对象本身的变化触发。即使在慢速机器上,3000个函数调用也应该在一秒钟内完成。你可以衡量一下,如果你触发了每次更改的重绘? 如果是,请查看是否有方法在重绘之前阻止重绘或批量更新。 – Munter

+0

我同意@Munter - 我现在明白我的问题是关于所有这些形状的实际重绘/渲染,而不是实际的函数调用。考虑到这一点,我仍然在某种程度上确保我能够改善_this_问题。相应地更新我的问题。 – oli

+0

如果您有能力损失非svg浏览器,那么您的问题更适合d3.js。这里是你的jsfiddle由d3处理的动画:http://jsfiddle.net/ekMd6/ – Duopixel

回答

10

我不知道为什么,但是D3.js在同时动画大量元素时效率更高。

Raphael.st.nodes = function() { 
    var elements = []; 
    this.forEach(function (i) { 
    elements.push(i.node); 
    }); 
    return elements; 
} 

然后你让D3从那里

//circleholder is a Raphael set 
elements = circleholder.nodes() 
d3.selectAll(elements) 
    .transition() 
    .attr("fill", function(d,i){return colours[randomNum(14)]}) 
    .duration(ANIMATION_DELAY) 

这里:您可以通过创建一个接收一组,并返回要进行动画处理的HTML对象拉斐尔功能让他们都工作无缝是jsfiddle:http://jsfiddle.net/mFecs/

+2

使用D3和Raphael的非常漂亮的例子。绝对是一个想法,我会为未来的项目窃取! – slebetman

+0

@slebetman您是否知道窃取代码违反了StackOverflow的使用条款? – ajax333221

+0

由于@Duopixel非常感谢你的多重输入。我将使用你的实现 - 在这一点上,我正在考虑在D3中重新实现它,但是我们会看到 - 无论哪种方式,我一定会在将来使用这个库 - 所以谢谢! – oli

0

。我不认为目前熟悉Rapael。js,我只是建议用一种通用的JavaScript方式,你可以创建一个changeRaphaelPathAttributeEvent,每次你想改变路径时发出一个改变,将属性改变作为所述事件的参数。然后将事件处理程序附加到将执行属性更改的每个路径(如果可能的话)。

这样就可以解决循环访问所有路径变量并同步更改属性的问题(这会直接影响页面在处理过程中的响应);该方法对用户体验的性能影响较小。

注意:这只是解决即时性能问题的解决方案。也许还有其他的解决方案可以最大限度地减少访问所需的对象数量,你也应该考虑(并且我不能告诉你,因为我不知道拉斐尔那么好)。

+0

谢谢@Sune,我正试图实现这个权利。我还没有完成,但是,我担心它仍然会遇到同样的问题,即浏览器试图一次性将更改应用到所有这些svg对象。 – oli

0

您是否手动编写了所有路径?如果你把所有的路径放在一个对象中,我认为更好。然后,您可以迭代对象并使用所有路径,例如for in。在这个过程中,您可以使用element.id = 'name'为每个路径提供一个内部ID。一旦你把所有的内部ID's和路径drawed,您可以使用getById方法:getById('pathId')如果你要使用集我建议你使用Clousures,可以先声明变量

var setName = Paper.Set() 

和那么,如果你想一些属性应用于元素推入另一个循环

for (countie in Lousiana){ 
    setName.push(countie) 
} 

然后你有一个像Paper.forEach()方法的路径。或者Set.FotEach()。两者都采用参数等回调函数,然后在每次迭代中执行该函数。

如果你想分享你的代码,这对我来说不会是一个问题,我可以检查一下,并且告诉我如何解决一些情况。我也在开发地图,我正在开发一个教育视频游戏,如果你愿意,我也可以和你分享我的代码,但是关于拉斐尔的文档没有那么多,所以这对我来说很有用,看看如何你使用它,也许你也一样。

再见!

+0

感谢您的建议,我已经实现了你现在提到的许多东西(特别喜欢漂亮的element.id/getById的东西 - 不知道你可以做到这一点)。不幸的是我仍然有一个问题加快速度,但很快就会在这里发布代码。 – oli

-1

说实话,改变3000个物品的属性对于任何电脑都应该很容易。 Raphael为每个动画元素使用setInterval。元素属性更改后,浏览器重新绘制整个页面。这是2999次不必要的重新抽奖。

这是我会做的:不使用拉斐尔动画,而是使用循环来更改每个元素。这有点复杂,但速度更快。另外,您可以更改每秒的步骤。如果您的动画运行速度太慢,只需减少每秒的步数。

下面是一个例子:http://jsfiddle.net/dqJps/25/

希望这有助于。

+0

谢谢@Joel。我没有机会尝试这一点,因为我不知道如何将其全部应用于它(例如,使用动画函数,它随着时间逐渐改变属性)。我相应地更新了我的问题,感谢您的帮助。 – oli

+0

直到JavaScript代码停止执行(浏览器进入事件循环),重绘才会发生,因此在循环中调用3000'changeAttribute()'只会导致重绘。 – slebetman

+0

@slebetman - 我同意你的意见,但我的观点是,拉斐尔设置了3000个setIntervals。这些变化永远不会出现在循环中。当每个间隔完成时,浏览器检测到HTML更改并重新绘制页面(或页面的相关部分)。 – Joel