Question

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 :)

Was it helpful?

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!

OTHER TIPS

The shake in your text comes from the fact that the context is not in a proper state when you draw the text : you just did quite some operations on it before.

I just added a

c.restore();
c.save();
c.translate(x,y);

before the text part of your code, and the text is solidly hung to the star now :

http://jsfiddle.net/gamealchemist/xUr4f/1/

Edit : There are in fact 2 issues at stake here : 1) the text rotation is not quite on track with the star and 2) the rounding of the text coordinates makes the text shake.

Both Chrome and FF exhibit 1) of course, and with a clean context 1) disappear on both.

For 2) : Chrome is ok with non-integer coordinates text, but FF does round, which creates a shake on a rotating text.

Only solution i see it to 'print' the text on a canvas, then have the canvas rotate. I did it for the 'extra' in this fiddle : http://jsfiddle.net/xUr4f/4/ There's a loss of quality compared to the fillText, but unless the coordinates rounding can be avoided, it seems as the best solution.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top