1

This answer and this answer explain how to show multiple lines of text and how to center one line of text with SVG, but how do you center multiple lines of text?

As you can see from this Code Pen, the text block is not centered because of the dy attribute, which is needed to display multiply lines.

The goal is to allow dynamic insertion/deletion of lines while preserving the centered nature of the text block. So the user might add a fourth line or delete two lines. In both cases, the text block should remain centered.

One approach is to modify the dy values each time a line is removed/inserted as some suggested, but is there a non-JS approach to vertically centering a block of text?

<svg style="border:1px solid black" width="200" height="300">
    <text x="50%" y="50%" font-size="15">
        <tspan x="0" dy="1.2em" dominant-baseline="central">tspan line 1</tspan>
        <tspan x="0" dy="1.2em" dominant-baseline="central">tspan line 2</tspan>
        <tspan x="0" dy="1.2em" dominant-baseline="central">tspan line 3</tspan>
    </text>
</svg>
Crashalot
  • 33,605
  • 61
  • 269
  • 439

1 Answers1

4

This is how I would do it:I'm centring everything around the center of the SVG canvas and I'm offsetting the first and the last line with dy

text{text-anchor:middle;dominant-baseline:central;}
<svg style="border:1px solid black" width="200" height="300">
    <text x="50%" y="50%" font-size="15">
        <tspan x="100" y="150" dy="-1.2em" >tspan line 1</tspan>
        <tspan x="100" y="150" >tspan line 2</tspan>
        <tspan x="100" y="150" dy="1.2em" >tspan line 3</tspan>
    </text>
</svg>

update

The OP commented that they: updated the question to reflect the need for dynamic insert/deletion of lines.

In this case I would put the whole text inside a group and I would use the bounding box of the group to center the text:

The red circle I've added is just in order to see the center of the SVG canvas.

let bb = txt.getBBox(); console.log()
let X = 100;
let Y = 150 - bb.y - (bb.height)/2;
txt.setAttributeNS(null,"transform",`translate(${X},${Y})`)
text{text-anchor:middle;dominant-baseline:central;font-size:15;}
<svg style="border:1px solid black" width="200" height="300">
 <text id="txt"><!--
--><tspan x="0" y="0">tspan line 1</tspan><!--
--><tspan x="0" y="1.2em">tspan line 2</tspan><!--
--><tspan x="0" y="2.4em" >tspan line 3</tspan><!--
--><tspan x="0" y="3.6em" >tspan line 4</tspan>
 </text>
<circle cx="100" cy="150" r="3" fill="red"/>
</svg>
Community
  • 1
  • 1
enxaneta
  • 31,608
  • 5
  • 29
  • 42
  • 1
    thanks for the suggestion, but updated the question to reflect the need for dynamic insert/deletion of lines. – Crashalot Dec 18 '18 at 09:27
  • is there a way to center the group without javascript? x=50% and y=50% wouldn't work? – Crashalot Dec 18 '18 at 10:10
  • Try it for yourself: put the group inside a `` and use it with: `` This will center the text horizontally but not vertically. Why don't you want to use javascript? After all you need to insert/delete lines dynamically - don't you? – enxaneta Dec 18 '18 at 10:23
  • Thanks, tried it in the CodePen, and it didn't work. The less code, the fewer opportunities for bugs and the less code to maintain. :) So there's no way to center the text block vertically without JavaScript? – Crashalot Dec 18 '18 at 11:12
  • If it's not possible to do this without JavaScript (question was updated again), please include this in the answer, and you'll be awarded the points. Thanks for helping! – Crashalot Dec 19 '18 at 04:51
  • Also why did you use a new group instead of positioning the element directly? – Crashalot Dec 19 '18 at 04:52
  • You don't need the `g` if you give the text the `id="text"`. Alternatively you can select the text in an other way if you prefer. – enxaneta Dec 19 '18 at 08:21