Dynamically adapt a text to a path element in an SVG - svg

My SVG has shapes with different dimensions as below, and I would like my text to have a size adapted to the length of its associated shape (fill without overflow).
I tried font-size-adjust but no result and textLength lengthAdjust deforms my text, should i use textPath & href logic ?
Thank you for your help
<svg viewBox="0 0 220 220">
<g>
<path fill="orange" d="M30 110 L 20 110 L 20 20 L 30 10 L 40 20 L 40 110 Z"/>
<text font-size="1em" transform="rotate(-90, 30, 110)" x="30" y="110" dominant-baseline="middle">Object number 1</text>
</g>
<g>
<path fill="red" d="M 50 110 L 40 110 L 40 50 L 50 40 L 60 50 L 60 110 Z"/>
<text transform="rotate(-90, 50, 110)" x="50" y="110" dominant-baseline="middle">Object number 2</text>
</g>
<g>
<path fill="yellow" d="M 80 110 L 60 110 L 60 50 L 80 40 L 100 50 L 100 110 Z"/>
<text transform="rotate(-90, 80, 110)" x="80" y="110" dominant-baseline="middle">Object number 3</text>
</g>
</svg>
This is the rendering I would like to obtain:
The space between letters is why i don't want to use textLength :
My render here would be:

First method: tou can set the textLength of the text to be equal to the height of the path. Since your path has a tip I've opted for the 90% of the height. However if your path is much smaller than the text the text will apear crammed. To understand what I mean change the font-size to 3em
let pthHeight = pth.getBBox().height;
txt.setAttribute("textLength",pthHeight*.9 )
svg{width:50vh}
<svg viewBox="0 0 50 120">
<path fill="orange" id="pth" d="M30 110 L 20 110 L 20 20 L 30 10 L 40 20 L 40 110 Z"/>
<text id="txt" font-size="1em" transform="rotate(-90, 30, 110)" x="30" y="110" dominant-baseline="middle" lengthAdjust="spacingAndGlyphs">Object number 1</text>
</svg>
yet another solution would be changing the font size in a while loop till the text length is smaller than the height of the path. This assumes that the initial length of the text is longet than the height.
let pthHeight = pth.getBBox().height;
function setFontSize(txt){
let fs = txt.getAttribute("font-size");
let textLength = txt.getComputedTextLength();
let fontSize = txt.getAttribute("font-size");
while(textLength > pthHeight){
fontSize -= 1;
txt.setAttribute("font-size",fontSize);
textLength = txt.getComputedTextLength();
}
}
setFontSize(txt)
svg{width:50vh}
<svg viewBox="0 0 50 120">
<path fill="orange" id="pth" d="M30 110 L 20 110 L 20 20 L 30 10 L 40 20 L 40 110 Z"/>
<text id="txt" font-size="16" transform="rotate(-90, 30, 110)" x="30" y="110" dominant-baseline="middle" >Object number 1</text>
</svg>

Related

How to change the style of individual components of an SVG path?

The following code assigns the colour green to all the three lines of the SVG path.
<svg height="210" width="400">
<path d="M 150 0
L 75 200
L 225 200
L 150 0"
fill ="none" stroke="green" stroke-width="3" />
</svg>
Can I know how I can assign separate styles to each line?
In this case the solution would be using 3 different lines:
<svg height="210" width="400">
<g stroke-linecap="round" stroke-width="3" >
<path d="M 150 0
L 75 200" stroke="green"/>
<path d="M75 200
L 225 200" stroke="gold"/>
<path d="M225 200
L 150 0" stroke="red"/>
</g>
</svg>
It is not possible to have multiple styles within a single SVG path.

why this svg does not fill the screen?

why this svg does not fill the screen?
i just open "and_gate.svg" (svg below) with last version of firefox/chrome. it doesn't fill height of the screen. (I wrote height because this svg's width:26 height:32.)
<svg viewBox="0 0 26 32" xmlns="http://www.w3.org/2000/svg">
<path d="M 0 19 A 13 13 0 0 1 26 19 v 19 h -26 v -19 Z" fill="#000" />
</svg>
however if a svg that width:26 height:32 fills entire height of the screen. (svg below)
<svg viewBox="0 0 26 32" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="26" height="32" fill="#000" />
</svg>
If you combine the two it is clear your path leaves white.. ehm green space
The A(rc) goes from y=19 to y=13 , not to y=0 (top)
<svg viewBox="0 0 26 32" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="26" height="32" fill="green" />
<path d="M 0 19 A 13 13 0 0 1 26 19 v 19 h -26 v -19 Z" fill="#000" />
</svg>

