Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Smoothly animate attribute changes to ~3000 Raphael objects at once

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

like image 304
oli Avatar asked Nov 23 '11 08:11

oli


1 Answers

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:

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

And then you let d3 take it from there

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

Here is the jsfiddle: http://jsfiddle.net/mFecs/

like image 135
methodofaction Avatar answered Nov 15 '22 00:11

methodofaction