【问题标题】:How to add easing to continuous animation?如何为连续动画添加缓动?
【发布时间】:2018-04-18 20:55:20
【问题描述】:

我有以下 JSFiddle,其中通过使用 requestAnimationFrame,一个元素会沿着 x 轴不断地在其容器的边缘反弹; https://jsfiddle.net/anhd08so/

基本上,在每一帧上,我将定义的速度 (vx) 添加到位置 (x)。然后我检查新位置是否超出范围,如果是,我设置为最小值,并将vx反转为另一个方向。

var x = 50;
var vx = 5;

var step = function(){
  x = x + vx;

  if(x < 0) {
    x = 1;
    vx = Math.abs(vx);
  } else if(x > 400) {
    x = 400;
    vx = -Math.abs(vx);
  }

  el.css("left", x);
  requestAnimationFrame(step);
};

这行得通,但方向的改变真的很突然,不现实。我想添加缓动,以便元素在接近边缘时逐渐减速,并在另一个方向再次加速。

我尝试用vx = vx - vx * 0.3 替换Math.abs 之类的东西来做到这一点,虽然它确实减慢了速度,但当它走另一条路时,它再也不会获得等量的反向速度。

这对于 CSS 过渡/关键帧来说当然是小菜一碟,但我的用例需要在代码中逐帧定义运动。

如何为这个动作添加缓动,让元素改变方向看起来更真实?

【问题讨论】:

  • 为什么不使用正弦函数?例如,var t = 0; var step = function() { var x = Math.floor(Math.cos(t)*198+200.5); t += 0.03; /*...*/ }
  • 这看起来更有希望!如果舞台或项目的大小不同,198 和 200.5 是什么关系?
  • 嗯,正弦函数(或余弦,在这种情况下)在 -1 和 +1 之间变化。所以如果你想覆盖从-200到+200的范围,你应该乘以200(所以它覆盖了-200到+200的范围),然后加上200(给你从0到400的范围)。我稍微降低了乘数,因为您移动的条的宽度为 2px,如果您坚持 200 的幅度,它将与封闭矩形的末端重叠。但是您可以输入任何您喜欢的数字。值 0.03 会影响运动的速度。把它改成0.06,动画会快一倍。

标签: javascript animation math


【解决方案1】:

更新 #1

你是https://jsfiddle.net/anhd08so/64/

请注意,使用translateX 代替left。如果您想要更流畅的动画,最好使用变换。否则,当您更改 left 或类似内容时,浏览器可能会因重新渲染而变慢。

您可以使用一些自定义的三次贝塞尔动画来代替ease-in-out

查看代码。有什么问题可以问我。

var el = document.querySelector('p');

function toggleDirection() {
	var style = window.getComputedStyle(el, null).getPropertyValue("transform");
  var matrix = new WebKitCSSMatrix(style);
  
  if (matrix.e === 50) {
  	el.classList.add('p--right');
  } else {
  	el.classList.remove('p--right');
  } 
}

el.addEventListener("transitionend", toggleDirection);

window.onload = toggleDirection();
div {
  position: absolute;
  width: 400px;
  height: 200px;
  top: 100px;
  left: 100px;
  background: #eee;
}

p {
  position: absolute;
  top: 50px;
  /* left: 50px; */
  transform: translateX(50px);
  width: 2px;
  height: 100px;
  margin: 0;
  background: #111;
  
  transition: transform 2s ease-in-out;
  
  will-change: transform;
}

.p--right {
  transform: translateX(350px);
}
<div>
  <p></p>
</div>

【讨论】:

  • 感谢您的回答。不过,看起来它确实需要更多的断点和大量的手动测试才能让它看起来自然。我确信有一种数学方法可以动态地做到这一点,但我不知道如何应用它。
  • 尝试使用 jQuery .animate() 它可以应用一些缓动,包括一些你可以在 Internet 上找到你应用你自己的行为的缓动。它将 x 从一种状态更改为另一种状态并进行缓动。在你的例子中400(想想如何制作一个循环)。此外,还有一个使用requestAnimationframeVelocity.js 库。所以对浏览器会更好。
  • 一分钟。我会尝试使用 css 与您的类似
【解决方案2】:

我认为您正在寻找的是这样的: 在 step 函数外声明修饰符:

var modifier = 1;

然后在步骤开始时,您只需像这样计算修饰符:

if ( x<=200) {
    modifier = Math.max(0.1 , ( x / 200));
} else {
    modifier = Math.max(0.1 , ( (200-(x % 200)) / 200));
}
x = x + modifier * vx;

所以你所做的,基本上是计算距离中点的距离(400/ 2 = 200),然后调整速度。

像这样: https://jsfiddle.net/anhd08so/71/

【讨论】:

  • 当然你总是调整速度并将 200 声明为全局变量。加上 math.max 就在那里,所以它不会降到 0 速度
猜你喜欢
  • 1970-01-01
  • 2013-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多