utils/animation.js

import _ from 'lodash';
import DOMUtils from 'dom-utils';

// t = current time, b = start value, c = change in value, d = duration
// http://stackoverflow.com/questions/8917921/cross-browser-javascript-not-jquery-scroll-to-top-animation
Math.easeInOutQuad = (t, b, c, d) => {
    t /= (d / 2);

    if (t < 1) {
        return c / 2 * t * t + b;
    }

    t--;

    return -c / 2 * (t * (t - 2) - 1) + b;
};

/**
 * Utilities for working with animations.
 * @module AnimationUtils
 */
const AnimationUtils = {
    /**
     * Rounds a given number down to the nearest specified number.
     * @static
     * @function scrollTo
     * @param {String|Element} el - The selector or element to scroll to.
     * @param {Number} [position=0] - The position to scroll the element to.
     * @param {Number} [duration=400] - The time (in milliseconds) to scroll.
     * @param {String} [axis='y'] - The axis to scroll on.
     * @example
     * AnimationUtils.scrollTo(window, 0, 1000);
     * @returns {void}
     */
    scrollTo(el, position = 0, duration = 400, axis = 'y') {
        const element = (_.isString(el))
            ? DOMUtils.el(el)
            : el;
        const start = (axis === 'y') ? element.scrollTop : element.scrollLeft;
        const change = position - start;
        const increment = 20;
        let currentTime = 0;

        const animateScroll = () => {
            currentTime += increment;

            const val = Math.easeInOutQuad(currentTime, start, change, duration);

            if (axis === 'y') {
                element.scrollTop = val;
            } else {
                element.scrollLeft = val;
            }

            if (currentTime < duration) {
                setTimeout(animateScroll, increment);
            }
        };

        animateScroll();
    }
};

export default AnimationUtils;