如何在 requestAnimationframe 循环中的 2 个点之间进行插值

How to interpolate between 2 points in a requestAnimationframe loop

如果可以的话,我很乐意为此找一个图书馆?或者对我的伪代码 api.

的任何其他建议

问题:

如何编写一个带有 4 个参数的函数 interpolate(start, end, time, ease) 并随着时间的推移轻松地对从开始到结束的数字进行插值?

问题:

这感觉特别难,因为我不知道如何控制时间或缓和请求动画帧。其次,我不知道如何编写贝塞尔曲线处理程序。最后,如果需要优化。

  interpolate(start:number, end:number, time:number, ease) {
    // easing
    return value;
  }

  function _draw() {
    currentValue = interpolate(0, 10, 0.7, 'cubic-bezier(.62,.28,.23,.99)');
    if(currentValue !== lastValue) {
      console.log(currentValue)
    }
    requestAnimationFrame(_draw);
  }

所以最后 currentValue 会在 0.7 的最后一个刻度中注销 10。

我建议使用 Penner Equations 进行通用缓动。这些函数可以作为库在 github 上找到: tween-functions.

一个简单的演示,展示如何在每一帧上计算值:

const Easings = [
  function easeInQuad(t, b, c, d) {
    return c * (t /= d) * t + b;
  },
  function easeOutBounce(t, b, c, d) {
    if ((t /= d) < (1 / 2.75)) {
      return c * (7.5625 * t * t) + b;
    } else if (t < (2 / 2.75)) {
      return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b;
    } else if (t < (2.5 / 2.75)) {
      return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;
    } else {
      return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;
    }
  },
  function easeInOutElastic(t, b, c, d) {
    // jshint eqeqeq: false, -W041: true
    var s = 1.70158;
    var p = 0;
    var a = c;
    if (t == 0) return b;
    if ((t /= d / 2) == 2) return b + c;
    if (!p) p = d * (0.3 * 1.5);
    if (a < Math.abs(c)) {
      a = c;
      s = p / 4;
    } else s = p / (2 * Math.PI) * Math.asin(c / a);
    if (t < 1) return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
    return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + c + b;
  },
];
const duration = 2000;
const div = document.querySelector('div');

let start = Date.now();
let from = 0;
let to = 300;
let fnCounter = 0;
let fn = Easings[fnCounter];


function tick() {
  let now = Date.now();
  let elapsed = now - start;
  let val = fn(elapsed, from, to - from, duration);
  div.style.transform = `translateX(${val}px)`;
  if (elapsed >= duration) {
    start = now;
    let x = from;
    from = to;
    to = x;
    fn = Easings[++fnCounter % Easings.length]
    setTimeout(tick, 300);
    return;
  }
  requestAnimationFrame(tick);
}

requestAnimationFrame(tick);
div {
  position: absolute;
  top: 0px;
  left: 0;
  width: 100px;
  height: 100px;
  background: orange;
}
<div></div>

对于自定义贝塞尔曲线,我建议使用此库:bezier-easing。这里的计算是相同的:在每个刻度上你得到经过的时间并计算持续时间的百分比,现在你在每个帧上有一个从 01 的刻度值。