Telokis
Telokis

Reputation: 3389

Center text in SVG with React

First of all, yes, I have searched and I have seen the many other answers available. But they didn't work for me.

I would like to be able to center the text in my SVG.

Since I have to be able to put it left, center or right, (both horizontally and vertically) I tried to be a little bit generic and compute x and y programmatically.

Here is an example : https://codesandbox.io/s/ll6ppwkyq7

You can see in the result that the text is not vertically centered.

The red box is the bounding box of the text.

The black box is the box in which I am supposed to be centered.

Upvotes: 3

Views: 1326

Answers (1)

Julien Grégoire
Julien Grégoire

Reputation: 17144

The relationship between x coordinate of an element and the coordinate of the right position of the text is not the same as of the y coordinate of an element and the bottom position. In fact it's inverted.

That's because vertically, the text is place at the bottom of an element and y coordinates go from top to bottom, while horizontally coordinates go in the same direction as the text.

This is easily seen when using GetBBbox() method, which you are using. For example, when adding a text element at coordinates 0 for x and y, you'll see that getBBbox will give you a x = 0 but a negative y.

console.log(document.getElementById('testbbox').getBBox());
<svg id="testbbox"><text x=0 y=0>test</text></svg>

So already, calculations to center your text will need to be different. What you have now is:

outerRect.x - ((outerRect.width - innerRect.width) / 2)

This works because you assume that inner rectangle starts from 0, which is not the case. Your bounding box is vertically in the negative. So complete formula should be something like:

outerRect.x - innerRect.x - ((outerRect.width - innerRect.width) / 2)

Which in your example would be:

x - bboxx + ( (width - boxWidth) / 2)

Where bbox is x of getBBox()

You could use baseline, but with dy on the tspan, it makes the calculations a bit more complex, not sure it's the good approach. Since anyway getBBox takes baseline into account in the calculation, it's not really necessary.

Also, if you look here, baseline for text should be dominant-baseline, not alignement-baseline: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/dominant-baseline

See how it affects the bounding box, especially y coordinate:

console.log(document.getElementById('central').getBBox());
console.log(document.getElementById('top').getBBox());
<svg id="central">
<text y=10 dominant-baseline="central" >test</text>
</svg>
<svg id="top">
<text y=10 dominant-baseline="top" >test</text>
</svg>

See end result: https://codesandbox.io/s/52wl31l8zn

Upvotes: 1

Related Questions