Poor performance - SVG animations

Ashmore11 picture Ashmore11 · Sep 2, 2015 · Viewed 10k times · Source

So I'm creating some animations for a client and I've been playing with two.js because I liked its SVG capabilities. Unfortunately I'm having issues with performance.

I'm plotting 100 circles on the screen. Each circle contains 6 further circles for a total of 700 circles being rendered on load.

The circles react to mouse movements on the x-axis and cascade slowly downwards on the y-axis.

Currently in Chrome its only running at around 32FPS. In Firefox it barely even works!

I've also tried two.js's webgl renderer but while there is a slight performance increase, the elements just don't look as good as SVG.

The source is here: https://github.com/ashmore11/verifyle/tree/develop

path to file: src/coffee/elements/dots

Let me know if there's any more info I can provide.

Answer

jonobr1 picture jonobr1 · Sep 4, 2015

What you've made is very beautiful!

Hmmm, so there are many factors as to why the performance isn't as stellar as you'd like.

  1. The size of the drawable area matters (i.e: the <svg /> or <canvas /> element). The bigger the area the more pixels to render.
  2. The amount of elements added to the DOM. Yes there are 100 dots, but each dot is comprised of many elements.
  3. Of those elements the amount of changes an element has on any given frame.
  4. Finally, of the elements changing how many operations (i.e: opacity, scale, translation, etc.)

These considerations compound in most computer generated imagery to affect real-time rendering. The goal is basically to reduce the load on any one of those dimensions and see if it's enough to give you the performance you're looking for. You're gonna have to get creative, but there are options. Here are a few things off the top of my head that you can do to try to speed things up:

  • Reducing the amount of shapes will make it run faster ^^
  • For something like this Two.Types.canvas might be fastest.
  • Instead of moving each dot split the translation into 2 or 3 groups and move them based on the container groups. Kind of like a foreground and background parallax.
  • If you're sticking with Two.Types.svg try animating only a handful of dots on any given frame. This way you're not doing entire traversal of the whole scene every frame and each dot isn't animating every frame.

Pseudo code for this might look like:

// ... some array : dots inferred ... //

var now = Date.now();
var index, length = 12;

two.bind('update', function() {
  for (var i = index; i < Math.min(index + 12, dots.length); i++) {
    var dot = dots[i];
    dot.scale = (Math.sin(now / 100) + 1) / 4 + 0.75;
  }
  index = (index + 12) % dots.length;
});
  • If none of these are giving you anything substantial you're looking for than I would highly recommend turning in each Dot into a texture and drawing those textures either directly through canvas2d or with WebGL and a library. Three.js will be able to render hundreds of thousands of these: http://threejs.org/examples/#webgl_particles_sprites You'll have to rethink a lot of how the texture itself is generated and how the opacity varies between the lines and of course it'll look slightly different as you described in your question. Bitmap is different from Vector >_<

Hope this helps!