文章目录
- 一、Canvas动画
- 1.1 Canvas绘图都是通过JavaScript 去操控的,如要实现一些交互性动画是相当容易的。那Canvas是如何做一些基本动画的?
- 1.2 Canvas 画出一帧动画的基本步骤(如要画出流畅动画,1s 需绘60帧):
- 二、Canvas-绘制秒针-setInterval实现
- 2.1 setTimout定时器的缺陷
- 三、Canvas-绘制秒针--requestAnimationFrame实现
- 3.1 requestAnimationFrame函数
- 四、其他动画案例
一、Canvas动画
1.1 Canvas绘图都是通过JavaScript 去操控的,如要实现一些交互性动画是相当容易的。那Canvas是如何做一些基本动画的?
◼ canvas可能最大的限制就是图像一旦绘制出来,它就是一直保持那样了。
◼ 如需要执行动画,不得不对画布上所有图形进行一帧一帧的重绘(比如在1秒绘60帧就可绘出流畅的动画了)。
◼ 为了实现动画,我们需要一些可以定时执行重绘的方法。然而在Canvas中有三种方法可以实现:分别为 setInterval 、 setTimeout 和 requestAnimationFrame 三种方法来定期执行指定函数进行重绘。
1.2 Canvas 画出一帧动画的基本步骤(如要画出流畅动画,1s 需绘60帧):
◼ 第一步:用 clearRect 方法清空 canvas ,除非接下来要画的内容会完全充满 canvas(例如背景图),否则你需要清空所有。
◼ 第二步:保存 canvas 状态,如果加了 canvas 状态的设置(样式,变形之类的),又想在每画一帧之时都是原始状态的话,
你需要先保存一下。
◼ 第三步:绘制动画图形(animated shapes) ,即绘制动画中的一帧。
◼ 第四步:恢复 canvas 状态,如果已经保存了 canvas 的状态,可以先恢复它,然后重绘下一帧。
二、Canvas-绘制秒针-setInterval实现
2.1 setTimout定时器的缺陷
◼ setTimeout定时器不是非常精准的,因为setTimeout的回调函数是放到了宏任务中等待执行。
◼ 如果微任务中一直有未处理完成的任务,那么setTimeout的回调函数就有可能不会在指定时间内触发回调。
◼ 如果想要更加平稳和更加精准的定时执行某个任务的话,可以使用requestAnimationFrame函数。
<!DOCTYPE html>
<html lang="zh-CH">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
padding: 100px;
margin: auto;
background-image: url(../images/grid.png);
}
canvas {
background-color: rgba(255, 0, 0, 0.1);
}
</style>
</head>
<body>
<!-- 如果不给宽高 默认宽300px 高150px -->
<canvas id="box" width="300" height="300">
您的浏览器不兼容Canvas,请升级浏览器
</canvas>
<script>
// 这个函数就是动画的一帧
function draw(ctx, count) {
// 清空画布
ctx.clearRect(0, 0, 300, 300)
ctx.save()
// 绘图
ctx.translate(100, 100)
// Math.PI * 2 圆
// Math.PI * 2 / 60 把圆分为60份
ctx.rotate(Math.PI * 2 / 60 * count)
ctx.lineWidth = 6
ctx.lineCap = 'round'
ctx.strokeStyle = 'green'
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.lineTo(0, -80)
ctx.stroke()
ctx.restore()
}
window.onload = function() {
const canvasEl = document.getElementById('box')
if (!canvasEl.getContext) return
let ctx = canvasEl.getContext('2d')
let count = 0
draw(ctx, count)
setInterval(() => {
count++
if (count >= 60) {
count = 0
}
draw(ctx, count)
}, 1000);
}
</script>
</body>
</html>
三、Canvas-绘制秒针–requestAnimationFrame实现
3.1 requestAnimationFrame函数
◼ 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用该函数的回调函数来更新动画。
◼ 该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
◼ 若想在浏览器下次重绘之前继续更新下一帧动画,那么在回调函数自身内必须再次调用 requestAnimationFrame()
◼ 通常每秒钟回调函数执行 60 次左右,也有可能会被降低。
<!DOCTYPE html>
<html lang="zh-CH">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
padding: 100px;
margin: auto;
background-image: url(../images/grid.png);
}
canvas {
background-color: rgba(255, 0, 0, 0.1);
}
</style>
</head>
<body>
<!-- 如果不给宽高 默认宽300px 高150px -->
<canvas id="box" width="300" height="300">
您的浏览器不兼容Canvas,请升级浏览器
</canvas>
<script>
// 这个函数就是动画的一帧
function draw(ctx) {
let second = new Date().getSeconds()
ctx.clearRect(0, 0, 300, 300)
ctx.save()
ctx.translate(100, 100)
ctx.rotate(Math.PI * 2 / 60 * second)
ctx.lineWidth = 6
ctx.lineCap = 'round'
ctx.strokeStyle = 'green'
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.lineTo(0, -80)
ctx.stroke()
ctx.restore()
requestAnimationFrame(() => {
draw(ctx)
})
}
window.onload = function() {
const canvasEl = document.getElementById('box')
if (!canvasEl.getContext) return
let ctx = canvasEl.getContext('2d')
requestAnimationFrame(() => {
draw(ctx)
})
}
</script>
</body>
</html>
四、其他动画案例
案列地址