I'm really having trouble to understand how <text>
elements are supposed to be rotated in a controllable way in <svg>
. The concrete example is here:
<svg version="1.1" baseProfile="full" viewBox="0 0 1000 200" xmlns="http://www.w3.org/2000/svg" id="timeline-container">
<line x1="11" x2="200" y1="11" y2="142.2" stroke="black"/>
<line x1="200" x2="400" y1="142.2" y2="121" stroke="black"/>
<line x1="400" x2="600" y1="121" y2="167.6" stroke="black"/>
<line x1="600" x2="989" y1="167.6" y2="11" stroke="black"/>
<rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="11" y="11" transform="translate(-10,-10)"/>
<text text-anchor="end" x="17" y="32" transform="rotate(-90,17,32)" class="label-below-project-point" >abcdef</text>
<rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="200" y="142.2" transform="translate(-10,-10)"/>
<text x="206" y="121.2" transform="rotate(-90,206,121.2)" class="label-above-project-point" >abc</text>
<rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="400" y="121" transform="translate(-10,-10)"/>
<text x="406" y="100" transform="rotate(-90,406,100)" class="label-above-project-point" >abcdefghijklmnopq</text>
<rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="600" y="167.6" transform="translate(-10,-10)"/>
<text x="606" y="146.6" transform="rotate(-90,606,146.6)" class="label-above-project-point" >abcdefg</text>
<rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="989" y="11" transform="translate(-10,-10)"/>
<text text-anchor="end" x="995" y="32" transform="rotate(-90,995,32)" class="label-below-project-point" >abcdefghijklmnopqrstuvwxy</text>
</svg>
I wanna rotate the text elements 90 degrees to display them horizontally, and align the label in relation to the timeline's rectangle to which it refers, when a user clicks on one of the rectangular timeline points. More precisely:
When the leftmost timeline point is clicked, the label shall rotate 90 degrees to be displayed horizontally + be left - aligned with the left border of the left-most rectangle.
For the rightmost point, first do a 90 deg rotation to also yield horizontal display, & then right-align the text element with the right border of the right-most rectangle.
For all the intermediary points, also first 90° rotate for horizontal display, but then center-align the text in relation to the respective timeline point's center.
The <text>
elements are generated programmatically with provided text labels, so they may contain any number from like 1 - 30 characters; resulting in variable widths and heights.
EXAMPLE
The rotations never behave as I expect them to. For example, when I attempt to rotate the left-most <text>
element by setting the rotation origin to it's bottom left corner, and the rotation angle to 90, the <text>
element gets rotated way atop of the top border of the svg. no idea why. To reproduce it:
- apply
getBBox()
onto the text element to get its widthW
. - add up
W
+ the value of they
attribute of thetext
element to get they
coordinate of the bottom left corner of that left-most text element;Y
. - Add the according rotation command:
rotate(90,0,Y)
into thetransform
element of the left-most text element, and you get: transform="rotate(-90,17,32) rotate(90,0,Y)
. The rotation totally does not behave as you expect it...
EXAMPLE 2
What am I misunderstanding ? Let me also illustrate my problem with the snippet provided by @Danny '365CSI' Engelman:
<style>
svg { height: 180px }
circle{ r:2px; fill:red }
</style>
<svg id=SVG viewbox="0 0 100 100">
<rect width="100%" height="100%" fill="pink"></rect>
<circle cx="25" cy="50"></circle>
<text x="25" y="50" text-anchor="start"
transform="rotate(-90 25 50)">Hello</text>
<circle cx="50" cy="50"></circle>
<text x="50" y="50" text-anchor="end" dominant-baseline="hanging"
transform="rotate(90 50 50)">SVG</text>
<circle cx="75" cy="50"></circle>
<text x="75" y="50" text-anchor="middle" dominant-baseline="middle"
transform="rotate(-45 75 50)">World</text>
</svg>
Let's say I now want to rotate the "Hello" text element by 90 degrees to make it become horizontally displayed, with its rotation origin at the center of the text element. I thus first calculate the center of the text element as follows:
Get the dimensions of the concerned element using
document.getElementsByTagName("text")[0].getBBox();
. This returns an SVG rect with a height of 16.38888931274414 SVG units and a width of 36.10185241699219 SVG units.I now calculate the coordinates of the text element's center, like so:
x = 25 - 16.38888931274414 / 2 = approx. 16.81
y = 50 - 36.10185241699219 / 2 = approx. 31.95
- I now add
rotate(90 16.81 31.95)
into the transform attribute, and then totally not get the 90° rotation of the text element as expected; as you can see here:
<style>
svg { height: 180px }
circle{ r:2px; fill:red }
</style>
<svg id=SVG viewbox="0 0 100 100">
<rect width="100%" height="100%" fill="pink"></rect>
<circle cx="25" cy="50"></circle>
<text x="25" y="50" text-anchor="start"
transform="rotate(-90 25 50) rotate(90 16.81 31.95)">Hello</text>
<circle cx="50" cy="50"></circle>
<text x="50" y="50" text-anchor="end" dominant-baseline="hanging"
transform="rotate(90 50 50)">SVG</text>
<circle cx="75" cy="50"></circle>
<text x="75" y="50" text-anchor="middle" dominant-baseline="middle"
transform="rotate(-45 75 50)">World</text>
</svg>
What am I not understanding here / How can I calculate rotation centers + thus predict rotations correctly?????????