I benchmarked offsetWidth() vs measureText and I am getting drastically different values. Shouldn't they be the same? Why are they different?
Here is the jsfiddle and raw code below: http://jsfiddle.net/WhGk7/2/
<canvas id="myCanvas" width="300" height="200" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<span id="visibilityHack" style="visibility: hidden; font: 15px Arial;">textAlign=start</span>
<div id="results"></div>
<script>
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
// Create a red line in position 150
ctx.strokeStyle="red";
ctx.moveTo(150,20);
ctx.lineTo(150,170);
ctx.stroke();
var measureTextWidth = ctx.measureText("textAlign=start").width;
var measureTextNode = document.createTextNode("measureTextWidth: " + measureTextWidth);
document.getElementById("results").appendChild(measureTextNode);
var swidth = document.getElementById("visibilityHack").offsetWidth;
var textnode = document.createTextNode(" offsetWidth: " + swidth);
document.getElementById("results").appendChild(textnode);
ctx.font="15px Arial";
// Show the different textAlign values
ctx.textAlign="start";
ctx.fillText("textAlign=start",117,60);
ctx.textAlign="center";
ctx.fillText("textAlign=start",150,120);
</script>
The support for context.measureText is very bad in most browsers. But there is a hack which allows you to get a much better measurement of text. Create a
<div>
node in your HTML document withvisibility: hidden
(so it isn't rendered) but notdisplay: none
(so it takes up space). Then set its style to the same style you want to use forcontext.fillText
(remember that when you use an external font, that font must be fully loaded to get an accurate measurement), put your text into the div, and check the div's.width
It seems that both measureText and "DOM element method" still do not return real text width. But context2d.measureText and "OM element method" return very similar values :) Let's try to measure width of text consisting of single character 'y' and printed with 'italic 90px arial'. You can try it on JSFiddle - i modified the Domi's code http://jsfiddle.net/White_Falkon/a23z6ryL/2/
You'll see, that part of 'y' on the right is outside the 'width rectangle'. Another case, when these measuring methods are incorrect is 'y' printed with 'italic 90px times new roman' - the left part of y is outside of width rectangle. You can try it on the same JSFiddle.
Unfortunately, i don't know if there is a way to measure full width of string.
Canvas support was less accurate in the past.
As of November 2014, most browsers seem to work just fine. Tested Chrome, IE and Firefox. Also note that most browsers'
Canvas.measureText
functions even yield results with sub-pixel accuracy. See this fiddle for reference.To save you the trouble of writing your own, you might want to use an existing string-measuring function.
You need to set the font on the canvas context before you do measureText, otherwise you will get whatever the default font style is on the context. You already set the font family and size on the hack div and that is why it is giving you the correct value.
What I did observe though is that Chrome 34 and Firefox 28 both returned 92 for the width, but IE10 returned 95, Grrr.