Prevent SVG SMIL click animation from running more than once - html

I have the following SVG I animate with SMIL - this works fine on click, but will be rerun on repeating clicks - how can I prevent this? I want it to only run once and then do nothing on another click!
<g id="Gruppe_703" data-name="Gruppe 703" transform="translate(0 -185)" opacity="0">
<animateTransform
attributeName="transform"
attributeType="XML"
type="translate"
from="0 -185"
to="0 -39"
dur="0.1s"
begin="Gruppe_589.click"
fill="freeze"/>
</g>

Set the pointer-events property to none at the end of the animation then further mouse clicks are ignored.
<svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
<polygon points="60,60 90,120 30,120">
<animateTransform
id="at"
attributeName="transform"
type="translate"
from="0 0"
to="0 -39"
dur="1s"
begin="click"
fill="freeze"/>
<set
attributeName="pointer-events"
to="none"
begin="at.end"/>
</polygon>
</svg>

Consider other options to prevent re-animation after a click:
restart = "whenNotActive"
This value indicates that the animation can only be restarted when it
is not active (i.e. after the active end). Attempts to restart the
animation during its active duration are ignored.
<svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
<polygon points="60,60 90,120 30,120">
<animateTransform
id="at"
attributeName="transform"
type="translate"
from="0 0"
to="0 -39"
dur="3s"
begin="click"
fill="freeze"
restart="whenNotActive"/>
</polygon>
</svg>
restart = "never"
This value indicates that the animation cannot be restarted for the
time the document is loaded.
In other words, the animation fires only once, it cannot be restarted.
The animation can only be started again after reloading the document.
<svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
<polygon points="60,60 90,120 30,120">
<animateTransform
id="at"
attributeName="transform"
type="translate"
from="0 0"
to="0 -39"
dur="3s"
begin="click"
fill="freeze"
restart="never"/>
</polygon>
</svg>

Related

In an SVG - how can you speed up an animation or change its duration without using javascript?

How can you change the duration of an animationTransition in an SVG to make the animation speed up or slow down? I tried the below, where the dur attribute would change.
<svg width="120" height="120" viewBox="0 0 120 120"
xmlns="http://www.w3.org/2000/svg">
<polygon points="60,30 90,90 30,90">
<animateTransform attributeName="transform"
attributeType="XML"
type="rotate"
from="0 60 70"
to="360 60 70"
dur="10s"
repeatCount="indefinite">
<animate attributeType="XML" attributeName="dur" values="10s;5s;1s" dur="3s" />
</animateTransform>
</polygon>
</svg>
This doesn't end up working.
I cannot use javascript for this purpose (just want to use pure svg).
Any suggestions?
You can use keytimes and multiple values to have the animation run as you wish.
Your total duration is 10 + 5 + 1 seconds i.e. 16 seconds
So your keyTimes need to be from 0 to 10/16, then to 15/16 and finally the end i.e. 1
<svg width="120" height="120" viewBox="0 0 120 120"
xmlns="http://www.w3.org/2000/svg">
<polygon points="60,30 90,90 30,90">
<animateTransform attributeName="transform"
attributeType="XML"
type="rotate"
values="0 60 70;360 60 70;720 60 70;1080 60 70;"
keyTimes="0 ; 0.625 ; 0.9375 ; 1"
dur="16s"
repeatCount="indefinite">
</animateTransform>
</polygon>
</svg>

Resize a group of paths in a svg file

I'm wondering if I can animate a group of paths directly in the svg file?
I have a complex svg file and I would like to scale only one part, which I wrapped in the <g> element.
I tried something like this, but nothing happen.
<g id="Fire">
<path/>
<circle/>
<path fill="#FEC33A" d="M216.562,546.14c-0.13-0.38-0.26-0.75-0.4-1.12C216.302,545.38,216.442,545.76,216.562,546.14z"/>
<path fill="#F27D16" d="M215.032,573.37c-0.15-0.19-0.3-0.37-0.46-0.54C214.742,573.01,214.892,573.19,215.032,573.37z"/>
<animateTransform attributeName="transform"
attributeType="XML"
type="scale"
from="1"
to="1.1"
dur="2s"
repeatCount="indefinite"/>
</g>
If you want to use SMIL animations you may put the group in a <defs> element and reuse it with <use>. Then you may animate the use element
svg{border:1px solid; overflow:visible}
path{stroke:black;}
<svg viewBox="210 540 15 40" width="100">
<defs>
<g id="Fire">
<path d="M216.562,546.14
c-0.13-0.38-0.26-0.75-0.4-1.12C216.302,545.38,216.442,545.76,216.562,546.14z">
</path>
<path d="M215.032,573.37c-0.15-0.19-0.3-0.37-0.46-0.54C214.742,573.01,214.892,573.19,215.032,573.37z"/>
</g>
</defs>
<use xlink:href="#Fire" >
<animateTransform attributeName="transform"
attributeType="XML"
type="scale"
from="1"
to="1.1"
dur="2s"
repeatCount="indefinite"/>
</use>
</svg>
PS I suppose you may have a reason to use such complicated paths instead of a line

