3

I am using Web Animation API to create a simple animation so that when a user moves the mouse on the target, the animation should start from left to right and when the user moves the mouse off the target, the animation should get reversed and the target should move from right to left.

Currently if the user moves the mouse in/out during animation, the animation is jerky, and I don't have a smooth effect.

I would like to know how to solve this issue.

Note: Currently I am using the Web Animation API. But the same issue occurs when using the CSS Keyframe Animation.

I have also tried to solve this issue using the following solution, which improved the situation but it's still problematic. Here is a live example https://jsfiddle.net/x784xwoa/5/

var elm = document.getElementById("target");
var player = document.getElementById("target");

elm.addEventListener('mouseover', function(event) {
  console.log('mouseover', player.playState, 'animate');
  player = elm.animate(
    [{
      left: "0px",
      boxShadow: 'rgba(0, 0, 0, 0.5) 0px 0px 0px 0px'
    }, {
      left: "100px",
      boxShadow: 'rgba(0, 0, 0, 0.9) 50px 150px 100px 0px'
    }], {
      duration: 3000,
      direction: "normal",
      fill: "forwards",
      iterations: 1
    }
  );
});

elm.addEventListener('mouseout', function(event) {
  console.log('mouseout', player.playState, 'reverse');
  player.reverse();
});
#target {
  position: relative;
  top: 0;
  left: 0;
  width: 100px;
  height: 150px;
  background-color: red;
}
<div id="target"></div>
ShellZero
  • 4,415
  • 12
  • 38
  • 56
GibboK
  • 71,848
  • 143
  • 435
  • 658
  • What is the jerkiness you are noticing with the updated codepen? Currently both Chrome and Firefox are implementing additive animation (part of Web Animations) which will allow you to make one animation that smoothly transitions into another. – brianskold Nov 22 '16 at 04:52

3 Answers3

1

I've always had success using mouseenter / mouseleave rather than mouseover / mouseout.

Though they operate the same way, however, the mouseenter event only triggers when the mouse pointer enters the selected element. The mouseover event is triggered if a mouse pointer enters any child elements as well.

rfornal
  • 5,072
  • 5
  • 30
  • 42
  • Thanks for your comment, I have tried your suggestion, unfortunately I still have the same issue https://jsfiddle.net/r39f461s/2/ – GibboK Nov 21 '16 at 13:45
0

I was able to solve this issue using the following script adding some logic to check playState. In case you have a better solution, please post it as answer as I would be really interested to have your feedback.

   document.addEventListener("DOMContentLoaded", function (event) {
            var elm = document.getElementById("target");
            var player = null;



            elm.addEventListener('mouseenter', function (event) {
                if (player === null) {
                    player = elm.animate(
                      [{
                          left: "0px",
                          boxShadow: 'rgba(0, 0, 0, 0.5) 0px 0px 0px 0px'
                      }, {
                          left: "100px",
                          boxShadow: 'rgba(0, 0, 0, 0.9) 50px 150px 100px 0px'
                      }], {
                          duration: 3000,
                          direction: "normal",
                          fill: "forwards",
                          iterations: 1
                      }
                    );
                }
                else if (player.playState === 'running') {
                    player.reverse();
                }
                else if (player.playState === 'finished') {
                    player.reverse();

                }
            });

            elm.addEventListener('mouseout', function (event) {
                if (player.playState === 'running' || player.playState === 'finished') {
                    player.reverse();
                }
            });

            setInterval(function () {
                if (player) {
                    console.log(player.playState);
                }
            }, 1000);


        });
        #target {
            position: relative;
            top: 0;
            left: 0;
            width: 100px;
            height: 150px;
            background-color: red;
        }
    <div id="target"></div>
GibboK
  • 71,848
  • 143
  • 435
  • 658
0

Every time the mouseover event is triggered you make a new animation for the element. Avoid this by creating the animation beforehand, and pausing it until it is used.

I also replaced player.reverse(); with player.playBackRate = (-)1;. I'm not sure why that also caused problems.

var elm = document.getElementById("target");
var player = elm.animate(
  [{
    left: "0px",
    boxShadow: 'rgba(0, 0, 0, 0.5) 0px 0px 0px 0px'
  }, {
    left: "100px",
    boxShadow: 'rgba(0, 0, 0, 0.9) 50px 150px 100px 0px'
  }], {
    duration: 3000,
    direction: "normal",
    fill: "forwards",
    iterations: 1
  }
);
player.pause();

elm.addEventListener('mouseover', function(event) {
  player.playbackRate = 1;
  player.play();
});

elm.addEventListener('mouseout', function(event) {
  player.playbackRate = -1;
});
#target {
  position: relative;
  top: 0;
  left: 0;
  width: 100px;
  height: 150px;
  background-color: red;
}
<div id="target"></div>

The only issue that remains is that the mouseout event doesn't fire when the element moves from underneath the mouse. It only fires when the mouse is moved.

Floris
  • 48
  • 7