Why does chrome struggle to display lots of images on a canvas when the other browsers don't?

前端 未结 2 1592
栀梦
栀梦 2021-02-13 13:09

We\'re working with the HTML5 canvas, displaying lots of images at one time.

This is working pretty well but recently we\'ve had a problem with chrome.

When draw

相关标签:
2条回答
  • 2021-02-13 13:35

    This was a legitimate bug in chrome.

    https://code.google.com/p/chromium/issues/detail?id=247912

    It has now been fixed and should be in a chrome mainline release soon.

    0 讨论(0)
  • 2021-02-13 13:50

    In Canary this code freezes it on my computer. As to why this happens in Chrome the simple answer is that it uses a different implementation than f.ex. FF. In-depth detail I don't know, but there is obviously room for optimizing the implementation in this area.

    I can give some tip however on how you can optimize the given code to make it run in Chrome as well :-)

    There are several things here:

    • You are storing each block of colors as images. This seem to have a huge performance impact on Canary / Chrome.
    • You are calling requestAnimationFrame at the beginning of the loop
    • You are clearing and rendering even if there are no changes

    Try to (addressing the points):

    • If you only need solid blocks of colors, draw them directly using fillRect() instead and keep the color indexes in an array (instead of images). Even if you draw them to an off-screen canvas you will only have to do one draw to main canvas instead of multiple image draw operations.
    • Move requestAnimationFrame to the end of the code block to avoid stacking.
    • Use dirty flag to prevent unnecessary rendering:

    I modified the code a bit - I modified it to use solid colors to demonstrate where the performance impact is in Chrome / Canary.

    I set a dirty flag in global scope as true (to render the initial scene) which is set to true each time the mouse move occur:

    //global
    var isDirty = true;
    
    //mouse move handler
    var handleMouseMove = function (eventArgs) {
    
        // other code
    
        isDirty = true;
    
        // other code
    };
    
    //render loop
    function renderLoop() {
        if (isDirty) {
            clearCanvas();
            renderCanvas();
        }
        stats.update();
        requestAnimFrame(renderLoop);
    }
    
    //in renderCanvas at the end:
    function renderCanvas() {
        // other code
        isDirty = false;
    }
    

    You will of course need to check for caveats for the isDirty flag elsewhere and also introduce more criteria if it's cleared at the wrong moment. I would store the old position of the mouse and only (in the mouse move) if it changed set the dirty flag - I didn't modify this part though.

    As you can see you will be able to run this in Chrome and in FF at a higher FPS.

    I also assume (I didn't test) that you can optimize the clearCanvas() function by only drawing the padding/gaps instead of clearing the whole canvas. But that need to be tested.

    Added a CSS-rule to prevent the canvas to be selected when using the mouse:

    For further optimizing in cases such as this, which is event driven, you don't actually need an animation loop at all. You can just call the redraw when the coords or mouse-wheel changes.

    Modification:
    http://jsfiddle.net/BtyL6/10/

    0 讨论(0)
提交回复
热议问题