开发者

Speeding up call to draw one pixel (thousands of times) in canvas

I'm creating a "bubble generator" as a background effect that will run on a page. The generator works fine, but it slows down, a lot after a short while.

开发者_StackOverflow中文版demo: http://jsfiddle.net/Dud2q/

I set the demo to run at 1ms intervals so it's easy to see the slow-down when you re-launch the fiddle (especially if you make the result window large).

The issue is that I have thousands of calls to this code (one for each bubble):

ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x+1, y+1);
ctx.stroke();

Does anyone know of a quicker way to draw one pixel in canvas?

Also, if anyone wants to take a stab at making the bubbles more realistic, I wouldn't complain :)


Instead of drawing the bubbles one-by-one, how about drawing the at once? i.e. moving the ctx.beginPath() and ctx.stroke() out of the loop? It looks a lot faster on Firefox. :)

$.extend(Number.prototype, {
    times    : function(cb){ for(var i=0; i<this; i++){ cb(i); }},
    interval : function(cb){ return setInterval(cb, this); },
    timeout  : function(cb){ return setTimeout(cb, this); }
});

$(function(){
    var $canvas = $('<canvas></canvas>'),
            ctx = $canvas[0].getContext('2d'),
          $cont = $('#fish-bubbles'),
     generators = [],
        bubbles = [],
        w, h;

    $cont.append($canvas);
    $(window).bind('resize', onResize);
    onResize();

    5..times(createBubbleGenerator);
    1..interval(drawBubbles);

    function drawBubbles(){
        ctx.clearRect(0, 0, w, h);

        var newBubbles = [],
            x, y, i, j, m, imgData, offset;

        for(var i=0, l=generators.length; i<l; i++){
            for(var j=0, m=0|Math.random()*6; j<m; j++){
                newBubbles.push( 0|generators[i] + j );
            }
            generators[i] = Math.max(0, Math.min(w, generators[i] + Math.random()*10 - 5));
        }

        bubbles.unshift(newBubbles);

        for(i=0; i<bubbles.length; i++){
            y = h - i*2;

            if(y<0){
                bubbles.splice(i);
                break;
            }

            ctx.beginPath();

            for(j=0, m=bubbles[i].length; j<m; j++){
                x = 0|(bubbles[i][j] += Math.random() * 6 - 3);

                ctx.moveTo(x, y);
                ctx.lineTo(x+1, y+1);
            }

            ctx.stroke();
        }
    }

    function createBubbleGenerator(){
        generators.push(0|Math.random() * w);
    }

    function onResize(){
        w = $cont.width();
        h = $cont.height();

        $canvas.attr('width', w).attr('height', h);
        ctx.strokeStyle = '#AAA';
    }
});

It does slow down when there are more bubbles however.


I'm guessing you will need to investigate the getImageData and the setImageData methods. The image data that is returned is writable down to the pixel level. I would imagine you could fill the canvas with black, call getImageData on it, update the pixel data returned with the next "frame" of bubbles, and write it back to the canvas with setImageData. Repeat the last two steps ad infinitum, ad nauseam.

See here for further details.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