SVG Error: Root Element Namespace does not Match that Requested

I am currently running into the following error when trying to load an SVG file into my java application using Apache's Batik library:
java.io.IOException: Root element namespace does not match that requested:
Requested: http://www.w3.org/2000/svg
Found: null
I know that this question was asked here, but the OP's solution was to remove an invalid element.
Does anyone know anything else on this error? Below is my svg file that is causing the exception:
<div id="MapMarker">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="41 -24 118 178" width="118" height="178" version="1.2" baseProfile="tiny">
<path fill="rgb(255, 128, 128)" fill-opacity="1" stroke="black" stroke-width="4" d="M 45 150 L 45 70 L 100 20 L 155 70 L 155 150" />
<path fill="rgb(255, 255, 128)" stroke="black" stroke-width="4" d="M 90 135 l 0 -10 l 5 -5 l 0 -55 l 5 -5 l 5 5 l 0 55 l 5 5 l 0 10 l -10 -10 Z" />
<text font-family="Arial" font-size="30" font-weight="bold" fill="black" stroke="none" stroke-width="4" text-anchor="middle" x="68" y="110">S</text>
<text font-family="Arial" font-size="30" font-weight="bold" fill="black" stroke="none" stroke-width="4" text-anchor="middle" x="132" y="110">A</text>
<g fill="none" stroke="black" stroke-width="4" transform="translate(0)">
<path d="M 100 10 L 100 -15" />
<path d="M 120 10 L 120 -15" />
<path d="M 80 10 L 80 -15" />
</g>
</svg>
</div>

SVG - arc animation jumping steps

