tween.js

/**
 * 缓动动画函数和各类算法
 * @module $ui/utils/tween
 * @author 陈华春
 */

// 动画每秒60帧
const UPDATE_TIME = 1000 / 60

const pow = Math.pow
const sqrt = Math.sqrt
const sin = Math.sin
const cos = Math.cos
const PI = Math.PI
const c1 = 1.70158
const c2 = c1 * 1.525
const c3 = c1 + 1
const c4 = (2 * PI) / 3
const c5 = (2 * PI) / 4.5

// 动画执行函数
const rAF = window.requestAnimationFrame || function (cb) {
  setTimeout(cb, UPDATE_TIME)
}

/**
 * 缓动动画函数
 * @param {number} startValue 开始时的值
 * @param {number} endValue 结束时的值
 * @param {number} during 动画持续时间,单位:毫秒
 * @param {Function} easingFunc 缓动算法函数
 * @param {function} stepCb 每次改变的回调函数
 * @returns {Promise} Promise实例
 *
 * @example
 *
 *  import tween, {easeInCubic} from '@/utils/tween'
 *  tween(0, 100, 300, easeInCubic, function(val){
 *      console.log(val)
 *      // to do something
 *  })
 */
export default function (startValue, endValue, during, easingFunc, stepCb) {
  // 改变的值大小
  const changeValue = endValue - startValue
  // 指定时间内更新的次数
  const updateCount = during / UPDATE_TIME
  // 每次更新的值距离
  const perUpdateDistance = 1 / updateCount
  let position = 0
  return new Promise(resolve => {
    function step() {
      const state = startValue + changeValue * easingFunc(position)
      let result = stepCb(state)
      // 如果返回false,停止运行
      if (result === false) return
      position += perUpdateDistance
      if (position < 1) {
        rAF(step)
      } else {
        rAF(() => {
          result = stepCb(endValue)
          if (result === false) return
          resolve()
        })
      }
    }

    step()
  })
}

/**
 * easeInQuad
 * @param {number} x
 * @returns {number}
 */
export function easeInQuad(x) {
  return x * x
}

/**
 * easeOutQuad
 * @param {number} x
 * @returns {number}
 */
export function easeOutQuad(x) {
  return 1 - (1 - x) * (1 - x)
}

/**
 * easeInOutQuad
 * @param x
 * @returns {number}
 */
export function easeInOutQuad(x) {
  return x < 0.5 ? 2 * x * x : 1 - pow(-2 * x + 2, 2) / 2
}

/**
 * easeInCubic
 * @param x
 * @returns {number}
 */
export function easeInCubic(x) {
  return x * x * x
}

/**
 * easeOutCubic
 * @param x
 * @returns {number}
 */
export function easeOutCubic(x) {
  return 1 - pow(1 - x, 3)
}

/**
 * easeInOutCubic
 * @param x
 * @returns {number}
 */
export function easeInOutCubic(x) {
  return x < 0.5 ? 4 * x * x * x : 1 - pow(-2 * x + 2, 3) / 2;
}

/**
 * easeInQuart
 * @param x
 * @returns {number}
 */
export function easeInQuart(x) {
  return x * x * x * x;
}

/**
 * easeInQuart
 * @param x
 * @returns {number}
 */
export function easeOutQuart(x) {
  return 1 - pow(1 - x, 4)
}

/**
 * easeInOutQuart
 * @param x
 * @returns {number}
 */
export function easeInOutQuart(x) {
  return x < 0.5 ? 8 * x * x * x * x : 1 - pow(-2 * x + 2, 4) / 2;
}

/**
 * easeInQuint
 * @param x
 * @returns {number}
 */
export function easeInQuint(x) {
  return x * x * x * x * x
}

/**
 * easeOutQuint
 * @param x
 * @returns {number}
 */
export function easeOutQuint(x) {
  return 1 - pow(1 - x, 5)
}

/**
 * easeInOutQuint
 * @param x
 * @returns {number}
 */
