anime icon indicating copy to clipboard operation
anime copied to clipboard

anime.path could be more efficient in its use of svgData

Open FrankReh opened this issue 5 years ago • 1 comments

Describe the bug Not a bug so much as a few performance improvements possible but perhaps they violate the spirit of keeping the code minimal and easy to read. Anyway, conserving cpu and battery power is becoming more important so wanted to put this out there and when there are a dozen or more active svg elements being tracked, one can actually see the difference because it affects the frame rate and garbage collection.

The svgData is used for calculating the x, y and angle values for an element at each tick. But the svgData itself only needs to be rebuilt when the window viewport or the parent's viewBox have changed. And each of the three properties does not need to track its own svgData.

To Reproduce Steps to reproduce the behavior:

  1. Go to the excellent anime documentation page.
  2. Click on the SVG 'Motion Path' example.
  3. If you want to actually see the difference, change the number of el elements for this example from one to twenty, and add a delay.
      <div class="small square el follow-path"></div>
      <div class="small square el follow-path"></div>
      ... twenty of these ...
      <div class="small square el follow-path"></div>
      <div class="small square el follow-path"></div>

...
  delay: function(el, i) { return i * 40 },

Expected behavior Visually, everything is fine for the standard example - the performance penalty when there is a single element being tracked is only marginally noticeable in an inspector timeline. Presumably the difference in cpu and memory usage is noise when compared to the frame refresh when there is a single element being tracked. But the difference becomes obvious when more elements are tracked.

I would expect the svg rectangle object (aka svgData, aka path.svg) to be computed once for all three properties, 'x', 'y' and 'angle' and just once for the call to anime.path() for that matter, and then only recomputed if the viewport or scroll position changed or the viewBox being used has been changed within the DOM.

But three svg dimension objects are created right off the bat, and then for each tick, a new object is created and used once in each one's place when computing pathProgress. Only recomputing the parent svg element is effectively cached away.

The function getPath computes a path.svg object for each call to the returned function, so the documentation example starts off with three copies of the same svgData. By making it one that is shared for the three properties (by building it outside the closure), the progress counter can be later used to make the calls just once per tick to the DOM getBoundingClientRect and the getAttribute for attribute viewBox.

Of equal importance. Function getPathProgress, which is typically called three times for the same progress tick per element, causes a new svgData object to be built each time, even when nothing about the viewport or the viewBox has changed from tick to tick.

So there are more calls to the DOM and more temporary objects created.

Using the same svg object for these two cases makes for less work and cleaner caches. And the performance difference is noticeable when there are many elements being tracked.

When I changed the example as described above so there were twenty elements being drawn on the path each tick, 90% or more of the work was saved on my desktop Safari and mobile Safari (as measured by the inspector's timeline) - the Animation Frame took 1/10th the time to process. The amount saved is obviously dependent on the number of elements being tracked so in most practical cases the savings won't be so significant.

I don't know where a design choice like this would have been mentioned. Searching through the git logs I didn't see it being called out.

Also, this doesn't affect the issues with responsive paths or how svg elements should be created in the html hierarchy. Those issues are made no better and no worse with these two proposals. I can offer a pull request if this is of interest.

On a related note, if the svgData were to be cached in the parent element itself - maybe using a Symbol, distinct paths with the same parent would also benefit from the cached data.

FrankReh avatar Jan 10 '20 19:01 FrankReh

Hi @FrankReh - again a great issue thanks for taking the time to look into this. I'll add it to the list of upcoming enhancements. Until then If you have time to make a PR I can get around to it faster!

kn0wn avatar Mar 15 '20 18:03 kn0wn

Closing given the complete v4 rewrite.

FrankReh avatar Sep 17 '25 12:09 FrankReh