Search code examples
javascriptjqueryanimationlottiebodymovin

How can I get one section of this rollover animation to loop continuously?


I have an animation I'd like to use for a rollover effect with the following basic states:

  1. resting: continuously loop between frames 0 and 55
  2. mouse enter: play once frames 56 to 78, then pause on 78
  3. mouse out: play once frames 79-95, then return to resting

I almost have it working except for a continuous loop on the resting state. The loop plays only once and then sits static. My code sits as follows:

Codepen: https://codepen.io/anon/pen/pBXKeN

var animationContainer = document.getElementById("animation-container");

var animation = lottie.loadAnimation({
    wrapper: document.getElementById("animation-wrapper"),
    renderer: "svg",
    loop: false,
    autoplay: false,
    prerender: true,
    animationData: animationData,
});

animation.addEventListener('DOMLoaded',resting);
animationContainer.addEventListener("mouseenter", hoverStart);
animationContainer.addEventListener("mouseleave", hoverEnd);

function resting() {
    animation.removeEventListener("complete", resting);
    console.log('resting');
    animation.playSegments([0, 55], true);
}

function hoverStart() {
    console.log('hover started');
    animationContainer.removeEventListener("mouseenter", hoverStart);
    animation.playSegments([56, 78], true);
    animationContainer.addEventListener("mouseleave", hoverEnd);
}

function hoverEnd() {
    console.log('hover ended');
    animationContainer.removeEventListener("mouseleave", hoverEnd);
    animation.playSegments([79, 95], true);
    animation.addEventListener("complete", resting);
    animationContainer.addEventListener("mouseenter", hoverStart);
}

I have tried setting loop to true, but this causes all 3 states to loop, which is not the desired effect for the mouseenter and mouseleave effects. Is there a way to get a single section to loop?

Also I'm happy to switch to jQuery if it makes things simpler.


Solution

  • Solved with a combination of setting loop to true, looping between 2 frames for the "pause" effect and more closely monitoring the hover state. I'm sure this could be improved further, but at this point I'm just glad to have it working.

    Updated Codepen: https://codepen.io/matt3/pen/NVxWYJ

    var hover = false;
    
    animationContainer.addEventListener("mouseenter", hoverStart);
    animation.addEventListener('DOMLoaded',resting);
    
    function resting() {
      console.log('resting. hover status: ' + hover);
      animation.removeEventListener("loopComplete", resting);
      animation.playSegments([0, 55], true);
    }
    
    function hoverStart() {
      console.log('hover started. hover status: ' + hover);
      animationContainer.removeEventListener("mouseenter", hoverStart);
      animation.playSegments([56, 78], true);
      animation.addEventListener("loopComplete", hoverPause);
    }
    
    function hoverPause() {
      console.log('hover paused. hover status: ' + hover);
      animation.removeEventListener("loopComplete", hoverPause);
      animationContainer.addEventListener("mouseleave", hoverEnd);
      animation.playSegments([77, 78], true);
      console.log('hover pause complete. hover status: ' + hover);
      if (!hover) {
        animation.addEventListener("loopComplete", hoverEnd);
      }
    }
    
    function hoverEnd() {
      console.log('hover ended. hover status: ' + hover);
      animationContainer.removeEventListener("mouseleave", hoverEnd);
      animation.removeEventListener("loopComplete", hoverEnd);
      animation.playSegments([79, 95], true);
      animation.addEventListener("loopComplete", resting);
      animationContainer.addEventListener("mouseenter", hoverStart);
    }
    
    animationContainer.onmouseout = function () {
        hover = false;
    }
    animationContainer.onmouseover = function () {
        hover = true;
    }