Home > Net >  How to get the exact BBox for svg <tspan>
How to get the exact BBox for svg <tspan>

Time:02-01

I am trying to figure out why getBBox() for tspan element of a svg does not return the dimension.

To demonstrate this with an example, if I run BBox on both tsp1 and rect1, it returns the correct dimension for rect1 but not for tsp1

var tsp = document.getElementById('tsp1');
var tspBBox = tsp.getBBox();
var rect = document.getElementById('rect1');
var rectBBox = rect.getBBox();
console.log(tspBBox);
console.log(rectBBox);
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">

    <text  id="t1" font-size="20" font-family="PT Mono" text-decoration="underline">
        <tspan  id="tsp1" x="10.23" y="135.05">Abc ef ghi</tspan>
    </text>
    <rect  id="rect1" x="9.23" y="112.73368530273439" height="31.546314697265625" width="1" fill="orange" />
</svg>

S1

I was expecting BBox to return the exact x and y for tsp1 but it does not. I don't know why. I need to pass on the exact values to the succeeding class dynamically.

How can javascript return the exact dimension for the tspan element?

CodePudding user response:

There are a number of methods for measuring text, and they are a bit more complex than defining a simple box. This is because with the dx, dy and rotate attributes, each addressable character can be be positioned individually - moved and rotated in every direction. Therefore, it makes more sense to answer the question where a single character is positioned, and where, after completing one sequence, the next character would be positioned.

In your case none of the above attributes are set ( on the <tspan> or <text> element). In this case is is possible to retrieve the start position of the <tspan> with .getStartPositionOfChar(0) and the horizontal width with .getComputedTextLength().* The height according to the font metrics is the same for all characters in the tspan, so it is enough to return one .getExtentOfChar(0) - 0 refers to the first character within the sequence of addressable characters.

As chrwahl pointed out in his answer, the start position refers to the font-specific baseline and normally will not be identical to the top left corner of a bounding box.

*There is a subtle trick here: if the letter-spacing or word-spacing CSS properties were defined, the "length" returned would not only return the width from the start of the first character to the end of the last, but also would add (or subtract) a spacing value that is defined after the end of the string. In other words: despite its name, the method returns the relative horizontal start position of the next character after the string examined.

var tsp = document.getElementById('tsp1');
var tspPos = tsp.getStartPositionOfChar(0);
console.log('start position', tspPos.x, tspPos.y);
console.log('horizontal advance', tsp.getComputedTextLength());
console.log('vertical extent', tsp.getExtentOfChar(0).height);
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">

    <text  id="t1" font-size="20" font-family="PT Mono" text-decoration="underline">
        <tspan  id="tsp1" x="10.23" y="135.05">Abc ef ghi</tspan>
    </text>
</svg>

CodePudding user response:

It is all about the dominant-baseline. So, there is a differences between where the text is placed according to the dominant-baseline and the box that the text takes up. The value text-before-edge will place the text according to the upper left corner of the box.

var tsp = document.getElementById('tsp1');
var tspBBox = tsp.getBBox();
var rect = document.getElementById('rect1');
var rectBBox = rect.getBBox();

console.log('tspBBox', tspBBox.x, tspBBox.y);
console.log('rectBBox', rectBBox.x, rectBBox.y);
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 100 400 200">
  <text  id="t1" font-size="20" font-family="PT Mono"
    text-decoration="underline" dominant-baseline="text-before-edge">
    <tspan  id="tsp1" x="10.23" y="135.05">Abc ef ghi</tspan>
  </text>
  <rect  id="rect1" x="9.23" y="112.73368530273439" height="31.546314697265625" width="1" fill="orange" />
</svg>

  •  Tags:  
  • Related