Lev
Lev

Reputation: 760

Text position on canvas is different in FireFox and Chrome

I need to draw a text string at a precise position on HTML5 canvas.

Here's my test code:

<!DOCTYPE html>
<html>
<body>
<canvas id="mainCanvas" width="320" height="240" style = "border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
   window.onload = function() {
      var canvas = document.getElementById("mainCanvas");
      var ctx = canvas.getContext("2d");      
      ctx.textBaseline = "top";
      ctx.font = '100px Arial';
      ctx.textAlign = 'left';
      ctx.fillStyle = 'rgba(0, 0, 0, 255)';
      ctx.fillText('Test', 0, 0);
   }
</script>
</body>
</html>

The margin at the top is different in Chrome and Firefox: Text in Chrome vs Firefox

I'm going to draw other elements (e.g. images, shapes) on the canvas, and I need to make sure the text appears at the same position in all browsers. Is it possible?

Upvotes: 7

Views: 4605

Answers (4)

peyman azizi
peyman azizi

Reputation: 43

You can fix it easily.

you can use textBaseline = "middle"; and must use transform to 50px of top

means:

    <canvas id="mainCanvas" width="320" height="240" style = "border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
    </canvas>
    <script>
    window.onload = function() {
          var canvas = document.getElementById("mainCanvas");
          var ctx = canvas.getContext("2d");      
          ctx.textBaseline = "middle";
          ctx.font = '100px Arial';
          ctx.textAlign = 'left';
          ctx.fillStyle = 'rgba(0, 0, 0, 1)';
          ctx.save();
          ctx.transform(1, 0, 0, 1, 0, 50);
          ctx.fillText('Test', 0, 0);
          ctx.restore();
       }
    </script>

A another bug is in your code: rgba(0, 0, 0, 255) fourth number in rgba must be between 0-1 for example 0.75.

why I write .save() and .restore() ? for reset transform and clear after use it.

Of course you can use

ctx.fillText('Test', 0, 50);

Instead

ctx.save();
ctx.transform(1, 0, 0, 1, 0, 50);
ctx.fillText('Test', 0, 0);
ctx.restore();

Upvotes: 3

miguel-svq
miguel-svq

Reputation: 2176

As stated in other answer it's some king of bug (or maybe just a different implementation). textBaseline bottom and Y position to 100 can fix it.

<canvas id="mainCanvas" width="320" height="240" style = "border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
   window.onload = function() {
      var canvas = document.getElementById("mainCanvas");
      var ctx = canvas.getContext("2d");      
      ctx.textBaseline = "bottom";
      ctx.font = '100px Arial';
      ctx.textAlign = 'left';
      ctx.fillStyle = 'rgba(150, 50, 0, 1)';
      ctx.fillText('Test', 0, 100);
   }
</script>

In general: Use baseline bottom and increase Y position the font size amount

Upvotes: 2

markE
markE

Reputation: 105015

Cause

As @iftah says: This mis-alignment is caused by a Firefox bug.

Please add your voice to the Firefox's bug page so they fix it soon.

Workaround

(Unfortunately), The workaround is to draw the text on a second canvas and scan that pixel data to find the topmost & leftmost pixel of the text.

Then draw the text on the main canvas but pulled upward and leftward by the calculated pixel offsets.

Here is annotated code and a Demo:

// canvas vars
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

// test vars
var text='Test';
var fontsize=100;
var fontface='arial';

drawTextAtXY(0,0,text,fontsize,fontface,'black');

function drawTextAtXY(x,y,text,fontsize,fontface,fill){
    // find the leftmost & topmost pixel of the text
    var minXY=getTextTop(text,fontsize,fontface);
    // set the font styles
    ctx.textBaseline='top';
    ctx.font=fontsize+'px '+fontface;
    ctx.fillStyle=fill;
    // draw the text
    // Pull the text leftward and topward by minX & minY
    ctx.fillText(text,x-minXY.x,y-minXY.y);
}


function getTextTop(text,fontsize,fontface){
    // create temp working canvas
    var c=document.createElement('canvas');
    var w=canvas.width;
    var h=fontsize*2;
    c.width=w;
    c.height=h;
    var cctx=c.getContext('2d');
    // set font styles
    cctx.textBaseline='top';
    cctx.font=fontsize+'px '+fontface;
    cctx.fillStyle='red';
    // draw the text
    cctx.fillText(text,0,0);
    // get pixel data
    var imgdata=cctx.getImageData(0,0,w,h);
    var d=imgdata.data;
    // scan pixel data for minX,minY
    var minX=10000000;
    var minY=minX;
    for(var y=0;y<h;y++){
    for(var x=0;x<w;x++){
        var n=(y*w+x)*4
        if(d[n+3]>0){
            if(y<minY){minY=y;}
            if(x<minX){minX=x;}
        }
    }}
    // return the leftmost & topmost pixel of the text
    return({x:minX,y:minY});
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<h4>Text drawn exactly at specified X,Y</h4>
<canvas id="canvas" width=300 height=200></canvas>

Upvotes: 11

Iftah
Iftah

Reputation: 9572

This appears to be a bug in Firefox dating back to 2012 and still not fixed!

See https://bugzilla.mozilla.org/show_bug.cgi?id=737852

Edit: Setting the baseLine to "alphabetic" (the default) results in both Chrome and Firefox having the same vertical location for the text.

Edit: Unfortunately, the vertical location isn't the only difference between Firefox and Chrome. Changing the string to "Testing" shows clearly that not only is the vertical location different, but also the space between the letters is slightly different - resulting in different width of the text.

If you really must have pixel perfect location AND size of the text maybe you should use Bitmap fonts

Upvotes: 2

Related Questions