I'm trying to make an svg animation for a path. The start result and the end result are fine, but for some reasons there are no intermediate positions (the animation just jumps from start to end after the duration.
This is the code I'm using:
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style>.cls-1{fill:none;stroke:#96cb61;stroke-linecap:round;stroke-linejoin:bevel;stroke-width:10px;}</style></defs><title>percentage-green</title>
<path
id="p1"
class="cls-1"
d="
M 20 40 A 20 20 0 1 0 40 20
"
/>
<animate xlink:href="#p1"
attributeName="d"
attributeType="XML"
from="M 20 40 A 20 20 0 1 0 40 20"
to="M 50 57.32050807568877 A 20 20 0 0 0 40 20"
dur="10s"
/>
</svg>
If I understand you correctly, despite the difficulties you want to do an arc animation.
Arc formula
<path d="M mx,my A rx,ry x-axis-rotation large-arc-flag, sweep-flag x,y" />
Large-arc-flag and sweep-flag are integer-constant, which take only two values of "0" or "1" and do not lend themselves to smooth animation.
You can make a discrete transition animation from a large arc when Large-arc-flag = 1 to a small arcLarge-arc-flag = 0
On the example below the location of the small arc is indicated by a red dashed line.
The coordinates of the beginning and end of the small and large arcs coincide, only the value of the flag `Large-arc-flag from" 1 "to" 0 "
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 300 300">
<defs>
<style>.cls-1{fill:none;stroke:#96cb61;stroke-linecap:round;stroke-linejoin:bevel;stroke-width:4px;}
</style>
</defs>
<title>percentage-green</title>
<g transform="scale(2)">
<path id="p1"
class="cls-1"
d="M 20 40 A 20 20 0 1 0 40 20">
<animate
attributeName="d"
attributeType="XML"
repeatCount="5"
begin="Layer_1.mouseover"
from="M 20 40 A 20 20 0 1 0 40 20"
to="M 20 40 A 20 20 0 0 0 40 20"
dur="2s" >
</animate>
</path>
<circle cx="40" cy="20" r="3" stroke="dodgerblue" fill="none" />
<path d="M 20 40 A 20 20 0 0 0 40 20" stroke-dasharray="3" stroke="red" fill="none" />
</g>
</svg>
Animation begins when you hover the cursor
The second example
Is similar to yours - the parameter "d" of the patch will change smoothly, with the constant value of large-arc-flag = 1 (large arc)
Animation begins when you hover the cursor
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 300 300">
<defs>
<style>.cls-1{fill:none;stroke:#96cb61;stroke-linecap:round;stroke-linejoin:bevel;stroke-width:4px;}
</style>
</defs>
<title>percentage-green</title>
<g transform="scale(2)">
<path id="p1"
class="cls-1"
d="M 20 40 A 20 20 0 1 0 40 20">
<animate xlink:href="#p1"
attributeName="d"
attributeType="XML"
repeatCount="5"
values="M 20 40 A 20 20 0 1 0 40 20;M 50 57 A 20 20 0 1 0 40 20;M 20 40 A 20 20 0 1 0 40 20"
begin="Layer_1.mouseover"
dur="3s"
restart="whenNotActive" >
</animate>
</path>
<circle cx="40" cy="20" r="4" stroke="dodgerblue" fill="none" />
<path d="M 50 57 A 20 20 0 1 0 40 20" stroke-dasharray="3" stroke="red" fill="none" />
</g>
</svg>

can I close an SVG path without using a z parameter?

Can I just finish a path where I started it and it will be considered closed or does the Z command have to be used?
For example, is this
path d="M150 0 L75 200 L225 200 L150 0" stroke="black" fill="none"
the same as this
path d="M150 0 L75 200 L225 200 Z" stroke="black" fill="none"
or are there two points on same spot (150, 0) in the first and the second example?
There is a slight difference. If a path isn't closed, then you are liable to see missing pixels at the corner where the two ends of the path meet. Here's an example:
<svg width="360" height="100" viewBox="0 0 360 100">
<g stroke-width="20" fill="none">
<path d="m10 10h80v80h-80v-80" stroke="#f00" stroke-linecap="butt" />
<path d="m130 10h80v80h-80v-80" stroke="#0a0" stroke-linecap="square" />
<path d="m250 10h80v80h-80z" stroke="#04f" />
</g>
</svg>
The path on the left is open, and since the two vertices at the top left are unconnected, you can see a gap where the two line caps overlap. This can be fixed by adding stroke-linecap="square" to the svg markup, but in most situations it would make more sense to use a closed path, as shown on the right.
Edit:
For curved shapes where you don't want a straight-line segment between the start and end points of the path, just put the start and end points in the same place. If your tangents are aligned in the same direction, it probably doesn't matter if you leave leave the path open unless you have the stroke-linecap set to butt, in which case the end sections will be liable to project away from the path slightly. For example:
<svg width="160" height="160" viewBox="-80 -80 160 160">
<path d="M0 70C20 70 0 40 20 20 40 0 70 20 70 0 70-20 40 0 20-20 0-40 20-70 0-70-20-70 0-40-20-20-40 0-70-20-70 0-70 20-40 0-20 20 0 40-20 70 0 70" fill="#fcc" stroke="#f00" stroke-width="20" stroke-linecap="square"/>
</svg>
<svg width="160" height="160" viewBox="-80 -80 160 160">
<path d="M0 70C20 70 0 40 20 20 40 0 70 20 70 0 70-20 40 0 20-20 0-40 20-70 0-70-20-70 0-40-20-20-40 0-70-20-70 0-70 20-40 0-20 20 0 40-20 70 0 70z" fill="#afa" stroke="#0a0" stroke-width="20" stroke-linecap="square"/>
</svg>
If you look closely, you can see some slight blockiness at the bottom of the red shape where the line caps extend past each other. The green shape has a closed curve, so there are no line caps to worry about.
■ Addendum:
Just landed back on this page after a few days, and it looks like Chrome has been updated in the meantime (currently using Chrome version 53.0.2785.116/64 bit on OS X). It now seems that open paths are closed automatically if the start and end points are coincident within a small margin of error.
Here's that first graphic again, but with three open paths where the start and end points are separated by 0.1px, 0.001px and 0.00001px respectively (from left to right):
<svg width="360" height="100" viewBox="0 0 360 100">
<g stroke-width="20" fill="none">
<path d="m10 10h80v80h-80v-79.99" stroke="#f00" stroke-linecap="butt" />
<path d="m130 10h80v80h-80v-79.9999" stroke="#0a0" stroke-linecap="butt" />
<path d="m250 10h80v80h-80v-79.999999" stroke="#04f" stroke-linecap="butt" />
</g>
</svg>
I'm not sure I agree with this behaviour. It's liable to cause glitchiness with animated paths:
<svg width="120" height="120" viewBox="0 0 120 120">
<path id="p" d="M10 10 110 10 110 110 10 110 10 10" stroke="#f00" fill="none" stroke-width="20" />
<animate xlink:href="#p" attributeName="d" attributeType="XML" from="M9.99999 9.99999 110 10 110 110 10 110 10 10" to="M10.00001 10.00001 110 10 110 110 10 110 10 10" dur="1s" fill="freeze" repeatCount="indefinite" />
</svg>
Adding Z command at the end of path or adding the starting point at the end of the path is essentially doing the same thing.And it does not add an extra point on the same spot.It just joins the points.

Resources