8

I'm trying to get the rendered width of a tspan element (located inside a text element) in SVG.

This is my markup:

<text>
    <tspan>Value 1</tspan>
    <tspan>Value 2</tspan>
</text>

Visually, I want value 1 to float left, while value 2 floats right, so that a multiple elements will align as such:

Value 1                                                                   Value 2
Value 10                                                                 Value 20
Value 100                                                               Value 200
Value 1000                                                             Value 2000

Since I want the width of the tpsan ("value 1"/"value 2") and not the text element, I can't use getBBox(), as that method doesn't apply to tspan elements.

Oddly enough, using jQuery's width() method will return the correct value in Chrome, but returns NaN in Firefox. Any ideas would be appreciated.

RussellUresti
  • 6,211
  • 4
  • 28
  • 26
  • Perhaps taking a look at the console & the core function for .width will yield an explanation? – mattsven Mar 19 '11 at 21:41
  • 1
    It seems jQuery just uses offsetWidth -- I tried consoling out just the offsetWidth values, Chrome gives me values, Firefox gives me 'undefined'. – RussellUresti Mar 19 '11 at 21:54

2 Answers2

12

After trying multiple solutions I found getComputedTextLength to be the most accurate way to get the width of an svg tspan. It is also well supported and behaves the same way on different browsers. I also found that the best way to get the height of a tspan is simply to read the font-size attribute.

madmed
  • 606
  • 6
  • 13
  • Note: This get's the width of the actual characters, not the bounding box of the tspans. The font characters can be slightly larger than the tspan bounding box. – Axel May 15 '14 at 17:03
  • Thanks! Very helpfull – Vladimir Tolstikov Apr 26 '17 at 13:48
  • I ended up using this, in order to simulate justification in a paragraph text element which contains multiple lines which are tspans. Using width of each one, it was then possible to left-justify and center-justify all the spans by changing their x value in the relation to the preceding tspan above. To left-justify spans, usually one has to do nothing, but if for some reason they are not already all left-justified, setting all x values to 0 does this and is the easiest thing to do. – Vasily Hall Mar 23 '18 at 15:25
5

You can use getBoundingClientRect() to find the screen-space bounding box of the tspan. I've tested and found this to work in Safari v5.0.4, Firefox 3.6 and 4.0RC, and Opera 11. However, it fails with Chrome, v10.0.648.151 and v11.0.696.14. (It returns a ClientRect with all values set to 0.)

You'll have to transform this client-space rectangle into SVG coordinates by multiplying by the inverse of the screen transform matrix. Here's a working example:
http://phrogz.net/SVG/tspan_bounding_box.xhtml

Pair this with offsetWidth (which works in Chrome and Safari, but not Firefox or Opera) and you have a solution that should work in all browsers that support SVG well.

iddo
  • 749
  • 3
  • 11
Phrogz
  • 296,393
  • 112
  • 651
  • 745
  • This certainly seems to work, though it doesn't seem to be quite as accurate (or maybe it's more accurate) than offsetWidth. Here's the real-world example of how I'm using it: http://jsfiddle.net/ArmRM/6411/ I didn't use the matrixTransform values, since Firefox offerred .width and .height attributes -- are these not supported in Opera / Safari? – RussellUresti Mar 22 '11 at 20:33
  • I haven't had time to look at your example code yet, but I'm guessing that `offsetWidth` might be specified in screen units while you need to transform the units from screen space to SVG space, or further transformation values. – Phrogz Mar 22 '11 at 23:29
  • 1
    getClientBoundingRect will not work in all browsers. I think getComputedTextLength is the best way. – madmed Sep 10 '13 at 21:55