I am trying to create text box in the HTML5 canvas, I know you can't actually do this, so I am creating a box and creating some text at the same location. But, I want to make sure the text stays in the box so I need to know when part of the text is extending out of the box. I figure I should be able to measure the text in terms of pixels and then pare it to the box. My question is, using javascript, how can I measure the size of the characters for any given font?
I am trying to create text box in the HTML5 canvas, I know you can't actually do this, so I am creating a box and creating some text at the same location. But, I want to make sure the text stays in the box so I need to know when part of the text is extending out of the box. I figure I should be able to measure the text in terms of pixels and then pare it to the box. My question is, using javascript, how can I measure the size of the characters for any given font?
Share Improve this question asked Jan 3, 2014 at 21:20 EasilyBaffledEasilyBaffled 3,88210 gold badges55 silver badges92 bronze badges2 Answers
Reset to default 4You can use context.measureText to get the width of your specified text:
// set the font
context.font = "14px verdana";
// use measureText to get the text width
var textWidth = context.measureText("Measure this!").width;
Text wrap would look something like this:
function wrapText(context, text, x, y, maxWidth, fontSizeFace) {
var words = text.split(' ');
var line = '';
var lineHeight=measureTextHeight(fontSizeFace);
for(var n = 0; n < words.length; n++) {
var testLine = line + words[n] + ' ';
var metrics = context.measureText(testLine);
var testWidth = metrics.width;
if(testWidth > maxWidth) {
context.fillText(line, x, y);
line = words[n] + ' ';
y += lineHeight;
}
else {
line = testLine;
}
}
context.fillText(line, x, y);
}
You can use as markE mention in his answer the measureText()
function.
The specifications defines its result (a TextMetrix
):
interface TextMetrics {
// x-direction
readonly attribute double width; // advance width
readonly attribute double actualBoundingBoxLeft;
readonly attribute double actualBoundingBoxRight;
// y-direction
readonly attribute double fontBoundingBoxAscent;
readonly attribute double fontBoundingBoxDescent;
readonly attribute double actualBoundingBoxAscent;
readonly attribute double actualBoundingBoxDescent;
readonly attribute double emHeightAscent;
readonly attribute double emHeightDescent;
readonly attribute double hangingBaseline;
readonly attribute double alphabeticBaseline;
readonly attribute double ideographicBaseline;
};
The problem however is that only width
is implemented in the major browsers so you cannot get the height (ascent + descent) with this function yet (and I wouldn't be surprised if a canvas based word processor from at least one of the "major 3" shows up right before this gets fully implemented... but that's a regression and a speculation :-) ).
In order to measure the font you will have to use a DOM element, and this little trick will allow you to measure a font's width and height:
Online demo here (open console to see result).
function measureText(font, txt) {
var el = document.createElement('div'),
cs, res;
el.style.cssText = 'position:fixed;left:-4000px;top:-4000px;padding:0;margin:0;font:' + font;
el.innerHTML = txt;
document.body.appendChild(el);
cs = getComputedStyle(el);
res = {width: cs.getPropertyValue('width'),
height: cs.getPropertyValue('height')};
document.body.removeChild(el);
return res;
}
The function creates a div element, applies some basic styles to it to place it outside window. This is because we have to attach it to the DOM tree in order to use getComputedStyle()
- we also have to get the property values before we remove the element again.
Pass arguments for font as you would with the context (ie. 20px sans-serif
) and the text.
It es with a small performance penalty obviously (though using fixed positioned elements won't cause any re-flow so it's not so bad) so use sparsely.