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

2

12

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?

Counterstroke answered 17/4, 2014 at 19:58 Comment(5)
Why would adding it to the DOM of your page be a problem?Aspasia
How are you creating the text element? Are you using a library like d3.js or Raphael, or are you using document.createElement(), or something different entirely? Give us some contextCommanding
Thanks for your comments. I tried to give some more context.Counterstroke
You can use measureText method of canvas element.Ascension
Unfortunately, using measureText I seem to loose the ability to measure H<tspan style="baseline-shift:sub;font-size:5px">2</tspan>O which can be used inside a SVG-text element. So this solution seems not to work.Counterstroke
C
20

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.

Counterstroke answered 20/4, 2014 at 17:14 Comment(2)
have you used this as "production" solution of eventually found a better way to do it without actually adding an element (which I assume is slowish)?Doti
Unfortunately I found no better way yet.Counterstroke
N
0

I have encountered a similar problem in VB.Net !

I written a VB.Net program that generate a SVG file and that needs to compute width of text to compute next vertical bar position as you can see in following image

enter image description here

The B line vertical bar is positionned in computing max text width of A line elements.

To do that in Console VB.Net application, I execute following lines of code

Private Sub WriteTextInfo(sInfo As String)

    If sInfo <> "" Then
        'display Text in SVG file
        sw.WriteLine("<text x ='" & (xPos + 10) & "' y='" & yPos & "' fill='black' font-family='Arial' font-size='20'>" & sInfo & "</text>")

        'Create Font object as defined in <text> SVG tag 
        Dim font As New Font("Arial", 20.0F)
        'Compute width of text in pixels
        Dim xSize = TextRenderer.MeasureText(sInfo, font)
        'Divide pixels witdh by a factor 1.4 to obtain SVG width !
        Dim iWidth As Decimal = Math.Truncate(CDec(xSize.Width) / 1.4)

        'If new vertical position is greater than old vertical position
        If xPos + iWidth > xPosMax Then
            xPosMax = xPos + iWidth
        End If
    End If
End Sub

In resume, I compute text's width in pixels using TextRenderer.MeasureText() function and I divide this number by 1.4 to obtain SVG width.

1.4 value is obtained by experiment relatively to my case !

To use TextRendered and Font objects, I have added reference to

System.Drawing
System.Windows.Forms

As you can see, I don't use any DOM method to compute text's width because I compute it in VB.Net program.

Noctambulism answered 12/9, 2020 at 3:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.