Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get the actual height of a SVG text (not the bounding box height)

I want to be able to calculate the actual height occupied by a text (or span) element in a SVG.

For now, I achieve this by calculating the height of the bounding box of the object, but it takes the height of the font glyph, so any text I put in the element has the same height, like in the example below :

var minA = document.getElementById('min-a'),
    capA = document.getElementById('cap-a'),
    minAHeight = document.getElementById('min-a-height'),
    capAHeight = document.getElementById('cap-a-height')
;

minAHeight.innerHTML = minA.getBBox().height;
capAHeight.innerHTML = capA.getBBox().height;
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 80">
  <text id="min-a" x="20" y ="20">a</text>
  <text id="cap-a" x="20" y ="50">Â</text>
  <text id="min-a-height" x="70" y ="20"></text>
  <text id="cap-a-height" x="70" y ="50"></text>
<svg>

How can I calculate the actual height of each element ?

like image 417
Fiti Avatar asked Feb 01 '26 01:02

Fiti


1 Answers

@Fuzzyma is on the right track. You want to use OpenType.js and load the font in the browser.

// These two match whatever you are doing in your code
const text = 'Hello'
const fontSize = 20

// Load font - I find ttf work better than woff (has extra data for other calculations if needed)
opentype.load(`/path/to/font.ttf`, (err, font) => {

   // Actual dimensions of the text
   const bb = font.getPath(text, 0, 0, fontSize)

})

That will give you the real bounding box which may be enough for your needs. If you actually need to use this to know the screen position on text it is possible but its quite a bit more challenging.

The gist of it is that you need to match baselines. The font contains the ascender/descender (font.tables.hhea.asscender, font.tables.hhea.descender) which total up to the font size once converted to em (font.tables.head.unitsPerEm * fontSize).

Armed with this you then need to go through each glyph of the font and get the yMax, yMin, xMin and xMax. Use the ascender/descender and the Y coords to determine how far away from the "fake" bounding box (the one the DOM returns) your new bb is. The left and right are easier except for some weird fonts that have letters that can stretch beyond their neighbors (edge case).

On top of that browsers add a per browser vertical offset... This can be extracted by getting the y attribute of the SVG text element (i.e -5) - then you take your font size, divide by half and take of this y and you have the vertical offset that browsers use (in our case 5). Each browser is different but the y coordinate reflects that.

like image 95
cyberwombat Avatar answered Feb 03 '26 20:02

cyberwombat