绘制基本功

概览

Canvas是HTML中的一系列2D绘制API的组合,目前说来其兼容性也较好,即使是IE9这样的较老的浏览器也支持它。Canvas允许你在不使用诸如Flash或Java等插件的情况下在网页上绘制任何你想要的东西。通过Canvas提供的一系列简单的API,Canvas为所有的web app的编写方式提供了新的可能。

Canvas可以绘制这样的图片

Canvas是什么

Canvas是一套2D绘图API,使用它时,浏览器会给你一块矩形区域。在这块区域中,你可以绘制线,形状,图片,文字等等几乎你能想要的所有事物。Canvas最早是Apple为Dashboardwidgets创建,之后很快就被其它主流浏览器所接收,现在Canvas已经是HTML5 规范的一部分了。

一段简单的Canvas代码如下:

<html>
<body>
<canvas width="800" height="600" id="canvas"></canvas>
<script>
var canvas = document.getElementById('canvas');
var c = canvas.getContext('2d');
c.fillStyle = "red";
c.fillRect(100, 100, 400, 300);
</script>
</body>
</html>

效果如下:

一个小正方形

知道Canvas是用来绘制像素的是很重要的,它并没有形状和向量的概念;也不提供一个对象,让我们可以加上事件触发器。Canvas能做的就是在屏幕上绘制像素点。这既是优点也是缺点。

web上绘图的不同方式

目前在web上有四种方法能够绘制图形:Canvas,SVG,CSS,DOM动画;Canvas和另外三种有显著差异;

  • SVG: SVG是用来绘制矢量图的API,每一个形状都对应一个对象,你可以给这个对象添加事件触发器,你可以平滑的放大SVG图形,但是如果你放大Canvas,图像会变得模糊;
  • CSS: CSS就是用以给DOM节点添加样式的,由于Canvas中并不存在DOM节点,因此CSS在Canvas中不可用,CSS只会影响Canvas矩形区域本身,通过这个你可以给Canvas画布添加边框和背景颜色,但是也仅仅只能做此了;
  • DOM animation: DOM即文档对象模型,他为屏幕上的所有元素定义了一个对应的对象。使用Javascript或者CSS控制的DOM动画在某些情况下可以和使用Canvas一样流畅,但是这种浏览性依赖于你的浏览器的执行。

Which?What?When?

那么我们应该在何时采用何种绘图方式呢? 相比其它方法,Canvas执行效率更高,更接近于底层,因此在绘制图形时,你拥有更多的控制权限并且使用更少的内存,但是也要求你写更多的代码。如果你已经有了一些形状(比如说由Adobe Illustrator导出的map),你可以使用SVG把它绘制在屏幕上;如果你想让大块的静态区域运动,或者你想进行3D变换,CSS是很好的选择。但是对于图表,游戏等,Canvas是你最合适的选择。稍后我们将讨论一些让你更高效的面向对象/绘制适量图的Canvas库。

在此,我还想强调的一点是,本文所讨论的Canvas只讨论Canvas的2D API。这里并不涉及Canvas也有3DAPI(WebGL)。

浏览器支持情况

在我们继续讨论之前,我们再看看浏览器目前对Canvas的兼容性。Canvas目前是一套稳定的API,大多现代浏览都兼容它。它的执行效率也非常高。

Desktop Brower Version
Safari 3.0+
Chrome 10+
Opera 9+
FireFox 4.0+
IE 9.0+

在移动端Canvas的支持情况也较好,因为大部分的移动端浏览器都基于WebKit,而WebKit一直以来就对Canvas有较好的支持。

Mobile Brower Version
IOS all
webOS all
Android 2.0+
BlackBerry PlayBook and OS 6.0+

绘制简单的图形

正如之前提到的,Canvas的2DAPI并不复杂,如果你有过任何Flash 或者 Java 2D的使用经验,你会觉得Canvas的使用非常熟悉,给物理性状,设置填充色,描边,绘制不同的性状。以下以一些实例:

// 绘制一个红色的矩形
ctx.fillStyle = "red";
//x, y, width, height
ctx.fillRect(20,30,40,50);

矩形

// 绘制一个边框和填充不同颜色的三角形
c.fillStyle = '#ccddff';
c.beginPath();
c.moveTo(50,20);
c.lineTo(200,50);
c.lineTo(150,80);
c.closePath();
c.fill();
c.strokeStyle = 'rgb(0,128,0)';
c.lineWidth = 5;
c.stroke();

