Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 430
Lev Avatar asked Mar 11 '16 03:03

Lev


1 Answers

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>
like image 84
markE Avatar answered Sep 26 '22 20:09

markE