I need your help with the implementation of svg animation.
https://youtu.be/lrWjkARl8Zg
(sorry for the poor video quality)
And I have such a structure of svg
I need the arrow (class = "arrow") itself to move along long lines and draw it.
<svg class="vector" width="1193" height="329" viewBox="0 0 1193 329" fill="none" xmlns="http://www.w3.org/2000/svg">
<path class="long_line" d="M1436 327.98L84.7148 327.98C73.8082 328.219 62.9639 326.275 52.818 322.262C42.6722 318.249 33.4293 312.249 25.6315 304.613C17.8337 296.977 11.6384 287.858 7.40866 277.793C3.17891 267.728 0.999997 256.919 0.999996 246C0.999996 235.081 3.17891 224.272 7.40866 214.207C11.6384 204.142 17.8337 195.023 25.6315 187.387C33.4292 179.751 42.6722 173.75 52.818 169.738C62.9638 165.725 73.8082 163.781 84.7147 164.02L589.173 164.02" stroke="black" stroke-width="2" stroke-miterlimit="10"/>
<path class="arrow" d="M544 204L589 164L548 124" stroke="black" stroke-width="2"/>
<path class="arrow" d="M504 1L459 41L500 81" stroke="black" stroke-width="2"/>
<path class="short_line" d="M1308 41L459 41" stroke="black" stroke-width="2" stroke-miterlimit="10"/>
</svg>
Advise which library I can use
You could do this using svg smil animations:
A Guide to SVG Animations (SMIL)
Your arrow animations could be achieved by
<animateMotion> for moving the arrow element and
animating the stroke-dashoffset property.
Animated example
svg {
border: 1px solid #ccc;
width: 33%;
overflow: visible;
display: block;
}
path {
stroke-width: 10;
stroke: #000;
}
<p>Click on animation for replay</p>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1400 500">
<defs>
<path id="arrow" fill="none" d="M-45,40L0,0l-41-40" />
</defs>
<use id="arrow1" href="#arrow" />
<use id="arrow2" href="#arrow" />
<g id="graphics">
<rect id="graphics" fill="#fff" fill-opacity="0" x="0" y="0" width="100%" height="100%" />
<path id="mpath-long" fill="none" pathLength="100" stroke-width="2" stroke-miterlimit="10" stroke-dashoffset="100" stroke-dasharray="100" d="M1571,413H219.7
c-10.9,0.2-21.8-1.7-31.9-5.7c-10.1-4-19.4-10-27.2-17.6c-7.8-7.6-14-16.8-18.2-26.8S136,341.9,136,331s2.2-21.7,6.4-31.8
s10.4-19.2,18.2-26.8c7.8-7.6,17-13.6,27.2-17.6c10.1-4,21-6,31.9-5.7h504.5" />
<path id="mpath-short" fill="none" pathLength="100" stroke-width="2" stroke-miterlimit="10" stroke-dashoffset="100" stroke-dasharray="100" d="M1443,126H594" />
</g>
<animateMotion href="#arrow1" dur="2" rotate="auto" repeatCount="1" begin="0;graphics.click" fill="freeze">
<mpath href="#mpath-long" />
</animateMotion>
<animate attributeType="XML" href="#mpath-long" id="strokeAni" attributeName="stroke-dashoffset" from="100" to="0" dur="2s" repeatCount="1" begin="0;graphics.click" fill="freeze" />
<animateMotion href="#arrow2" dur="2s" rotate="auto" repeatCount="1" begin="0;graphics.click" fill="freeze">
<mpath href="#mpath-short" />
</animateMotion>
<animate attributeType="XML" href="#mpath-short" attributeName="stroke-dashoffset" from="100" to="0" dur="2s" repeatCount="1" fill="freeze" begin="0;graphics.click" />
</svg>
Quite likely, you will have to tweak your svg viewBox to get the desired result.
A common trick is to position element that's supposed to move along the motion path to x/y = 0.
Static example
<style>
svg{
border: 1px solid #ccc;
width: 33%;
overflow:visible;
display:block;
}
path{
stroke-width:10;
stroke: #000;
}
</style>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1400 500">
<defs>
<path id="arrow" fill="none" d="M-45,40L0,0l-41-40" />
</defs>
<use id="arrow1" href="#arrow" />
<use id="arrow2" href="#arrow" />
<g id="graphics">
<rect id="graphics" fill="#fff" fill-opacity="0" x="0" y="0" width="100%" height="100%" />
<path id="mpath-long" fill="none" pathLength="100" stroke-width="2" stroke-miterlimit="10" stroke-dashoffset="0" stroke-dasharray="100" d="M1571,413H219.7
c-10.9,0.2-21.8-1.7-31.9-5.7c-10.1-4-19.4-10-27.2-17.6c-7.8-7.6-14-16.8-18.2-26.8S136,341.9,136,331s2.2-21.7,6.4-31.8
s10.4-19.2,18.2-26.8c7.8-7.6,17-13.6,27.2-17.6c10.1-4,21-6,31.9-5.7h504.5" />
<path id="mpath-short" fill="none" pathLength="100" stroke-width="2" stroke-miterlimit="10" stroke-dashoffset="0" stroke-dasharray="100" d="M1443,126H594" />
</g>
</svg>
Hope I am explaining this correctly.
I have two pulse animations that are running along two different paths. I have played with the duration of the animations but I can seem to get them to "sync" at the point where they join so that only one circle goes to the top.
Is this possible?
Here is my code :
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="300"
height="300"
viewBox="0 0 120 120"
version="1.1"
id="svg11"
sodipodi:docname="testAn.svg"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
<metadata
id="metadata17">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs15" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1600"
inkscape:window-height="837"
id="namedview13"
showgrid="false"
inkscape:zoom="2.4857496"
inkscape:cx="201.80878"
inkscape:cy="187.12268"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg11" />
<g
id="g140"
transform="translate(35.662173,31.252367)">
<path
id="theMotionPath-sa"
d="M 10,10 V 40 H 52"
inkscape:connector-curvature="0"
style="fill:none;stroke:#4789d0;stroke-width:1" />
<circle
id="circle119"
r="2"
cy="0"
cx="0"
style="fill:#4789d0">
<!-- Define the motion path animation -->
<animateMotion
keyTimes="0;1"
calcMode="linear"
keyPoints="1;0"
repeatCount="indefinite"
dur="3s"
begin="0s">
<mpath
xlink:href="#theMotionPath-sa" />
</animateMotion>
</circle>
<circle
id="circle121"
r="2"
cy="0"
cx="0"
style="fill:#4789d0">
<!-- Define the motion path animation -->
<animateMotion
keyTimes="0;1"
calcMode="linear"
keyPoints="1;0"
repeatCount="indefinite"
dur="3s"
begin="1s">
<mpath
xlink:href="#theMotionPath-sa" />
</animateMotion>
</circle>
<circle
id="circle123"
r="2"
cy="0"
cx="0"
style="fill:#4789d0">
<!-- Define the motion path animation -->
<animateMotion
keyTimes="0;1"
calcMode="linear"
keyPoints="1;0"
repeatCount="indefinite"
dur="3s"
begin="2s">
<mpath
xlink:href="#theMotionPath-sa" />
</animateMotion>
</circle>
<circle
id="circle125"
r="2"
cy="0"
cx="0"
style="fill:#4789d0">
<!-- Define the motion path animation -->
<animateMotion
keyTimes="0;1"
calcMode="linear"
keyPoints="1;0"
repeatCount="indefinite"
dur="3s"
begin="3s">
<mpath
xlink:href="#theMotionPath-sa" />
</animateMotion>
</circle>
</g>
<g
id="g57"
transform="translate(15.662173,36.252367)">
<path
id="theMotionPath-ch"
d="M 10,35 H 30 V 3"
inkscape:connector-curvature="0"
style="fill:none;stroke:#4789d0;stroke-width:1" />
<circle
id="circle36"
r="2"
cy="0"
cx="0"
style="fill:#4789d0">
<!-- Define the motion path animation -->
<animateMotion
keyTimes="0;1"
calcMode="linear"
keyPoints="0;1"
repeatCount="indefinite"
dur="3s"
begin="0s">
<mpath
xlink:href="#theMotionPath-ch" />
</animateMotion>
</circle>
<circle
id="circle38"
r="2"
cy="0"
cx="0"
style="fill:#4789d0">
<!-- Define the motion path animation -->
<animateMotion
keyTimes="0;1"
calcMode="linear"
keyPoints="0;1"
repeatCount="indefinite"
dur="3s"
begin="1s">
<mpath
xlink:href="#theMotionPath-ch" />
</animateMotion>
</circle>
<circle
id="circle40"
r="2"
cy="0"
cx="0"
style="fill:#4789d0">
<!-- Define the motion path animation -->
<animateMotion
keyTimes="0;1"
calcMode="linear"
keyPoints="0;1"
repeatCount="indefinite"
dur="3s"
begin="2s">
<mpath
xlink:href="#theMotionPath-ch" />
</animateMotion>
</circle>
<circle
id="circle42"
r="2"
cy="0"
cx="0"
style="fill:#4789d0">
<!-- Define the motion path animation -->
<animateMotion
keyTimes="0;1"
calcMode="linear"
keyPoints="0;1"
repeatCount="indefinite"
dur="3s"
begin="3s">
<mpath
xlink:href="#theMotionPath-ch" />
</animateMotion>
</circle>
</g>
</svg>
Hope this makes sense!
Just building from #ccprog's answer, you can also use keyTimes and keyPoints to change the speed of the animation in the horizontal and vertical parts. You need to realise a couple of things:
First, you need to #theMotionPath-ch's d attribute to d="M 10,35 H 30 V 5", so that it gets to the same vertical point as the other path
Then, calculate the point where each path changes relative to its length: 0.4167 in #theMotionPath-sa and 0.4 in #theMotionPath-ch.
Finally, add an additional keyTime (I set it at 0.6, meaning at the 0.6 * 3s = 1.8s and the corresponding keyPoint from the previous step.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="300"
height="300"
viewBox="0 0 120 120"
version="1.1"
id="svg11"
sodipodi:docname="testAn.svg"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
<metadata
id="metadata17">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs15" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1600"
inkscape:window-height="837"
id="namedview13"
showgrid="false"
inkscape:zoom="2.4857496"
inkscape:cx="201.80878"
inkscape:cy="187.12268"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg11" />
<g
id="g140"
transform="translate(35.662173,31.252367)">
<path
id="theMotionPath-sa"
d="M 10,10 V 40 H 52"
inkscape:connector-curvature="0"
style="fill:none;stroke:#4789d0;stroke-width:1" />
<circle
id="circle119"
r="2"
cy="0"
cx="0"
style="fill:#4789d0">
<!-- Define the motion path animation -->
<animateMotion
keyTimes="0;0.6;1"
calcMode="linear"
keyPoints="1;0.4167;0"
repeatCount="indefinite"
dur="3s"
begin="0s">
<mpath
xlink:href="#theMotionPath-sa" />
</animateMotion>
</circle>
<circle
id="circle121"
r="2"
cy="0"
cx="0"
style="fill:#4789d0">
<!-- Define the motion path animation -->
<animateMotion
keyTimes="0;0.6;1"
calcMode="linear"
keyPoints="1;0.4167;0"
repeatCount="indefinite"
dur="3s"
begin="1s">
<mpath
xlink:href="#theMotionPath-sa" />
</animateMotion>
</circle>
<circle
id="circle123"
r="2"
cy="0"
cx="0"
style="fill:#4789d0">
<!-- Define the motion path animation -->
<animateMotion
keyTimes="0;0.6;1"
calcMode="linear"
keyPoints="1;0.4167;0"
repeatCount="indefinite"
dur="3s"
begin="2s">
<mpath
xlink:href="#theMotionPath-sa" />
</animateMotion>
</circle>
<circle
id="circle125"
r="2"
cy="0"
cx="0"
style="fill:#4789d0">
<!-- Define the motion path animation -->
<animateMotion
keyTimes="0;0.6;1"
calcMode="linear"
keyPoints="1;0.4167;0"
repeatCount="indefinite"
dur="3s"
begin="3s">
<mpath
xlink:href="#theMotionPath-sa" />
</animateMotion>
</circle>
</g>
<g
id="g57"
transform="translate(15.662173,36.252367)">
<path
id="theMotionPath-ch"
d="M 10,35 H 30 V 5"
inkscape:connector-curvature="0"
style="fill:none;stroke:#4789d0;stroke-width:1" />
<circle
id="circle36"
r="2"
cy="0"
cx="0"
style="fill:#4789d0">
<!-- Define the motion path animation -->
<animateMotion
keyTimes="0;0.6;1"
calcMode="linear"
keyPoints="0;0.40;1"
repeatCount="indefinite"
dur="3s"
begin="0s">
<mpath
xlink:href="#theMotionPath-ch" />
</animateMotion>
</circle>
<circle
id="circle38"
r="2"
cy="0"
cx="0"
style="fill:#4789d0">
<!-- Define the motion path animation -->
<animateMotion
keyTimes="0;0.6;1"
calcMode="linear"
keyPoints="0;0.40;1"
repeatCount="indefinite"
dur="3s"
begin="1s">
<mpath
xlink:href="#theMotionPath-ch" />
</animateMotion>
</circle>
<circle
id="circle40"
r="2"
cy="0"
cx="0"
style="fill:#4789d0">
<!-- Define the motion path animation -->
<animateMotion
keyTimes="0;0.6;1"
calcMode="linear"
keyPoints="0;0.40;1"
repeatCount="indefinite"
dur="3s"
begin="2s">
<mpath
xlink:href="#theMotionPath-ch" />
</animateMotion>
</circle>
<circle
id="circle42"
r="2"
cy="0"
cx="0"
style="fill:#4789d0">
<!-- Define the motion path animation -->
<animateMotion
keyTimes="0;0.6;1"
calcMode="linear"
keyPoints="0;0.40;1"
repeatCount="indefinite"
dur="3s"
begin="3s">
<mpath
xlink:href="#theMotionPath-ch" />
</animateMotion>
</circle>
</g>
</svg>
After Looking at the examples it occurred to me that as long as the time of each animation stays the same and the interval at witch each animation run also stays the same then the lengths of the paths would not make any difference. All that will change is the speed of the animation.
Here is another exsample:
<svg width="300" height="300" viewBox="0 0 120 120"
xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink" >
<!-- Edit This Path . -->
<path d="M 10,60 H 60 " stroke="#4789D0" stroke-width="1" fill="none" id="M-Right"/>
<path d="M 60,60 v -50 " stroke="#4789D0" stroke-width="1" fill="none" id="M-Up"/>
<path d="M 60,60 h 30" stroke="#4789D0" stroke-width="1" fill="none" id="M-Left"/>
<!-- Here is a green circle which will be moved along the motion path. -->
<circle cx="" cy="" r="2" fill="#4789D0" >
<!-- Define the motion path animation -->
<animateMotion id="c1" begin='0s' dur='3s' repeatCount="indefinite" keyPoints="0;1" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Right"/> </animateMotion>
</circle>
<circle cx="" cy="" r="2" fill="#4789D0" >
<!-- Define the motion path animation -->
<animateMotion id="c2" begin='1s' dur='3s' repeatCount="indefinite" keyPoints="0;1" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Right"/> </animateMotion>
</circle>
<circle cx="" cy="" r="2" fill="#4789D0" >
<!-- Define the motion path animation -->
<animateMotion id="c3" begin='2s' dur='3s' repeatCount="indefinite" keyPoints="0;1" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Right"/> </animateMotion>
</circle>
<circle cx="" cy="" r="2" fill="#4789D0" >
<!-- Define the motion path animation -->
<animateMotion id="c4" begin='3s' dur='3s' repeatCount="indefinite" keyPoints="0;1" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Right"/> </animateMotion>
</circle>
<circle cx="" cy="" r="2" fill="#4789D0" >
<!-- Define the motion path animation -->
<animateMotion id="vc1" begin='c1.begin+3s' dur='3s' repeatCount="indefinite" keyPoints="0;1" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Up"/> </animateMotion>
</circle>
<circle cx="" cy="" r="2" fill="#4789D0" >
<!-- Define the motion path animation -->
<animateMotion id="vc2" begin='c2.begin+3s' dur='3s' repeatCount="indefinite" keyPoints="0;1" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Up"/> </animateMotion>
</circle>
<circle cx="" cy="" r="2" fill="#4789D0" >
<!-- Define the motion path animation -->
<animateMotion id="vc3" begin='c3.begin+3s' dur='3s' repeatCount="indefinite" keyPoints="0;1" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Up"/> </animateMotion>
</circle>
<circle cx="" cy="" r="2" fill="#4789D0" >
<!-- Define the motion path animation -->
<animateMotion id="vc4" begin='c4.begin+3s' dur='3s' repeatCount="indefinite" keyPoints="0;1" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Up"/> </animateMotion>
</circle>
<circle cx="" cy="" r="2" fill="#4789D0" >
<!-- Define the motion path animation -->
<animateMotion id="lc1" begin='c1.begin+0s' dur='3s' repeatCount="indefinite" keyPoints="1;0" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Left"/> </animateMotion>
</circle>
<circle cx="" cy="" r="2" fill="#4789D0" >
<!-- Define the motion path animation -->
<animateMotion id="lc2" begin='c2.begin+0s' dur='3s' repeatCount="indefinite" keyPoints="1;0" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Left"/> </animateMotion>
</circle>
<circle cx="" cy="" r="2" fill="#4789D0" >
<!-- Define the motion path animation -->
<animateMotion id="lc3" begin='c3.begin+0s' dur='3s' repeatCount="indefinite" keyPoints="1;0" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Left"/> </animateMotion>
</circle>
<circle cx="" cy="" r="2" fill="#4789D0" >
<!-- Define the motion path animation -->
<animateMotion id="lc4" begin='c4.begin+0s' dur='3s' repeatCount="indefinite" keyPoints="1;0" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Left"/> </animateMotion>
</circle>
</svg>
You can edit the length but it will still stay in sync
Your main problem is that your dots are moving at different speeds, because the motion paths have different lengths. I think the most sensible solution is to define three separate motion paths, one for the left and right leg, and one for the upward leg. Then, time your animations such that the animations end at the central point at the same time for the left and right leg, and that they start at that same time for the upward leg.
This requires carefull planing of motion speeds and timing, and implicitely knowledge about path lengths. To make it easier to follow the reasoning, I've resolved the transforms from your SVG and repositioned and resized the paths a bit. Also, I have reversed the direction of the right leg so that you do not need to reverse the direction of the motion - sparing you to spell out the keyPoints/keyTimes attributes.
Here is what I got:
id d length dur
theMotionPath-left M 25 70 H 45 20 1.5s
theMotionPath-right M 85 70 H 45 40 3s
theMotionPath-up M 45 70 V 40 30 2s
The speeds in the different legs do match up perfectly, only approximately. But that is no deterrent, all that matters is that all dots reach/leave the central point on every full second.
The left leg has a problem, though. repeatCount="indefinite" means that the animation restarts immediately after finishing. A motion starting at 1.5s would end at 3s, then again after 4.5s, 6s, 7.5s,... Every second motion would not match up with the other parts as required.
What would solve this is an additional delay between each animation start: run for 1.5s, wait for 1.5s, run again etc.
This can be done with a trick. It is possible to bind the start of an animation to the end of another animation - or to a different run of the same animation. Leave out the repeatCount attribute, but define a list of begin times:
<animateMotion id="leftDot1" dur="1.5s" begin="1.5s;leftDot1.end + 1.5s">
<mpath xlink:href="#theMotionPath-left" />
</animateMotion>
After 1.5s, the animation is started for the first time, and additionally each time the animation with the id leftDot1 (which is itself) ends, it waits for 1.5s and then starts again.
<svg width="300" height="300" viewBox="0 0 120 120"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g>
<path id="theMotionPath-left" d="M 25 70 H 45"
style="fill:none;stroke:#4789d0;stroke-width:1" />
<circle r="2" cy="0" cx="0" style="fill:#4789d0">
<animateMotion id="leftDot1" dur="1.5s" begin="1.5s;leftDot1.end + 1.5s">
<mpath xlink:href="#theMotionPath-left" />
</animateMotion>
</circle>
<circle r="2" cy="0" cx="0" style="fill:#4789d0">
<animateMotion id="leftDot2" dur="1.5s" begin="2.5s;leftDot2.end + 1.5s">
<mpath xlink:href="#theMotionPath-left" />
</animateMotion>
</circle>
<circle r="2" cy="0" cx="0" style="fill:#4789d0">
<animateMotion id="leftDot3" dur="1.5s" begin="3.5s;leftDot3.end + 1.5s">
<mpath xlink:href="#theMotionPath-left" />
</animateMotion>
</circle>
</g>
<g>
<path id="theMotionPath-right" d="M 85 70 H 45"
style="fill:none;stroke:#4789d0;stroke-width:1" />
<circle r="2" cy="0" cx="0" style="fill:#4789d0">
<animateMotion repeatCount="indefinite" dur="3s" begin="0s">
<mpath xlink:href="#theMotionPath-right" />
</animateMotion>
</circle>
<circle r="2" cy="0" cx="0" style="fill:#4789d0">
<animateMotion repeatCount="indefinite" dur="3s" begin="1s">
<mpath xlink:href="#theMotionPath-right" />
</animateMotion>
</circle>
<circle r="2" cy="0" cx="0" style="fill:#4789d0">
<animateMotion repeatCount="indefinite" dur="3s" begin="2s">
<mpath xlink:href="#theMotionPath-right" />
</animateMotion>
</circle>
</g>
<g>
<path id="theMotionPath-up" d="M 45 70 V 40"
style="fill:none;stroke:#4789d0;stroke-width:1" />
<circle r="2" cy="0" cx="0" style="fill:#4789d0">
<animateMotion repeatCount="indefinite" dur="2s" begin="3s">
<mpath xlink:href="#theMotionPath-up" />
</animateMotion>
</circle>
<circle r="2" cy="0" cx="0" style="fill:#4789d0">
<animateMotion repeatCount="indefinite" dur="2s" begin="4s">
<mpath xlink:href="#theMotionPath-up" />
</animateMotion>
</circle>
</g>
</svg>
I need to show a loading indicator any time an ajax request occurs. Based on this question RxJs How to set default request headers? I believe I'll have to create an ajax wrapper to use.
My requirements are to start the loading indicator when a request occurs. It can start again if there is already a request running. When a request completes/errors, I need the loading to go away. It should only go away if all requests have completed though.
In axios I just use interceptors and have a counter. It's pretty simple. I really have no clue how to handle this with RxJS though. My guess would be it needs to do something similar, I just really don't know how to write it.
Build a custom HTTP client that exposes a loading BehaviorSubject. Every time a connection is opened increment the count and decrement the count each time a connection finishes. Have your loading indicator show when the connection count is greater than 0 and hide when it is 0.
class HttpClient {
constructor() {
this.connectionCount$ = new rxjs.BehaviorSubject(0);
this.loading$ = new rxjs.BehaviorSubject(false);
}
incrementConnectionCount() {
this.connectionCount$.next(this.connectionCount$.getValue() + 1);
if (this.connectionCount$.getValue() === 1) {
this.loading$.next(true);
}
}
decrementConnectionCount() {
this.connectionCount$.next(this.connectionCount$.getValue() - 1);
if (this.connectionCount$.getValue() === 0) {
this.loading$.next(false);
}
}
get(url) {
this.incrementConnectionCount();
setTimeout(() => { // Simulate a http call that takes 2 seconds
this.decrementConnectionCount();
}, 2000);
}
// Do the same for the other verbs, put, post, delete etc
}
const httpClient = new HttpClient();
// Anywhere you want a loading spinner subscribe to the loading observable and show and hide the spinner
httpClient.loading$.subscribe(loading => {
document.getElementById('loading').style.display = loading ? 'block' : 'none';
});
// Show the connection count
httpClient.connectionCount$.subscribe(connectionCount => {
document.getElementById('connectionCount').innerText = connectionCount;
});
// Each time you click the button you will simulate a http get that takes two seconds, press it multople times and it will show for 2 seconds after the last click
document.getElementById('load').addEventListener('click', () => {
httpClient.get('someUrl');
});
#loading {
display: none;
}
svg {
vertical-align: middle;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.3.3/rxjs.umd.min.js"></script>
<button id="load">Load</button> Connection count: <span id="connectionCount"></span>
<div id="loading"> <!-- Get a funky loading spinner from loading.io -->
<svg xmlns="http://www.w3.org/2000/svg" class="lds-cutiefox" width="80px" height="80px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
<g transform="rotate(80.5368 50 50)">
<animateTransform attributeName="transform" type="rotate" values="360 50 50;0 50 50" keyTimes="0;1" dur="1.5s" repeatCount="indefinite" calcMode="spline" keySplines="0.5 0 0.5 1" begin="-0.15000000000000002s"/>
<circle cx="50" cy="50" r="39.891" stroke="#ffc254" stroke-width="14.4" fill="none" stroke-dasharray="0 300">
<animate attributeName="stroke-dasharray" values="15 300;55.1413599195142 300;15 300" keyTimes="0;0.5;1" dur="1.5s" repeatCount="indefinite" calcMode="linear" keySplines="0 0.4 0.6 1;0.4 0 1 0.6" begin="-0.069s"/>
</circle>
<circle cx="50" cy="50" r="39.891" stroke="#fff1cf" stroke-width="7.2" fill="none" stroke-dasharray="0 300">
<animate attributeName="stroke-dasharray" values="15 300;55.1413599195142 300;15 300" keyTimes="0;0.5;1" dur="1.5s" repeatCount="indefinite" calcMode="linear" keySplines="0 0.4 0.6 1;0.4 0 1 0.6" begin="-0.069s"/>
</circle>
<circle cx="50" cy="50" r="32.771" stroke="#000000" stroke-width="1" fill="none" stroke-dasharray="0 300">
<animate attributeName="stroke-dasharray" values="15 300;45.299378454348094 300;15 300" keyTimes="0;0.5;1" dur="1.5s" repeatCount="indefinite" calcMode="linear" keySplines="0 0.4 0.6 1;0.4 0 1 0.6" begin="-0.069s"/>
</circle>
<circle cx="50" cy="50" r="47.171" stroke="#000000" stroke-width="1" fill="none" stroke-dasharray="0 300">
<animate attributeName="stroke-dasharray" values="15 300;66.03388996804073 300;15 300" keyTimes="0;0.5;1" dur="1.5s" repeatCount="indefinite" calcMode="linear" keySplines="0 0.4 0.6 1;0.4 0 1 0.6" begin="-0.069s"/>
</circle>
</g>
<g transform="rotate(143.103 50 50)">
<animateTransform attributeName="transform" type="rotate" values="360 50 50;0 50 50" keyTimes="0;1" dur="1.5s" repeatCount="indefinite" calcMode="spline" keySplines="0.5 0 0.5 1"/>
<path fill="#ffc254" stroke="#000000" d="M97.2,50c0,6.1-1.2,12.2-3.5,17.8l-13.3-5.4c1.6-3.9,2.4-8.2,2.4-12.4"/>
<path fill="#fff1cf" transform="translate(0,-0.1)" d="M93.6,50c0,1.2,0,2.4-0.1,3.6L93,57.2c-0.4,2-2.3,3.3-4.2,2.8l-0.2-0.1c-1.8-0.5-3.1-2.3-2.7-3.9l0.4-3 c0.1-1,0.1-2,0.1-3"/>
<path fill="#ffc254" stroke="#000000" d="M85.4,62.5c-0.2,0.7-0.5,1.4-0.8,2.1c-0.3,0.7-0.6,1.4-0.9,2c-0.6,1.1-2,1.4-3.2,0.8v0c-1.1-0.7-1.7-2-1.2-2.9 c0.3-0.6,0.5-1.2,0.8-1.8c0.2-0.6,0.6-1.2,0.7-1.8"/>
<path fill="#ffc254" stroke="#000000" d="M94.5,65.7c-0.3,0.9-0.7,1.7-1,2.6c-0.4,0.8-0.7,1.7-1.1,2.5c-0.7,1.4-2.3,1.9-3.4,1.3l0,0 c-1.1-0.7-1.5-2.2-0.9-3.4c0.4-0.8,0.7-1.5,1-2.3c0.3-0.8,0.7-1.5,0.9-2.3"/>
<path fill="#ffc254" stroke="#000000" d="M85.6,67c0,0.8,0.1,1.6,0.3,2.4c0.6-0.5,1.1-1,1.4-1.7c0.2-0.7,0.2-1.5-0.1-2.2C86.5,64,85.6,66.3,85.6,67z"/>
</g>
<g transform="rotate(80.5368 50 50)">
<animateTransform attributeName="transform" type="rotate" values="360 50 50;0 50 50" keyTimes="0;1" dur="1.5s" repeatCount="indefinite" calcMode="spline" keySplines="0.5 0 0.5 1" begin="-0.15000000000000002s"/>
<path fill="#fff1cf" stroke="#000000" d="M91,33.6l-10,4c-0.4-1.2-1.1-2.4-1.7-3.5c-0.2-0.5,0.3-1.1,0.9-1C83.6,32.9,87.4,32.9,91,33.6z"/>
<path fill="#fff1cf" stroke="#000000" d="M83.2,36.7l10-4c-0.6-1.7-1.5-3.3-2.3-4.9c-0.3-0.7-1.2-0.6-1.4,0.1C87.6,31.1,85.7,34,83.2,36.7z"/>
<path fill="#ffc254" stroke="#000000" transform="translate(0,0.2)" d="M82.8,50c0-3.4-0.5-6.8-1.5-10c-0.2-0.8-0.4-1.5-0.3-2.3c0.1-0.8,0.4-1.6,0.7-2.4c0.7-1.5,1.9-3.1,3.7-4l0,0 c1.8-0.9,3.7-1,5.6-0.3c0.9,0.4,1.7,1,2.4,1.8c0.7,0.8,1.3,1.7,1.7,2.8c1.5,4.6,2.2,9.5,2.2,14.4"/>
<path fill="#fff1cf" transform="translate(0,0.3)" d="M86.4,50l0-0.9l-0.1-0.9l-0.1-1.9c0-0.9,0.2-1.7,0.7-2.3c0.5-0.7,1.3-1.2,2.3-1.4l0.3,0c0.9-0.2,1.9,0,2.6,0.6 c0.7,0.5,1.3,1.4,1.4,2.4l0.2,2.2l0.1,1.1l0,1.1"/>
<path fill="#000000" d="M88.6,36.6c0.1,0.3-0.2,0.7-0.6,0.8c-0.5,0.2-0.9,0-1.1-0.3c-0.1-0.3,0.2-0.7,0.6-0.8C88,36.1,88.5,36.2,88.6,36.6z"/>
<path fill="none" stroke="#000000" d="M86,38.7c0.2,0.6,0.8,0.9,1.4,0.7c0.6-0.2,0.9-0.9,0.6-2.1c0.3,1.2,1,1.7,1.6,1.5c0.6-0.2,0.9-0.8,0.8-1.4"/>
<path fill="#ffc254" stroke="#000000" d="M86.8,42.2l0.4,2.2c0.1,0.4,0.1,0.7,0.2,1.1l0.1,1.1c0.1,1.2-0.9,2.3-2.2,2.3h0c-1.3,0-2.5-0.8-2.5-1.9l-0.1-1 c0-0.3-0.1-0.6-0.2-1l-0.3-1.9"/>
<path fill="#ffc254" stroke="#000000" d="M96.2,40.2l0.5,2.7c0.1,0.5,0.2,0.9,0.2,1.4l0.1,1.4c0.1,1.5-0.9,2.8-2.2,2.8c-1.3,0-2.5-1.1-2.6-2.4l-0.1-1.2 c0-0.4-0.1-0.8-0.2-1.2l-0.4-2.5"/>
<path fill="none" stroke="#000000" d="M90.9,36.4c1.1-1.1,2.7-1.6,4.3-1.9"/>
<path fill="none" stroke="#000000" d="M91.6,37.5c1.3-0.5,2.8-0.8,4.2-0.7"/>
<path fill="none" stroke="#000000" d="M91.7,38.8c0.2-0.1,0.4-0.1,0.7-0.1c1.2-0.1,2.5,0,3.8,0.3"/>
<path fill="none" stroke="#000000" d="M85,38.4c-1.6-0.1-3.1,0.6-4.6,1.2"/>
<path fill="none" stroke="#000000" d="M85,39.5c-1.4,0.3-2.8,0.9-4,1.6"/>
<path fill="none" stroke="#000000" d="M85.5,40.4c-0.2,0-0.4,0.1-0.7,0.2c-1.1,0.5-2.2,1.1-3.2,1.8"/>
<path fill="#ff7bac" d="M92.8,34.2c0.1,0.3-0.3,0.8-0.9,1c-0.6,0.2-1.2,0.1-1.4-0.2c-0.1-0.3,0.3-0.8,0.9-1 C92.1,33.8,92.7,33.9,92.8,34.2z"/>
<path fill="#ff7bac" d="M82.2,38.2c0.1,0.3,0.7,0.3,1.3,0.1c0.6-0.2,1-0.6,0.9-0.9c-0.1-0.3-0.7-0.3-1.3-0.1 C82.5,37.5,82,37.9,82.2,38.2z"/>
<path fill="#000000" d="M90,35.7L89.3,36l-0.3-0.7c-0.3-0.9,0.1-1.9,0.9-2.3l0.7-0.3l0.3,0.7C91.3,34.4,90.9,35.4,90,35.7z"/>
<path fill="#000000" d="M85.3,37.4l0.7-0.2l-0.2-0.6c-0.3-0.8-1.3-1.2-2.1-0.8L82.9,36l0.2,0.6C83.5,37.4,84.4,37.7,85.3,37.4z"/>
</g></svg>
Loading...
</div>
could you please help me out, how to create SVG animation, which will behave like this? https://framer.cloud/aSUDY/
I did my best, but it always misbehaves :-(
Here is my code, where I used 6 animations to cycle through (3 to animate from 0.5 to 1 opacity and three to animate vice versa)
<?xml version="1.0" encoding="UTF-8"?>
<svg width="100%" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="background: #000085;">
<defs>
<ellipse id="CON11" fill="#FFFFFF" fill-opacity="0.5" cx="0.583333333" cy="1.5" rx="1" ry="1" >
<animate
id="anim1"
attributeType="xml"
attributeName="fill-opacity"
begin="0s;anim33.end"
from="0.5"
to="1"
dur="1s"
fill="freeze"
/>
</ellipse>
<path id="CON22" fill="#FFFFFF" fill-opacity="0.5" d="M1.78441961,0.25 L0.75,1.24747605 C1.2672098,1.94570929 1.2672098,2.84343773 0.75,3.54167097 L1.78441961,4.53914702 C3.02572314,3.34217576 3.02572314,1.54671887 1.78441961,0.25 Z">
<animate
id="anim2"
attributeType="xml"
attributeName="fill-opacity"
begin="anim1.end"
from="0.5"
to="1"
dur="1s"
fill="freeze"
/>
</path>
<path id="CON33" fill="#FFFFFF" fill-opacity="1" d="M1.53441961,8.85936702e-16 L0.5,0.99747605 C2.36195529,2.79293294 2.36195529,5.58586588 0.5,7.48107038 L1.53441961,8.47854643 C4.12046863,6.18435151 4.12046863,2.39394252 1.53441961,0 L1.53441961,8.85936702e-16 Z">
<animate
id="anim3"
attributeType="xml"
attributeName="fill-opacity"
begin="anim2.end"
from="0.5"
to="1"
dur="1s"
fill="freeze"
/>
</path>
<ellipse id="CON11" fill="#FFFFFF" fill-opacity="1" cx="0.583333333" cy="1.5" rx="1" ry="1" >
<animate
id="anim11"
attributeType="xml"
attributeName="fill-opacity"
begin="anim3.end"
from="1"
to="0.5"
dur="0.1"
fill="freeze"
/>
</ellipse>
<path id="CON22" fill="#FFFFFF" fill-opacity="1" d="M1.78441961,0.25 L0.75,1.24747605 C1.2672098,1.94570929 1.2672098,2.84343773 0.75,3.54167097 L1.78441961,4.53914702 C3.02572314,3.34217576 3.02572314,1.54671887 1.78441961,0.25 Z">
<animate
id="anim22"
attributeType="xml"
attributeName="fill-opacity"
begin="anim11.end"
from="1"
to="0.5"
dur="0.1"
fill="freeze"
/>
</path>
<path id="CON33" fill="#FFFFFF" fill-opacity="0.5" d="M1.53441961,8.85936702e-16 L0.5,0.99747605 C2.36195529,2.79293294 2.36195529,5.58586588 0.5,7.48107038 L1.53441961,8.47854643 C4.12046863,6.18435151 4.12046863,2.39394252 1.53441961,0 L1.53441961,8.85936702e-16 Z">
<animate
id="anim33"
attributeType="xml"
attributeName="fill-opacity"
begin="anim22.end"
from="1"
to="0.5"
dur="0.1"
fill="freeze"
/>
</path>
</defs>
<g id="ACFT" transform="translate(2.000000, 2.000000)" fill="#FFFFFF" fill-opacity="0.5">
<path d="M19,14 L19,12 L11,7 L11,1.5 C11,0.67 10.33,0 9.5,0 C8.67,0 8,0.67 8,1.5 L8,7 L0,12 L0,14 L8,11.5 L8,17 L6,18.5 L6,20 L9.5,19 L13,20 L13,18.5 L11,17 L11,11.5 L19,14 Z" id="Shape"></path>
</g>
<g id="CON3" transform="translate(18.000000, 2.000000)" >
<use xlink:href="#CON33" ></use>
</g>
<g id="CON2" transform="translate(16.000000, 4.000000)" >
<use xlink:href="#CON22" ></use>
</g>
<g id="CON1" transform="translate(15.000000, 5.000000)" >
<use xlink:href="#CON11" ></use>
</g>
</svg>
I've changed the animations to use values, they don't really need to be linked.
I've removed the duplication and the elements that really were'nt doing anything other than add complexity.
<svg width="100%" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="background: #000085;">
<g id="ACFT" transform="translate(2.000000, 2.000000)" fill="#FFFFFF" fill-opacity="0.5">
<path d="M19,14 L19,12 L11,7 L11,1.5 C11,0.67 10.33,0 9.5,0 C8.67,0 8,0.67 8,1.5 L8,7 L0,12 L0,14 L8,11.5 L8,17 L6,18.5 L6,20 L9.5,19 L13,20 L13,18.5 L11,17 L11,11.5 L19,14 Z" id="Shape"></path>
</g>
<g id="CON3" transform="translate(18.000000, 2.000000)" >
<path id="CON33" fill="#FFFFFF" fill-opacity="1" d="M1.53441961,8.85936702e-16 L0.5,0.99747605 C2.36195529,2.79293294 2.36195529,5.58586588 0.5,7.48107038 L1.53441961,8.47854643 C4.12046863,6.18435151 4.12046863,2.39394252 1.53441961,0 L1.53441961,8.85936702e-16 Z">
<animate
id="anim3"
attributeType="xml"
attributeName="fill-opacity"
begin="0s"
values="0.5;0.5;0.5;0.5;1"
dur="2s"
repeatCount="indefinite"
/>
</path>
</g>
<g id="CON2" transform="translate(16.000000, 4.000000)" >
<path id="CON22" fill="#FFFFFF" fill-opacity="0.5" d="M1.78441961,0.25 L0.75,1.24747605 C1.2672098,1.94570929 1.2672098,2.84343773 0.75,3.54167097 L1.78441961,4.53914702 C3.02572314,3.34217576 3.02572314,1.54671887 1.78441961,0.25 Z">
<animate
id="anim2"
attributeType="xml"
attributeName="fill-opacity"
begin="0s"
values="0.5;0.5;0.5;1;1"
dur="2s"
repeatCount="indefinite"
/>
</path>
</g>
<g id="CON1" transform="translate(15.000000, 5.000000)" >
<ellipse id="CON11" fill="#FFFFFF" fill-opacity="0.5" cx="0.583333333" cy="1.5" rx="1" ry="1" >
<animate
id="anim1"
attributeType="xml"
attributeName="fill-opacity"
begin="0s"
values="0.5;0.5;1;1;1"
dur="2s"
repeatCount="indefinite"
/>
</ellipse>
</g>
</svg>