svg SMIL animation transform origin question - svg

I cannot figure out where to put the transform origin and with what values at the second path (#tran) to resemble the first path (#drop). I want them both to move the same way. The path #tran is the one that I need to behave like the smooth d-animated #drop. Here is the code:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<defs>
<path id="drop">
<animate attributeName="d" begin="0s" dur="3s" values="M 50 0 Q 48 4 50 4 Q 52 4 50 0 Z; M 50 10 Q 48 6 50 6 Q 52 6 50 10 Z; M 50 0 Q 48 4 50 4 Q 52 4 50 0 Z;" repeatCount="indefinite"/>
</path>
<path id="tran" d="M 50 0 Q 48 4 50 4 Q 52 4 50 0 Z" transform="translate(4,0)"/>
</defs>
<use href="#drop"/><!--this is correct-->
<use href="#tran" ><!--this one to behave like the one above (#drop)-->
<animateTransform
attributeName="transform"
attributeType="XML"
type="scale"
values="1 1;1 -1; 1 1"
dur="3s"
repeatCount="indefinite" /><!--transform-origin here? what values-->
<animateTransform
attributeName="transform"
attributeType="XML"
type="translate"
values="0 0; 0 -10; 0 0"
dur="3s"
repeatCount="indefinite" additive="sum"/><!--transform-origin here? what values-->
</use>
</svg>
I tried putting origin-transform all over the place, including css madness - but i prefer non-css - seems transform-origin does not work inside the animate tags. Okay, in a few days I might figure out the values with keysplines or something but I want a neat solution with few calculations. I'm trying to build a whole animation with a mandala being built rotated and mirrored so I need clean logic with as little math as possible -no javascript-.

Related

SVG filter on a path with userSpaceOnUse and a large filter region, my path still gets clipped

I'm using an SVG filter that I want to use on paths.
Since my path could be straight lines, I'm using userSpaceOnUse for the filter unit. To make sure that the path doesn't get clipped I make sure that my filter region is large enough.
<svg width="200px" height="200px" viewbox="0 0 200 200">
<defs>
<filter filterUnits="userSpaceOnUse" id="dark" x="0" y="0" width="200" height="200">
<feColorMatrix type="matrix" values="0.2 0 0 0 0, 0 .2 0 0 0, 0 0 0.2 0 0, 0 0 0 1 0" />
</filter>
</defs>
<path transform="translate(100,100)" d="M3.989422804014327,0A3.989422804014327,3.989422804014327,0,1,1,-3.989422804014327,0A3.989422804014327,3.989422804014327,0,1,1,3.989422804014327,0" transform="translate(0,12)" fill-opacity="0.4" fill="hsl(207,59%,56%)" stroke="hsl(207,59%,56%)" filter="url(#dark)" stroke-width="1" stroke-opacity="1" />
<path d="M 10 10 H 90 V 90 H 10 L 10 10" fill-opacity="0.4" stroke="hsl(207,59%,56%)" filter="url(#dark)" fill="hsl(207,59%,56%)" stroke-width="1" stroke-opacity="1"/>
<path d="M 10 10 H 90 V 90 H 10 L 10 10" transform="translate(100,100)" fill-opacity="0.4" stroke="hsl(207,59%,56%)" filter="url(#dark)" fill="hsl(207,59%,56%)" stroke-width="1" stroke-opacity="1"/>
</svg>
The filter is applied on the three paths: the two squares and the circle. However the circle gets clipped.
If I use objectBoundingBox the circle is rendered entirely. However this is not an option because I also want to use the filter on straight lines that have no dimensions.
If I play around with x and y of the filter, like -10 for both for instance, it works fine as well.
Is there something wrong with my filter region? My understanding is that it covers the SVG entirely so anything that uses the filter should not be cropped.
Or this is a use case not supported by userSpaceOnUse that I'm not aware ?
change the translate to (0,0) instead of (100,100) see how the shape is off the canvas.
<svg width="200px" height="200px" viewbox="0 0 200 200">
<defs>
<filter filterUnits="userSpaceOnUse" id="dark" x="0" y="0" width="200" height="200">
<feColorMatrix type="matrix" values="0.2 0 0 0 0, 0 .2 0 0 0, 0 0 0.2 0 0, 0 0 0 1 0" />
</filter>
</defs>
<path transform="translate(0,0)" d="M3.989422804014327,0A3.989422804014327,3.989422804014327,0,1,1,-3.989422804014327,0A3.989422804014327,3.989422804014327,0,1,1,3.989422804014327,0" transform="translate(0,12)" fill-opacity="0.4" fill="hsl(207,59%,56%)" stroke="hsl(207,59%,56%)" filter="url(#dark)" stroke-width="1" stroke-opacity="1" />
<path d="M 10 10 H 90 V 90 H 10 L 10 10" fill-opacity="0.4" stroke="hsl(207,59%,56%)" filter="url(#dark)" fill="hsl(207,59%,56%)" stroke-width="1" stroke-opacity="1"/>
<path d="M 10 10 H 90 V 90 H 10 L 10 10" transform="translate(100,100)" fill-opacity="0.4" stroke="hsl(207,59%,56%)" filter="url(#dark)" fill="hsl(207,59%,56%)" stroke-width="1" stroke-opacity="1"/>
</svg>
Translating it doesn't change that it's drawn above and left of the filter area originally. We could move the filter by changing its x and y values to fix that...
<svg width="200px" height="200px" viewbox="0 0 200 200">
<defs>
<filter filterUnits="userSpaceOnUse" id="dark" x="-10" y="-10" width="200" height="200">
<feColorMatrix type="matrix" values="0.2 0 0 0 0, 0 .2 0 0 0, 0 0 0.2 0 0, 0 0 0 1 0" />
</filter>
</defs>
<path transform="translate(100,100)" d="M3.989422804014327,0A3.989422804014327,3.989422804014327,0,1,1,-3.989422804014327,0A3.989422804014327,3.989422804014327,0,1,1,3.989422804014327,0" transform="translate(0,12)" fill-opacity="0.4" fill="hsl(207,59%,56%)" stroke="hsl(207,59%,56%)" filter="url(#dark)" stroke-width="1" stroke-opacity="1" />
<path d="M 10 10 H 90 V 90 H 10 L 10 10" fill-opacity="0.4" stroke="hsl(207,59%,56%)" filter="url(#dark)" fill="hsl(207,59%,56%)" stroke-width="1" stroke-opacity="1"/>
<path d="M 10 10 H 90 V 90 H 10 L 10 10" transform="translate(100,100)" fill-opacity="0.4" stroke="hsl(207,59%,56%)" filter="url(#dark)" fill="hsl(207,59%,56%)" stroke-width="1" stroke-opacity="1"/>
</svg>

Why does the marker-start in my SVG path not show in the browser (but in the generated PNG)?

Can someone please tell me, why the left arrow head in the following file shows correctly in the generated PNG, but not in the browser?
https://commons.wikimedia.org/wiki/File:SVG_double_arrow_with_marker-start_and_marker-end.svg
In Firefox it is just not there, and in Chrome I see it pointing to the bottom right instead of left.
These are the two markers:
<marker id="arrowend" viewBox="0 0 13 10" refX="2" refY="5" markerWidth="3.5" markerHeight="3.5" orient="auto">
<path d="M 0 0 C 0 0, 3 5, 0 10 L 0 10 L 13 5" fill="red"/>
</marker>
<marker id="arrowstart" viewBox="0 0 -13 -10" refX="-2" refY="-5" markerWidth="-3.5" markerHeight="-3.5" orient="auto">
<path d="M 0 0 C 0 0, -3 -5, 0 -10 L 0 -10 L -13 -5" fill="red"/>
</marker>
My solution based on the hint below:
<marker id="arrowstart" viewBox="0 0 13 10" refX="11" refY="5" markerWidth="3.5" markerHeight="3.5" orient="auto">
<path d="M 13 0 C 13 0, 10 5, 13 10 L 13 10 L 0 5" fill="red"/>
</marker>
So I changed the actual path. All my attempts to just mirror it failed, so for me this was the best solution.
This is where I put it in action, BTW: https://commons.wikimedia.org/wiki/Category:Full_octahedral_group;_single_elements;_signed_perm_mat,_perm_mat_and_cube
A viewBox with negative width and height is invalid. The contents of invalid viewBoxes do not render.
If Chrome renders arrowstart in any way, that's a Chrome bug. Whatever png generator you're using is clearly also buggy.
Here's one way to get the arrows on both ends, at least on browsers that support orient="auto-start-reverse"
<svg width="500" height="300" viewBox="0 0 200 50">
<defs>
<marker id="arrow" viewBox="0 0 13 10" refX="2" refY="5" markerWidth="3.5" markerHeight="3.5" orient="auto-start-reverse">
<path d="M 0 0 C 0 0, 3 5, 0 10 L 0 10 L 13 5" fill="red"/>
</marker>
</defs>
<line x1="25" y1="25" x2="175" y2="25" stroke="red" stroke-width="5" marker-start="url(#arrow)" marker-end="url(#arrow)"/>
</svg>

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.

Twice-interrupted circular path in SVG

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>

Resources