I'm currently working on a JavaScript project that uses the HTML5 canvas as a rendering target. In order for my code to play nicely with the (rigidly specified) interfaces I've been provided, I need to be able to take a font and extract the ascent and descent heights of that font. This will allow clients to more accurately position the text. I'm aware that I can change where the text draws by setting the textBaseline attribute, but I actually need the numeric values describing these different heights. Is there a simple way to do this? If not, is there a (hopefully lightweight) library that can handle it for me? Most of the proposed solutions I've found are heavyweight font rendering libraries, which seems like massive overkill for this problem.
4 Answers
This article on HTML5 Typographic Metrics discusses the problem and a part solution using CSS - although the integer rounding of offsetTop etc is a problem (potentially can use getBoundingClientRect() to get proper floating point values for some browsers).
Comments
The short answer is that there is no built in way and you are sort-of on your own.
Because of this, most people simply estimate them. Some people pre-calculate all the values, which isn't too much work provided you are using only a few fonts.
The third way is to make a canvas in memory and print some letters (say, a Q and an O) and programatically attempt to determine the ascent and descent using per-pixel collision. It's a pain and can be slow depending on the number of fonts and how accurate you want to be, but it is the most accurate way of going about it if you do not want to pre-compute the values.
Comments
Just as a reference here: The width of the text can be measured with:
ctx.measureText(txt).width
Comments
For both the width and height, you could try this:
let txt="AVA BC efg hij IÍ";
let measure=ctx.measureText(txt);
let width=measure.width;
let fullHeight=measure.fontBoundingBoxAscent+measure.fontBoundingBoxDescent;
let ascentHeight=measure.fontBoundingBoxAscent;
The width value handles all of the possible kerning between letters. (ie. AVA) The ascentHeight would measure from the baseline of where the text is drawn to the height of the tallest capital letter. And the fullHeight can cover from the highest letter to lowercase "g" and "j".
1 Comment
TextMetrics was the width. I am glad to see that has evolved in the intervening decade!
ctx.measureText("text").width. I think that's right. I'll double check it if you still need it.