三角形

在这个三角形的例子中,我们绘制了路径,设置了填充色和边框色,值得我们注意的是,context可以单独设置填充色和边框色。同样值得注意的是Canvas支持所有CSS中的颜色模式,包括hex,names,rgb().

路径

Canvas只支持直接绘制矩形,想要绘制其它形状,都需要你自己利用路径来绘制。路径由多条直线或曲线组成。在Canvas中,使用beginPath()函数开始绘制路径,之后你可以对路径进行填充,描边或者剪裁(clip)。定义线的方法包括moveTo(),lineTo(),bezierCurveTo()。下面的例子由一个moveTo(),然后是一条贝塞尔曲线,以及一些直线组成。绘制完路径以后,我们对其进行了填充和描边。

特殊曲线

c.fillStyle = 'red';
c.beginPath();
c.moveTo(10,30);
c.bezierCurveTo(50,90,159,-30,200,30);
c.lineTo(200,90);
c.lineTo(10,90);
c.closePath();
c.fill();
c.lineWidth = 4;
c.strokeStyle = 'black';
c.stroke();

坐标系统

简言之,Canvas中的坐标系以左上角为原点,X轴向右,Y轴向下。对电脑图形学来说,这是传统,如果你想要不同的坐标系,你也可以通过transforms来实现,这一点我们将在稍后做介绍。另一点值得注意的是,Canvas的坐标原点占据了1px,这意味着,如果你要在坐标为(5,0)处绘制一像素的直线,其实绘制的位置是4.5至5.5之间。有0.5的偏差。 Canvas坐标系

绘制图片

Canvas中drawImage函数可以用以绘制图像。 drawImage有多种形式,你可以直接绘制一个图片到Canvas中,也可以按你的喜好伸展图片,裁剪图片。这些功能在游戏开发中非常有效,使用图片做这些事情是高效的。

ctx.drawImage(img, 0,0); //normal drawing
ctx.drawImage(img, //draw stretched
    0,0,66,66, //source (x,y,w,h)
    100,0,100,100//destination (x,y,w,h)
    );
ctx.drawImage(img, //draw a slice
    20,10,20,20, //source coords (x,y,w,h)
    250,0,250,50//destination coords (x,y,w,h)
    );

图片处理 想要伸展图片,你需要指明源坐标和目的坐标,源坐标告诉drawImage函数,绘制图片的那些部分到Canvas,上述图片的分辨率为67*67,因此0,0,66,66能展现出整个图片。目的坐标,告诉drawImage函数,在屏幕中的何处开始放置图片。通过改变宽高,你可以伸展或者压缩图片。

剪裁也是类似的,只是此时的的源坐标不会覆盖整个图片,当你剪裁图片时,要注意不要超出了原图片的范围否则图片将不会显示。

绘制文本

使用fillText(string,x,y)函数可以在Canvas也能绘制文字,且文字支持的属性和CSS中文本支持的属性一致。值得注意的是此函数使用文本的baseline做为文字的绘制边界,因此如果,你将文字绘制在(0,0)处,文字会超出屏幕的顶部。

ctx.fillStyle = "black";
ctx.font = "italic "+96+"pt Arial ";
ctx.fillText("this is text", 20,150);

绘制文字

绘制渐变色

Canvas可以给路径填充渐变色。

var grad = ctx.createLinearGradient(0,0,200,0);
grad.addColorStop(0, "white");
grad.addColorStop(0.5, "red");
grad.addColorStop(1, "black");

ctx.fillStyle = grad;
ctx.fillRect(0,0,400,200);

渐变1 值得注意的是渐变色是以坐标系为基准而非以图形为基准的,因此如果把上述开始的坐标(0,0)更改为(100,100)将得到以下效果。

    var grad = ctx.createLinearGradient(0,0,200,0);
    grad.addColorStop(0, "white");
    grad.addColorStop(0.5, "red");
    grad.addColorStop(1, "black");

    ctx.fillStyle = grad;
    ctx.fillRect(100,100,400,200);

渐变2

因此如果你给图形设置了渐变色,但是只看到了单一的颜色,也许你该考虑是不是坐标系的问题了。

这就是基础的绘制方法了,下一节,我们开展一些练习。准备好浏览器和编辑器0_0.

results matching ""

    No results matching ""