一次平滑地对约 3000 个 Raphael 对象进行属性更改动画
更新的问题 我已将其更新为更加简洁..:
在这个小提琴中: http://jsfiddle.net/ pX2Xb/4/ 我有一些 raphael 代码,可以在页面上绘制 3000 个圆圈。然后,它会尝试在 10 秒内一次为所有圆圈设置动画(更改填充颜色),这会导致视觉动画显得笨拙。将圆圈数更改为 20,可以看到更流畅的动画进行比较。
我的问题是 (a) 我是否可以使 3000 个元素的更新更加平滑,(b) 如果可以,执行此操作的代码是什么样的?
一些注意事项:
- 如果有某种方法可以优化此问题,我愿意在时间上稍作调整,但是,例如,我希望所有圆圈至少更新 1.5 倍,无论动画如何时间设置为。因此,如果动画为 10 秒,则所有圆圈应该在 15 秒内发生变化。
- 目前,3000 个元素大致是我的极限,所以我会很高兴它能实现这一点:) 话虽如此,如果解决方案可以有效地处理更多元素相比之下,对于一般情况来说,那就太好了。
较旧的详细信息,以防有帮助
我正在创建一张美国县的大型地图,其中有 3000 多个县;我正在使用 此 Wikipedia svg 文件 获取相关的 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 毫秒的延迟)。超过 3000 个项目,这会变得相当慢,并且仍然使用大量 CPU。
谢谢, 奥利
UPDATED QUESTION
I've updated this to be a little more succinct..:
In this fiddle: http://jsfiddle.net/pX2Xb/4/ I have some raphael code that draws 3000 circles to a page. It then attempts to animate all circles at once (changes fill colour) over 10 seconds, which results in a clunky visual animation. Change the number of circles to 20 to see a much smoother animation for comparison.
My questions are (a) is it possible for me to make the update to the 3000 elements smoother and (b) if so, what does the code to do that look like?
Some notes:
- I'm willing to take a small timing hit if there's some way to optimise around this, but, for example, I would like all circles to at least have updated in 1.5x whatever the animation time is set to. So, if animation is 10 seconds, all circles should have changed in 15.
- 3000 elements is roughly my limit at the moment, so I'd be happy with it working for that :) In saying that, if a solution can effectively handle more than that, for a general case, that'd be really great.
older details, in case it helps
I'm creating a large map of US counties, of which there are over 3000; I'm using this Wikipedia svg file to get the relevant SVG paths to create the map, and am rendering the map using RaphaelJs.
Accordingly, I end up with over 3000 statements similar to the following:
var cc_02130 = rsr.path("M 140.66674,.... 320.11635"); // county path
cc_02130.attr({id: '02130',.. .."marker-start": 'none'}); // init attrs
I'm also creating a Paper.set()
object to hold all of these elements:
var myset = paper.set([cc_56039, cc_56040, cc_56041 ...])
Forgetting for a moment that the file actually generated here is quite large, I would very much appreciate suggestions of how I can apply changes to the volume of objects detailed above, that is both quick and reasonably ok CPU wise (possible a big ask).
I'm definitely open to changing the structure of my code/objects, as long as I can individually change attributes of specific counties.
For example, I would like to be able to apply a different colour to each path content in a second or two (for all 3000+).
The challenge I'm facing is not how to apply the colour changes, animations, etc, but how to do this quickly and efficiently. Right now, my machine screams at me if I loop and apply changes over the 3000+ objects; as an alternative, I was using setTimeout
to break the changes out into smaller chunks (maybe 10 at a go, with a 40 ms delay). Over 3000 items, this becomes quite slow, and still uses a lot of CPU.
Thanks,
oli
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
所有路径都是你手动写的吗?我认为如果将所有路径放在一个对象中会更好。然后,您可以迭代该对象并使用例如
for in
绘制所有路径。在此过程中,您可以使用element.id = 'name'
为每个路径提供内部 ID。获得所有内部 ID 和绘制的路径后,您可以使用 getById 方法:getById('pathId')
如果您打算使用 Sets,我建议您使用 Clousures,您可以首先声明变量,然后将路径推入另一个循环中
然后,如果您想将某些属性应用于元素,则可以使用诸如 Paper.forEach() 之类的方法。或者
Set.FotEach()
。两者都采用回调函数(如参数),然后在每次迭代中执行该函数。如果您想分享您的代码,对我来说检查它并就如何解决某些情况提出我的意见不会有问题。我也在使用地图,我正在开发一个教育视频游戏,如果您愿意,我也可以与您分享我的代码,没有太多关于拉斐尔的文档,所以对我来说了解如何是有用的你使用它,也许对你来说也是一样。
再见!
Did you write all the paths manually? I think is better if you put all the paths in an object. Then you can iterate the object and draw all the paths using, for example,
for in
. In that process you can give an internal ID to every path usingelement.id = 'name'
. Once you have all the internal ID´s and the paths drawed, you can use the getById method:getById('pathId')
If you are going to use Sets I recommend you to use Clousures, you can first declare the variablesand then push the paths in another loop
Then you have methods like
Paper.forEach()
if you want to apply some attributes to the elements. OrSet.FotEach()
. Both take a callback function like argument, and then executes that function in each iteration.If you want to share your code it wouldn´t be a problem for me to check it out and give my opinion on how to solve some of the situations. I´m also working with maps, I´m developing an Educative Video Game, if you want I can also share my code with you, there aren´t that much documentation about Raphael, so it would be useful for me to see how are you using it and maybe the same for you.
Bye!
老实说,更改 3000 个项目的属性对于任何计算机来说都应该很容易。
Raphael 对每个动画元素使用 setInterval。元素的属性更改后,浏览器将重新绘制整个页面。这是 2999 次不必要的重新绘制。这是我要做的:不使用 Raphael 动画,而是使用循环来更改每个元素。它稍微复杂一点,但速度更快。此外,您还可以更改每秒的步数。如果您的动画运行速度太慢,只需减少每秒的步数即可。
这是一个示例: http://jsfiddle.net/dqJps/25/
希望这会有所帮助。
To be honest, changing the attributes of 3000 items should be easy for any computer.
Raphael uses a setInterval for each animated element. After the element's attribute is changed, the browser re-draws the entire page. This is 2999 un-necessary re-draws.Here is what I would do: Instead of using the Raphael animation, use a loop to change each element. It is a little more complex, but it is faster. In addition, you can change the steps per second. If your animation is running too slow, just reduce the steps per second.
Here is an example: http://jsfiddle.net/dqJps/25/
Hope this helps.
我不知道为什么,但是 D3.js 在一次为大量元素设置动画时效率更高。您可以通过创建一个 Raphael 函数来使它们无缝工作,该函数接收一组并返回您想要设置动画的 html 对象:
然后让 d3 从那里获取它
这是 jsfiddle: http://jsfiddle.net/mFecs/
I don't know why, but D3.js is more efficient when animating a large number of elements at once. You can make them both work seamlessly by creating a Raphael function that receives a set and returns the html objects you want to animate:
And then you let d3 take it from there
Here is the jsfiddle: http://jsfiddle.net/mFecs/
由于我目前对 Rapael.js 不太熟悉,我只是建议,以通用 JavaScript 方式,您可以创建一个changeRaphaelPathAttributeEvent,每次您想要更改路径时都会发出该事件,该属性作为所述事件的参数而变化。然后,如果可能的话,将事件处理程序附加到将执行属性更改的每个路径。
这样,您就可以解决循环访问所有路径变量并同步更改属性的问题(这将直接影响页面在处理时的响应能力);该方法对用户体验的性能影响较小。
注意:这只是解决立即性能影响的解决方案。也许还有其他解决方案可以最大限度地减少需要访问的对象数量,您也应该考虑这些解决方案(我无法告诉您,因为我不太了解 Raphael)。
As I'm not currently that familiar with Rapael.js, I'd just suggest, in a generic JavaScript manner, that you could maybe create an changeRaphaelPathAttributeEvent, that you'd emit each time you'd like to change the paths, with the attribute changes as arguments to said event. And then attach event handlers to each of the paths that would carry out the attribute change, if that's possible.
That way, you would get around the problem of having a loop access all the paths variables and change the attributes synchronously (which would directly affect the page's responsiveness while processing); the method would have a lower impact on the performance that the user experiences.
Note: This is just a solution to get around the immediate performance hit. Maybe there are other solutions available of minimizing the amount of objects needed to access, that you should also consider (and that I'm not capable of telling you, as I don't know Raphael that well).