参加工作以来做了很多和canvas相关的工作,也因此看了一些相关的书籍和文章,所学很是杂乱,于是便有了这些文章,对以往所学进行梳理,以供将来复习所用。 这个系列的文章不会系统的介绍canvas相关的API,有兴趣可以去看API文档。我们只在引言部分简单介绍一下canvas绘制的基本流程和canvas动画的基本原理。
1. canvas绘制的基本流程
canvas的绘制流程很简单,大致上有一个套路,分为如下几步:
- 获取指向canvas的引用
- 使用getContext方法获取绘图环境变量
- 使用绘图环境变量在canvas元素上进行绘制 先通过一个例子来看如何在canvas上绘制一个Hello Canvas。首先我们需要在HTML里插入一个canvas标签:
<canvas id="canvas" width="600" height="300">
Canvas not support!
</canvas>
复制代码
标签里面的面的内容“Canvas not support!”只有在浏览器不支持canvas的时候才会显示出来。
接下来看js代码:
//1. 获取指向canvas的引用
var canvas = document.getElementById("canvas");
//2. 获取指向canvas的引用
var context = canvas.getContext('2d');
//3.使用绘图环境变量在canvas元素上进行绘制
context.font = "38pt Arial";
context.fillStyle = "cornflowerblue";
context.strokeStyle = "blue";
context.fillText("Hello Canvas", canvas.width / 2 - 150, canvas.height / 2 + 15);
context.strokeText("Hello Canvas", canvas.width / 2 - 150, canvas.height / 2 + 15);
复制代码
这样,就得到了一个很基础的图形:
2. canvas动画的基本原理
在canvas中实现动画的原理很简单,就是在播放动画时持续更新并绘制。最简单的做法,就是在每一帧中擦除上一帧的内容,然后重新绘制这一帧的内容。那么如何实现这种持续的更新呢?
首先可以想到用while循环:
function animate(){
//这里面写动画更新逻辑
}
while(true){
animate();
}
复制代码
但是while循环是一个死循环,会导致浏览器失去响应,而且也无法绘制出动画的效果,因此应该排除。
然后我们可以想到用一些异步的方法,如setTimeout或者setInterval:
/**
* 使用setInterval
**/
function animate(){
//这里面写动画更新逻辑
}
setInterval(animate, 1000/60);
/**
* 使用setTimeout
**/
function animate(){
var start = +new Date(),
finish;
//这里面写动画更新逻辑
finish = +new Date();
setTimeout(animate, (1000/60) - (finish-start));
}
复制代码
使用setTimeout和setInterval确实可以实现持续的更新,但是这两个方法并不是专门为动画而设计的,他们有如下缺陷:
- 都是通用方法,并不是专门为动画设计
- 即使向其传递以毫秒为单位的参数值,也达不到毫秒的精确度
- 没有对调用动画循环的机制作优化
- 不会考虑动画的最佳时机,只会以某个大致的时间间隔来调用动画循环 基于以上原因,使用这两个方法来绘制canvas动画,其效果可能不如预期流畅,而且还会占用其他资源。
因此,浏览器提供了一个名为requestAnimationFrame()的方法。从这个方法的名字就可以感觉到,它是专门为动画而生的。因为浏览器是知道绘制的最佳时机的,它会在可以绘制时通知你,而requestAnimationFrame正是用来实现此功能的。该方法不需要使用者指定帧速率,浏览器会自行决定最佳帧速率。
现在,我们就用这个方法来实现一个简单的动画。向HTML里插入一个id为canvas2的canvas标签,js代码如下:
var canvas2 = document.getElementById("canvas2"),
ctx = canvas2.getContext('2d'),
img = new Image(),
x = 0,
y = 0;
img.onload = function () {
animate();
}
img.src = './images/ball.png';
function animate() {
//擦除上一帧的内容
ctx.clearRect(0, 0, canvas2.width, canvas2.height);
//更新逻辑
x += 2;
y++;
ctx.drawImage(img, x, y, img.width, img.height);
//持续更新
requestAnimationFrame(animate);
}
复制代码
这样就实现了一个动画效果:
requestAnimationFrame的缺点,主要是兼容性问题。后续章节中我们会提供一个polyfill方法实现一个兼容性比较好的解决方案。
小结
本文主要介绍了canvas的基本用法和动画原理。为了使用方便,后续章节不会再用这些基本的API,而是对它们进行了一些封装,实现了几个基本的类,如Stage、Renderer、Sprite、Graphics和Loader等,在下一篇文章中会有一个简单的介绍。
最后为大家推荐几本学习canvas的书籍,这个系列文章的大部分知识点都是来源于这几本书。
- HTML5 Canvas核心技术-图形、动画与游戏开发。这本书系统而又详细地介绍了canvas相关的API及用法,以及各种物理效果、碰撞检测等技术,最后实现了一个简单的游戏引擎,在此基础上开发了一个弹珠游戏,并用canvas实现了一些自定义控件。该书内容丰富,十分推荐。
奉上本系列文章所涉及的源码的git地址,喜欢的话麻烦给个star哦!