Home > Software engineering >  How to start and stop execution of a JavaScript script with two buttons?
How to start and stop execution of a JavaScript script with two buttons?

Time:06-06

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 to repeat: -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>

  • Related