何为Canvas?请向维基老师请教:维基条目Canvas

Canvas与其它一些GDI有些类似,如果你做过Windows下的图形编程或类似项目,你会对Canvas感到比较熟悉、亲切;如果你只熟悉HTML和Javascript,那么你要准备好转变一下思路。Canvas本身并不局限于浏览器、HTML5,但本系列文章只讲浏览器中的Canvas。

本连载将从Canvas基础开始,逐步实现一个可用的象棋游戏。阅读本文要求具备Javascript基础。

Canvas与HTML的首次对接

Canvas在HTML中用一个专门的标签表示,即canvas标签。这个标签通常只需要一个id属性,当然也可以在此节点添加宽高等属性。示例如下:

<canvas id=”first-canvas” width=“100” height=“100″></canvas>

剩下的事情主要在Javascript里做了。首先要获取一个“上下文”:

var canvas = document.getElementById(“first-canvas”);
var ctx = canvas.getContext(“2d”);

“上下文”可以理解为与当前环境相关的一个对象。比如Windows里的右键弹出菜单,也叫上下文菜单,它会根据你点击的区域不同,展示有针对性的菜单项。

canvas的上下文是用来进行绘图输出的最重要的对象。它提供了各种形状的绘图方法,如直线、矩形、圆形、文字等。作为对接成功的证据,让我们画点东西出来吧:

ctx.fillStyle = “#9cf”;
ctx.rect(0, 0, 100, 100);
ctx.fill();

将上述代码整合出来运行,你是否看到了一个蓝色的方块?当然你不能用IE6等古老的浏览器。请查询相关资料以确定你的浏览器对canvas的支持情况。

Canvas常用绘图方法与属性

beginPath()

开始一个路径。路径可以由单个或多个形状组成,可以用fill进行路径填充等。

closePath()

结束一个路径。

moveTo(x, y)

移动到一个位置。想象一下现实中的绘图,先要把画笔移动到要开始绘制的点,再开始绘制。这个开始的点,不妨称之为当前位置。

lineTo(x, y)

从当前位置到目标坐标画一条直线。

rect(x, y, width, height)

绘制一个矩形。

arc(x, y, r, start, end)

绘制一个圆弧,r为半径,start、end为开始和结束角度(整个圆为360度)。

fillText(text, x, y)

输出text文本。

fill()

对当前路径进行填充。

stroke()

对当前路径进行描边。

fillStyle

填充样式,如”#999″,”rgba(128, 128, 128, 0.5)”。

strokeStyle

描边样式,与填充样式类似。

lineWidth

指定线条的宽度。

font

字体。如:”36px Arial”。

textAlign

左右对齐方式,可选值为”left”, “center”, “right”。当选定居中时,指定的输出文字坐标将对应文字的横向中心位置。

textBaseline

文本基线,影响输出文本时的纵向定位。比如使用”middle”值时,指定的坐标点将对应文本的中部。基线是字体及文字输出常用的一个概念,它的其它一些可选值及其含义请参考维基条目基线

以上介绍的是我们将会用到的一些方法和属性。更详尽的API参考请自行查询相关资料。另外较新的浏览器可能还支持诸如带有高斯模糊效果的阴影,但经笔者测试,静态效果很好,做动画等需要重绘的应用时会有性能问题,所以基于我们的目标考虑,就不再关注这些特性。

始入正题:绘制棋盘和棋子

将上面所介绍的知识混合运用起来,实现这一步目标并不困难。我的思路如下:

  1. 绘制一个大矩形区域,并填充上背景色;
  2. 计算好坐标,逐条绘出棋盘上的纵横线,以及斜线;
  3. 输出文字“楚河”、“汉界”;
  4. 绘制棋子的半透明阴影;
  5. 绘制棋子的圆形,填充背景色并描边;
  6. 输出有位置偏移的白色半透明棋子名称,用作“白”影;
  7. 输出正常位置的棋子名称。
Canvas绘制的中国象棋

Canvas绘制的中国象棋

这幅图就是笔者做出来的效果。棋子的阴影实现方式为先绘制一个带一定位置偏移的半透明圆形,再在上面绘制棋子。同样,棋子上的文字也用了类似的处理。Canvas里有一点遗憾,就是文字的反锯齿效果并不太好。加个半透明“白”影,也算弥补一下。当然如果你不考虑后期做动画之类需要频繁重绘的效果,也可以使用canvas的阴影效果,比我这图要酷不少。

此外考虑我们后期要做一个真正能玩的象棋游戏,在坐标的处理上要尽可能设计得方便易用,至少要有统一的棋盘坐标与图象坐标的换方法。

你的棋盘画成什么样子了?欢迎大家来交流。

下面是我的源码主要片断,其中layout对象是我定义的一个专门保存一些绘图参数的对象。王大妈的裹脚布来了:

        // draw background
	ctx.fillStyle=style.board.background;
	ctx.beginPath();
	ctx.rect(0, 0, layout.offsetWidth, layout.offsetHeight);
	ctx.fill();
	ctx.closePath();
	// prepare to draw lines
	var p = layout.padding,
		s = layout.cell,
		w = layout.width,
		h = layout.height;
	ctx.strokeStyle=style.board.border;
	ctx.lineWidth=2;
	ctx.beginPath();
	// horizonal lines
	for(var i = 0; i &lt; 10; i++){
		ctx.moveTo(p, s * i + p);
		ctx.lineTo(w + p, s * i + p);
	}
	// vertical lines
	ctx.moveTo(p, p);
	ctx.lineTo(p, h + p);
	ctx.moveTo(w + p, p);
	ctx.lineTo(w + p, h + p);
	for(var i = 1; i &lt; 8; i++){
		ctx.moveTo(s * i + p, p);
		ctx.lineTo(s * i + p, s * 4 + p);
		ctx.moveTo(s * i + p, s * 5 + p);
		ctx.lineTo(s * i + p, h + p);
	}
	// "X" shapes
	ctx.moveTo(s * 3 + p, p);
	ctx.lineTo(s * 5 + p, s * 2 + p);
	ctx.moveTo(s * 5 + p, 0 + p);
	ctx.lineTo(s * 3 + p, s * 2 + p);
	ctx.moveTo(s * 3 + p, s * 7 + p);
	ctx.lineTo(s * 5 + p, s * 9 + p);
	ctx.moveTo(s * 5 + p, s * 7 + p);
	ctx.lineTo(s * 3 + p, s * 9 + p);

	ctx.stroke();
	ctx.closePath();

	// 楚河汉界
	ctx.font=style.board.font;
	ctx.fillStyle=style.board.border;
	ctx.textAlign="center";
	ctx.textBaseline="middle";
	ctx.fillText("楚河", p + s * 2, p + s * 4.5);
	ctx.fillText("漢界", p + s * 6, p + s * 4.5);

下一篇笔者将介绍Canvas的事件处理及动画制作方式,让棋子动起来。敬请期待!

本文作者:admin 转载请注明来自:携程设计委员会