SVG: right-align text at the end of a textPath - html

I'd like to right-lign text at the end of a textPath:
<svg height="300" width="400">
<defs>
<path id="myTextPath" d="M30,160 A175,175 0 0,1 370,160" />
</defs>
<path d="M30,160 A175,175 0 0,1 370,160" style="stroke: black; stroke-width:1; fill:none;" />
<g fill="black" stroke="none">
<text x="0%" y="0" text-anchor="start">
<textPath xlink:href="#myTextPath">Start</textPath>
</text>
<text x="50%" y="0" text-anchor="middle">
<textPath xlink:href="#myTextPath">Middle</textPath>
</text>
<text x="100%" y="0" text-anchor="end">
<textPath xlink:href="#myTextPath">End</textPath>
</text>
</g>
</svg>
You can see this working here: http://jsfiddle.net/7sqdxw11/
The Start text begins right where I'd expect - at the beginning of the textPath.
However, the end text ends well short of the end of the textPath.
(The Middle is also well shy of the middle of the textPath).
Here's a screenshot:
What am I doing wrong? How to I get the End to end at the right end of the textPath arc?

In SVG percentage coordinates generally refer to the either the width of the SVG, or in some cases the width of the parent object.
So in your example the "100%" will result in a value of 400px - the width of your SVG. However your path actually has a length of 466. You can get the length by experimentation, or by using some Javascript:
var len = document.getElementById("myTextPath").getTotalLength();
So if you change the "100%" to "466" you get the effect you wanted.
<svg height="300" width="400">
<defs>
<path id="myTextPath" d="M30,160 A175,175 0 0,1 370,160" />
</defs>
<path d="M30,160 A175,175 0 0,1 370,160" style="stroke: black; stroke-width:1; fill:none;" />
<g fill="black" stroke="none">
<text x="0" y="0" text-anchor="start">
<textPath xlink:href="#myTextPath">Start</textPath>
</text>
<text x="233" y="0" text-anchor="middle">
<textPath xlink:href="#myTextPath">Middle</textPath>
</text>
<text x="466" y="0" text-anchor="end">
<textPath xlink:href="#myTextPath">End</textPath>
</text>
</g>
</svg>

Related

How to vertically center a character within a svg path?

I have an svg path with a text and a character like this:
<svg id="svg1" style="overflow:visible">
<path id="path1" stroke="black" d="M 0 50 L 100 50" stroke-width="10" />
<text text-anchor="middle" dy="-30" >
<textPath href="#path1" startOffset="50%" fill="red">Shape</textPath>
<textPath href="#path1" startOffset="50%" fill="red" dominant-baseline="central" >
<tspan font-size="30" dy="-5">⬤</tspan>
</textPath>
</text>
</svg>
And I want the circle (or any character in general) to align perfectly at the center of the line regardless of font-size or any other attribute
I tried changing dy but it's really isn't a universal solution.
Here's what it looks like for different browsers:
for font-size="50" in firefox
for font-size="50" in Brave
for font-size="10" in firefox & Brave
So how do I universally align the character to the vertical center for any given style and/or attribute?
Edit
as mentioned in the comments, I tried this solution but it really doesn't solve the problem for varying font-size nor does it perfectly align to the center cross browser
<svg id="svg1" style="overflow:visible">
<path id="path1" stroke="black" d="M 0 50 L 100 50" stroke-width="10" />
<text text-anchor="middle" dy="-30" >
<textPath href="#path1" startOffset="50%" fill="red">Shape</textPath>
<textPath href="#path1" startOffset="50%" fill="red" dominant-baseline="central"
alignment-baseline="central">
<tspan font-size="30" dy="-5">⬤</tspan>
</textPath>
</text>
</svg>
Unfortunately, there is no reliable way to center text vertically.
Firefox and chrome will interpret dominant-baseline quite differently.
For a consistent rendering, you could use some javaScript.
This approach also requires to measure some character/glyph proportions to calculate an ideal baseline shift.
So we need to get a ratio between font size and character height.
E.g write a capital in Arial at 100 points in inkscape, Illustrator etc. and convert it to paths/outlines and check it's height: 71.582 pt
So the capital to font-size ratio is: 100/71.582 = 0.71582
Example 1: emulate dominant-baseline:central; font-size 10 and 20
<style>
svg{
height:90vmin;
border:1px solid #ccc
}
</style>
<svg viewBox="0 0 50 20">
<line x1="0" x2="100%" y1="50%" y2="50%" stroke="#000" stroke-width="10" /></line>
<text font-size="10" style="font-family:Arial" x="0" y="50%" fill="red" dy="3.5791">I⬤</text>
<text font-size="20" style="font-family:Arial" x="20" y="50%" fill="red" dy="7.1582">I⬤</text>
</svg>
The dy values are calculated like so:
10 (1. font-size) * 0.71582 (capheight ratio) / 2 = 3.5791
20 (2. font-size) * 0.71582 (capheight ratio) / 2 = 7.1582
The bad news: you need to get different ratios for each type of character e.g lowercase letters.
Albeit, it might be enough to check the x-height for lowercase characters.
Example 2: save ratios to data-attribute; calculate dy via js
let texts = document.querySelectorAll('text');
texts.forEach(function(text){
let offsetRatio = parseFloat(text.getAttribute('data-offsetratio'));
let style = window.getComputedStyle(text);
let fontSize = parseFloat(style.fontSize);
let dy = fontSize * offsetRatio /2;
text.setAttribute('dy', dy );
})
svg{
width:100%;
border:1px solid #ccc
}
<svg id="svg1" style="overflow:visible" viewBox="0 30 100 40">
<path id="path1" stroke="black" d="M 0 50 L 100 50" stroke-width="10" />
<path id="path2" stroke="#fff" d="M 0 50 L 100 50" stroke-width="0.25" />
<g font-size="10" style="font-family:Arial,Georgia,'Segoe UI'">
<text data-offsetratio="0.71582" x="0" y="50" fill="red">I⬤</text>
<text data-offsetratio="0.51855" x="15" y="50" fill="red">x</text>
</g>
<g font-size="25" style="font-family:Arial,Georgia,'Segoe UI'">
<text data-offsetratio="0.71582" x="30" y="50" fill="red">I⬤</text>
<text data-offsetratio="0.56409" x="60" y="50" fill="red">●</text>
<text data-offsetratio="0.70081" x="75" y="50" fill="red">•</text>
</g>
</svg>
Vertically aligning a text is done using dominant-baseline, but you can see from this example that it is not easy to do. Here I align ⬤Gga using the values middle and central.
I added a viewBox to <svg> so that it is easier to control the position. But I guess it all depends on the font used.
<svg overflow="hidden" viewBox="0 0 100 65" width="250">
<rect width="100" height="65" fill="#eee" />
<path id="path1" stroke="black" d="M 0 50 L 100 50" stroke-width="10" />
<text text-anchor="middle" dy="-30" fill="red">
<textPath href="#path1" startOffset="50%">Shape</textPath>
<textPath href="#path1" startOffset="50%" dominant-baseline="middle" font-size="30">⬤Gga</textPath>
</text>
</svg>
<svg overflow="hidden" viewBox="0 0 100 65" width="250">
<rect width="100" height="65" fill="#eee" />
<path id="path1" stroke="black" d="M 0 50 L 100 50" stroke-width="10" />
<text text-anchor="middle" dy="-30" fill="red">
<textPath href="#path1" startOffset="50%">Shape</textPath>
<textPath href="#path1" startOffset="50%" dominant-baseline="central" font-size="30">⬤Gga</textPath>
</text>
</svg>

