I want to create a circular path with multiple "Holes" in it, preferably without using masks and the like.
Currently, what I've got is this:
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600" viewBox="0 0 400 400">
<path d="M 100 100 A 90 90 0 1 0 200 100 M 110 90 A 90 90 0 0 1 190 90" stroke="#424242" stroke-width="5" fill="transparent" />
</svg>
As you can see, this relies on manually moving the start of the new arc, which results in the arc being off.
I'd rather not have to do a lot of math to get the position for the move just right, so is there a sort of "Arc move" I can use?
If not, how does the math for this work (I'm very rusty in geometry stuff)
The simplest way to achieve what you want is probably just to use a dash array.
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600" viewBox="0 0 400 400">
<path d="M 100 100 A 90 90 0 1 0 200 100 M 110 90 A 90 90 0 0 1 190 90" stroke="#424242" stroke-width="5" fill="transparent" />
<path d="M 60 175 A 90 90 0 0 1 240 175 A 90 90 0 0 1 60 175" stroke="red" stroke-width="5" fill="transparent" stroke-dasharray="88 14 78 14 372"/></svg>
Related
How can I draw half of ellipse in SVG? What I'm trying to do
<path d="M 198, 160 a 50,20 1 1,0 1,0" fill="pink" style="fill:pink;stroke:black;stroke-width:1;"/>
You already found the right command for your path; the elliptical arc curve.
In these examples I created half-ellipses with the same dimensions. You can see the two numbers after the A are all 10 and 2. 10 is the x radius and 2 the y radius. The two numbers after M are all stating points and the two numbers just before Z are the end points. The three numbers in between (0 0 0 and 0 0 1) are different flags. The only one I use here is the sweep-flag that indicates clockwise or anticlockwise.
A usefull tool that I use a lot for creating paths is this: SvgPathEditor.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 8">
<path transform="translate(0 0)" fill="blue" d="M 10 0 A 10 2 0 0 0 10 4 Z"/>
<path transform="translate(10 0)" fill="pink" d="M 0 0 A 10 2 0 0 1 0 4 Z"/>
<path transform="translate(0 4)" fill="orange" d="M 0 2 A 10 2 0 0 1 20 2 Z"/>
<path transform="translate(0 6)" fill="lime" d="M 0 0 A 10 2 0 0 0 20 0 Z"/>
</svg>
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 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.
I would like to know how to highlight (change the color) a self overlapping zone of an SVG path (or even polyline). Actually, if i change the opacity and stroke property of a path the self ovverlaping zone has no change in color.
For example, having the following path <path d="M187 240 L188 240 L315 217 L317 217 L330 306 L247 233 L258 226 L292 222 L303 178 L353 165" fill="none" opacity="0.6" stroke-width="14" stroke = "red"/>, the overlapping zone is not red-dark.
Here is what i've found so far but doesn't help me with the issue.
http://www.svgopen.org/2005/papers/abstractsvgopen/index.html#S2.
thanks
Messing with opacity won't help as the path is rendered in one pass and it doesn't matter how many times it overlaps itself. All that matters is whether the pixel is considered "inside" the path stroke, or not. If it is, it is given the final line colour and opacity.
There is basically no good simple solution to your problem as far as I can see. The closest you can get is to draw all of the individual line segment individually. That way your opacity trick will highlight the overlaps (use stroke-opacity rather than opacity), but the joins between the line segments won't look very good. They'll have gaps, and you will see the overlap effects there as well.
<svg width="500" height="500" fill="none" stroke-opacity="0.6" stroke-width="14" stroke = "red">
<path d="M187 240 L188 240" />
<path d="M188 240 L315 217" />
<path d="M315 217 L317 217" />
<path d="M317 217 L330 306" />
<path d="M330 306 L247 233" />
<path d="M247 233 L258 226" />
<path d="M258 226 L292 222" />
<path d="M292 222 L303 178" />
<path d="M303 178 L353 165" />
</svg>
The only good solution would be to determine the overlap mathematically and then generate "overlap polygons" of the correct shape. That is a rather tricky bit of code.
Here's a version that works for you (although it makes the lines a bit crispier than we'd like). It takes what Paul has suggested, but improves it by using 2-segment lines so the line joins are rendered correctly, then it uses a filter to select and recolor the high opacity areas that overlap. The table values are set exactly to select in just the true overlap and select out the small overlap artifacts caused at line joins by the fact that we're double-drawing. You could probably add a very small blur to "hand anti-alias" the final line.
<svg width="800px" height="600px" viewBox= "0 0 800 600">
<defs>
<filter id="overlappy">
<feComponentTransfer result="overlap">
<feFuncA type="table" tableValues="0 0 0 0 0 0 0 0 1"/>
</feComponentTransfer>
<feColorMatrix in="overlap" result="solid-blue" type="matrix" values ="0 0 0 0 0
0 0 0 0 0
0 0 0 0 1
0 0 0 4 0"/>
<feColorMatrix in="SourceGraphic" result="opaque-source" type="matrix"
values ="1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 4 0"/>
<feComposite operator="atop" in="solid-blue" in2="opaque-source"/>
</filter>
</defs>
<g filter="url(#overlappy)" fill="none" stroke="red" stroke-width="4" stroke-opacity="0.5">
<path d="M187 240 L188 240 L315 217" />
<path d="M188 240 L315 217 L317 217" />
<path d="M315 217 L317 217 L330 306" />
<path d="M317 217 L330 306 L247 233"/>
<path d="M330 306 L247 233 L258 226" />
<path d="M247 233 L258 226 L292 222" />
<path d="M258 226 L292 222 L303 178" />
<path d="M292 222 L303 178 L353 165" />
<path d="M303 178 L353 165" />
</g>
</svg>
How I can draw a SVG path with a repeated symbol along the path ?
An example in this picture :
http://i.stack.imgur.com/jqy0Z.png
Thanks a lot !
You can use a <marker> element to place a symbol at each vertex of a polyline. This has the advantage that the symbols can be automatically aligned to the path direction. However, you will still have to place each vertex there yourself. I don't think there is any way of having a symbol repeat automatically at a fixed interval along a path.
<svg width="400" height="100" viewBox="0 0 400 100">
<defs>
<marker id="chevron"
viewBox="0 0 20 20" refX="10" refY="10"
markerUnits="userSpaceOnUse"
markerWidth="20" markerHeight="20"
orient="auto" fill="#49f">
<path d="M0 0 10 0 20 10 10 20 0 20 10 10Z" />
</marker>
</defs>
<path d="M40 50 60 59.57 80 67.68 100 73.1 120 75 140 73.1 160 67.68 180 59.57 200 50 220 40.43 240 32.32 260 26.9 280 25 300 26.9 320 32.32 340 40.43 360 50"
fill="none" stroke="none"
marker-start="url(#chevron)"
marker-mid="url(#chevron)"
marker-end="url(#chevron)" />
</svg>