HTML5定义的 <canvas>
元素可以使用 javascript
在网页上绘制图像,canvas(可以称作“画布”)是网页上的一个矩形区域,我们就是在这个区域内进行绘制;在这个矩形区域内,我们可以控制其每个像素,而且 <canvas>
拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。
<canvas>
元素的浏览器兼容情况:
元素 | Chrome | IE | Firefox | Safari | Opera |
---|---|---|---|---|---|
<canvas> |
4.0 | 9.0 | 2.0 | 3.1 | 9.0 |
canvas 元素基础知识
<canvas>
元素用起来很简单,但有几个需要注意的地方:
<canvas>
元素默认是没有内容和边框的<canvas>
元素一般需要设置一个id
属性,方便javascript
代码引用<canvas>
元素需要定义宽度和高度,不然不能正常显示
我们定义一个带有边框的画布,如下所示:
|
|
可以看到,这与使用普通的HTML DOM元素没什么区别,其实除了有绘制能力外,<canvas>
元素就是一个普通的DOM元素;我们也可以同时定义多个画布,使用DOM元素的 id
属性来区分。
使用 JavaScript 绘制
<canvas>
元素本身没有任何绘制功能,它只是一个绘图的容器;要在 <canvas>
元素上绘制内容必须使用JavaScript,下面通过一个最简单的示例来说明这个过程。
|
|
可以看到,在 <canvas>
元素中绘制图形的过程共分成三步。
第一步,得到 canvas 元素
要在画布上绘制内容首先要拿到画布元素,这一步跟其它DOM一样,通过文档对象的 getElementById
方法来获取就可以了。
|
|
第二步,创建绘制对象
拿到画布元素后,我们还需要需要通过调用 <canvas>
元素的 getContext()
方法来获取该元素的绘制对象,绘制对象是一个定义了绘制属性与方法的HTML内置对象。
|
|
在 getContext
方法中传了2d字符串作为参数可能会让人误解 <canvas>
元素是否也支持3d绘制,其实现阶段它是不支持的,这个方法现在只能接受2d字符串作为参数,但HTML5规范中对此也有说明:
A future version of this specification will probably define a 3d context.
第三步,开始绘制
经过上面两步准备,我们可以在画布上绘制内容了,这一步很复杂,因为我们可以在画布上绘制任何内容,而绘制对象也包含多种绘制属性和方法,这些内容会在接下来的部分介绍。
在上面的示例中,我们将绘制对象的填充颜色设置为红色(默认是黑色),然后调用绘制对象的 fillRect(x,y,width,height)
方法绘制了一个矩形。
|
|
canvas 坐标系
canvas元素是一个二维网格,画布的左上角是坐标系原点(0,0),横轴向右延伸,纵轴向下延伸;在上面的简单示例中,我们调用了 fillRect(10, 10, 150, 45)
这么一个绘制矩形方法,意思是从(10,10)坐标点开始画一个150x45像素的矩形。
canvas API 参考
下面以分类的形式列举canvas绘图相关的所有API,在上面解释过了,canvas
元素本身没有任何绘制能力,因此这些API主要是绘制对象的属性和各种绘制方法。
除了列举API,还会对一些比较复杂或难以理解的属性或方法进一步解释,较为简单的API就不再具体介绍了。
颜色、样式及阴影
属性 | 说明 |
---|---|
fillStyle | 设置或返回用于填充绘制的颜色、渐变和图案 |
strokeStyle | 设置或返回用于线条绘制的颜色、渐变和图案 |
shadowColor | 设置或返回阴影的颜色 |
shadowBlur | 设置或返回阴影的模糊级别 |
shadowOffsetX | 设置或返回阴影的水平距离 |
shadowOffsetY | 设置或返回阴影的垂直距离 |
方法 | 说明 |
---|---|
createLinearGradient() | 创建一个线性渐变 |
createPattern() | 在指定方向上重复一个元件 |
createRadialGradient() | 创建径向渐变 |
addColorStop() | 指定梯度对象的颜色和停止位置 |
createLinearGradient()方法
createLinearGradient()
方法可以创建一个线性渐变对象,该对象可以用于填充矩形、圆、线条及文本等形状,也就用于 fillStyle
或 strokeStyle
属性的值。
使用 addColorStop()
方法指定不同的颜色及该颜色在渐变对象的位置。
|
|
上面是 createLinearGradient()
方法的语法,四个参数分别用于指定起点(x0,y0)和终点(x1,y1)。
createPattern()方法
createPattern()
方法用于在指定的方向上重复一个元件,该元件可以是图像、视频或其它的canvas元素,并可以用于填充矩形、线条等形状。
|
|
在上面 createPattern()
方法的语法定义中,image用于指定图案要使用的图像、视频或其它的canvas元素,第二个参数指定重复方向。
createRadialGradient()方法
createRadialGradient()
方法可以创建一个径向渐变对象,其行为及用途与 createLinearGradient()
方法创建的线性渐变一样。
|
|
在上面 createRadialGradient()
方法的语法定义中,x0,y0是径向渐变起始圆形圆心的坐标,r0起始圆形的半径;x1,y1是结束圆形圆心的坐标,r1是结束圆形的半径。
addColorStop() 方法
addColorStop()
方法用于指定渐变对象中颜色和其位置,必要要配合 createRadialGradient()
方法或 createLinearGradient()
方法使用;该方法可以调用多次以实现多色渐变(至少调用一次),如果我们创建了渐变对象却没有调用 addColorStop()
方法,则该渐变并不会显示出来。
|
|
从定义语法上看,addColorStop()
方法接受两个参数:stop是一个[0,1]区间的值,表示从渐变起点到终点之间的位置比例;color就是指的颜色喽!
线条样式
属性 | 说明 |
---|---|
lineCap | |
lineJoin | 设置或返回当两线会合时产生角的类型 |
lineWidth | 设置或返回当前的线条宽度 |
miterLimit |
矩形
方法 | 说明 |
---|---|
rect(x,y,width,height) | 创建一个矩形,该方法不会真正绘制,需要调用 fill() 或 stroke 方法完成绘制 |
fillRect(x,y,width,height) | 绘制一个填充的矩形(绘制矩形后使用 fillStyle 属性值填充) |
strokeRect(x,y,width,height) | 绘制一个矩形(不填充,仅是绘制 strokeStyle 定义的边框) |
clearRect(x,y,width,height) | 清除指定矩形区域的像素 |
路径
方法 | 说明 |
---|---|
fill() | 填充当前的绘图(路径),默认使用黑色 |
stroke() | 绘制定义好的路径,不填充 |
beginPath() | 开始一个路径,或重置当前路径 |
moveTo() | 将画笔移到画布的指定坐标点,该方法不会绘制线条 |
closePath() | 创建一个路径,从当前坐标点回到起始坐标点 |
lineTo(x,y) | 添加一个新的坐标点并创建一条到上一个点的线,该方法不会真正绘制线条 |
clip() | 从原始画布上裁剪任何形状和尺寸的区域 |
quadraticCurveTo() | 创建一个二次贝塞尔曲线 |
bezierCurveTo() | 创建一个三次贝塞尔曲线 |
arc() | 创建一个弧线,用于创建圆或圆的一部分圆弧 |
ellipse() | 创建椭圆弧线 |
arcTo() | 在两条切线中间创建弧线 |
isPointInPath(x,y) | 判断指定的点是否在当前路径上 |
arc()方法
arc()
方法用于创建一段弧线(圆或圆的一部分),但该方法与 rect()
类似,它只是描述了路径并不会真正绘制,因此还是需要调用 fill()
方法填充或 stroke()
方法绘制。
|
|
上面的 arc()
方法语法定义中,参数还是比较多的;x和y两个参数组成一个点的坐标指定圆心,r是该圆的半径,sAngle和eAngle分别指定圆弧的起始角度和结束角度(用 弧度
表示,0度在时钟3点位置),anticlockwise是可选的,指定是否逆时针绘制,默认是false即顺时针绘制。
ellipse()方法
ellipse()
方法用于创建一段椭圆弧线(椭圆或椭圆的一部分),用法与 arc()
方法基本一致,当 ellipse()
方法的两个半径相等时,其结果与 arc()
方法一样。
|
|
ellipse()
方法参数比 arc()
方法要多,其中radiusX和radiusY分别指定X轴和Y轴的半径,rotation指定旋转角度(弧度),其余参数与 arc()
方法一样。
arcTo()方法
arcTo()
方法理解起来略显复杂,它是向当前子路径添加一个弧线(该弧线会连接到画笔当前位置点上),该弧线由指定的控制点和半径定义,实际上是以通过两个控制点(实际上是三个点)定义的两条直线为切线绘制弧线。
|
|
在上面的语法定义中,(x1,y1)是第一个控制点坐标,(x2,y2)是第二个控制点坐标,r是圆的半径;这里的两个点必须与画笔当前所在点联合起来,也就是三个点形成两条线,这两条线作为圆弧的切线。
这个过程描述起来很费劲且难以理解,下面的图示演示了三个点的位置关系及两条切线的形成,以及圆弧最终的效果:
转换
方法 | 说明 |
---|---|
scale() | 缩放当前绘制的内容 |
rotate() | 旋转当前绘制的内容 |
translate() | 重置画布原点(0,0)的位置 |
transform() | Replaces the current transformation matrix for the drawing |
setTransform() |
文本
属性 | 说明 |
---|---|
font | 设置或返回当前的字体 |
textAlign | 设置或返回文本内容当前的对齐方式,相对绘制时指定珠锚点来说,默认值为start |
textBaseline | 设置或返回当前用于绘制文本的基线,默认值是alphabetic |
font属性
font
属性用于定义或返回当前绘制文本的字体属性,其语法与CSS中的定义一样:
|
|
font
属性的默认值是 10px sans-serif
方法 | 说明 |
---|---|
fillText(text,x,y) | 在画布上绘制填充的文本 |
strokeText(text,x,y) | 绘制文本(非填充) |
measureText(text) | 返回一个包含指定文本宽度的对象 |
绘制图片
方法 | 说明 |
---|---|
drawImage() | 在画布上绘制图片、其它画布或视频 |
drawImage()方法
drawImage()
方法有三种形式,如下所示:
|
|
前两种形式比较简单,这里不再细说;第三种形式参数较多,(sx,sy)是开始裁剪的坐标点,swidth和sheight表示裁剪的宽和高,另外几个参数与第一种形式一样。
像素操作
属性 | 说明 |
---|---|
width | 返回ImageData对象的宽度 |
height | 返回ImageData对象的高度 |
data | 返回一个指定ImageData对象的包含图像数据的对象 |
方法 | 说明 |
---|---|
createImageData() | 创建一个新的空白ImageData对象 |
getImageData() | 返回一个画布上指定矩形像素数据的ImageData对象 |
putImageData() | 将指定ImageData对象的图像数据放回到画布上 |
createImageData()方法
createImageData()
方法创建一个新的空ImageData对象,该对象包含指定尺寸内所有的像素数据,其中每个像素都包含4条信息,也就是RGBA值(红绿蓝三色加一个alpha通道值,值都是0~255);新对象的像素数据(RGBA值)默认是黑色透明(即(0,0,0,0));这些RGBA值会放在一个数组存储在ImageData对象的 data
属性中,因为数组包含每个像素的4条信息,因此该数组的长度是ImageData对象的4倍: width*height*4。
|
|
由上面的语法定义可以看出 createImageData()
方法有两种形式,第一种是通过指定尺寸(以像素为单位)来创建,第二种是使用与另一个ImageData对象相同的尺寸来创建(并不会复制该对象的像素数据)。
getImageData()方法
getImageData()
方法可以返回一个ImageData对象,该对象复制了画布上指定矩形区域的像素数据;但ImageData对象并不是图像,它只是持有画布指定区域(矩形)每个像素的信息。
|
|
在上面的语法定义中,(x,y)是 getImageData()
方法复制起始点坐标,width和height分别是要复制区域的宽和高。
putImageData()
putImageData()
方法可以将图像数据(指定的ImageData对象)放回画布上,图像数据一般是由 getImageData()
方法获取或 createImageData()
方法生成。
|
|
上面的语法定义中,前三个参数是必须的,后面四个参数是可选的;(x,y)是ImageData对象的左上角坐标,以像素为单位;(dirtyX,dirtyY)是ImageData要放置的画布位置坐标;dirtyWidth和dirtyHeight分别指定图像要绘制的宽度和高度。
混合
属性 | 说明 |
---|---|
globalAlpha | 设置或返回当前绘图的透明度,设置后绘制的内容都应用该透明度,默认值为1.0 |
globalCompositeOperation | 设置或返回如何在已有图像上绘制新图像,默认值为“source-over” |
globalCompositeOperation属性
globalCompositeOperation
属性设置或返回源图像(准备绘制到画布上的内容)如何绘制到目标图像(画布上已存在的内容,即原来绘制的内容)上;该属性提供了非常强大的绘图功能,可以让绘制的图片产生诸如互相叠加、互相剪切等效果。
其取值及其解释参见文档:HTML canvas globalCompositeOperation Property,该页面的解释比较详细,也有不同取值的演示效果图。
其它
方法 | 说明 |
---|---|
save() | 保存当前上下文状态 |
restore() | 返回上次保存的路径状态和属性 |
createEvent() | |
getContext() | |
toDataURL() |
示例
“纸上得来终觉浅,绝知此事要躬行”,上面一堆都是对canvas相关知识的理论解释,看起来很容易让人烦躁,而且并不能很容易理解其用法与效果,这部分就用一些例子来说明。
绘制矩形
该示例绘制了三个矩形,主要演示了填充矩形及非填充矩形的绘制、线性渐变定义与应用等知识。需要注意 rect()
方法仅是创建一个矩形,还需要调用 fill()
或 stroke()
来完成绘制才能显示在画布上;也就是说 rect() + fill()
两个方法效果等于 fillRect()
,rect() + stroke()
两个方法效果等于 strokeRect()
。
|
|
绘制弧线/圆形
该部分示例绘制了三个弧线形状,第一个用 arcTo()
方法,该方法很难控制,需要多查资料;第二个比较简单,直接用 ellipse()
方法绘制半个椭圆并旋转;第三个使用 arc()
方法绘制了一个圆并用径向渐变填充。
|
|
绘制文本
|
|
绘制图像
|
|
像素操作
像素操作是非常复杂也极其强大的功能,它可以在画布上做任何事情,但由于ImageData将所有像素数据放在一个一维数组中,因此使用起来很麻烦。
下面是一个比较复杂的示例,我想了差不多一天才理清如何实现,具体过程很难用文字描述清楚,因此我在代码中添加了少量注释。我觉得将画布相像成二维网格,每个像素都是一个格子去分析比较简单。
|
|
这个示例没有涉及到 getImageData()
方法,由于篇幅关系就不再写相关示例了。