Changing mothionPath during animation is not working in Chrome

I have an SVG animation where I move an object alongside a path. At some point I am changing the motion path.
While in Firefox the animated object follows the new path, in Chrome it continue to move on the old one. Does anyone knows why it happens and how can this be fixed?
Here is an example:
function change(){
elem = document.getElementById("Zuerich_Geneva");
elem.setAttribute('d','M382500,53500 C632500,53500 549500,80000 499500,181000')
}
setTimeout(function() { change(); }, 5000);
<svg xml:space="preserve" viewBox="480000 0 360000 240000" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<symbol id="airplane" overflow="visible">
<path stroke="blue" stroke-width="100" fill="lightgray" d="M-4000,0 a1000,300 0 0,1 1000,-300 H-1000 L1500,-3000 h400 L0,-300 h2000 L3000,-1500 h500 L2500,-50 V100 L3500,1500 h-500 L2000,300 h-2000 L1900,3000 h-400 L-1000,300 H-3000 a1000,300 0 0,1 -1000,-300"/>
</symbol>
</defs>
<g id="AnimationPaths">
<path id="Zuerich_Geneva" stroke="orange" stroke-width="2000" fill="none" d="M682500,53500 C632500,53500 549500,80000 499500,181000"/>
<use id="AirplaneZurichGeneva" xlink:href="#airplane">
<animateMotion id="animMotionZurGen" dur="10s" repeatCount="indefinite" rotate="auto-reverse" keyPoints="1;0" keyTimes="0;1" calcMode="linear">
<mpath xlink:href="#Zuerich_Geneva"/>
</animateMotion>
</use>
</g>
</svg>
Thanks!
According to the SVG 1.1 spec, <mpath> is not animatable.
https://www.w3.org/TR/SVG/animate.html#MPathElementHrefAttribute
However, you are not actuall animating the <mpath>, you are animating the <path> that it is referencing. So I think it should work. It seems like a bug in Chrome, which you should report. However since Chrome have deprecated SMIL, they may not be interested in fixing it.
There are workarounds. For instance, you can define more than one <animateMotion> and switch between them. In the example below, I have programmed the switch in the animation. But you could also do it with JS.
<svg xml:space="preserve" viewBox="480000 0 360000 240000" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<symbol id="airplane" overflow="visible">
<path stroke="blue" stroke-width="100" fill="lightgray" d="M-4000,0 a1000,300 0 0,1 1000,-300 H-1000 L1500,-3000 h400 L0,-300 h2000 L3000,-1500 h500 L2500,-50 V100 L3500,1500 h-500 L2000,300 h-2000 L1900,3000 h-400 L-1000,300 H-3000 a1000,300 0 0,1 -1000,-300"/>
</symbol>
</defs>
<g id="AnimationPaths">
<path id="Zuerich_Geneva" stroke="orange" stroke-width="2000" fill="none" d="M682500,53500 C632500,53500 549500,80000 499500,181000"/>
<path id="Zuerich_Geneva2" stroke="orange" stroke-width="2000" fill="none" d="M382500,53500 C632500,53500 549500,80000 499500,181000"/>
<use id="AirplaneZurichGeneva" xlink:href="#airplane">
<animateMotion id="animMotionZurGen" dur="5s" repeatCount="indefinite"
rotate="auto-reverse" keyPoints="1;0.5" keyTimes="0;1"
calcMode="linear" begin="0s; animMotionZurGen2.begin + 5s">
<mpath xlink:href="#Zuerich_Geneva"/>
</animateMotion>
<animateMotion id="animMotionZurGen2" dur="5s" repeatCount="indefinite"
rotate="auto-reverse" keyPoints="0.5;0" keyTimes="0;1"
calcMode="linear" begin="animMotionZurGen.begin + 5s">
<mpath xlink:href="#Zuerich_Geneva2"/>
</animateMotion>
</use>
</g>
</svg>

animateTransform not working for transform scale

