动画的基本步骤
你可以通过以下的步骤来画出一帧:
清空 canvas 除非接下来要画的内容会完全充满 canvas(例如背景图),否则你需要清空所有。最简单的做法就是用 clearRect 方法。
保存 canvas 状态 如果你要改变一些会改变 canvas 状态的设置(样式,变形之类的),又要在每画一帧之时都是原始状态的话,你需要先保存一下。
绘制动画图形(animated shapes) 这一步才是重绘动画帧。
恢复 canvas 状态 如果已经保存了 canvas 的状态,可以先恢复它,然后重绘下一帧。
更新画布
为了执行动画,需要 定时执行重绘 的方法,可以通过下面三个函数实现页面渲染的重绘(推荐使用 requestAnimationFrame)。
setInterval(function, delay)
当设定好间隔时间后,function 会定期执行。setTimeout(function, delay)
在设定好的时间之后执行函数requestAnimationFrame(callback)
告诉浏览器你希望执行一个动画,并在重绘之前,请求浏览器执行一个特定的函数来更新动画。
如果你并不需要与用户互动,你可以使用 setInterval() 方法,它就可以定期执行指定代码。
如果我们需要做一个游戏,我们可以使用键盘或者鼠标事件配合上 setTimeout() 方法来实现。通过设置事件监听,我们可以捕捉用户的交互,并执行相应的动作。
更推荐使用 requestAnimationFrame()
setInterval()
是一个定时器,用于定时执行一段代码,通过这个特定可以定时调用会canvas的重绘,实现动画效果。
setInterval(function, milliseconds) 定时执行并不是严格的间隔固定时间执行。因为 milliseconds 会包含 function 执行的耗时。
对于先要实现 固定间隔 执行一段代码的效果,推荐使用 setTimeout() 函数。
例子
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="js/CanvasRecorder.js"></script>
<style>
#c{
width: 400px;
height: 300px;
}
</style>
</head>
<body>
<canvas id="c" ></canvas>
<script>
var c=document.getElementById("c");
c.width=c.clientWidth*window.devicePixelRatio;
c.height=c.clientHeight*window.devicePixelRatio;
// console.log("画布宽度高度:",c.width,c.height)
// c.style.imageSmoothingEnabled = false;
// c.style.webkitImageSmoothingEnabled = false;
// c.style.mozImageSmoothingEnabled = false;
var ctx=c.getContext("2d");
let x = 20
let speed = 1
function draw(){
//1. 先把画布清空
ctx.clearRect(0, 0, c.width, c.height);
// 设置背景色,本质是画一个与canvas相同大小的矩形
// 设置颜色
ctx.fillStyle = 'bisque';
// 填充矩形
ctx.fillRect(0, 0, c.width, c.height);
//设置颜色
ctx.fillStyle = "green";
// 设置字体
ctx.font="40px Georgia";
// 设置文字
ctx.fillText("Hello World!",80,150);
//设置颜色
ctx.fillStyle = "blue";
// 设置字体
ctx.font="30px 微软雅黑";
ctx.fillText("你好,世界!",80,200);
// 画矩形
ctx.fillStyle = "red";
ctx.fillRect(x, 50, 50, 50);
// 让矩形框左右移动
x+=speed
if(x>c.width - 50 - 20||x<20){
speed = -speed;
}
}
// 一秒刷新60
setInterval(function(){
draw()
},1000/60)
</script>
</body>
</html>
setTimeout()延迟执行
setTimeout() 用于延迟指定的时间执行一次函数,通过 setTimeout 定时执行的回调中嵌套调用 setTimeout() 可以实现,固定间隔的执行一段代码。
具体使用和 setInterval 类似,不再赘述
setTimeout和setInterval 缺点
setTimeout和setInterval指定的回调函数,必须等到本轮事件循环的所有同步任务都执行完,才会开始执行。
由于前面的任务到底需要多少时间执行完,是不确定的,所以没有办法保证,setTimeout和setInterval指定的任务,一定会按照预定时间执行。
requestAnimationFrame
setTimeout 和 setInterval 有可能无法按指定时间运行,同时也无法保证在正确的页面重绘时执行,影响浏览器的绘制性能等,所以通常在动画中,推荐使用requestAnimationFrame()。
优点
requestAnimationFrame 是html5专门请求动画帧的API。由系统决定回调函数的执行(根据显示器刷新频率等多种因素),不会引起丢帧和卡顿。requestAnimationFrame 要想循环执行,需要在回调中再次调用 requestAnimationFrame
window.requestAnimationFrame() 告诉浏览器 —— 你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。
该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。
例子
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="js/CanvasRecorder.js"></script>
<style>
#c{
width: 400px;
height: 300px;
}
</style>
</head>
<body>
<canvas id="c" ></canvas>
<script>
var c=document.getElementById("c");
c.width=c.clientWidth*window.devicePixelRatio;
c.height=c.clientHeight*window.devicePixelRatio;
var ctx=c.getContext("2d");
let x = 20
let speed = 1
function draw(){
//1. 先把画布清空
ctx.clearRect(0, 0, c.width, c.height);
// 设置背景色,本质是画一个与canvas相同大小的矩形
// 设置颜色
ctx.fillStyle = 'bisque';
// 填充矩形
ctx.fillRect(0, 0, c.width, c.height);
//设置颜色
ctx.fillStyle = "green";
// 设置字体
ctx.font="40px Georgia";
// 设置文字
ctx.fillText("Hello World!",80,150);
//设置颜色
ctx.fillStyle = "blue";
// 设置字体
ctx.font="30px 微软雅黑";
ctx.fillText("你好,世界!",80,200);
// 画矩形
ctx.fillStyle = "red";
ctx.fillRect(x, 50, 50, 50);
// 让矩形框左右移动
x+=speed
if(x>c.width - 50 - 20||x<20){
speed = -speed;
}
// 递归调用 draw() 函数更新画布
window.requestAnimationFrame(draw)
}
// 调用 draw() 函数更新画布
window.requestAnimationFrame(draw)
</script>
</body>
</html>
参考:
https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Tutorial/Basic_animations
https://juejin.cn/post/7002131643326529572