4
\$\begingroup\$

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.

This answer mentioned using canvas:

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.

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

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.

Suggested reading:

  1. requestAnimationFrame for smart animating

  2. Cross Browser GPU Acceleration and requestAnimationFrame in Depth

\$\endgroup\$
1
\$\begingroup\$

Just some ideas, not sure or they are usefull

Personally I would go for a more 'EVENT' based solution. Instead of looping over all those elemnts everytime the mouse moves, iw ould simply trigger a 'mouse moved' event. then all elements listen to that event and randomly decide wether to change opacity or not.

Events it the way to go :p

Then for the animation, this could be done with css3. Instead of using the animate() function with different times, simply at random change the transition time (just an idea).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.