Canvas 动画原理 作者:马育民 • 2024-09-15 08:57 • 阅读:10035 # 动画的基本步骤 你可以通过以下的步骤来画出一帧: 1. 清空 canvas 除非接下来要画的内容会完全充满 canvas(例如背景图),否则你需要清空所有。最简单的做法就是用 clearRect 方法。 2. 保存 canvas 状态 如果你要改变一些会改变 canvas 状态的设置(样式,变形之类的),又要在每画一帧之时都是原始状态的话,你需要先保存一下。 3. 绘制动画图形(animated shapes) 这一步才是重绘动画帧。 4. 恢复 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 原文出处:/show_1IX8QiEkcrID.html