export function easeInOutQuint(x) {
  return x < 0.5 ? 16 * x * x * x * x * x : 1 - pow(-2 * x + 2, 5) / 2;
}

/**
 * easeInSine
 * @param x
 * @returns {number}
 */
export function easeInSine(x) {
  return 1 - cos(x * PI / 2)
}

/**
 * easeOutSine
 * @param x
 * @returns {number}
 */
export function easeOutSine(x) {
  return sin(x * PI / 2)
}

/**
 * easeInOutSine
 * @param x
 * @returns {number}
 */
export function easeInOutSine(x) {
  return -(cos(PI * x) - 1) / 2
}

/**
 * easeInExpo
 * @param x
 * @returns {number}
 */
export function easeInExpo(x) {
  return x === 0 ? 0 : pow(2, 10 * x - 10)
}

/**
 * easeOutExpo
 * @param x
 * @returns {number}
 */
export function easeOutExpo(x) {
  return x === 1 ? 1 : 1 - pow(2, -10 * x)
}

export function easeInOutExpo(x) {
  return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ? pow(2, 20 * x - 10) / 2 : (2 - pow(2, -20 * x + 10)) / 2
}

/**
 * easeInCirc
 * @param x
 * @returns {number}
 */
export function easeInCirc(x) {
  return 1 - sqrt(1 - pow(x, 2))
}

/**
 * easeOutCirc
 * @param x
 * @returns {number}
 */
export function easeOutCirc(x) {
  return sqrt(1 - pow(x - 1, 2))
}

export function easeInOutCirc(x) {
  return x < 0.5 ? (1 - sqrt(1 - pow(2 * x, 2))) / 2 : (sqrt(1 - pow(-2 * x + 2, 2)) + 1) / 2
}

/**
 * easeInElastic
 * @param x
 * @returns {number}
 */
export function easeInElastic(x) {
  return x === 0 ? 0 : x === 1 ? 1 : -pow(2, 10 * x - 10) * sin((x * 10 - 10.75) * c4)
}

/**
 * easeOutElastic
 * @param x
 * @returns {number}
 */
export function easeOutElastic(x) {
  return x === 0 ? 0 : x === 1 ? 1 : pow(2, -10 * x) * sin((x * 10 - 0.75) * c4) + 1
}

export function easeInOutElastic(x) {
  return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ? -(pow(2, 20 * x - 10) * sin((20 * x - 11.125) * c5)) / 2 : pow(2, -20 * x + 10) * sin((20 * x - 11.125) * c5) / 2 + 1
}

/**
 * easeInBack
 * @param x
 * @returns {number}
 */
export function easeInBack(x) {
  return c3 * x * x * x - c1 * x * x
}

/**
 * easeOutBack
 * @param x
 * @returns {number}
 */
export function easeOutBack(x) {
  return 1 + c3 * pow(x - 1, 3) + c1 * pow(x - 1, 2)
}

/**
 * easeInOutBack
 * @param x
 * @returns {number}
 */
export function easeInOutBack(x) {
  return x < 0.5 ? (pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2 : (pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2
}

/**
 * easeInBounce
 * @param x
 * @returns {number}
 */
export function easeInBounce(x) {
  return 1 - easeOutBounce(1 - x)
}

/**
 * easeOutBounce
 * @param x
 * @returns {number}
 */
export function easeOutBounce(x) {
  const n1 = 7.5625
  const d1 = 2.75
  if (x < 1 / d1) {
    return n1 * x * x
  } else if (x < 2 / d1) {
    return n1 * (x -= (1.5 / d1)) * x + 0.75;
  } else if (x < 2.5 / d1) {
    return n1 * (x -= (2.25 / d1)) * x + 0.9375;
  } else {
    return n1 * (x -= (2.625 / d1)) * x + 0.984375;
  }
}

/**
 * easeInOutBounce
 * @param x
 * @returns {number}
 */
export function easeInOutBounce(x) {
  return x < 0.5 ? (1 - easeOutBounce(1 - 2 * x)) / 2 : (1 + easeOutBounce(2 * x - 1)) / 2
}