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/
/**
* Uses canvas.measureText to compute and return the width of the given text of given font in pixels.
*
* @param text The text to be rendered.
* @param {String} font The css font descriptor that text is to be rendered with (e.g. "14px verdana").
*
* @see http://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
*/
function getTextWidth(text, font) {
// if given, use cached canvas for better performance
// else, create new canvas
var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.getElementById("myCanvas"));
var context = canvas.getContext("2d");
var oldFont = context.font;
context.font = font;
var metrics = context.measureText(text);
context.font = oldFont;
return metrics.width;
};
function getTextWidthDOM(text, font) {
var f = font || '12px arial',
o = $('<span>' + text + '</span>')
.css({'font': f, 'float': 'left', 'white-space': 'nowrap'})
//.css({'visibility': 'hidden'})
.appendTo($('body')),
w = o.width();
o.remove();
return w;
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.clearRect ( 0 , 0 , canvas.width, canvas.height );
var x = canvas.width / 2;
var y = canvas.height / 2 - 100;
var text = 'y';
var font = 'italic 90px Arial';
context.font = font;
context.fillStyle = 'blue';
context.fillText(text, x, y);
// get text metrics
var widthUsingDOM = getTextWidthDOM(text, font);
var widthUsingMeasureText = getTextWidth(text, font);
context.font = '20pt Calibri';
context.textAlign = 'center';
context.fillStyle = 'red';
context.fillText('(' + widthUsingDOM + 'px wide using DOM)', x, y + 100);
context.fillStyle = 'green';
context.fillText('(' + widthUsingMeasureText + 'px wide using measureText)', x, y + 150);
context.beginPath();
context.rect(x, y-75, widthUsingDOM, 125);
context.lineWidth = 1;
context.strokeStyle = 'red';
context.stroke();
context.beginPath();
context.rect(x, y-75, widthUsingMeasureText, 125);
context.lineWidth = 1;
context.strokeStyle = 'green';
context.stroke();
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.