<canvas>
HTML中的元素和JavaScript中的Canvas API结合在一起,形成了网络上主要的光栅图形和动画之一。一个常见的画布用例是以编程方式为网站(尤其是游戏)生成图像。
在本文中,我们专门研究一下画布中的动画以及使它们看起来更平滑的技术。我们将专门研究缓和的过渡(例如“缓入”和“缓出”),这些过渡在画布中并非像CSS中那样免费提供。
让我们从静态画布开始。我已经从DOM中抓取了一张纸牌到画布上:
让我们从一个基本的动画开始:在画布上移动该纸牌。即使对于相当基本的事情,例如需要在画布上从头开始工作,因此我们也必须开始构建可以使用的功能。
首先,我们将创建函数来帮助计算X和Y坐标:
function getX(params) {
let distance = params.xTo - params.xFrom;
let steps = params.frames;
let progress = params.frame;
return distance / steps * progress;
}
function getY(params) {
let distance = params.yTo - params.yFrom;
let steps = params.frames;
let progress = params.frame;
return distance / steps * progress;
}
这将帮助我们在动画图像时更新位置值。然后,我们将继续重新渲染画布,直到动画完成。为此,我们将以下代码添加到我们的addImage()
方法中。
if (params.frame < params.frames) {
params.frame = params.frame + 1;
window.requestAnimationFrame(drawCanvas);
window.requestAnimationFrame(addImage.bind(null, params))
}
现在我们有了动画!每次我们都稳定地增加1个单位,我们称之为线性动画。
您可以看到形状如何以线性方式从A点移动到B点,并保持点之间相同的一致速度。它具有功能,但缺乏现实性。开始和停止令人讨厌。
我们想要的是物体加速(缓入)和减速(缓和),因此它模仿了现实世界中物体在摩擦和重力作用下会做什么。
JavaScript动画平滑函数
我们将通过“立方”缓入和缓出过渡来实现这一目标。我们已经修改了罗伯特·彭纳(Robert Penner)的 Flash easing functions中找到的方程式之一,以适合我们在此处要执行的操作。
function getEase(currentProgress, start, distance, steps) {
currentProgress /= steps/2;
if (currentProgress < 1) {
return (distance/2)*(Math.pow(currentProgress, 3)) + start;
}
currentProgress -= 2;
return distance/2*(Math.pow(currentProgress, 3)+ 2) + start;
}
将其插入到我们的代码中(这很容易实现),我们得到的结果要平滑得多。请注意,卡片是如何朝着空间的中心加速,然后在到达末端时减速。
使用JavaScript实现平滑的效果
我们可以通过二次或正弦缓和得到较慢的加速度。
function getQuadraticEase(currentProgress, start, distance, steps) {
currentProgress /= steps/2;
if (currentProgress <= 1) {
return (distance/2)*currentProgress*currentProgress + start;
}
currentProgress--;
return -1*(distance/2) * (currentProgress*(currentProgress-2) - 1) + start;
}
function sineEaseInOut(currentProgress, start, distance, steps) {
return -distance/2 * (Math.cos(Math.PI*currentProgress/steps) - 1) + start;
};
为了获得更快的加速度,请轻松地进行五次或指数化处理:
function getQuinticEase(currentProgress, start, distance, steps) {
currentProgress /= steps/2;
if (currentProgress < 1) {
return (distance/2)*(Math.pow(currentProgress, 5)) + start;
}
currentProgress -= 2;
return distance/2*(Math.pow(currentProgress, 5) + 2) + start;
}
function expEaseInOut(currentProgress, start, distance, steps) {
currentProgress /= steps/2;
if (currentProgress < 1) return distance/2 * Math.pow( 2, 10 * (currentProgress - 1) ) + start;
currentProgress--;
return distance/2 * ( -Math.pow( 2, -10 * currentProgress) + 2 ) + start;
};
使用GSAP更复杂的动画
滚动自己的缓动功能可能很有趣,但是如果您想要更多的功能和灵活性怎么办?您可以继续编写自定义代码,也可以考虑使用功能更强大的库。让我们转向GSAP。
使用GSAP可以轻松实现动画。以该示例为例,该卡最后会弹起。请注意,GSAP库包含在演示中。
关键功能是moveCard
:
function moveCard() {
gsap.to(position, {
duration: 2,
ease: "bounce.out",
x: position.xMax,
y: position.yMax,
onUpdate: function() {
draw();
},
onComplete: function() {
position.x = position.origX;
position.y = position.origY;
}
});
}
该gsap.to
方法是所有魔术发生。在两秒钟的持续时间内,position
对象会更新,并且每次更新都会调用onUpdate来触发画布重绘。
组装在一起
仍不确定在缓动时应在画布中使用哪种动画样式和方法?这是一支笔,显示了不同的缓动动画,包括GSAP中提供的动画。
查看我的纸牌纸牌游戏 ,观看非GSAP动画的实时演示。在这种情况下,我添加了动画,以便游戏中的纸牌在堆之间移动时可以轻松移动和轻松移动。
除了创建运动之外,还可以将缓动函数应用于具有“ 从”和“ 到”状态的任何其他属性,例如不透明度,旋转和缩放的更改。希望您能找到许多使用缓动功能的方法,以使您的应用程序或游戏看起来更流畅。