Source: src/ease.js

src/ease.js

const EventEmitter = require('eventemitter3')

const Number = require('./number')
const Color = require('./color')
const Transform = require('./transform')
const Margin = require('./margin')
const utils = require('./utils')

class Ease extends EventEmitter
{
    /**
     * Ease class returned by DomEase.add()
     * @extends EventEmitter
     * @param {HTMLElement} element
     * @param {object} params
     * @param {number} [params.left] in px
     * @param {number} [params.right] in px
     * @param {number} [params.top] in px
     * @param {number} [params.bottom] in px
     * @param {number} [params.width] in px
     * @param {number} [params.height] in px
     * @param {number} [params.scale]
     * @param {number} [params.scaleX]
     * @param {number} [params.scaleY]
     * @param {number} [params.opacity]
     * @param {number} [params.marginLeft] in px
     * @param {number} [params.marginRight] in px
     * @param {number} [params.marginTop] in px
     * @param {number} [params.marginBottom] in px
     * @param {(color|color[])} [params.color]
     * @param {(color|color[])} [params.backgroundColor]
     * @param {object} [options]
     * @param {number} [options.start] use this as the starting value
     * @param {number} [options.duration]
     * @param {(string|function)} [options.ease]
     * @param {(boolean|number)} [options.repeat]
     * @param {boolean} [options.reverse]
     * @param {number} [options.wait]
     * @returns {Ease}
     * @fires Ease#each
     * @fires Ease#complete
     * @fires Ease#loop
     * @hideconstructor
     */
    constructor(element, params, options)
    {
        super()
        this.element = element
        this.list = []
        this.time = 0
        this.duration = options.duration
        this.ease = options.ease
        this.repeat = options.repeat
        this.reverse = options.reverse
        this.wait = options.wait || 0
        for (let entry in params)
        {
            switch (entry)
            {
                case 'left':
                    this.list.push(new Number(element, entry, element.offsetLeft, params[entry], 'px'))
                    break

                case 'top':
                    this.list.push(new Number(element, entry, element.offsetTop, params[entry], 'px'))
                    break

                case 'bottom':
                    this.list.push(new Number(element, entry, element.parentNode.offsetHeight - (element.offsetTop + element.offsetHeight), params[entry], 'px'))
                    break

                case 'right':
                    this.list.push(new Number(element, entry, element.parentNode.offsetWidth - (element.offsetLeft + element.offsetWidth), params[entry], 'px'))
                    break

                case 'color':
                    this.list.push(new Color(element, 'color', params[entry], this.duration / (1 + params[entry].length)))
                    break

                case 'backgroundColor':
                    this.list.push(new Color(element, 'backgroundColor', this.duration / (1 + params[entry].length)))
                    break

                case 'scale':
                    if (this.transform)
                    {
                        this.transform.add('scaleX', params[entry])
                    }
                    else
                    {
                        this.transform = new Transform(element, 'scaleX', params[entry])
                        this.list.push(this.transform)
                    }
                    this.transform.add('scaleY', params[entry])
                    break

                case 'scaleX':
                case 'scaleY':
                    if (this.transform)
                    {
                        this.transform.add(entry, params[entry])
                    }
                    else
                    {
                        this.transform = new Transform(element, entry, params[entry])
                        this.list.push(this.transform)
                    }
                    break

                case 'opacity':
                    this.list.push(new Number(element, entry, parseFloat(utils.getComputed(element, 'opacity')), params[entry]))
                    break

                case 'width':
                    this.list.push(new Number(element, entry, element.offsetWidth, params[entry], 'px'))
                    break

                case 'height':
                    this.list.push(new Number(element, entry, element.offsetHeight, params[entry], 'px'))
                    break

                case 'marginLeft':
                case 'marginRight':
                case 'marginTop':
                case 'marginBottom':
                    if (this.margin)
                    {
                        this.margin.add(entry, params[entry])
                    }
                    else
                    {
                        this.margin = new Margin(element, entry, params[entry])
                        this.list.push(this.margin)
                    }
                    break

                default:
                    console.warn(entry + ' not setup for animation in dom-ease.')
            }
        }
    }

    update(elapsed)
    {
        if (this.wait)
        {
            this.wait -= elapsed
            if (this.wait < 0)
            {
                elapsed = -this.wait
                this.wait = 0
            }
            else
            {
                return
            }
        }
        const list = this.list
        let leftover = null
        this.time += elapsed
        if (this.time >= this.duration)
        {
            leftover = this.time - this.duration
            this.time -= leftover
        }
        const percent = this.ease(this.time, 0, 1, this.duration)
        for (let i = 0, _i = list.length; i < _i; i++)
        {
            list[i].update(percent, this.time)
        }
        this.emit('each', this)

        // handle end of duration
        if (leftover !== null)
        {
            if (this.reverse)
            {
                this.reverseEases()
                this.time = leftover
                this.emit('loop', this)
                if (!this.repeat)
                {
                    this.reverse = false
                }
                else if (this.repeat !== true)
                {
                    this.repeat--
                }
            }
            else if (this.repeat)
            {
                this.emit('loop', this)
                this.time = leftover
                if (this.repeat !== true)
                {
                    this.repeat--
                }
            }
            else
            {
                this.emit('complete', this)
                return true
            }
        }
    }

    reverseEases()
    {
        const list = this.list
        for (let i = 0, _i = list.length; i < _i; i++)
        {
            const ease = list[i]
            ease.reverse()
        }
    }
}

/**
 * fires when eases are complete
 * @event Ease#complete
 * @type {Ease}
 */

/**
 * fires on each loop while eases are running
 * @event Ease#each
 * @type {Ease}
 */

/**
 * fires when eases repeat or reverse
 * @event Ease#loop
 * @type {Ease}
 */

module.exports = Ease