Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper way to calculate the height and width of a SVG text

I need to calculate the height and width of a svg text element. Is there a way to do so without actually adding it to the DOM of my page? I need only the measures not the actual element.

I am using neither d3 nor Raphael, but only plain JavaScript. (Maybe I should use one of the former for my calculations?)

What I am after is just a function like imagettfbbox in PHP, but in plain JavaScript. Is there such a thing? Or is it easy to write?

Since I am not actually using the text elements it seems strange to me to add them and hide them (I also have read somewhere that Firefox has problems with calculating the bbox of hidden elements, Calculating vertical height of a SVG text). But maybe this is the only way to go? Will I have to work with opacity in that case? Do I destroy the element somehow afterwards?

like image 605
Daniel Avatar asked Apr 17 '14 19:04

Daniel


1 Answers

Maybe there is no good way to achieve exactly what I was after. However, giving up the "without actually adding it to the DOM of my page" part, the following function seems to achieve my goal.

function bboxText( svgDocument, string ) {
    var data = svgDocument.createTextNode( string );

    var svgElement = svgDocument.createElementNS( svgns, "text" );
    svgElement.appendChild(data);

    svgDocument.documentElement.appendChild( svgElement );

    var bbox = svgElement.getBBox();

    svgElement.parentNode.removeChild(svgElement);

    return bbox;
}

Edit:

A note on the calculation of the height: the height of the bbox returned, i.e. bbox.height, is always the full height of the glyph, i.e. a will have the same height as A. And I could not find a way to calculate them more exactly.

However, one can calculate the height of uppercase accented characters, e.g. Ä. This will be just the negative of the y coordinate of the bbox, i.e. -bbox.y.

Using this one can calculate, for example, some coordinates for vertical alignment. For example to emulate the dominantBaseline attribute set to text-before-edge, text-after-edge, and central.

text-before-edge: dy = -bbox.y

text-after-edge: dy = -bbox.height -bbox.y

central: dy = -bbox.y -bbox.height/2

Where dy is the vertical translation. This can be used to get around limitations of some applications that do not support these alignments set by attributes.

like image 83
Daniel Avatar answered Nov 03 '22 17:11

Daniel