Search code examples
csssvgrotationoverwrite

Rotate svg text around central text position using css


I want to apply a single css rotation transformation to a set of elements in an SVG, such that each element is rotated independently, without having to calculate the centre of each element in the css. For example, I have an SVG that looks like the picture on the left, and want to apply css to achieve the effect on the right

initial SVG Desired result

I'm writing the svg myself, and am creating something like this

<svg baseProfile="full" height="200" version="1.1" width="200" xmlns="http://www.w3.org/2000/svg">
    <text transform="translate(50 100)" text-anchor="middle">Text 1</text>
    <text transform="translate(100 100)" text-anchor="middle">Text 2</text>
</svg>

When I apply a css rotation, e.g. by inserting <style>text {transform: rotate(10deg)}</style>, it seems to overwrite the first transformation, and the rotated text is placed in the top left corner:

enter image description here

I can modify the svg to use `x="X" y="Y" instead of a transform attribute, but that results in the transformation being applied around a different centre instead:

<svg baseProfile="full" height="200" version="1.1" width="200" xmlns="http://www.w3.org/2000/svg">
    <style>text {transform: rotate(10deg)}</style>
    <text x="50" y="100" text-anchor="middle">Text 1</text>
    <text x="100" y="100"  text-anchor="middle">Text 2</text>
</svg>

enter image description here

How can I structure the svg so that I can apply a rotation which works independently on each element without overwriting the initial transform?


Solution

  • This is a possible solution:

    -The text has x="0" y="0" and is rotated with CSS.

    -You put the text in the <defs>.

    -You use the text and the <use> element has the x and y values you need.

    text{transform:rotate(90deg)}
    <svg baseProfile="full" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
      <defs>
      <text id="a" text-anchor="middle" >Text 1</text>
      <text id="b" text-anchor="middle" >Text 2</text>
      </defs>
      <use xlink:href="#a" x="50" y="50" />
      <use xlink:href="#b" x="100" y="50" />
    </svg>

    Yet another solution (inspired by the comment of Robert Longson) would wrapping the rotated text in a g element and translate the g

    text{transform:rotate(90deg)}
    <svg baseProfile="full" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
     
          <g transform="translate(50,50)"><text text-anchor="middle" >Text 1</text></g>
          <g transform="translate(100,50)"><text text-anchor="middle" >Text 2</text></g>
    
     </svg>