I am animating an element in SVG so that it travels around a circular track. It runs around the track 3x and stops. I am using the GSAP MotionPath plugin to do the animation. I want to control the motion with start and stop buttons. The stop button can either pause the motion or stop it completely and have the element return to its place - whichever involves the simpler method.
I managed to get the animation to start by clicking the "START" button. But I can't get it to stop by clicking the "STOP" button.
I show below the animation with the start button.
function myFunction(){
gsap.registerPlugin(MotionPathPlugin);
gsap.to("#comet-horizontal", {
duration: 5,
repeat: 2,
repeatDelay: 0,
yoyo: false,
ease: "none",
motionPath:{
path: "#racetrack",
align: "#racetrack",
autoRotate: true,
alignOrigin: [0.5, 0.5]
}
});
}
html, body {
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
body {
/*background-color: black;*/
min-height: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
svg {
overflow: visible;
height: 100%;
background-color: orange;
/* Fix Safari rendering bug */
transform: translateZ(0);
}
circle {
fill: pink;
}
#button{
width: 60px;
height: 30px;
background-color: orange;
position: relative;
margin-top: 5px;
margin-bottom: 5px;
}
#button2{
width: 60px;
height: 30px;
background-color: yellow;
position: relative;
margin-top: 5px;
margin-bottom: 5px;
}
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.3/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.3/MotionPathPlugin.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="snap.svg-min.js"></script>
</head>
<body>
<button id="button" onclick="myFunction()">START</button>
<button id="button2">STOP</button>
<svg
width="100%"
height="100%"
viewBox="0 0 338.66667 190.5">
<path
id="racetrack"
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffaaaa;stroke-width:2.32673;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke;stop-color:#000000;stop-opacity:1"
d="M 184.04496,79.375006 A 51.753304,51.753307 0 0 1 132.29166,131.1283 51.753304,51.753307 0 0 1 80.538365,79.375006 51.753304,51.753307 0 0 1 132.29166,27.621698 a 51.753304,51.753307 0 0 1 51.7533,51.753308 z" />
<path
id="comet-horizontal"
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#00d3ff;fill-opacity:1;fill-rule:evenodd;stroke-width:2.82278;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
d="m 241.75652,61.794127 v 2.645839 l -13.22916,-0.661459 v -0.66146 -0.66146 z"
sodipodi:nodetypes="cccccc" />
</svg>
</body>
I browsed StackOverflow but could not find the answer. For example, How to control the execution of javascript functions? is a similar question to mine but the asker wants a new function to start after the first one is stopped.
I cannot use typical animation functions such as animation-play-state
since the animation is using a GreenSock script.
I also tried out the top solution from How to stop a function during its execution - JavaScript but it didn't work for me (maybe because I implemented it wrongly). I am having trouble writing the "if" condition for when the Stop button is clicked. I tried if(document.getElementById('button').clicked == true)
but it didn't work.
Below is the solution mentioned above in the last link.
function foo1(){
console.log("Foo started...");
if(prompt("Type 1 to terminate right now or anything else to continue...") == "1"){
return; // Function will terminate here if this is encountered
}
console.log("Foo ending..."); // This will only be run if something other than 1 was entered
}
foo1();
I would prefer to stick with vanilla JS solutions if possible rather than JQuery because I am not familiar with JQuery, but if a JQuery solution is the easiest way of doing it, I am open to it.
This is the attempt to implement the "foo1" solution that failed:
function myFunction(){
gsap.registerPlugin(MotionPathPlugin);
gsap.to("#comet-horizontal", {
duration: 5,
repeat: 2,
repeatDelay: 0,
yoyo: false,
ease: "none",
motionPath:{
path: "#racetrack",
align: "#racetrack",
autoRotate: true,
alignOrigin: [0.5, 0.5]
}
});
if (document.getElementById("button2").clicked == true)
return;
}
myFunction();
CodePudding user response:
The gsap.to
method returns a Tween object with which you can control the animation. It has pause
, resume
, restart
and several other useful methods.
Here I adapted your script:
- Renamed the HTML buttons with more telling names.
- Attached the click handlers in code, not via HTML attribute
- Added a global variable to allow each event handler to access the above mentioned object
- Added the logic to pause and resume the animation
- Change the
repeat: 2
parameter torepeat: -1
, so the animation has no end.
let tween; // global so both handlers can access it
document.getElementById("buttonStart").addEventListener("click", function () {
if (tween) { // Not first time:
tween.resume(); // Continue from where it was paused
return;
}
gsap.registerPlugin(MotionPathPlugin);
tween = gsap.to("#comet-horizontal", {
duration: 5,
repeat: -1,
repeatDelay: 0,
yoyo: false,
ease: "none",
motionPath:{
path: "#racetrack",
align: "#racetrack",
autoRotate: true,
alignOrigin: [0.5, 0.5]
}
});
});
document.getElementById("buttonStop").addEventListener("click", function () {
tween?.pause();
});
html, body {
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
body {
/*background-color: black;*/
min-height: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
svg {
overflow: visible;
height: 100%;
background-color: orange;
/* Fix Safari rendering bug */
transform: translateZ(0);
}
circle {
fill: pink;
}
#button{
width: 60px;
height: 30px;
background-color: orange;
position: relative;
margin-top: 5px;
margin-bottom: 5px;
}
#button2{
width: 60px;
height: 30px;
background-color: yellow;
position: relative;
margin-top: 5px;
margin-bottom: 5px;
}
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.3/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.3/MotionPathPlugin.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="snap.svg-min.js"></script>
</head>
<body>
<button id="buttonStart">START</button>
<button id="buttonStop">STOP</button>
<svg
width="100%"
height="100%"
viewBox="0 0 338.66667 190.5">
<path
id="racetrack"
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffaaaa;stroke-width:2.32673;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke;stop-color:#000000;stop-opacity:1"
d="M 184.04496,79.375006 A 51.753304,51.753307 0 0 1 132.29166,131.1283 51.753304,51.753307 0 0 1 80.538365,79.375006 51.753304,51.753307 0 0 1 132.29166,27.621698 a 51.753304,51.753307 0 0 1 51.7533,51.753308 z" />
<path
id="comet-horizontal"
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#00d3ff;fill-opacity:1;fill-rule:evenodd;stroke-width:2.82278;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
d="m 241.75652,61.794127 v 2.645839 l -13.22916,-0.661459 v -0.66146 -0.66146 z"
sodipodi:nodetypes="cccccc" />
</svg>
</body>