Search code examples
javascriptcssdojo

Dojo infinite bounce animation


I need to make this css3 animation using Dojo, but I'm not getting the desired result. The arrow should bounce when its hovered. Simiilar to this http://codepen.io/dodozhang21/pen/siKtp but horizontal. HTML:

            <a href="#" class="uiAnimatedArrow" title="Buying a Home">
                <!-- -->
                <span>
                    <i data-copy="Learn More"><b></b></i>
                    Buying a Home
                </span>
            </a>

CSS:

a.uiAnimatedArrow i b {
  position: absolute;
  top: 50%;
  width: 9px;
  height: 12px;
  margin: -6px 0 0 0;
  content: '';
  background: url("/assets/images/icons/arrow-right-black.png") 0 0 no-repeat;
  right: 13px;
}

  a.uiAnimatedArrow span:hover i b {
  -webkit-animation: bounce 1.5s infinite;
  -moz-animation: bounce 1.5s infinite;
  -ms-animation: bounce 1.5s infinite;
  -o-animation: bounce 1.5s infinite;
  animation: bounce 1.5s infinite;
}

Any suggestion?


Solution

  • To do that in Dojo you'll have to use dojo/_base/fx to animate the right property. However, you cannot do this in a single animation, because there are multiple keyframes defined. So, you'll have to split it up in the following cases (if you want it similar to the given Codepen):

    0%  0
    20% 0
    40% -30
    50% 0
    60% -15
    80% 0
    

    So, we'll need 4 separate animations, from 20% to 40%, from 40% to 50%, from 50% to 60% and from 60% to 80%.

    Using dojo/_base/fx you can make something like this:

    function frame40(node) {
        return fx.animateProperty({
            node: node,
            properties: {
                right: {
                    start: 0,
                    end: 30
                }
            },
            delay: 800,
            duration: 200,
            easing: easing.quadInOut
        });
    }
    
    function frame50(node) {
        return fx.animateProperty({
            node: node,
            properties: {
                right: {
                    start: 30,
                    end: 0
                }
            },
            duration: 200,
            easing: easing.quadInOut
        });
    }
    
    function frame60(node) {
        return fx.animateProperty({
            node: node,
            properties: {
                right: {
                    start: 0,
                    end: 15
                }
            },
            duration: 200,
            easing: easing.quadInOut
        });
    }
    
    function frame80(node) {
        return fx.animateProperty({
            node: node,
            properties: {
                right: {
                    start: 15,
                    end: 0
                }
            },
            duration: 400,
            easing: easing.quadInOut
        });
    }
    

    In this case I'm animating the right property for a given duration. The duration is based on the keyframe percentage * the total animation (2s in the Codepen).

    I also added an easing property using dojo/fx/easing because otherwise it's just a linear animation which doesn't feel natural to me.

    To invoke the animation, we need to create two event listeners, a mouseenter listener and a mouseleave listener. In the mouseenter listener we will have to chain the animation and play it. To chain them, you can use the dojo/fx::chain() function. However, this only plays the animation once. To run it infinitely, we use the setInterval() function to repeat the animation every 2 seconds:

    var interval, anim;
    query(".arrow").on("mouseenter", function() {
        var node = this;
        var keyframes = function() {
            anim = coreFx.chain([
                frame40(node),
                frame50(node),
                frame60(node),
                frame80(node)
            ]).play();
        };
        interval = setInterval(keyframes, 2000);
        keyframes();
    });
    

    Now, in the mouseleave event handler we have to clear the interval and we have to stop the animation if it was playing. However, stopping the animation may cause the arrow to be stopped in "mid air", so we have to properly put it back to the right, you could do that with an animation as well:

    query(".arrow").on("mouseleave", function() {
        if (interval != null) {
            clearInterval(interval);
        }
        if (anim != null) {
            anim.stop();
            fx.animateProperty({
                node: this,
                properties: {
                    right: 0
                },
                duration: 200,
                easing: easing.quadInOut
            }).play();
        }
    });
    

    That should be everything, you can check out the complete example on JSFiddle: http://jsfiddle.net/ro55btas/