SVG text not horizontally center aligning

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!

How to display the text the was cropped at end using svg of specified width

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>

SVG curved text along a circle clip path element not displaying

Here's a link to my codepen: https://codepen.io/Bryandbronstein/pen/QVaQpa
So basically what I have is an svg circle set as a clipPath element to cut my image into a circle. Then I want to curve my text around the circle, rather than it being in a straight line on top of my circular image, like this:
image with curved text
The thing is, I have this image to show off as my example because this code works in Firefox, but no other browser I could test. What gives?
Here's my code:
<svg height="300" width="350">
<defs>
<clipPath id="circleView">
<circle id="curve" cx="150" cy="180" r="110" fill="transparent" />
</clipPath>
</defs>
<text x="390" y="-20" width="100">
<textpath id="homepageText" xlink:href="#curve">
My Homepage!
</textpath>
</text>
<image width="300" height="410" xlink:href="meee.jpg" clip-path="url(#circleView)" />
</svg>
Just to clarify, I have moderate experience in HTML and CSS but very little in SVG. Thank you!
Use path insted of circle, and text-anchor + startOffset to center the text:
<svg x="0px" y="0px" width="350" height="300" viewBox="0 0 350 300">
<defs>
<path id="curve" d="M40,180c0-60.751,49.248-110,110-110c60.751,0,110,49.249,110,110"/>
</defs>
<text fill="black" class="curved-text">
<textPath xlink:href="#curve" text-anchor="middle" startOffset="50%">My homepage!</textPath>
</text>
</svg>
Working Codepen.
Using svg path tag we can achieve curved text. Below is the modification to your code. Corrected x and y for text tag and have added path with id "forText.
<svg height="300" width="350">
<defs>
<clipPath id="circleView">
<circle id="curve" cx="150" cy="180" r="110" fill="transparent" />
</clipPath>
</defs>
<path id="forText" d="M32,110, C25,90, 180,-39,290,130" stroke="" fill="none"/>
<text x="0" y="35" width="100">
<textpath xlink:href="#forText">
My Homepage!
</textpath>
</text>
<image width="300" height="410" xlink:href="meee.jpg" clip-path="url(#circleView)" />
</svg>

Multiple lines in HTML circle?

I would like to write multiple lines in this circles without css, but only if it's needed style tag.
Here's the code:
<svg height="300" width="300">
<circle cx="150" cy="150" r="120" stroke="red" stroke-width=4 fill="#ffffff" />
<text x="50%" y="50%" text-anchor="middle" stroke="#000000" stroke-width="1px" dy=".3em">My code<br/>isn't good</text>
</svg>
Thank you!
this is the best i was able to do. It works but its hardcoded which obviously is not ideal. I looked at this other post btw, might be of some help: How to linebreak an svg text within javascript?
<svg height="300" width="300">
<circle cx="150" cy="150" r="120" stroke="red" stroke-width=4 fill="#ffffff" />
<text text-anchor="middle" stroke="#000000" stroke-width="1px" dy=".3em">
<tspan x="50%" y="40%" dy="1.2em">very long text</tspan>
<tspan x="50%" y="50%" dy="1.2em">I would like to linebreak</tspan>
</text>
</svg>