I wanted to animate some paths one after another automatically using animate's begin attribute:
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="500"
height="500"
viewBox="0 0 20 20">
<path d="M10,10 m0,-5 a5,5 0 0,1 5,5 a5,5 0 0,1 -5,5 a5,5 0 0,1 -5,-5 a5,5 0 0,1 5,-5 z" fill="green">
<animate attributeName="fill" from="green" to="white" begin="0s" dur="1s" fill="freeze" />
<animate attributeName="fill" from="white" to="blue" begin="prev.end" dur="1s" fill="freeze" />
</path>
</svg>
But it seems that the prev.end on the second animation is not working. When I rewrite the animations as below and refer to the first one by ID, it does work.
<animate id="first"
attributeName="fill"
from="green"
to="white"
begin="0s"
dur="1s"
fill="freeze" />
<animate
attributeName="fill"
from="white"
to="blue"
begin="first.end"
dur="1s"
fill="freeze" />
The reason I would like to use prev.end to sync my animations, is because I am generating these animations automatically in JavaScript. Number and order of animations are variable, which makes the use of IDs more difficult for me.
Related
As the title suggests, i'm trying to create an animation in svg with a point/circle that follows an irregular path. I am using the animateTransform, for example:
<animateTransform attributeName="transform"
attributeType="XML"
type="translate"
from="0 60 70"
to="360 60 70"
dur="10s"
repeatCount="definite"/>
Can i implement this method (in svg) to let the circle to follow the path, or i have to use necessarily javascript?
If i can do it in svg could you give me a basic example with an explanation?
You can use the <animateMotion> element.
Example adapted from MDN:
<svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg">
<path id="path" fill="none" stroke="lightgrey"
d="M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z" />
<circle r="5" fill="red">
<animateMotion dur="10s" repeatCount="indefinite">
<mpath xlink:href="#path"/>
</animateMotion>
</circle>
</svg>
Trying to animate an SVG element with the skewX. It works, however, not exactly the way I want it to.
Now: the bottom part moves to the left
Goal: the upper part should move to the right instead (and bottom stays in place)
I tried with transform-origin but it didn't work. Any ideas how to solve this mystery?
<svg xmlns="http://www.w3.org/2000/svg" width="102" height="102" viewBox="-50 -50 102 102">
<g>
<rect width="10%" height="50%"
style="fill:none; stroke:red; stroke-with:3;">
<animateTransform
attributeName="transform"
attributeType="XML"
type="skewX"
from="0"
to="-20"
begin="0.5s"
dur="0.2s"
repeatCount="1"
fill="freeze"
id="fallen"/>
</rect>
</g>
</svg>
Use another transform to move the whole thing to the right at the same time as the bottom moves left.
<svg xmlns="http://www.w3.org/2000/svg" width="102" height="102" viewBox="-50 -50 102 102">
<g>
<rect width="10%" height="50%"
style="fill:none; stroke:red; stroke-with:3;">
<animateTransform
attributeName="transform"
attributeType="XML"
type="skewX"
from="0"
to="-20"
begin="0.5s"
dur="0.2s"
repeatCount="1"
fill="freeze"
id="fallen"/>
<animateTransform
attributeName="transform"
attributeType="XML"
type="translate"
from="0"
to="20"
begin="0.5s"
dur="0.2s"
repeatCount="1"
fill="freeze"
additive="sum"/>
</rect>
</g>
</svg>
Hi I have an SVG which is 5 arrow shapes stacked. I am wanting to fade in each arrow from the bottom up. When the top arrow has faded in, I want the first one to fade out, then the second etc. And then start the animation again by fading in each arrow.
Here is a code pen of the SVG code:
https://codepen.io/anon/pen/gyJZEy
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 122.91 110.38">
<defs>
<style>.hg{fill:#ee2330;opacity:0}</style>
</defs>
<g id="Layer_2" data-name="Layer 2">
<g id="Layer_1-2" data-name="Layer 1">
<rect>
<animate id="hg0" begin="0;hg0.end" dur="8s"
attributeName="visibility" from="hide" to="hide"/>
</rect>
<path class="hg" d="M61.65 86.78l-.16-.06L0 109.38v.99l61.49-22.65 61.43 22.66v-.99L61.65 86.78z">
<animate id="hg1" attributeName="opacity" values="0;1;0" dur="4s" begin="hg0.begin;hg0.end" repeatCount="indefinite"/>
</path>
<path class="hg" d="M0 87.69v1.49l61.49-22.66 61.43 22.67v-1.48L61.49 65.04 0 87.69z">
<animate id="hg2" attributeName="opacity" values="0;1;0" dur="4s" begin="hg0.begin+1s;hg0.end+1s" repeatCount="indefinite"/>
</path>
<path class="hg" d="M0 66.05v1.97l61.49-22.66 61.43 22.67v-1.97L61.49 43.39 0 66.05z">
<animate id="hg3" attributeName="opacity" values="0;1;0" dur="4s" begin="hg0.begin+2s;hg0.end+2s" repeatCount="indefinite"/>
</path>
<path class="hg" d="M61.49 21.65L0 44.31v2.64l61.49-22.66 61.43 22.67v-2.64l-61-22.51-.43-.16z">
<animate id="hg4" attributeName="opacity" values="0;1;0" dur="4s" begin="hg0.begin+3s;hg0.end+3s" repeatCount="indefinite"/>
</path>
<path class="hg" d="M0 22.66v3.13L61.49 3.13l61.43 22.67v-3.13L61.49 0 0 22.66z">
<animate id="hg5" attributeName="opacity" values="0;1;0" dur="4s" begin="hg0.begin+4s;hg0.end+4s" repeatCount="indefinite"/>
</path>
</g>
</g>
</svg>
Here a #keyfrmes + animation-delay version:
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 122.91 110.38">
<style>
path {
fill: red; opacity: 0;
animation: 5.5s opacity infinite;
}
#keyframes opacity {
15% {opacity: 0}
35% {opacity: 1}
65% {opacity: 1}
85% {opacity: 0}
}
#hg2 {animation-delay: 0.5s}
#hg3 {animation-delay: 1.0s}
#hg4 {animation-delay: 1.5s}
#hg5 {animation-delay: 2.0s}
</style>
<path id="hg1" d="M61.65 86.78l-.16-.06L0 109.38v.99l61.49-22.65 61.43 22.66v-.99L61.65 86.78z"></path>
<path id="hg2" d="M0 87.69v1.49l61.49-22.66 61.43 22.67v-1.48L61.49 65.04 0 87.69z"></path>
<path id="hg3" d="M0 66.05v1.97l61.49-22.66 61.43 22.67v-1.97L61.49 43.39 0 66.05z"></path>
<path id="hg4" d="M61.49 21.65L0 44.31v2.64l61.49-22.66 61.43 22.67v-2.64l-61-22.51-.43-.16z"></path>
<path id="hg5" d="M0 22.66v3.13L61.49 3.13l61.43 22.67v-3.13L61.49 0 0 22.66z"></path>
</svg>
The simplest approach is to use a keyTimes attribute to control the fade in and fade out timing.
We have five arrows. The first one takes one second to fade in, then waits for the other four to fade in. Then takes one second to fade out again, and waits for the other four to do the same.
This means that the animation takes 10s in total for each arrow. And there are five key times in that animation:
at 0s, opacity value is 0
at 1s, opacity value is 1
at 5s, opacity value is 1
at 6s, opacity value is 0
at 10s, opacity value is 0
The keyTimes attribute works in conjunction with the values attribute. It specifies at which time in the animation the opacity has to be at each value. So it needs to have the same number of values as there are in the values attribute. The other thing you need to know about keyTimes values is that its time values have to be in fractions of the duration. So for the second time above (1s), we need to use 0.1 (1s of 10s).
So our values attribute should be "0; 1; 1; 0; 0", and our keyTimes attribute will be "0; 0.1; 0.5; 0.6; 1".
Then to offset the start of each arrow's animation, we just use staggered begin times.
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 122.91 110.38">
<defs>
<style>.hg{fill:#ee2330;opacity:0}</style>
</defs>
<g id="Layer_2" data-name="Layer 2">
<g id="Layer_1-2" data-name="Layer 1">
<path class="hg" d="M61.65 86.78l-.16-.06L0 109.38v.99l61.49-22.65 61.43 22.66v-.99L61.65 86.78z">
<animate attributeName="opacity" dur="10s" keyTimes="0;0.1;0.5;0.6;1" values="0;1;1;0;0" repeatCount="indefinite"/>
</path>
<path class="hg" d="M0 87.69v1.49l61.49-22.66 61.43 22.67v-1.48L61.49 65.04 0 87.69z">
<animate attributeName="opacity" dur="10s" keyTimes="0;0.1;0.5;0.6;1" values="0;1;1;0;0" repeatCount="indefinite" begin="1s"/>
</path>
<path class="hg" d="M0 66.05v1.97l61.49-22.66 61.43 22.67v-1.97L61.49 43.39 0 66.05z">
<animate attributeName="opacity" dur="10s" keyTimes="0;0.1;0.5;0.6;1" values="0;1;1;0;0" repeatCount="indefinite" begin="2s"/>
</path>
<path class="hg" d="M61.49 21.65L0 44.31v2.64l61.49-22.66 61.43 22.67v-2.64l-61-22.51-.43-.16z">
<animate attributeName="opacity" dur="10s" keyTimes="0;0.1;0.5;0.6;1" values="0;1;1;0;0" repeatCount="indefinite" begin="3s"/>
</path>
<path class="hg" d="M0 22.66v3.13L61.49 3.13l61.43 22.67v-3.13L61.49 0 0 22.66z">
<animate attributeName="opacity" dur="10s" keyTimes="0;0.1;0.5;0.6;1" values="0;1;1;0;0" repeatCount="indefinite" begin="4s"/>
</path>
</g>
</g>
</svg>
The difference of the following code?
Why the result is different from?
I thought it was the same.
However, different results when the cell actually animation.
<svg width="1000" height="1000">
<circle cx="10" cy="10" r="10">
<animate
attributeType="XML" attributeName="cx"
dur="10s" values="100; 200; 100"
repeatCount="indefinite" />
<animate
attributeType="XML" attributeName="cx"
dur="10s" values="0; 300; 0"
repeatCount="indefinite" additive="sum" />
</circle>
</svg>
<svg width="1000" height="1000">
<circle cx="10" cy="10" r="10">
<animate
attributeType="XML" attributeName="cx"
dur="19s" values="100; 200; 100"
repeatCount="indefinite" />
<animate
attributeType="XML" attributeName="cx"
dur="1s" values="0; 300; 0"
repeatCount="indefinite" additive="sum" />
</circle>
</svg>
Its not the time thats additive, if thats what you think, its the value of the attribute (cx).
As you have 2 animations running at the same time, cx will build up as a combination of whatever the values of cx are on each animation.
On the 2nd example. As one of the animations is only 1 second long, it will fluctuate very fast, on top of a slower animation.
If you forget about the additive for the moment, and just replace the 2nd cx value with cy on both, you will see why the animations are fundamentally different as well.
After the end of an AnimateTransform action, the element snaps back to the original value.
This isn't exactly unexpected as it's in the SMIL documentation:
As with all animation elements, this only manipulates the presentation value, and when the animation completes, the effect is no longer applied
But it is unwanted. I'd like to find a way to persist the changes using XML animations
Here's an example in SVG
<svg width="200" height="200" viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<rect id="outline" stroke="black" fill="white"
width="100" height="100" >
<animateTransform id="one"
attributeType="XML"
attributeName="transform"
type="translate"
from="0" to="-7"
dur="1s" repeatCount="1" />
</rect>
</svg>
One idea I had was to call a set action with dur="indefinite" that was triggered by the end of the first animation with begin="one.end", but can't quite seem to get the syntax right. I haven't found any documentation that show how to call set for a transformed value.
<svg width="200" height="200" viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<rect id="outline" stroke="black" fill="white"
width="100" height="100" >
<animateTransform id="one"
attributeType="XML"
attributeName="transform"
type="translate"
from="0" to="-7"
dur="1s" repeatCount="1" />
<!-- Doesn't work -->
<set attributeType="XML"
attributeName="transform"
type="translate"
to="-7" begin="one.end" />
<!-- Does work (as POC) -->
<set attributeType="css"
attributeName="fill"
to="green" begin="one.end" />
</rect>
</svg>
This question on persisting the end state of the animation shows how to do this with css transforms by using -webkit-animation-fill-mode: forwards;, but that obviously won't have any affect on an svg animation
fill="freeze" will persist the state of an animation e.g.
<svg width="200" height="200" viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<rect id="outline" stroke="black" fill="white"
width="100" height="100" >
<animateTransform id="one"
attributeType="XML"
attributeName="transform"
type="translate"
from="0" to="-7"
dur="1s" repeatCount="1"
fill="freeze"/>
</rect>
</svg>