Search code examples
htmlhtml5-canvashtml5-animation

html5 canvas animation, rotating the text is not smooth enough


The idea is simple, create a star with text and rotate it.

But its not smooth after making a quick script here is my fiddle

The star is moving oke, but the text is shaking like a snake :)


Solution

  • Cause

    The reason why this happening is due to the browser's text rendering engine. They are translating each point in the text path using the same rotation matrix but due to the engine you will get rounding errors in there causing the text to "jibber".

    This is not only happening for canvas but for CSS transformations as well, with text.

    Solution

    Simply render the text to a canvas "layer" and use that as an image which you rotate instead of the text itself. This rasterizes the text in its normal position and the transformation happens on the bitmap instead which most browsers handle pretty well.

    Here is one example integrating the answer I linked to in the comments. I'm showing only the main text as it works as a comparer as well, before and after:

    // canvas layer
    var tcanvas = document.createElement('canvas'); //tcanvas must be in global scope
    var tctx = tcanvas.getContext('2d');
    
    tcanvas.width = canvas.width;
    tcanvas.height = canvas.height;
    
    tctx.translate(250, 250);
    tctx.fillStyle = "black";
    tctx.font = "bold 60px Arial";
    tctx.textAlign = 'center';
    tctx.fillText('€ 1215,34', 0, 0);
    

    Now the layer is ready and we can replace the text drawing methods with a single drawImage instead:

    c.drawImage(tcanvas, -x, -y);
    

    Result of this modification

    To draw the "extra" just move those lines down to the layer creation as well. Note that tcanvas in the example must be accessible globally.

    If the rotation speed of the text is not intentional just remove the second call to rotate you have there before rendering the text.

    Tip: instead of redrawing gradients and the star just render it once to another layer and rotate that as an image as well. This will be much more efficient. You could also avoid save/restore (which are relative costly) by just accumulating the step on rotate() itself and use setTransform to transform the matrix using absolute values.

    Ways to optimize memory usage: for text layer use a canvas size where the text fits in exact (don't use fixed values as text size may vary in size and position from browser to browser depending on the text rendering engine), same for star if you go with a layer for that as well.

    Hope this helps!