2D绘图上下文提供了绘制2D图形的方法,包括矩形、弧形和路径。
2D上下文的坐标原点(0, 0)在
18.3.1 填充和描边
2D上下文有两个基本绘制操作:填充和描边。
填充以指定样式(颜色、渐变或图像)自动填充形状;
描边只为图形边界着色。
大多数2D上下文操作有填充和描边的变体,显示效果取决于两个属性:fillStyle和strokeStyle。
这两个属性可以是字符串、渐变对象或图案对象,默认值都为”#000000”。
字符串表示颜色值,可以是CSS支持的任意格式:名称、十六进制代码、rgb、rgba、hsl或hsla。
let drawing = document.getElementById('drawing');// 确保浏览器支持<canvas>if (drawing.getContext) {let context = drawing.getContext('2d');context.strokeStyle = 'red';context.fillStyle = '#000ff';}
18.3.2 绘制矩形
矩形是唯一一个可以直接在2D绘图上下文中绘制的形状。
与绘制矩形相关的方法有3个:fillRect()、strokeRect()和clearRect()。
这些方法都接收4个参数:矩形x坐标、矩形y坐标、矩形宽度和矩形高度。
这几个参数的单位都是像素。
fillRect()方法用于以指定颜色在画布上绘制并填充矩形。填充的颜色使用fillStyle属性指定。
strokeRect()方法使用通过strokeStyle属性指定的颜色绘制矩形轮廓(不是实心的)。
注:描边宽度由lineWidth属性控制,它可以是任意整数值。
使用clearRect()方法可以擦除画布中某个区域。该方法用于把绘图上下文中的某个区域变透明。
通过先绘制形状再擦除指定区域,可以创建出有趣的效果,比如从已有矩形中开个孔。
18.3.3 绘制路径
2D绘图上下文支持很多在画布上绘制路径的方法。
通过路径可以创建复杂的形状和线条。
要绘制路径,必须首先调用beginPath()方法以表示要开始绘制新路径。然后,再调用各种方法来绘制路径。
创建路径之后,可以使用closePath()方法绘制一条返回起点的线。
如果路径已经完成,则既可以指定fillStyle属性并调用fill()方法来填充路径,也可以指定strokeStyle属性并调用stroke()方法来描画路径,还可以调用clip()方法基于已有路径创建一个新剪切区域。
路径是2D上下文的主要绘制机制,为绘制结果提供了很多控制。
因为路径经常被使用,所以也有一个isPointInPath()方法,接收x轴和y轴坐标作为参数。
这个方法用于确定指定的点是否在路径上,可以在关闭路径前随时调用。
18.3.4 绘制文本
fillText()和strokeText()
这两个方法都接收4个参数:要绘制的字符串、x坐标、y坐标和可选的最大像素宽度。
还有第四个参数,即文本的最大宽度。这个参数是可选的(Firefox 4是第一个实现它的浏览器),如果调用fillText()和strokeText()时提供了此参数,但要绘制的字符串超出了最大宽度限制,则文本会以正确的字符高度绘制,这时字符会被水平压缩,以达到限定宽度。
这两个方法最终绘制的结果都取决于以下3个属性:
❑ font:以CSS语法指定的字体样式、大小、字体族等,比如”10pxArial”。
❑ textAlign:指定文本的对齐方式,可能的值包括”start”、”end”、”left”、”right”和”center”。推荐使用”start”和”end”,不使用”left”和”right”,因为前者无论在从左到右书写的语言还是从右到左书写的语言中含义都更明确。
❑ textBaseLine:指定文本的基线,可能的值包括”top”、”hanging”、”middle”、”alphabetic”、”ideographic”和”bottom”。
这些属性都有相应的默认值,因此没必要每次绘制文本时都设置它们。
fillText()方法使用fillStyle属性绘制文本;
strokeText()方法使用strokeStyle属性。
通常,fillText()方法是使用最多的,因为它模拟了在网页中渲染文本。
2D上下文提供了用于辅助确定文本大小的measureText()方法。接收一个参数,即要绘制的文本,然后返回一个TextMetrics对象。
18.3.5 变换
上下文变换可以操作绘制在画布上的图像。
2D绘图上下文支持所有常见的绘制变换。
以下方法可用于改变绘制上下文的变换矩阵:
❑ rotate(angle):围绕原点把图像旋转angle弧度。
❑ scale(scaleX, scaleY):通过在x轴乘以scaleX、在y轴乘以scaleY来缩放图像。scaleX和scaleY的默认值都是1.0。
❑ translate(x, y):把原点移动到(x, y)。执行这个操作后,坐标(0, 0)就会变成(x, y)。
❑ transform(m1_1, m1_2, m2_1, m2_2, dx, dy)
❑ setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy):把矩阵重置为默认值,再以传入的参数调用transform()。
所有这些变换,包括fillStyle和strokeStyle属性,会一直保留在上下文中,直到再次修改它们。
如果想着什么时候再回到当前的属性和变换状态,可以调用save()方法。调用这个方法后,所有这一时刻的设置会被放到一个暂存栈中。保存之后,可以继续修改上下文。
在需要恢复之前的上下文时,可以调用restore()方法。这个方法会从暂存栈中取出并恢复之前保存的设置。
多次调用save()方法可以在暂存栈中存储多套设置,然后通过restore()可以系统地恢复。
注:save()方法只保存应用到绘图上下文的设置和变换,不保存绘图上下文的内容。
18.3.6 绘制图像
2D绘图上下文内置支持操作图像。
如果想把现有图像绘制到画布上,可以使用drawImage()方法。可接收3组不同的参数,并产生不同的结果。
最简单的调用是传入一个HTML的元素,以及表示绘制目标的x和y坐标,结果是把图像绘制到指定位置。
还可以只把图像绘制到上下文中的一个区域。
需要给drawImage()提供9个参数:要绘制的图像、源图像x坐标、源图像y坐标、源图像宽度、源图像高度、目标区域x坐标、目标区域y坐标、目标区域宽度和目标区域高度。
结合其他一些方法,drawImage()方法可以方便地实现常见的图像操作。
操作的结果可以使用toDataURL()方法获取。
不过有一种情况例外:如果绘制的图像来自其他域而非当前页面,则不能获取其数据。
此时,调用toDataURL()将抛出错误。
比如,如果来自www.example.com的页面上绘制的是来自www.wrox.com的图像,则上下文就是“脏的”,获取数据时会抛出错误。
18.3.7 阴影
2D上下文可以根据以下属性的值自动为已有形状或路径生成阴影:
❑ shadowColor: CSS颜色值,表示要绘制的阴影颜色,默认为黑色。
❑ shadowOffsetX:阴影相对于形状或路径的x坐标的偏移量,默认为0。
❑ shadowOffsetY:阴影相对于形状或路径的y坐标的偏移量,默认为0。
❑ shadowBlur:像素,表示阴影的模糊量。默认值为0,表示不模糊。
这些属性都可以通过context对象读写。
只要在绘制图形或路径前给这些属性设置好适当的值,阴影就会自动生成。
18.3.8 渐变
渐变通过CanvasGradient的实例表示。
要创建一个新的线性渐变,调用上下文的createLinearGradient()方法。接收4个参数:起点x坐标、起点y坐标、终点x坐标和终点y坐标。
调用之后,该方法会以指定大小创建一个新的CanvasGradient对象,并返回实例。
有了gradient对象后,接下来要使用addColorStop()方法为渐变指定色标。接收两个参数:色标位置和CSS颜色字符串。色标位置通过0~1范围内的值表示,0是第一种颜色,1是最后一种颜色。
let drawing = document.getElementById('drawing');if (drawing.getContext) {let context = drawing.getContext('2d');let gradient = context.createLinearGradient(30, 30, 70, 70);gradient.addColorStop(0, 'white');gradient.addColorStop(1, 'black');// 绘制红色矩形context.fillStyle = '#ff0000';context.fillRect(10, 10, 50, 50);// 绘制渐变矩形context.fillStyle = gradient;context.fillRect(30, 30, 50, 50);} else {console.log('wrong');}
这个gradient对象现在表示的就是在画布上从(30, 30)到(70, 70)绘制一个渐变。渐变的起点颜色为白色,终点颜色为黑色。可以把这个对象赋给fillStyle或strokeStyle属性,从而以渐变填充或描画绘制的图形。
为了让渐变覆盖整个矩形,而不只是其中一部分,两者的坐标必须搭配合适。
保持渐变与形状的一致非常重要,有时候可能需要写个函数计算相应的坐标。
let drawing = document.getElementById('drawing');if (drawing.getContext) {let context = drawing.getContext('2d');function createRectLinearGradient(context, x, y, width, height) {return context.createLinearGradient(x, y, x + width, y + height);}// 绘制红色矩形context.fillStyle = '#ff0000';context.fillRect(10, 10, 50, 50);let gradient = createRectLinearGradient(context, 30, 30, 50, 50);gradient.addColorStop(0, 'white');gradient.addColorStop(1, 'black');// 绘制渐变矩形context.fillStyle = gradient;context.fillRect(30, 30, 50, 50);} else {console.log('wrong');}
这个函数会基于起点的x、y坐标和传入的宽度、高度创建渐变对象,之后调用fillRect()方法时可以使用相同的值。
径向渐变(或放射性渐变)要使用createRadialGradient()方法来创建。接收6个参数,分别对应两个圆形圆心的坐标和半径。
前3个参数指定起点圆形中心的x、y坐标和半径,后3个参数指定终点圆形中心的x、y坐标和半径。
在创建径向渐变时,可以把两个圆形想象成一个圆柱体的两个圆形表面。
把一个表面定义得小一点,另一个定义得大一点,就会得到一个圆锥体。
然后,通过移动两个圆形的圆心,就可以旋转这个圆锥体。
要创建起点圆心在形状中心并向外扩散的径向渐变,需要将两个圆形设置为同心圆。
因为创建起来要复杂一些,所以径向渐变比较难处理。不过,通常情况下,起点和终点的圆形都是同心圆,只要定义好圆心坐标,剩下的就是调整各自半径的问题了。
18.3.9 图案
图案是用于填充和描画图形的重复图像。
要创建新图案,调用createPattern()方法并传入两个参数:一个HTML 元素和一个表示该如何重复图像的字符串。
第二个参数的值与CSS的background-repeat属性是一样的,包括”repeat”、”repeat-x”、”repeat-y”和”no-repeat”。
注:跟渐变一样,图案的起点实际上是画布的原点(0, 0)。将填充样式设置为图案,表示在指定位置而不是开始绘制的位置显示图案。
18.3.10 图像数据
2D上下文中比较强大的一种能力是:可用getImageData()方法获取原始图像数据。
接收4个参数:要取得数据中第一个像素的左上角坐标,和要取得的像素宽度及高度。
返回的对象是一个ImageData的实例。
每个ImageData对象都包含3个属性:width、height和data
其中,data属性是包含图像的原始像素信息的数组。
每个像素在data数组中都由4个值表示,分别代表红、绿、蓝和透明度值。
换句话说,第一个像素的信息包含在第0到第3个值中。
18.3.11 合成
2D上下文中绘制的所有内容都会应用两个属性:globalAlpha和globalComposition Operation,
其中,globalAlpha属性是一个范围在0~1的值(包括0和1),用于指定所有绘制内容的透明度,默认值为0。
如果所有后来的绘制都需要使用同样的透明度,那么可以将globalAlpha设置为适当的值,执行绘制,然后再把globalAlpha设置为0。
globalCompositionOperation属性表示新绘制的形状如何与上下文中已有的形状融合。这个属性是一个字符串,可以取下列值。
使用globalCompositeOperation属性时,一定记得要在不同浏览器上进行测试。不同浏览器在实现这些选项时可能存在差异。
