DmitryBaranovskiy / raphael

JavaScript Vector Library
https://dmitrybaranovskiy.github.io/raphael/
MIT License
11.27k stars 1.67k forks source link

[2.0] Degraded animation performance with multiple objects along long paths #388

Open ghost opened 13 years ago

ghost commented 13 years ago

I have to animate some objects (with same little shape like circle or ellipse) along the same path at the same moment. The path is long about 1300 px and is generated with Catmull-Rom and the number of elements is near 20. At the start the elements run really smooth, but step by step the fps-animation decrease until 1-2.. This it seems caused by a growing memory consumed in every browser ( Firefox 6, Opera 11.5, Chrome 13, IE 8/9...).

I have used both the customAttribute example method I found to use the "along" attribute for animation. Other attempts were toggle styles, change shape of elements, not to rotate elements using only translate.

I think is a bug or there are some optimization to do, because at the animation start all is fine and smooth, so it is not dependent by hardware/browser of the client ( I have tested in 3 different PCs ).

ghost commented 13 years ago

The problem is caused by the way to re-implement the "along" animation, as I see in both example. Every frame call getPointAtLength, but this function take longer time to execution as the path is long. That's caused by getLengthFactory and in particular by "for (var i = 0, ii = path.length; i < ii; i++) {" loop (I think). getPointAtLength is usefull to discover point coordinates in a path, but it can't be used in an animation. I guess a dedicated function like the old "animateAlong" or dedicated attributes or a better way to do that.

Here a workaround:

  1. When page open I do a simple "for" loop to get all the coordinates step-by-step in the path positions = new Array(); for ( len = 0; len <= totalLength; len++ ) { positions.push( path.getPointAtLength(len) ); }
  2. Now I create a custom attribute (note the Math.round): paper.customAttributes.distance = function (value) { var p = positions[ Math.round(value) ]; return { cx: p.x, cy: p.y, transform: "r"+p.alpha }; };
  3. Then I start animation with the distance to run along the path: myObject.animate( {distance: myDistanceOnPath}, ms );

OK, now the animation is a little less smooth than before, but I can animate as many object I want on the same long path without any big performance problem. And yes, the time to open the page is too much, but the solution is to pre-calculate the coordinates of the path and store them in a JSON file, for example. Obviously if the path not change at every page reload.

dalyons commented 13 years ago

I can confirm this one quite easily.

use animateAlong to move a small png along a ~1000px long path, works fine.

however, doing more than one of these at the same time results in severe performance degradation. I suspect as Fizzolo said, the path calculation algorithm is not very efficient when called repetitively(from animate).