mozilla
Your Search Results

    Optimizing canvas

    The <canvas> element is one of the most widely used standards for rendering 2D graphics on the Web. It is used widely in games and complex visualizations. However, as Web sites and apps push canvas to the limits, performance begins to suffer. This article aims to provide suggestions for optimizing your use of the canvas element, to ensure that your Web site or app performs well.

    Performance tips

    The following is a collection of tips to improve performance

    Pre-render similar primitives or repeating objects on an off-screen canvas

    If you find yourself with complex drawing operations on each frame, consider creating an offscreen canvas, draw to it once (or whenever it changes) on the offscreen canvas, then on each frame draw the offscreen canvas.

    myEntity.offscreenCanvas = document.createElement(“canvas”);
    myEntity.offscreenCanvas.width = myEntity.width;
    myEntity.offscreenCanvas.height = myEntity.height;
    myEntity.offscreenContext = myEntity.offscreenCanvas.getContext(“2d”);
    
    myEntity.render(myEntity.offscreenContext);
    

    Avoid floating-point coordinates and use integers instead

    Sub-pixel rendering occurs when you render objects on a canvas without whole values.

    ctx.drawImage(myImage, 0.3, 0.5);
    

    This causes the browser to do extra calculations to create the anti-aliasing effect. To avoid this, make sure to round all co-ordinates used in calls to drawImage() using Math.floor(), for example.

    Don’t scale images in drawImage

    Cache various sizes of your images on an offscreen canvas when loading as opposed to constantly scaling them in drawImage().

    Use multiple layered canvases for complex scenes.

    You may find you have some elements that are frequently changing and moving around whereas other things (like UI) never change. An optimization in this situation is to create layers using multiple canvas elements.

    For example you could create a UI layer that sits on top of everything and is only drawn during user input. You could create game layer where the frequently updating entities exist and a background layer for entities that rarely update.

    <div id="stage">
      <canvas id="ui-layer" width="480" height="320"></canvas>
      <canvas id="game-layer" width="480" height="320"></canvas>
      <canvas id="background-layer" width="480" height="320"></canvas>
    </div>
     
    <style>
      #stage {
        width: 480px;
        height: 320px;
        position: relative;
        border: 2px solid black
      }
      canvas { position: absolute; }
      #ui-layer { z-index: 3 }
      #game-layer { z-index: 2 }
      #background-layer { z-index: 1 }
    </style>
    

    CSS for large background images

    If like most games you have a static background image, use a plain <div> element with a CSS background property and position it under the canvas. This will avoid drawing a large image to the canvas on every tick.

    Scaling canvas using CSS transforms

    CSS transforms are faster by using the GPU. Best case is to not scale the canvas or have a smaller canvas and scale up rather than a bigger canvas and scale down. For Firefox OS, target 480 x 320 px.

    var scaleX = canvas.width / window.innerWidth;
    var scaleY = canvas.height / window.innerHeight;
    
    var scaleToFit = Math.min(scaleX, scaleY);
    var scaleToCover = Math.max(scaleX, scaleY);
    
    stage.style.transformOrigin = "0 0"; //scale from top left
    stage.style.transform = "scale(" + scaleToFit + ")";
    

    Use the moz-opaque attribute (Gecko only)

    If your game uses canvas and doesn’t need to be transparent, set the moz-opaque attribute on the canvas tag. This information can be used internally to optimize rendering.

    <canvas id="mycanvas" moz-opaque></canvas>

    More tips

    • Batch canvas calls together (for example, draw a poly-line instead of multiple separate lines).
    • Avoid unnecessary canvas state changes.
    • Render screen differences only, not the whole new state.
    • Avoid the shadowBlur property whenever possible.
    • Avoid text rendering whenever possible.
    • Try different ways to clear the canvas (clearRect() vs. fillRect() vs. resizing the canvas)
    • With animations, use window.requestAnimationFrame() instead of window.setInterval() .
    • Be careful with heavy physics libraries
    • Test performance with JSPerf.

    See also

    Document Tags and Contributors

    Contributors to this page: Sheppy, trevorh, fscholz, Jeremie
    Last updated by: fscholz,