javascript - 如何独立于刷新率计时 requestAnimationFrame()

标签 javascript animation

我有一种情况,我想在 1 秒内将 600px 宽的 div 的宽度设置为 0px。为此,我可以使用 requestAnimationFrame()。但我真的不能 100% 确定动画是否需要 1 秒。

它看起来像这样:

let width = 600;
let animation;
function animateWidth(){
  if(width <= 0){
    window.cancelAnimationFrame();
  }else{
    width -= 10; // (600px/60fps)
  }
  document.getElementById('id1').setAttribute('width', width);
  animation = window.requestAnimationFrame(animateWidth);
}
animation = window.requestAnimationFrame(animateWidth);

问题是,当设备具有不同的 fps 时,它会影响动画的持续时间(在 30 fps 时需要 2 秒,在 60 fps 时需要 1 秒)。我想确保动画的持续时间始终为一秒。如果 fps-rate 不同,我想根据持续时间更改宽度的新值(因此以 30 fps 设置动画我们将每步更改宽度 20 (600px/30fps))。

  • 有什么方法可以在使用 requestAnimationFrame 时实现这一点?如果我能得到帧之间的平均间隔或我认为可行的 fps。
  • 我是不是在担心一些并不是什么大问题的事情?
  • 我在不同设备(移动设备、个人电脑、平板电脑等)上预期的 fps 是多少?

文档:https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame

最佳答案

requestAnimationFrame 将页面加载后的时间传递给回调,例如

const startValue = 600;
const endValue = 0;

// return a value between start and end as l goes from 0 to 1
function lerp(start, end, l) {
  return start + (end - start) * l;
}

const startTime = performance.now();
const durationInSeconds = 1;
const element = document.getElementById('id1');

function animateWidth(now) {
  const timeSinceStartInSeconds = (now - startTime) * 0.001;

  // l goes from 0 to 1 over durationInSeconds;
  const l = Math.min(timeSinceStartInSeconds / durationInSeconds, 1);

  element.setAttribute('width', lerp(startValue, endValue, l));

  // if we haven't finished request another animation frame
  if (l < 1) {
    requestAnimationFrame(animateWidth);
  }
}
requestAnimationFrame(animateWidth);
#id1 { background: red; }
<canvas id="id1"></canvas>

如果是我,我可能会尝试让它成为一个函数

// return a value between start and end as l goes from 0 to 1
function lerp(start, end, l) {
  return start + (end - start) * l;
}

function animateAttribute(element, attribute, startValue, endValue, duration) {
  const startTime = performance.now();

  function animate(now) {
    const timeSinceStart = (now - startTime) * 0.001;

    // l goes from 0 to 1 over durationInSeconds;
    const l = Math.min(timeSinceStart / duration, 1);

    element.setAttribute(attribute, lerp(startValue, endValue, l));

    // if we haven't finished request another animation frame
    if (l < 1) {
      requestAnimationFrame(animate);
    }
  }
  requestAnimationFrame(animate);
}

const element = document.getElementById('id1');
const attribute = 'width';
const start = 600;
const end= 0;
const duration = 1;

animateAttribute(element, attribute, start, end, duration);
#id1 { background: red; }
<canvas id="id1"></canvas>

也可以将 l 传递给 these functions 中的任何一个并将结果传递给 lerp,您可以更改动画与 these styles of motion 中的任何一个相匹配的方式。 .

关于你的其他问题

Is there any way I can achieve this while using requestAnimationFrame? If I could get the average interval between frames or the fps that would work I think.

您可以计算帧之间的间隔。示例:

let then = performance.now();
function animate(now) {
  deltaTimeInMilliseconds = (now - then);
  then = now;

  ...
  requestAnimationFrame(animate);
}
requestAnimationFrame(animate);

Am I perhaps worrying about something that isn't really a big issue?

只有你能回答这个问题

What fps can I expect on different devices (mobile, pc, tablet, etc.)?

大多数设备的帧率为 60fps,但也有以 120fps 或 240fps 运行的游戏显示器以及通常以 90fps 或更高帧率运行的 VR(和 WebVR),您可以在 VR 中使用浏览器。您是否关心其中任何一种情况取决于您。

关于javascript - 如何独立于刷新率计时 requestAnimationFrame(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46852857/

相关文章:

html - 某些 CSS3 动画在 eBay 中不起作用说明

r - R 中高清动画视频的最佳实践

iphone - 如何知道/测试动画何时播放完毕

javascript - 使用 Google 文档作为数据端点来获取 JSON

javascript - 如何让 Meteor react 性地更新 "time since"字符串?

javascript - 无法在 Atom 编辑器中使用 eslint

javascript - chrome.idle.onStateChanged 不触发函数

javascript - Google 跟踪代码管理器模板无效

WPF/Windows 7 : Disable Default Progress Bar Glow Animation

WPF进度条继续动画