I'm struggling to understand how the rotation of text works with the Html SVG Text tags.
I read this, somewhat, similar question rotate x axis text in d3 but the answer doesn't really seem to apply - that i can figure anyway.
Take the following SVG Markup:
<svg>
<g>
<rect x="0" y="0" width="20" height="75" fill="white" stroke="#CCC" stroke-width="0.5"></rect>
<text x="2" y="73" font-size="10">1</text>
</g>
<g>
<rect x="20" y="0" width="20" height="75" fill="white" stroke="#CCC" stroke-width="0.5"></rect>
<text x="22" y="73" font-size="10">2</text>
</g>
<g>
<rect x="40" y="0" width="20" height="75" fill="white" stroke="#CCC" stroke-width="0.5"></rect>
<text x="42" y="73" font-size="10">3</text>
<!-- Trying to rotate this 270 degrees -->
<text x="42" y="73" font-size="10">Missing</text>
</g>
<g>
<rect x="60" y="0" width="20" height="75" fill="white" stroke="#CCC" stroke-width="0.5"></rect>
<text x="62" y="73" font-size="10">4</text>
</g>
</svg>
There is some text, in the 3rd group; 'Missing'
I am trying to rotate this 270 degrees, but struggling to understand where it rotates from. I have read it rotates from the origin, but what is the origin in this?
I've tried things like transform="rotate(270, 42, 73)" and various other numbers in place of 42 and 73. I can eventually, with guesswork, get it in the right position though without understanding how it actually works, then i can't add text to the other groups and rotate it.
So, how do i rotate this and, in laymen terms, how does it work?
For clarification - I am looking to achieve:
Text is positioned with the baseline starting at the coordinates you provide. In your example you are positioning the "3" and the "Missing" at the same position. Trying to find the right values for the transform, that will rotate the text into position from there, is unnecessarily complicating the process.
I would suggest positioning the "Missing" where you want the (soon to be vertical) baseline to start and apply the rotation once you find the right position.
First step: position the text
<svg width="200" viewBox="0 0 100 100">
<g>
<rect x="0" y="0" width="20" height="75" fill="white" stroke="#CCC" stroke-width="0.5"></rect>
<text x="2" y="73" font-size="10">1</text>
</g>
<g>
<rect x="20" y="0" width="20" height="75" fill="white" stroke="#CCC" stroke-width="0.5"></rect>
<text x="22" y="73" font-size="10">2</text>
</g>
<g>
<rect x="40" y="0" width="20" height="75" fill="white" stroke="#CCC" stroke-width="0.5"></rect>
<text x="42" y="73" font-size="10">3</text>
<!-- Trying to rotate this 270 degrees -->
<text x="52" y="63" font-size="10">Missing</text>
</g>
<g>
<rect x="60" y="0" width="20" height="75" fill="white" stroke="#CCC" stroke-width="0.5"></rect>
<text x="62" y="73" font-size="10">4</text>
</g>
</svg>
Second step: now rotate
(52,63) looks about right. So now we can re-use those coordinates for the rotate().
<svg width="200" viewBox="0 0 100 100">
<g>
<rect x="0" y="0" width="20" height="75" fill="white" stroke="#CCC" stroke-width="0.5"></rect>
<text x="2" y="73" font-size="10">1</text>
</g>
<g>
<rect x="20" y="0" width="20" height="75" fill="white" stroke="#CCC" stroke-width="0.5"></rect>
<text x="22" y="73" font-size="10">2</text>
</g>
<g>
<rect x="40" y="0" width="20" height="75" fill="white" stroke="#CCC" stroke-width="0.5"></rect>
<text x="42" y="73" font-size="10">3</text>
<!-- Trying to rotate this 270 degrees -->
<text x="52" y="63" font-size="10" transform="rotate(270 52 63)">Missing</text>
</g>
<g>
<rect x="60" y="0" width="20" height="75" fill="white" stroke="#CCC" stroke-width="0.5"></rect>
<text x="62" y="73" font-size="10">4</text>
<text x="72" y="63" font-size="10" transform="rotate(270 72 63)">Missing</text>
</g>
</svg>
Ultimately, Robert's solution is simpler, but I wanted to help you understand how the rotate transform works with text.
This seems to roughly match the drawing. The rotation origin at the bottom left by default.
<svg>
<g>
<rect x="0" y="0" width="20" height="75" fill="white" stroke="#CCC" stroke-width="0.5"></rect>
<text x="2" y="73" font-size="10">1</text>
</g>
<g>
<rect x="20" y="0" width="20" height="75" fill="white" stroke="#CCC" stroke-width="0.5"></rect>
<text x="22" y="73" font-size="10">2</text>
</g>
<g>
<rect x="40" y="0" width="20" height="75" fill="white" stroke="#CCC" stroke-width="0.5"></rect>
<text x="42" y="73" font-size="10">3</text>
<!-- Trying to rotate this 270 degrees -->
<text transform="rotate(270, 42, 73) translate(10,10)" x="42" y="73" font-size="10">Missing</text>
</g>
<g>
<rect x="60" y="0" width="20" height="75" fill="white" stroke="#CCC" stroke-width="0.5"></rect>
<text x="62" y="73" font-size="10">4</text>
</g>
</svg>
Related
I generated a SVG using Adobe XD. They use transform for positioning things but the text in my mini computer screen is not always the same width (it is dynamically generated). I have tried anchored, anything I could find but it still didn't work. This is how it looks with the current code:
Here is the code:
<svg xmlns="http://www.w3.org/2000/svg" width="903.5" height="860.5" viewBox="0 0 1200 1041">
<g transform="translate(-397)">
<g
transform="translate(507 975)"
fill="#fff"
stroke="#707070"
strokeWidth="1"
>
<rect width="907" height="66" rx="33" stroke="none" />
<rect x="0.5" y="0.5" width="906" height="65" rx="32.5" fill="none" />
</g>
<rect width="119" height="395" transform="translate(901 613)" fill="#fff" />
<g
transform="translate(397)"
fill="#232323"
stroke="#fff"
stroke-width="30"
>
<rect width="1127" height="627" rx="103" stroke="none" />
<rect x="15" y="15" width="1097" height="597" rx="88" fill="none" />
</g>
<text
fill="white"
fontSize="96"
fontFamily="Fredoka"
>
{screenText}
</text>
</g>
</svg>
You can use transform/translate, text-anchor and dominant-baseline to place a text in the middle of something.
body {
background: gray;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 1041">
<g
transform="translate(600 975)"
fill="#fff"
stroke="#707070"
stroke-width="1">
<rect x="-453.5" width="907" height="66" rx="33" stroke="none" />
<rect x="-454" y="0.5" width="906" height="65" rx="32.5" fill="none" />
</g>
<rect width="119" height="395" transform="translate(545.5 613)" fill="#fff" />
<g transform="translate(50)"
fill="#232323"
stroke="#fff"
stroke-width="30">
<rect width="1127" height="627" rx="103" stroke="none" />
<rect x="15" y="15" width="1097" height="597" rx="88" fill="none" />
</g>
<text
fill="#fff"
font-size="96"
font-family="Fredoka"
transform="translate(600 300)"
text-anchor="middle"
dominant-baseline="middle">
{screenText}
</text>
</svg>
Thanks to Buhan Yu's comment I learned that you need to specify x and y to center align it. I set x="50%" and it worked!
I'm trying to generate a task timeline coded as SVG in a generic way, and managed to do it until this point:
https://jsfiddle.net/dx7uryob/
What remains to do is the following animation (on any task point):
From:
:
To the "task" label rotating 90 deg until displayed perfectly horizontally and centered above the task point. I managed to do this by adding rotate(90, x+45, y) into the transform attribute of the according <text> tag, but this fails to rotate gradually when I use svg text { transition: transform 1s; }.
I would really like to know how to animate that (working also in IE, so I guess animateTransform is not an option..?).
Then, the final step would be to blend in a second label below the rotated "task" label, ideally by turning an opacity to 1 to gradually make it appear / disappear. For this, I could not even find out how to place a second text label below the first one in an SVG.
Concering solutions; I'd really prefer to stick to SVG, as my solution copied in the snippet can be generated in a generic way and then scaled as you please; it's just these last two pieces missing and I can't find them out.
.label-below-task-point {
text-anchor: end;
}
<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 x="11" y="11" transform="translate(6,20) rotate(-90,11,11)" class="label-below-task-point">task</text>
<rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="200" y="142.2" transform="translate(-10,-10)" />
<text x="200" y="142.2" transform="translate(6,-20) rotate(-90,200,142.2)" class="label-above-task-point">task</text>
<rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="400" y="121" transform="translate(-10,-10)" />
<text x="400" y="121" transform="translate(6,-20) rotate(-90,400,121)" class="label-above-task-point">task</text>
<rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="600" y="167.6" transform="translate(-10,-10)" />
<text x="600" y="167.6" transform="translate(6,-20) rotate(-90,600,167.6)" class="label-above-task-point">task</text>
<rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="989" y="11" transform="translate(-10,-10)" />
<text x="989" y="11" transform="translate(6,20) rotate(-90,989,11)" class="label-below-task-point">task</text>
</svg>
Am I maybe better off using a canvas here? I've no experience with it, but I wonder if it's the better choice for what I'm trying to do..
I have solved it for the second text, task2, using transform-origin :
.label-below-task-point {
transform: rotate(90deg);
transition: transform 1s;
}
.label-below-task-point:hover {
transform: rotate(0deg);
}
<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 x="11" y="11" class="label-below-task-point">task</text>
<rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="200" y="142.2" transform="translate(-10,-10)" />
<text x="180" y="125" transform-origin="199px 120px" class="label-below-task-point">task2</text>
<rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="400" y="121" transform="translate(-10,-10)" />
<text x="400" y="121" transform="translate(6,-20) rotate(-90,400,121)" class="label-above-task-point">task</text>
<rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="600" y="167.6" transform="translate(-10,-10)" />
<text x="600" y="167.6" transform="translate(6,-20) rotate(-90,600,167.6)" class="label-above-task-point">task</text>
<rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="989" y="11" transform="translate(-10,-10)" />
<text x="989" y="11" transform="translate(6,20) rotate(-90,989,11)" class="label-below-task-point">task</text>
</svg>
I am using svg to display text at specific position, But the text at end of the svg container is cropped.
How to display that text.
I am using the following code
<svg width="100" style="background:yellow">
<text x="0" y="100" stroke="red" text-anchor="middle">0</text>
<text x="20" y="100" stroke="red" text-anchor="middle">20</text>
<text x="40" y="100" stroke="red" text-anchor="middle">40</text>
<text x="60" y="100" stroke="red" text-anchor="middle">60</text>
<text x="80" y="100" stroke="red" text-anchor="middle">80</text>
<text x="100" y="100" stroke="red" text-anchor="middle">100</text>
</svg>
I want to display 0 and 100 completely and don't want to change the svg container width
In order not to change the size of the numbers and see all of them, you need to add a viewBox and increase the width
<svg width="130" viewBox="-10 0 130 130" style="background:yellow">
<text x="0" y="100" stroke="red" text-anchor="middle">0</text>
<text x="20" y="100" stroke="red" text-anchor="middle">20</text>
<text x="40" y="100" stroke="red" text-anchor="middle">40</text>
<text x="60" y="100" stroke="red" text-anchor="middle">60</text>
<text x="80" y="100" stroke="red" text-anchor="middle">80</text>
<text x="100" y="100" stroke="red" text-anchor="middle">100</text>
</svg>
I'm trying to put some text as labels inside some scaled elements, and the text is too big to fit in the container. What can I do here?
<div class="t_container">
<div class="t_x" style="position: relative;">
<svg position="absolute" viewBox="0 0 6 1" preserveAspectRatio="none">
<g>
<rect x="0" y="0" width="1" height="0.4"><title>Nov-21</title></rect>
<text x="0.5" y="0.5" fill="red">A<text>
</g>
<rect x="1" y="0" width="1" height="1"><title>Nov-22</title></rect>
<rect x="2" y="0" width="1" height="1"><title>Nov-23</title></rect>
<rect x="3" y="0" width="1" height="1"><title>Nov-24</title></rect>
<rect x="4" y="0" width="1" height="1"><title>Nov-25</title></rect>
<rect x="5" y="0" width="1" height="1"><title>Nov-26</title></rect></svg>
</div>
Here is a codepen with the result.
You have a very small custom viewport="0 0 6 1" size. 6px - width, 1px - height, so the font can not be displayed with such parameters.
I increased the size of the viewBox 100 times viewBox="0 0 600 100"
Squares for clarity painted in different colors. You can change their coloring according to your choice.
The text is placed inside the squares. I hope that's exactly what you wanted when you used the command
<title> Nov-24 </ title> inside the squares.
But the command <title> in SVG is a system tooltip, the information from which appears when you hover the cursor.
The size of the tooltip and its font can not be changed, so I added in the squares more tags <text> ... </ text>, the parameters of which you can change.
<div class="t_container">
<div class="t_x" style="position: relative;">
<svg position="absolute" viewBox="0 0 600 100" >
<g>
<rect x="0" y="0" width="100" height="40"><title>Nov-21</title></rect>
<text x="35" y="75" font-size="36" fill="red">A</text>
</g>
<rect x="100" y="0" width="100" height="100" fill="orange">
<title>Nov-22</title></rect>
<text x="125" y="55" font-size="18" fill="white">Nov-22</text>
<rect x="200" y="0" width="100" height="100" fill="orangered">
<title>Nov-23</title></rect>
<text x="225" y="55" font-size="18" fill="white">Nov-23</text>
<rect x="300" y="0" width="100" height="100" fill="green">
<title>Nov-24</title></rect>
<text x="325" y="55" font-size="18" fill="white">Nov-24</text>
<rect x="400" y="0" width="100" height="100" fill="dodgerblue">
<title>Nov-25</title></rect>
<text x="425" y="55" font-size="18" fill="white">Nov-25</text>
<rect x="500" y="0" width="100" height="100" fill="yellowgreen">
<title>Nov-26</title></rect>
<text x="525" y="55" font-size="18" fill="white">Nov-26</text>
</svg>
</div>
My svg looks very bad in Google Chrome and Firefox too, the Svg borders have poor quality:
Meanwhile, in Illustrator the svg looks awesome:
I have saved the .svg file with this configuration:
What is happened?
If your SVG has a lot of horizontal and/or vertical lines, you can improve its appearance by aligning the coordinates to the pixel grid. I'll give you an example:
Here are three SVG images made of rounded rectangles. (The source code for these images is pasted below.)
In (A), the rectangle coordinates aren't aligned to the pixel grid at all. As a result, some of the lines are clear and sharp while others are fuzzy and a bit darker.
In (B), the rectangle coordinates are snapped to integer values, giving them a uniform appearance. However, they all look fuzzy now, because the antialiasing spreads each line across a width of two pixels.
In (C), the coordinates are snapped to integer values and given an additional offset of 0.5 pixels in the x and y directions. You should be able to see a definite improvement here.
If you're working in Illustrator, try viewing your artwork at 100% in "Pixel Preview" mode.
I would also recommend not using stroke widths smaller than 1 pixel. If you want to simulate thinner lines, try reducing the opacity instead.
<svg width="200" height="150" viewBox="0 0 200 150">
<!-- (Original drawing) -->
<rect x="0" y="0" width="200" height="150" fill="#47f" stroke="none" />
<g fill="none" stroke="#fff" stroke-width="1.2">
<rect x="20.1" y="20.1" width="160" height="110" rx="50" ry="50"/>
<rect x="25.3071" y="25.3071" width="149.5857" height="99.5857" rx="44.7929" ry="44.7929"/>
<rect x="30.5143" y="30.5143" width="139.1714" height="89.1714" rx="39.5857" ry="39.5857"/>
<rect x="35.7215" y="35.7215" width="128.7571" height="78.7571" rx="34.3785" ry="34.3785"/>
<rect x="40.9286" y="40.9286" width="118.3428" height="68.3428" rx="29.1714" ry="29.1714"/>
</g>
<text x="100" y="80" text-anchor="middle" font-family="sans-serif" font-size="20" fill="#fff">(A)</text>
</svg>
<svg width="200" height="150" viewBox="0 0 200 150">
<!-- (Lines snapped to integer coordinates) -->
<rect x="0" y="0" width="200" height="150" fill="#47f" stroke="none" />
<g fill="none" stroke="#fff" stroke-width="1.2">
<rect x="20" y="20" width="160" height="110" rx="50" ry="50"/>
<rect x="25" y="25" width="150" height="100" rx="45" ry="45"/>
<rect x="30" y="30" width="140" height="90" rx="40" ry="40"/>
<rect x="35" y="35" width="130" height="80" rx="35" ry="35"/>
<rect x="40" y="40" width="120" height="70" rx="30" ry="30"/>
</g>
<text x="100" y="80" text-anchor="middle" font-family="sans-serif" font-size="20" fill="#fff">(B)</text>
</svg>
<svg width="200" height="150" viewBox="0 0 200 150">
<text x="100" y="80" text-anchor="middle" font-family="sans-serif" font-size="20" fill="#fff">(A)</text>
<!-- (Lines snapped to integer coordinates with 0.5px offset) -->
<rect x="0" y="0" width="200" height="150" fill="#47f" stroke="none" />
<g fill="none" stroke="#fff" stroke-width="1.2">
<rect x="20.5" y="20.5" width="160" height="110" rx="50" ry="50"/>
<rect x="25.5" y="25.5" width="150" height="100" rx="45" ry="45"/>
<rect x="30.5" y="30.5" width="140" height="90" rx="40" ry="40"/>
<rect x="35.5" y="35.5" width="130" height="80" rx="35" ry="35"/>
<rect x="40.5" y="40.5" width="120" height="70" rx="30" ry="30"/>
</g>
<text x="100" y="80" text-anchor="middle" font-family="sans-serif" font-size="20" fill="#fff">(C)</text>
</svg>
In your "bad" example, the SVG has been reduced to roughly half size. That means some of the lines that are approx 1 pixel thick in your "good" example are now only around 0.5 pixels thick. That doesn't give the anti-aliasing routines in the SVG renderer much to play with. Try making the stroke widths thicker.
You should get better results then.