Canvas Bitmap
图片源
两种方式:
1.
<img id="xxx" src="xxx" />
2.
var img = new Image(); img.src = "xxx";
加载
如果想在代码里使用图片,我们必须确保图片加载完了,如下:
img.addEventListener('load', imageLoaded, false);
这种为每张图片创建一个事件侦听器的方式效率上不太好,如果只是一张图片倒是没什么问题。
drawImage
drawImage() 方法被重载了,它有三个版本,下面我按需求进行分解:
现有一张100 * 100的图片,中间我用蓝线框出了一个区域,蓝框的左上角坐标为 (14, 9),蓝框的大小为 72 * 82

需求一:按原大小把图片的画出来
版本:drawImage(img, x, y);

var img = new Image();
img.src = '1.jpg';
img.addEventListener('load', function() {
context.drawImage(img, 10, 10);
}, false);
需求二:对图片进行缩放
版本:drawImage(img, x, y, width, height);

context.drawImage(img, 10, 10, 50, 50);
可见,图片被缩小到一半大小。
需求三:从图片中取出一部分画到canvas上
版本:drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh);

context.drawImage(img, 14, 9, 72, 82,
10, 10, 72, 82);
这个没有缩放,下面我改变 dw 和 dh 的值,就会出现缩放了(缩小一半):

context.drawImage(img, 14, 9, 72, 82,
10, 10, 36, 41);
关于tile
tile 这词是游戏开发中常用的,中文还真不好说,比如下面这张图就是一个tile:

这张图画了坦克运行中的8个状态,连续播放就是一段动画。
下面我简单说说怎么使用tile。比如这里的一个tank,大小是34 * 34,同时我们需要8帧动画,每一帧都会在相同的区域绘制一个tank,原理就是这样,来看代码:
var tile = new Image();
tile.src = 'tile.jpg';
tile.addEventListener('load', function() {
var x = 0, tankWidth = 34, tankHeight = 34,
totalFrame = 8, curFrame = 0;
// 设置一个定时器,这里是每秒24帧的动画
setInterval(function() {
x = curFrame * tankWidth;
context.drawImage(tile, x, 0, tankWidth, tankHeight,
10, 10, tankWidth, tankHeight);
curFrame++;
if (curFrame === totalFrame) {
curFrame = 1;
}
}, 1000 / 24);
}, false);
图片的transform
还是用tile的图片举例,我们需要tank朝向右边,即旋转90°。
如果你熟悉Flash,肯定知道它有Sprite 和 MovieClip 之类的显示对象,这样添加效果就比较独立,都是一个个的对象,互不影响。但是Canvas不是这样的,一个canvas就是一个“显示对象”,比如你有两个tank,你知道这是两个对象,但是你画到canvas上之后,只不过是canvas的两块像素区域。
如果我们应用了transform,那么整个canvas都会影响(当然应用transform之前绘制的东西不会受影响),就本例来说,我们只需要临时旋转一下tank,只是临时的用一下旋转,用完了要赶紧复原,不然之后的绘制都会受影响。
话不多说,直接看代码:
var tile = new Image();
tile.src = 'tile.jpg';
tile.addEventListener('load', function() {
// 第一个tank的信息
var x = 0, y = 0, width = 34, height = 34;
// 保存当前的context
context.save();
// 重置transform
context.setTransform(1, 0, 0, 1, 0, 0);
// 接着是旋转部分的代码
// 平移坐标系统,把坐标原点移到tank的中心
context.translate(x + width / 2, y + height / 2);
context.rotate(90 * Math.PI / 180);
context.drawImage(tile, x, y, width, height,
-0.5 * width, -0.5 * height, width, height);
// 复原刚才的状态
context.restore();
}, false);
效果如下:

图片的运动
有了tile,我们自然会想着怎么让它动起来,运动不外乎位移,位移说白了就是(x, y)的变化,下面我来分解步骤:
1. 把坐标系统的原点移动到对象的中心,这样可方便transform
2. 坐标原点变为对象中心点的另一个好处是,不再需要操心对象的坐标,只需要考虑translate(x, y)的坐标,因为对象的坐标不再变化了
来看代码:
var tile = new Image();
tile.src = 'tile.jpg';
tile.addEventListener('load', function() {
// 第一个tank的信息
var x = 0, y = 0, width = 34, height = 34;
// 定义运动的方向,这里定为水平向右运动
var dx = 1, dy = 0;
// 运动也是需要动画的
setInterval(function() {
// 重绘画布
context.fillStyle = 'lightblue';
context.fillRect(0, 0, canvas.width, canvas.height);
// 更新坐标
x += dx;
y += dy;
context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.translate(x + width / 2, y + height / 2);
context.rotate(90 * Math.PI / 180);
context.drawImage(tile, 0, 0, width, height,
-0.5 * width, -0.5 * height, width, height);
context.restore();
}, 1000 / 24);
}, false);
最后奉上三个制作tile的工具软件:

浙公网安备 33010602011771号