Reputation: 100
I'm still learning SMIL and one thing that bothers me is the no support for automatic reversed animations. So here's my test SVG I made quicky flor the purpose of testing SVG position animations.
In the simplest form, I want the animation to reverese back to its original starting position when reaching the end, like how the CSS animation alternate
works.
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 124 82">
<defs>
<style>
.cls-1 {
fill: none;
stroke: #000;
stroke-miterlimit: 10;
stroke-width: 2px;
}
</style>
</defs>
<title>Untitled-5</title>
<line class="cls-1" x1="12" y1="70" x2="44" y2="12">
<animate class="anim_1" attributeName="y1" from="70" to="35" dur="2s" repeatCount="indefinite"/>
<animate class="anim_1" attributeName="x2" from="44" to="59" dur="2s" repeatCount="indefinite"/>
<animate class="anim_1" attributeName="y2" from="12" to="56" dur="2s" repeatCount="indefinite"/>
</line>
<line class="cls-1" x1="44" y1="12" x2="112" y2="45">
<animate class="anim_1" attributeName="x1" from="44" to="59" dur="2s" repeatCount="indefinite"/>
<animate class="anim_1" attributeName="y1" from="12" to="56" dur="2s" repeatCount="indefinite"/>
<animate class="anim_1" attributeName="x2" from="112" to="100" dur="2s" repeatCount="indefinite"/>
<animate class="anim_1" attributeName="y2" from="45" to="12" dur="2s" repeatCount="indefinite"/>
</line>
<circle cx="12" cy="70" r="11" fill="white" stroke="black" stroke-width="2">
<animate class="anim_1" attributeName="cy" from="70" to="35" dur="2s" repeatCount="indefinite"/>
</circle>
<circle cx="44" cy="12" r="11" fill="white" stroke="black" stroke-width="2">
<animate class="anim_1" attributeName="cx" from="44" to="59" dur="2s" repeatCount="indefinite"/>
<animate class="anim_1" attributeName="cy" from="12" to="56" dur="2s" repeatCount="indefinite"/>
</circle>
<circle cx="112" cy="45" r="11" fill="white" stroke="black" stroke-width="2">
<animate class="anim_1" attributeName="cx" from="112" to="100" dur="2s" repeatCount="indefinite"/>
<animate class="anim_1" attributeName="cy" from="45" to="12" dur="2s" repeatCount="indefinite"/>
</circle>
</svg>
As you can see, the animation runs perfectly until it reaches the end, and just skips back to the start. Unfortunately, the way I'm implementing my larger SVG has no support for JS changing the <svg>
element.
I know this question has been asked a few times already, Here for example. They all seem to cover only the <motionPath>
element using keyPoints
and keyTimes
, if there's a way to accomplish this with my SVG using motion paths that'd be fine too, I'm just not sure how.
Thanks in advance for help!
Upvotes: 0
Views: 1937
Reputation: 136638
Yes you are on the good path with keyTimes
.
But what you need for your <animate>
is the values
attribute.
Basically, for each <animate>
, I
keyTimes = "0; .5; 1"
so that we've got our 3 way pointsfrom
and to
attributes to values="from;to;from"
dur
to make it twice longer.<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 124 82">
<defs>
<style>
.cls-1 {
fill: none;
stroke: #000;
stroke-miterlimit: 10;
stroke-width: 2px;
}
</style>
</defs>
<title>Untitled-5</title>
<line class="cls-1" x1="12" y1="70" x2="44" y2="12">
<animate class="anim_1" attributeName="y1" dur="4s" repeatCount="indefinite" keyTimes="0;0.5;1" values="70;35;70"></animate>
<animate class="anim_1" attributeName="x2" dur="4s" repeatCount="indefinite" keyTimes="0;0.5;1" values="44;59;44"></animate>
<animate class="anim_1" attributeName="y2" dur="4s" repeatCount="indefinite" keyTimes="0;0.5;1" values="12;56;12"></animate>
</line>
<line class="cls-1" x1="44" y1="12" x2="112" y2="45">
<animate class="anim_1" attributeName="x1" dur="4s" repeatCount="indefinite" keyTimes="0;0.5;1" values="44;59;44"></animate>
<animate class="anim_1" attributeName="y1" dur="4s" repeatCount="indefinite" keyTimes="0;0.5;1" values="12;56;12"></animate>
<animate class="anim_1" attributeName="x2" dur="4s" repeatCount="indefinite" keyTimes="0;0.5;1" values="112;100;112"></animate>
<animate class="anim_1" attributeName="y2" dur="4s" repeatCount="indefinite" keyTimes="0;0.5;1" values="45;12;45"></animate>
</line>
<circle cx="12" cy="70" r="11" fill="white" stroke="black" stroke-width="2">
<animate class="anim_1" attributeName="cy" dur="4s" repeatCount="indefinite" keyTimes="0;0.5;1" values="70;35;70"></animate>
</circle>
<circle cx="44" cy="12" r="11" fill="white" stroke="black" stroke-width="2">
<animate class="anim_1" attributeName="cx" dur="4s" repeatCount="indefinite" keyTimes="0;0.5;1" values="44;59;44"></animate>
<animate class="anim_1" attributeName="cy" dur="4s" repeatCount="indefinite" keyTimes="0;0.5;1" values="12;56;12"></animate>
</circle>
<circle cx="112" cy="45" r="11" fill="white" stroke="black" stroke-width="2">
<animate class="anim_1" attributeName="cx" dur="4s" repeatCount="indefinite" keyTimes="0;0.5;1" values="112;100;112"></animate>
<animate class="anim_1" attributeName="cy" dur="4s" repeatCount="indefinite" keyTimes="0;0.5;1" values="45;12;45"></animate>
</circle>
</svg>
And if you want the js I made :
document.querySelectorAll('animate').forEach(a => {
a.setAttribute('keyTimes', '0;0.5;1');
let f = a.getAttribute('from');
let t = a.getAttribute('to');
a.setAttribute('values', f + ';' + t + ';' + f)
a.removeAttribute('from');
a.removeAttribute('to');
a.setAttribute('dur', (parseFloat(a.getAttribute('dur')) * 2) + 's');
})
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 124 82">
<defs>
<style>
.cls-1 {
fill: none;
stroke: #000;
stroke-miterlimit: 10;
stroke-width: 2px;
}
</style>
</defs>
<title>Untitled-5</title>
<line class="cls-1" x1="12" y1="70" x2="44" y2="12">
<animate class="anim_1" attributeName="y1" from="70" to="35" dur="2s" repeatCount="indefinite"/>
<animate class="anim_1" attributeName="x2" from="44" to="59" dur="2s" repeatCount="indefinite"/>
<animate class="anim_1" attributeName="y2" from="12" to="56" dur="2s" repeatCount="indefinite"/>
</line>
<line class="cls-1" x1="44" y1="12" x2="112" y2="45">
<animate class="anim_1" attributeName="x1" from="44" to="59" dur="2s" repeatCount="indefinite"/>
<animate class="anim_1" attributeName="y1" from="12" to="56" dur="2s" repeatCount="indefinite"/>
<animate class="anim_1" attributeName="x2" from="112" to="100" dur="2s" repeatCount="indefinite"/>
<animate class="anim_1" attributeName="y2" from="45" to="12" dur="2s" repeatCount="indefinite"/>
</line>
<circle cx="12" cy="70" r="11" fill="white" stroke="black" stroke-width="2">
<animate class="anim_1" attributeName="cy" from="70" to="35" dur="2s" repeatCount="indefinite"/>
</circle>
<circle cx="44" cy="12" r="11" fill="white" stroke="black" stroke-width="2">
<animate class="anim_1" attributeName="cx" from="44" to="59" dur="2s" repeatCount="indefinite"/>
<animate class="anim_1" attributeName="cy" from="12" to="56" dur="2s" repeatCount="indefinite"/>
</circle>
<circle cx="112" cy="45" r="11" fill="white" stroke="black" stroke-width="2">
<animate class="anim_1" attributeName="cx" from="112" to="100" dur="2s" repeatCount="indefinite"/>
<animate class="anim_1" attributeName="cy" from="45" to="12" dur="2s" repeatCount="indefinite"/>
</circle>
</svg>
Upvotes: 5