# Animating opacity of 1400 Raphael.js objects hurts animating performance

I am animating 1400 objects trying to create a 'twinkling effect'. As the user moves the mouse faster more hexagon shapes pop into full opacity and have varying fade out rates. The version in the fiddle fills the space with enough color but feels jerky and clumpy. If I lessen the fade_time variable amounts it is smoother but does not have enough hexagons with full opacity. The end goal is to spell words with the hexagons.

JSFiddle code

Here's the JS if you don't want to go over to jsfiddle:

function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function shuffle(array) {
var tmp, current, top = array.length;

if(top){
while(--top) {
current = Math.floor(Math.random() * (top + 1));
tmp = array[current];
array[current] = array[top];
array[top] = tmp;
}
}

return array;
}

Raphael.el.animate_hex = function() {
var fade_time = [1000, 2000, 3000, 4000];
//var fade_time = [3000, 4000, 5000, 6000];
this.attr({"fill-opacity": 1});
this.animate({"fill-opacity": 0}, fade_time[getRandomInt(0, 4)], 'linear', function(){
});
};
//set paper to width and height of container
var container_width = document.getElementById('wrap').offsetWidth;
var container_height = document.getElementById('wrap').offsetHeight;
var paper = Raphael(document.getElementById('wrap'), container_width, container_height);

//create and position hexagon shapes.
var set = paper.set();
var abs_x = 0;
var abs_y = 0;
var total_hex = 1400;
for(h=0;h<total_hex;h++){
var HexM = [7.478, 8.66];
var HexL = [[7.478, 8.66], [2.542, 8.66], [0.05, 4.32], [2.542, 0.028], [7.478, 0.028], [9.97, 4.32], [7.478, 8.66]];
var hex = paper.path('M ' + HexM[0] + ' ' + HexM[1] + ' L ' + HexL[0][0] + ' ' + HexL[0][2] + ' L ' + HexL[1][0] + ' ' + HexL[1][3] + ' L ' + HexL[2][0] + ' ' + HexL[2][4] + ' L ' + HexL[3][0] + ' ' + HexL[3][5] + ' L ' + HexL[4][0] + ' ' + HexL[4][6] + ' L ' + HexL[5][0] + ' ' + HexL[5][7] + ' L ' + HexL[6][0] + ' ' + HexL[6][8]).attr({'fill':'#ec2b26','stroke-width':'0' ,'fill-opacity': 0 });
if(abs_x * 10 == container_width){ abs_y = abs_y + 10; abs_x = 0;}
hex.transform('...T' + 10 * abs_x + ',' + abs_y ).attr('id','hex' + h);
set.push(hex);
abs_x++;

}

//create an object to tie the mousemove event to (paper was only working with onmouseover)
var hover_span = paper.rect(0,0, container_width, container_height).attr({'opacity': '0', 'id': 'cover', 'fill': '#000000'});

newx = 0;
newy  = 0;
beginx = 0;
beginy = 0;
//compare new and old cursor coordinates to get an idea of how far the cursor has moved.
hover_span.mousemove(function(e) {
newx = beginx;
newy = beginy;
beginx = e.pageX;
beginy = e.pageY;

var animate_count = 0;
animate_count = Math.sqrt((newx * beginx) + (newy * beginy)) / 1;
//animate an amount based on cursor movement.  The division in the line above helps lessen or increase the amount of hexagons animated in a call of mousemove.
for(i=0; i<animate_count; i++){
var rdm_index = getRandomInt(0, 1400);
set[rdm_index].animate_hex();
}
});​


The performance in Chrome is best, less so in FireFox and IE. I tested (using Raphael's element.touchmove) in mobile safari on an iPad and it was even worse.

I'm looking for any advice on what pieces of the code could be done differently for performance gains.

I saw this answer somebody else gave that was supposed to help with performance, but I'm trying to base the amount of animating hexagons on cursor movement and I'm not sure I could do that with a timer.

A good alternative would be using Canvas to draw the elements. From my experiments it will be faster than SVG at drawing this many although if you are using some animations, they will be harder to implement than with the RaphaelJS library.

Does that seem like a better route to people, even with the animations the code is using?

This is my first use of Raphael.js. I'm not very experienced in JS in general, so any help is wunderbar!

Edit: Also, seeing this answer about .resize being called more times than the questioner might have thought got me wondering if the .mousemove function may be called more times (more than I would need) than I would expect.

-

You are most certainly using a wrong tool for the job. <canvas> element and requestAnimationFrame() are your friends.

Also, I'd expect opacity animation to tax the graphics stack heavily (unless GPU accelerated, perhaps.) If the background color is going to be white, animating the fill color should work better.