1

Here is a simple pulsating animation using CSS keyframes.

The problem is if I want to discard or remove the animation in the middle of it, the animation stops with a jerking movement (a sudden jump to its initial state as you can see in the snippet).

I want the animation to go back to its initial state smoothly even if you stop it in the middle of the animation.

JQuery and TweenMax are accepted.

Is there any way to do that?

let test = document.getElementById("test");


setTimeout(function(){

test.classList.add("addAniamte");

}, 2000)


setTimeout(function(){

test.classList.remove("addAniamte");
test.classList.add("removeAniamte");
console.log('stoping aniamtion!');

}, 4500)
@-webkit-keyframes pulse {
 0% {
 -webkit-transform: scale(1, 1);
}
 50% {
 -webkit-transform: scale(3, 3);
}
 100% {
 -webkit-transform: scale(1, 1);
};
}


#test {
 background: red;
 width: 20px;
 height: 20px;
  margin: 60px;
}

.addAniamte{
  -webkit-animation: pulse 1s linear infinite;
 animation: pulse 1s linear infinite; 
}

.removeAniamte{
  -webkit-animation: none;
 animation:none;
}
<div id="test"></div>
Sara Ree
  • 3,417
  • 12
  • 48
  • Does https://stackoverflow.com/a/29682311 help? – IamAshKS Dec 14 '19 at 18:38
  • Are you targeting chrome browser or other browser? – Plochie Dec 14 '19 at 20:33
  • Only chrome and I'm disappointed about the possibility of doing this ... I'm working on GSAP .... – Sara Ree Dec 14 '19 at 20:39
  • Is it the result https://stackblitz.com/edit/js-tg6zch? If this satisfy your need I ll explain it in answer. Click on start to start animation and click on stop to stop. After the duration only animation will stop. – Plochie Dec 14 '19 at 21:17

2 Answers2

1

This is quite easy to do with GSAP! Here's how to do something like this in GSAP 3.

var tween = gsap.from("#test", {duration: 1, scale: 0.33, repeat: -1, yoyo: true, paused: true});

function startAnimation() {
    tween.play();
}

function stopAnimation() {
    tween.pause();
    gsap.to(tween, {duration: 0.5, progress: 0});
}
   
#test {
  background: red;
  width: 60px;
  height: 60px;
  margin: 60px;
}
<div id="test"></div>

<button onclick="startAnimation()">Start</button>
<button onclick="stopAnimation()">Stop</button>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.0.4/dist/gsap.min.js"></script>

Without GSAP (or at least a JS-only approach), it's incredibly messy and error prone as the other answer shows. In fact, I had my own question which lead to a CSS-Tricks article on the subject.

Zach Saucier
  • 24,871
  • 12
  • 85
  • 147
0

I have tried to make the javascript completely dynamic by using getComputedStyle. To stop animation smoothly, we need to have a watcher variable, which will count the duration of each animation cycle. (tempAnimationWatcher).

  1. Add animation start event to element.
  2. Calculate single animation duration (testAnimationTime) and initiate tempAnimationWatcherInterval to watch animation cycle time tempAnimationWatcher
  3. if stopAnimation, stop animation after remaining css time. (testAnimationTime - tempAnimationWatcher)

NOTE: the testAnimationTime calculations are based on consideration that the css animation time is written in seconds. see line testAnimationTime = parseInt(animationDurationInCss.substring(0, animationDurationInCss.length - 1)) * 1000;, this is removing last char and converting it in milliseconds.

const test = document.getElementById("test");
let tempAnimationWatcher = 0;
let testAnimationTime = 0;
let tempAnimationWatcherInterval;

test.addEventListener('animationstart', function (e) {
    console.log('animation starts')

    const animationDurationInCss = getComputedStyle(test).animationDuration;
    testAnimationTime = parseInt(animationDurationInCss.substring(0, animationDurationInCss.length - 1)) * 1000;
    tempAnimationWatcher = 0;
    tempAnimationWatcherInterval = setInterval(() => {
        tempAnimationWatcher += 10;
        if (tempAnimationWatcher >= testAnimationTime) tempAnimationWatcher = 0;
    }, 10);
});

function startAnimation() {
    test.classList.add("addAniamte");
}

function stopAnimation() {
    clearInterval(tempAnimationWatcherInterval);
    setTimeout(() => {
        test.classList.remove("addAniamte");
        console.log("stoping aniamtion!");
    }, (testAnimationTime - tempAnimationWatcher));
}

startAnimation();
@keyframes pulse {
    0% {
        -webkit-transform: scale(1, 1);
    }
    50% {
        -webkit-transform: scale(3, 3);
    }
    100% {
        -webkit-transform: scale(1, 1);
    }
    ;
}

#test {
    background: red;
    width: 20px;
    height: 20px;
    margin: 60px;
}

.addAniamte {
    animation: pulse 2s linear infinite;
}
<div id="test"></div>
<hr>
<button onclick="startAnimation()">Start</button>
<button onclick="stopAnimation()">Stop</button>
Plochie
  • 3,944
  • 1
  • 17
  • 33
  • @ZachSaucier you might be correct. I never used GSAP. So I was thinking in vanilla javascript only. – Plochie Dec 15 '19 at 19:02