I am trying to get #moon svg group to follow a path and apply timed transforms. I cannot seem to get animateTransform to work in this situation.
When I set the animateMotion it causes the <g> to move out of frame. I adjust that with the attribute transform="translate(-53,-130)" which is fine. When I add the addTransform, the <g> drops down and out of the frame and I cannot adjust the translate to bring it back to frame. So, is there a trick to keeping the <g> in place or re-adjusting it back into frame with the addTransform?
<svg width="100%" height="100%" viewBox="0 0 570 594" preserveAspectRatio="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="padding: 0 10px 0 18px;fill-rule:evenodd;clip-rule:evenodd;stroke-miterlimit:10;">
<path id="orbit" d="M146.719,183.637l-18.408,-7.796l-13.233,-6.252l-12.327,-6.302l-18.44,-9.379l-12.42,-11.695l-16.36,-10.421l-15.546,-10.511l-12.326,-12.281l-14.415,-14.728l-8.426,-16.45l-4.168,-14.276l2.084,-14.272l6.297,-11.239l8.019,-10.103l12.013,-6.302l16.682,-8.426l16.356,-4.169l22.804,-4.217l27.474,-4.168l22.03,0l21.75,1.042l24.881,1.042l20.524,1.042l26.875,3.126l27.917,5.211l41.477,9.293l37.047,10.702l41.159,12.782l35.33,14.012l19.808,8.426l25.874,12.554l18.86,11.423l18.578,11.556l18.815,14.105l17.777,16.951l12.233,16.718l8.345,17.187l1.091,27.64l-7.434,8.207l-11.194,10.466l-15.595,10.559l-24.221,7.844l-22.609,5.211l-30.925,3.265l-43.658,0l-32.546,-2.085" style="fill:none;stroke-width:0px;stroke:#ff6060;"/>
<g id="moon" transform="translate(-53, -130)">
<path d="M77.39,295.34c0,-10.683 -8.658,-19.343 -19.342,-19.343c-10.683,0 -19.344,8.66 -19.344,19.343c0,10.683 8.661,19.343 19.344,19.343c10.684,0 19.342,-8.66 19.342,-19.343" style="fill:#fff;fill-rule:nonzero;"/>
<path d="M61.54,304.476c0,-2.967 -2.404,-5.373 -5.371,-5.373c-2.969,0 -5.373,2.406 -5.373,5.373c0,2.967 2.404,5.373 5.373,5.373c2.967,0 5.371,-2.406 5.371,-5.373" style="fill:#878787;fill-opacity:0.199997;fill-rule:nonzero;"/>
<animateMotion dur="6s" repeatCount="indefinite">
<mpath xlink:href="#orbit" />
</animateMotion>
<animateTransform attributeName="transform"
type="scale"
keyTimes="0;0.2;0.8;1" values="1.5;4;4;1.5"
dur="6s" additive="replace" fill="freeze"
repeatCount="indefinite"/>
</g>
</svg>
animateTransform normally replaces the current transform with the animated value, the additive attribute controls this.
If you set additive="sum" then the animation will be applied on top of the existing transform rather than replacing it.

Restart entire SVG animateTransform sequence?

I have a SVG graphic that I am animating via animateTransform. It animates in, then stays on screen until you click it, then it scales down to 0 and cannot be brought back. What I want to do is restart the entire animation sequence over say 2 seconds after the last animation has ended (scaled to 0), so it will animate back in.
How can I do this? Thanks!
<!-- Keep scaled at 0 on load -->
<animateTransform
attributeName="transform"
attributeType="XML"
type="scale"
from="0"
to="0"
dur="0.5s"/>
<!-- Scale up after 0.5 seconds -->
<animateTransform
attributeName="transform"
attributeType="XML"
type="scale"
from="0"
to="1"
begin="0.5s"
dur="0.3s"
fill="freeze"
additive="sum"/>
<!-- Scale down on click -->
<animateTransform id="animatFinished"
attributeName="transform"
attributeType="XML"
type="scale"
from="1"
to="0"
begin="click"
dur="0.6s"
fill="freeze"
additive="sum"/>
We need to start the first transform both at time 0 and 2 seconds after the onclick animation has ended which gives us begin="0s;animatFinished.end+2s"
The second animation needs to start when the first has ended otherwise it will only fire once.
And the use of additive="sum" is giving you problems as the animations end up trying to add a scale to something which has a scale of 0 which does nothing as 0 x value = 0.
So, I think this is what you're looking for:
<!-- Keep scaled at 0 on load -->
<animateTransform id="one"
attributeName="transform"
attributeType="XML"
type="scale"
from="0"
to="0"
begin="0s;animatFinished.end+2s"
dur="0.5s"
fill="freeze"/>
<!-- Scale up after 0.5 seconds -->
<animateTransform
attributeName="transform"
attributeType="XML"
type="scale"
from="0"
to="1"
begin="one.end"
dur="0.3s"
fill="freeze"/>
<!-- Scale down on click -->
<animateTransform id="animatFinished"
attributeName="transform"
attributeType="XML"
type="scale"
from="1"
to="0"
begin="click"
dur="0.6s"
fill="freeze"/>
get the animateTransform element(s) you want to restart and use beginElement() method
const animateEl = document.querySelector("#animatFinished");
animateEl.beginElement();