在HTML5网页中可以使用Canvas元素定义一个画布,这是使用Canvas API 进行画图的前提。
定义Canvas元素的语法如下所示。
Canvas元素的常用属性如下。
之间的字符串指定当浏览器不支持Canvas时显示的字符串。
Internet Explorer 9、Firebox、Opera、Chrome 和 Safari 支持 Canvas 元素。Internet Explorer 8 及其以前版本不支持 Canvas 元素。
定义Canvas画布只是开始绘画的准备工作,真正绘画要在JavaScript程序中调用Canvas API 完成。
在Canvas画布中绘图前需要使用JavaScript获取网页中的Canvas对象,然后使用该对象调用Canvas API 完成绘图。
在JavaScript中,可以使用document.getElementById()方法获取网页中的对象,语法如下。
document.getElementById(对象id)
获取到对象后,想要在其中绘图还需要获得该对象的2d渲染上下文(CanvasRenderingContext2D)对象,代码如下。
var ctx = object.getContext("2d");
使用CanvasRenderingContext2D对象即可调用Canvas API 在 Canvas 画布中绘图。
在绘图时需要指定图形的位置和大小,因此,需要引入一个坐标系统。坐标系统是描述位置的一组数值,可以使用坐标轴和度量单位来描述坐标系统。Canvas 使用二维坐标系统,即有X轴和Y轴两个坐标轴。默认情况下,坐标轴原点位于窗口客户区的左上角,X轴向右为正,Y轴向下为正,度量单位为像素。
在绘图和输出文字时,可以指定其颜色。可以设置颜色的最小图形单位是像素点。Windows使用红、绿、蓝三原色组合表示一个颜色,每个原色用8位数字表示,合在一起即用24位数字来表示一个颜色,也就是通常所说的24位色。
Canvas采用HTML的颜色表示方法。
可以使用一组颜色关键字字符表示颜色。
颜色关键字 | 具体描述 | 颜色关键字 | 具体描述 |
---|---|---|---|
maroon | 酱紫色 | green | 绿色 |
red | 红色 | navy | 藏青色 |
orange | 橙色 | blue | 蓝色 |
yellow | 黄色 | silver | 银色 |
olive | 橄榄色 | aqua | 浅绿色 |
purple | 紫色 | white | 白色 |
gray | 灰色 | teal | 蓝绿色 |
fuchsia | 紫红色 | black | 黑色 |
lime | 绿黄色 |
可以使用一个十六进制字符串表示颜色,格式为#RGB。其中,R表示红色集合,G表示绿色集合,B表示蓝色集合。例如,#F00表示红色,#0F0表示绿色,#00F表示蓝色,#FFF表示白色,#000表示黑色。
可以使用rgb(r,g,b)的格式表示颜色。其中r表示红色集合,g表示绿色集合,b表示蓝色集合。r、g、b都是十进制数,取值范围为0~255。
颜色 | 红色值 | 绿色值 | 蓝色值 | RGB()表示 |
---|---|---|---|---|
黑色 | 0 | 0 | 0 | RGB(0,0,0) |
蓝色 | 0 | 0 | 255 | RGB(0,0,255) |
绿色 | 0 | 255 | 0 | RGB(0,255,0) |
青色 | 0 | 255 | 255 | RGB(0,255,255) |
红色 | 255 | 0 | 0 | RGB(255,0,0) |
洋红色 | 255 | 0 | 255 | RGB(255,0,255) |
黄色 | 255 | 255 | 0 | RGB(255,255,0) |
白色 | 255 | 255 | 255 | RGB(255,255,255) |
使用Canvas API 可以绘制各种基本图形,包括直线、曲线、矩形和圆形等。
在JavaScript中可以使用Canvas API 绘制直线。
(1)在网页中使用Canvas元素定义一个Canvas画布,用于绘画。
(2)使用JavaScript获取网页中的Canvas对象,并获取Canvas对象的2d上下文ctx。使用2d上下文可以调用Canvas API 绘制图形。
(3)调用beginPath()方法,指示开始绘图路径,即开始绘图。语法如下。
ctx.beginPath();
(4)调用moveTo()方法将坐标移至直线起点。moveTo()方法的语法如下。
ctx.moveTo(x, y);
x 和 y 为要移动至的坐标。
(5)调用lineTo()方法绘制直线。lineTo()方法的语法如下。
ctx.lineTo(x, y);
x 和 y 为直线的终点坐标。
(6)调用stroke()方法,绘制图形的边界轮廓。语法如下。
ctx.stroke();
使用Canvas API 绘制直线,起点为(10,10),终点为(100,100),代码如下。
Test
在JavaScript程序中,定义了一个绘制直线的方法drawline(),并调用window.addEventListener将drawline()方法添加到网页的load事件中。也就是说,加载网页时会调用drawline()方法。
在调用lineTo()方法后,当前坐标会自动移至所绘制直线的终点。因此,连续画线时不需要每次都调用moveTo()方法设置起点坐标。
使用连续画线的方法绘制一个三角形,代码如下。
Test
通过画线绘制复杂图形。
Test
贝塞尔曲线是参数化的曲线,常用于计算机图形和相关领域。贝塞尔曲线是依据n个位置任意的点坐标绘制出的一条光滑曲线。研究贝塞尔曲线的人最初是按照已知曲线参数方程来确定4个点的思路设计出这种矢量曲线绘制法。贝塞尔曲线的独特之处在于它的“皮筋效应”,也就是说,随着点有规律地移动,曲线将产生皮筋伸展一样的变换,带来视觉上的冲击。1962年,法国数学家Pierre Bezier第一个研究了这种矢量绘制曲线的方法,并给出了详细的计算公式,因此按照这样的公式绘制出来的曲线就用他的姓氏来命名为贝塞尔曲线。贝塞尔曲线的示意图如下所示。移动两端的端点时,贝塞尔曲线会改变曲线的曲率(弯曲的程度);移动中间的控制点时,贝塞尔曲线在两端的端点锁定的情况下做均匀移动。
二次方贝塞尔曲线的路径由3个给定点确定。可以通过quadraticCurveTo()方法绘制二次方贝塞尔曲线,语法如下。
quadraticCurveTo(cpX, cpY, x, y)
参数cpX和cpY为控制点的坐标,参数x和y为曲线的终点坐标。
提示:二次方贝塞尔曲线的起始点坐标为调用quadraticCurveTo()方法时的当前位置坐标。调用quadraticCurveTo()方法后的当前位置坐标为(x,y)。
绘制二次方贝塞尔曲线,代码如下。
Test
绘制三次方贝塞尔曲线,代码如下。
Test
利用贝塞尔曲线绘制心形图形,代码如下。
Test
可以调用rect()、strokeRect()、fillRect()和clearRect()等4个API在Canvas画布中绘制矩形。其中,前两个API用于绘制矩形边框,调用fillRect()可以填充指定的矩形区域,调用clearRect()可以擦除指定的矩形区域。
rect()方法的语法如下。
rect(x, y, width, height)
参数说明如下。
使用rect()方法绘制矩形边框。
Test
strokeRect()方法的语法如下。
strokeRect(x, y, width, height)
参数的含义与上述的rect()方法的参数相同。
strokeRect()方法与rect()方法的区别在于调用strokeRect()方法时不需要使用beginPath()和stroke()即可绘图。
使用strokeRect()方法绘制矩形边框。
Test
fillRect()方法的语法如下。
fillRect(x, y, width, height)
参数的含义与上述的rect()方法的参数相同。
使用fillRect()方法填充矩形区域。
Test
clearRect()方法的语法如下。
clearRect(x, y, width, height)
参数的含义与上述的rect()方法的参数相同。
将上述fillRect()方法绘制的矩形的中央擦除一个小矩形。
Test
可以调用arc()方法绘制圆弧,语法如下。
arc(centerX, centerY, radius, startingAngle, endingAngle, antiClockwise);
参数说明如下。
使用arc()方法绘制圆弧。
Test
圆是一种特殊的圆弧,将startingAngle设置为0,将endingAngle设置为2*Math.PI,使用arc()方法即可画图。
使用arc()方法画圆。
Test
在绘图时可以指定线条的宽度和颜色,画出图形边缘的线条,通俗地讲就是在图形边缘加上边框,就是描边。也可以使用指定的样式和颜色填充图形的内部。
设置CanvasRenderingContext2D对象的strokeStyle属性可以指定描边的颜色,设置CanvasRenderingContext2D对象的lineWidth属性可以指定描边的宽度。
设置描边颜色和宽度。
Test
设置CanvasRenderingContext2D对象的lineCap属性可以指定线段的末端如何绘制。
可选值 | 具体描述 |
---|---|
butt | 指定线段没有线帽,为默认值。线条的末点是平直的,而且和线条的方向正交,这条线段在其端点之外没有扩展 |
round | 指定线段带有一个半圆形的线帽,半圆的直径等于线段的宽度,并且线段在端点之外扩展了线段宽度的一半 |
square | 指定线段一个矩形线帽。这个值和butt一样,但是线段扩展了自己宽度的一半 |
提示:lineCap属性只有绘制较宽线段时才有效。
指定线段的末端。
Test
设置CanvasRenderingContext2D对象的lineJoin属性可以指定如何绘制线段或曲线的交点。
可选值 | 具体描述 |
---|---|
miter | 指定线段的外边缘一直扩展到它们相交,为默认值。当两条线段以一个锐角相交时,斜角连接可能会变得很长 |
round | 指定顶点的外边缘应该和一个填充的弧接合,这个弧的直径等于线段的宽度 |
bevel | 指定顶点的外边缘应该和一个填充的三角形相交 |
指定如何绘制矩形交点。
Test
设置CanvasRenderingContext2D对象的fillStyle属性可以指定填充图形内部的颜色。
填充图形内部。
Test
fillRect()方法只能填充矩形,如果要填充其他封闭图形的内部,可以调用fill()方法。fill()方法的功能是使用fillStyle属性指定的颜色、渐变和模式来填充当前路径。这一路径的每一条子路径都单独填充。
填充图形内部。
Test
在描边和填充图形时,可以使用渐变颜色。渐变颜色从字面上理解就是逐渐变化的颜色。专业地讲,渐变是指在颜色采集上使用逐步抽样算法。
CanvasGradient是用于定义画布中的一个渐变颜色的对象。如果要使用渐变颜色,首先需要创建一个CanvasGradient对象。可以通过下面2种方法创建CanvasGradient对象。
1、以线性颜色渐变方式创建CanvasGradient对象。
使用CanvasRenderingContext2D对象的createLinearGradient()方法可以用线性颜色渐变方式创建CanvasGradient对象。createLinearGradient()方法的语法如下。
createLinearGradient(xStart, yStart, xEnd, yEnd)
参数xStart和yStart是渐变的起始点的坐标,参数xEnd和yEnd是渐变的结束点的坐标。
2、以放射颜色渐变方式创建CanvasGradient对象。
使用CanvasRenderingContext2D对象的createRadialGradient()方法可以用放射颜色渐变方式创建CanvasGradient对象。createRadialGradient()方法的语法如下。
createRadialGradient(xStart, yStart, radiusStart, xEnd, yEnd, radiusEnd)
参数xStart和yStart是开始圆的圆心坐标,radiusStart是开始圆的半径;参数xEnd和yEnd是结束圆的圆心坐标,radiusEnd是结束圆的半径。
创建CanvasGradient对象后,还需要为其设置颜色基准,可以通过CanvasGradient对象的addColorStop()方法在渐变中的某一点添加一个颜色变化,渐变中其他点的颜色将以此为基准。addColorStop()方法的语法如下。
addColorStop(offset, color)
参数offset是一个范围为0.0~1.0的浮点值,表示渐变的开始点和结束点之间的一部分。offset为0对应开始点,offset为1对应结束点。color指定offset显示的颜色。沿着渐变某一点的颜色是根据这个值以及任何其他的颜色色标来插值的。
只要将前面创建的CanvasGradient对象赋值给用于绘图的CanvasRenderingContext2D对象的strokeStyle属性,即可使用渐变颜色描边。
例如:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var Colordiagonal = ctx.createLinearGradient(10, 10, 100, 10);
ctx.strokeStyle = Colordiagonal;
ctx.stroke();
使用由黄到红的渐变颜色绘制一条直线。
Test
在上述的代码的基础上,在中间添加蓝色过渡。
Test
使用黄、绿、红的渐变颜色绘制一个矩形。
Test
只要将前面创建的CanvasGradient对象赋值给用于绘图的CanvasRenderingContext2D对象的fillStyle属性,即可使用渐变颜色进行填充。
例如:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var Colordiagonal = ctx.createLinearGradient(10, 10, 100, 10);
ctx.fillStyle = Colordiagonal;
ctx.fill();
使用黄、绿、红的直线渐变颜色填充一个矩形。
Test
使用黄、绿、红的放射渐变颜色填充一个圆。
Test
在指定颜色时,可以使用rgba()方法定义透明颜色,格式如下。
rgba(r, g, b, alpha)
其中r表示红色集合,g表示绿色集合,b表示蓝色集合。r、g、b都是十进制数,取值范围为0~255。alpha的取值范围为0~1,用于指定透明度,0表示完全透明,1表示不透明。
使用透明颜色填充10个连成一串的圆,模拟太阳光照射的光环。
Test
可以使用Canvas API 在画布的指定位置绘制图像。相比而言,传统使用标签的方法只能在固定的位置以固定的大小显示图像,显然Canvas API 更具有灵活性。
在画布上绘制图片的Canvas API 是 drawImage()方法,语法如下。
drawImage(image, x, y)
drawImage(image, x, y, width, height)
drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight,
destX, destY, destWidth, destHeight)
可以看到,drawImage()方法有3种用法。第1种用法用于以原始大小在指定位置绘制图像;第2种方法用于在指定位置以指定大小绘制图像;第3种用法用于在指定位置以指定大小绘制图像的一部分(即对图像进行剪裁)。
参数说明如下。
以原始大小在指定位置(100,100)绘制图像。
Test
在指定位置(100,100)绘制图像的缩略图(宽160、高120)。
Test
在指定位置(0,0)绘制图像中的一部分(左上角的坐标为(100,100),宽度为200,高度为160)。
Test
可以使用strokeText()方法在画布的指定位置输出文字,语法如下。
strokeText(string text, float x, float y)
参数说明如下。
在指定位置(10,10)输出字符串“你好,HTML5”。
Test
可以通过Context.font属性来设置输出字符串的字体,格式如下。
Context.font = "字体大小 字体名称"
使用隶书输出字符串"你好,HTML5",字体大小为40。
Test
可以通过Context.TextAlign属性来设置输出字符串的对齐方式,可选值为left(左对齐)、center(居中对齐)和right(右对齐)。
在画布的正中输出字符串"你好,HTML5"。
Test
可以设置CanvasRenderingContext2D对象的strokeStyle属性指定输出文字的颜色。
使用蓝色边框、隶书输出字符串“你好,HTML5”,字体大小为40。
Test
使用strokeText()方法输出的文字是中空的,只绘制了边框。如果要填充文字内部,可以使用fillText()方法,语法如下。
fillText(string text, float x, float y)
可以使用Context.fillStyle属性指定填充的颜色。
使用蓝色、隶书输出字符串“你好,HTML5”,字体大小为60。
Test
也可以使用渐变颜色填充输出的字符串。
使用黄、绿、红的直线渐变颜色填充字符串“你好,HTML5”。
Test
可以对Canvas图形进行一系列操作,包括移动、旋转、缩放和变形等。通过这些操作可以使绘图的效果更加丰富。这里所说的移动、旋转、缩放和变形等操作并不是对已经绘制的图形进行的,而是作用于后面即将绘制的图形的操作。
在绘图和对图形进行操作时,经常要使用不同的样式或变形,在绘制复杂图形时就需要保存绘图状态,并在需要时恢复之前保存的绘图状态。
调用Context.save()方法可以保存当前的绘图状态。Canvas状态下以堆(Stack)的方式保存绘图状态,绘图状态包括以下几种。
调用Context.restore()方法可以从堆中弹出之前保存的绘图状态。
Context.save()方法和Context.restore()方法都没有参数。
保存和恢复绘图状态。
Test
可以调用Context.translate()方法将Canvas画布的原点移动到指定的位置,移动后再绘图就会按照新的坐标设置位置。这就相当于将之前已经绘制的图形反向移动了位置。
Context.translate()方法的语法如下。
void translate(x, y);
参数 x 和 y 指定将Canvas画布的原点移动到的新位置。
使用Context.translate()方法移动Canvas画布原点。
Test
可以调用Context.scale()方法缩小或放大Canvas图形或位图,语法如下。
void scale(x, y);
参数 x 和 y 分别是x轴和y轴的缩放因子,它们都必须是正值。值比1.0小表示缩小,比1.0大表示放大,值为1.0时什么效果都没有。
使用Context.scale()方法缩放Canvas对象。
Test
可以调用Context.rotate()方法将绘制的Canvas图形旋转一个角度,语法如下。
void rotate(angle);
参数angle是旋转的角度,单位为弧度,旋转方向是顺时针的。
使用Context.rotate()方法旋转绘制的Canvas图形。
Test
可以调用Context.setTransform()方法对绘制的Canvas图形进行变形,语法如下。
context.setTransform(m11, m12, m21, m22, dx, dy);
参数构成如下的变形矩阵。
假定点(x,y)经过变形后变成了(X,Y),则变形的转换公式如下。
X = m11*x + m21*y + dx
Y = m12*x + m22*y + dy
通常可以使用变形绘制影子效果。
使用Context.setTransform()方法实现倒影效果。
Test
为了增强视觉效果,程序还在绘制阴影时使用了渐变颜色。
使用Context.setTransform()方法实现侧阴影效果。
Test
在绘制图形时,如果画布上已经有图形,就涉及两个图形如何组合的问题。可以通过CanvasRenderingContext2D.globalCompositeOperation属性来设置组合方式。
可选值 | 具体描述 |
---|---|
source-over | 新图形会覆盖在原有内容之上,为默认值。 |
destination-over | 在原有内容之下绘制新图形 |
source-in | 新图形会仅仅出现与原有内容重叠的部分,其他区域都变成透明的 |
destination-in | 原有内容中与新图形重叠的部分会被保留,其他区域都变成透明的 |
source-out | 只有新图形中与原有内容不重叠的部分会被绘制出来 |
destination-out | 原有内容中与新图形不重叠的部分会被保留 |
source-atop | 新图形中与原有内容重叠的部分会被绘制,并覆盖于原有内容之上 |
destination-atop | 原有内容中与新内容重叠的部分会被保留,并会在原有内容之下绘制新图形 |
lighter | 两图形中重叠的部分做减色处理 |
darker | 两图形中重叠的部分做加色处理 |
xor | 重叠的部分会变成透明 |
copy | 只有新图形会被保留,其他都被清除掉 |
使用Context.globalCompositeOperation属性实现图形组合的例子。
Test
在绘制图形时,可以通过CanvasRenderingContext2D的一组属性设置图形的阴影。
属性名 | 具体描述 |
---|---|
shadowBlur | 阴影的像素模糊值 |
shadowOffsetX | 阴影在x轴上的偏移值 |
shadowOffsetY | 阴影在y轴上的偏移值 |
shadowColor | 阴影颜色值 |
绘制一个蓝色的矩形,同时绘制阴影。
Test
首先绘制一个三角形路径,代码如下。
Test
上面的程序只是定义了绘图路径,并没有绘制,因此还看不出效果。
警告牌的3个角应该是圆滑的。下面使用前面定义的渐变颜色给警告牌绘制一个最外侧边框,将context.lineJoin设置为round,即可出现圆角的效果。为了增加图形的层次感,程序使用了垂直渐变颜色进行填充,并增加了阴影效果。在前面的draw()函数的最后添加如下代码。
context.shadowBlur = 10;
context.shadowColor = "black";
// 使用垂直渐变颜色填充
gradient = context.createLinearGradient(0, padding, 0, padding+height);
gradient.addColorStop(0, "#faf100");
gradient.addColorStop(0.9, "#fca009");
gradient.addColorStop(1, "#ffc821");
// 绘制最外侧边框
context.lineWidth = 20;
context.lineJoin = "round";
context.strokeStyle = gradient;
context.stroke();
下面使用前面定义的渐变颜色填充警告牌的内部。在前面的draw()函数的最后添加如下代码。
context.shadowColor = "transparent";
context.fillStyle = gradient;
context.fill();
为了取消内部的阴影效果,这里将context.shadowColor属性设置为transparent。
下面绘制警告牌的黑色三角边框。在前面的draw()函数的最后添加如下代码。
// 绘制黑色边框
context.lineWidth = 5;
context.lineJoin = "round";
context.strokeStyle = "#333";
context.stroke();
下面绘制中心的感叹号,在前面的draw()函数的最后添加如下代码。
context.textAlign = "center";
context.textBaseline = "middle";
context.font = "bold 60px 'Times New Roman', Times, serif";
context.fillStyle = "#333";
context.fillText("!", padding + width/2, padding + height/1.5);
最后效果:
完整代码。
Test