参考资料
前言
本人菜鸟,入IT只为当鼓励师。本编文章旨在总结《Javascript高级层序设计(第3版)》一书中第15章canvas的一些api。第(一)篇只总结2D上下文。
一、<canvan>元素
出处:HTML5。
用途:设定一个区域,通过JS动态地在区域上绘制图形。
组成:由几组API构成,可分为 2D上下文(基本绘图能力) 和 3D上下文(WebGL)。
兼容性:
- 浏览器:IE9+、Firefox1.5+、Safari2+、Opera9+、Chrome、IOS版Safari、Android版WebKit。
- 操作系统:Windows XP因缺少必要的绘图程序,不管用什么浏览器都不支持。
二、基本用法
1. 建立区域
要使用<canvas>元素,必须设置width和height属性,指定可以绘图的区域大小。设置完后,如果浏览器兼容<canvas>标签,则建立的区域应是空白的;否则,会显示其中的文本:A drawing of something。
<canvas id="drawing" width="200" height="200">A drawing of something</canvas>
2. 取得绘图上下文(<canvas>元素的DOM对象)
要在这块画布上绘图,需要取得绘图上下文。绘图上下文也就是取得相应<canvas>元素的DOM对象。
// 取得DOM对象,也为canvas对象
var drawing = document.getElementById("drawing");
3. 取得2D上下文对象 getContext("2d")
只取得DOM对象还不行,还要调用<canvas>DOM对象拥有的 getContext(param)
方法。其中传入参数为一个字符串,因为本篇文章总结的是2D上下文(平面),故传入"2d",获得2D上下文对象。后面一切关于绘图的方法和属性,其实都是围绕着2D上下文对象开展的,也就是代码示例中的context。
method | param | return |
---|---|---|
getContext(param) | 上下文对象的类型,有如下选择:</br>"2d"(2d上下文)</br>"3d"(3d上下文) | 上下文对象 |
在调用该方法之前,为了保证程序的健壮性,最好加入检测代码。
// 确定浏览器支持<canvas>元素
if(drawing.getContext) {
// 取得2D上下文对象
var context = drawing.getContext("2d");
// 更多代码
}
4. 导出在<canvas>元素上绘制的图像
当在<canvas>元素上绘制完图像后,可以调用DOM对象的 toDataURL(param)
方法,将该图像导出成为一张图片,传入参数为欲导出图片的MIME类型,例如:image/png
、image/jpeg
等等。拥有该方法的对象是<canvas>元素的DOM对象,并不是2d上下文对象context,两者要区分开来。
method | param | return | compatibility |
---|---|---|---|
toDataURL(param) | 图像的MIME类型格式,有如下选择:</br>"image/jpeg"(Firefox和Opera默认)</br>"image/png"(其他默认) | 图像的数据URI | IE9+、Firefox3.5+ 、Opera10 |
var drawing = document.getElementById("drawing");
// 确定浏览器支持<canvas>元素
if(drawing.getContext) {
// 取得图像的数据URI
var imgURI = drawing.toDataURI("image/png");
// 显示图像
var image = document.createElement("img");
image.src = imgURI;
document.body.appendChild(image);
}
三、2D上下文 context
(0, 0)为<canvas>元素所占区域的原点坐标,x向右递增,y向下递增
1. 填充和描边
attribute | value | effect |
---|---|---|
fillStyle | String类型:颜色名、十六进制码、rgb等,如"#0000ff" | 设置填充颜色 |
strokeStyle | String类型:颜色名、十六进制码、rgb等,如"red" | 设置描边颜色 |
var drawing = document.getElementById("drawing");
// 确定浏览器支持<canvas>元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
// 以红色描边
context.strokeStyle = "red";
// 以蓝色填充
context.fillStyle = "#0000ff";
// 绘制描边矩形
context.strokeRect(10, 10, 50, 50);
// 绘制填充矩形 context.fillRect
(65, 10, 50, 50);
}
2. 绘制矩形
2.1 填充矩形
method | param | effect |
---|---|---|
fillRect(param1,param2, param3,param4) | param1:矩形的x坐标</br>param2:矩形的y坐标</br>param3:矩形的宽度</br>param4:矩形的高度 | 绘制填充矩形,默认为黑色,可给fillStyle赋值改变其填充颜色 |
// 填充
var drawing = document.getElementById("drawing");
// 确定浏览器支持<canvas>元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
// 以红色填充
context.fillStyle = "#ff0000";
// 绘制填充矩形
context.fillRect(10, 10, 50, 50);
// 以半透明的蓝色填充
context.fillStyle = "rgba(0, 0, 255, 0.5)";
// 绘制填充矩形
context.fillRect(30, 30, 50, 50);
}
2.2 描边矩形
method | param | effect |
---|---|---|
strokeRect(param1, param2, param3, param4) | param1:矩形的x坐标</br>param2:矩形的y坐标</br>param3:矩形的宽度</br>param4:矩形的高度 | 绘制描边矩形,默认为黑色,可给strokeStyle赋值改变其边框颜色 |
// 描边
var drawing = document.getElementById("drawing");
// 确定浏览器支持<canvas>元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
// 以红色描边
context.strokeStyle = "#ff0000";
// 绘制描边矩形
context.strokeRect(10, 10, 50, 50);
// 以蓝色描边
context.strokeStyle = "rgba(0, 0, 255, 0.5)";
// 绘制描边矩形 context.strokeRect(30, 30, 50, 50);
}
2.3 清除矩形
method | param | effect |
---|---|---|
clearRect(param1, param2, param3, param4) | param1:矩形的x坐标</br>param2:矩形的y坐标</br>param3:矩形的宽度</br>param4:矩形的高度 | 清除一块矩形区域 |
// 清除矩形区域
var drawing = document.getElementById("drawing");
// 确定浏览器支持<canvas>元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
// 绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
// 绘制半透明的蓝色矩形
context.fillStyle = "rgba(0, 0, 255, 0.5)";
context.fillRect(30, 30, 50, 50);
// 在两个矩形重叠的地方清楚一个小矩形
context.clearRect(40, 40, 10, 10);
}
3. 绘制路径
3.1 创建路径
method | param | effect |
---|---|---|
arc(x,y,radius,startAngle,counterclockwise) | (x, y):圆心的坐标</br>radius:弧线半径</br>startAngle:起始角度</br>endAngle:结束角度</br>counterclockwise:角度的方向(true:逆时针方向,false:顺时针方向 | 给定圆心(x,y)和半径radius、起始和结束的角度、方向,绘制一条弧线 |
arcTo(x1,y1,x2,y2,radius) | (x1, y1):需穿过的点的坐标</br>(x2, y2):终点坐标</br>radius:以给定的半径穿过(x1, y1) | 从上一点绘制一条弧线,到(x2,y2)为止,并且以给定的半径穿过(x1, y1) |
bezierCurveTo(c1x,c1y,c2x,c2y,x,y) | (c1x,c1y):控制点</br>(c2x,c2y):另一个控制点</br>(x, y):终点坐标 | 从上一点绘制一条弧线,到(x,y)为止,并且以(c1x,c1y)和(c2x,c2y)为控制点 |
lineTo(x,y) | (x,y):终点坐标 | 从上一点开始绘制一条直线,到(x,y)为止 |
moveTo(x,y) | (x,y):绘图游标移动到的点的坐标 | 将绘图游标移动到(x,y),不画线 |
quadraticCurveTo(cx,cy,x,y) | (cx,cy):控制点</br>(x,y):终点坐标 | 从上一点开始绘制一条二次曲线,到(x,y)为止,并且以(cx,cy)为控制点 |
rect(x,y,width,height) | (x,y):起点坐标</br>width:矩形的宽</br>height:矩形的高 | 从点(x,y)开始绘制一个矩形,宽高分别为width和height。这个方法绘制的是矩形路径,而不是strokeRect()和fillRect()所绘制的独立形状 |
3.2 处理路径
method | param | effect |
---|---|---|
beginPath() | null | 开始创建路径 |
closePath() | null | 关闭路径,回到起点 |
fill() | null | 用fillStyle来填充路径 |
stroke() | null | 用strokeStyle来对路径描边 |
clip() | null | 在路径上创建一个剪切区域 |
3.2.1 用上面某些方法描绘一个时钟
var drawing = document.getElementById("drawing");
// 确定浏览器支持<canvas>元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
// 开始路径
context.beginPath();
// 绘制外圆
context.arc(100, 100, 99, 0, 2*Math.PI, false);
// 绘制内圆
context.moveTo(194, 100);
context.arc(100, 100, 94, 0, 2*Math.PI, false);
// 绘制分针
context.moveTo(100, 100);
context.lineTo(100, 15);
// 绘制时针
context.moveTo(100, 100);
context.lineTo(35, 100);
// 为路径描边
context.stroke();
}
3.2.2 用fill()方法填充路径
var drawing = document.getElementById("drawing");
// 确定浏览器支持<canvas>元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
// 开始路径
context.beginPath();
// 绘制圆
context.arc(100, 100, 99, 0, 2*Math.PI, false);
// 填充路径
context.fill();
}
3.2.3 当路径不闭合时fill()方法无效
var drawing = document.getElementById("drawing");
// 确定浏览器支持<canvas>元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
// 绘制一条对角线
context.moveTo(0, 0);
context.lineTo(200, 200);
// 填充路径
context.fill();
}
3.3 判断路径点
method | param | effect |
---|---|---|
isPointInPath(x,y) | (x,y):某一任意点的坐标 | 在路径被关闭前确定判断画布上的点(x,y)是否在路径上 |
4. 绘制文本
4.1 2d上下文的文本属性
attribute | value | effect |
---|---|---|
font | String类型,如"bold 14px Arial" | 字体粗细、大小和样式 |
textAlign | String类型,有如下选择:</br>"start"(x坐标表示文本左端),"center"(正中),"end"(右端) | 文本的水平对齐方式 |
textBaseline | String类型,有如下选择:</br>"top"(y坐标表示文本顶端),"middle"(正中),"bottom"(底端),"hanging"、"alphabetic"、"ideographic"(y坐标指向特定基线坐标) | 文本的垂直对齐方式 |
其实,fillText()和strokeText()方法都可以接受第四个参数,表示文本的最大像素宽度,如果传入字符串大于最大宽度,会收缩以适应最大宽度。但这个可选参数尚未得到大多数浏览器的支持。
4.2 用fillText()绘制数字12
method | param | effect |
---|---|---|
fillText(string,x,y) | string:要绘制的文本字符串</br>x:x坐标可选的最大像素宽度</br>y:y坐标可选的最大像素宽度 | 使用fillStyle属性绘制文本 |
strokeText(string,x,y) | string:要绘制的文本字符串</br>x:x坐标可选的最大像素宽度</br>y:y坐标可选的最大像素宽度 | 使用strokeStyle属性为文本描边 |
var drawing = document.getElementById("drawing");
// 确定浏览器支持<canvas>元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
// 开始路径
context.beginPath();
// 绘制外圆
context.arc(100, 100, 99, 0, 2*Math.PI, false);
// 绘制内圆
context.moveTo(194, 100);
context.arc(100, 100, 94, 0, 2*Math.PI, false);
// 绘制分针
context.moveTo(100, 100);
context.lineTo(100, 15);
// 绘制时针
context.moveTo(100, 100);
context.lineTo(35, 100);
// 为路径描边
context.stroke();
// 绘制数字12
context.font = "bold 14px Arial";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("12", 100, 20);
}
</br>
4.3 给定宽度的区域,找到文本合适的字体大小
method | param | return | effect |
---|---|---|---|
mearsureText(string) | string类型:要确定大小的文本字符串 | object:返回一个对象,该对象只有一个width属性 | 获得存有文本大小的对象 |
var fontSize = 100,
context.font = fontSize + "px Arial";
if (context.measureText) {
while(context.measureText("Hello world!").width > 140) {
fontSize--;
context.font = fontSize + "px Arial";
}
}
context.fillText("Hello world!", 10, 10);
context.fillText("Font size is " + fontSize + "px", 10, 50);
上面的代码从100像素的字体大小开始递减,最终会找到合适的字体大小,在一个140像素的矩形区域中绘制文本 Hello world!
5. 变换
5.1 用translate()方法变换原点位置
var drawing = document.getElementById("drawing");
// 确定浏览器支持<canvas>元素
if (drawing.getContext) {
var context = drawing.getContext("2d");
// 开始路径
context.beginPath();
// 绘制外圆
context.arc(100, 100, 99, 0, 2 * Math.PI, false);
// 绘制内圆
context.moveTo(194, 100);
context.arc(100, 100, 94, 0, 2 * Math.PI, false);
// 变换原点
context.translate(100, 100);
// 绘制分针
context.moveTo(0,0);
context.lineTo(0, -85);
// 绘制时针
context.moveTo(0, 0);
context.lineTo(-65, 0);
// 绘制路径
context.stroke();
}
可以看出结果与3.2.1的图形相同,但把原点变换到时钟表盘中心点(100, 100)后,在同一方向上绘制线条的数学计算就变得简单起来了。
5.2 用rotate()方法旋转表针
var drawing = document.getElementById("drawing");
// 确定浏览器支持<canvas>元素
if (drawing.getContext) {
var context = drawing.getContext("2d");
// 开始路径
context.beginPath();
// 绘制外圆
context.arc(100, 100, 99, 0, 2 * Math.PI, false);
// 绘制内圆
context.moveTo(194, 100);
context.arc(100, 100, 94, 0, 2 * Math.PI, false);
// 变换原点
context.translate(100, 100);
// 绘制分针
context.moveTo(0,0);
context.lineTo(0, -85);
// 绘制时针
context.moveTo(0, 0);
context.lineTo(-65, 0);
// 旋转表针,旋转弧度值为1,2π对应360°,则1对应(360/2π)°,约为57.30°
context.rotate(1);
// 绘制路径
context.stroke();
}
图中红色的部分不存在,是我做给大家的提示和比较而已,用来指明不加最后一句代码的指针原来的位置。
5.3 跟踪上下文的状态变化
栈:先进后出。
method | param | effect |
---|---|---|
save() | null | 当下所有设置都会进入一个栈结构 |
restore() | null | 在保存设置的栈结构中向前返回一级 |
var drawing = document.getElementById("drawing");
// 确定浏览器支持<canvas>元素
if (drawing.getContext) {
var context = drawing.getContext("2d");
context.fillStyle = "#ff0000";
context.save();
context.fillStyle = "#00ff00";
context.translate(100, 100);
context.save();
context.fillStyle = "#0000ff";
//从点(100,100)开始绘制蓝色矩形
context.fillRect(0,0,100,200);
context.restore();
//从点(110,110)开始绘制绿色矩形
context.fillRect(10,10,100,200);
context.restore();
//从点(0, 0)开始绘制红色矩形
context.fillRect(0,0,100,200);
}
6. 绘制图像
把一幅图像绘制到画布上,可以使用drawImage()方法。
method | param | effect |
---|---|---|
drawImage(image,</br>tx,ty) | image:要绘制的图像</br>tx:目标图像的x坐标</br>ty:目标图像的y坐标 | 把图像绘制到画布上,起点坐标为(tx,ty) |
drawImage(image,</br>tx,ty,twidth,theight) | image:要绘制的图像</br>tx:目标图像的x坐标</br>ty:目标图像的y坐标</br>twidth:目标图像的宽度</br>theight:目标图像的高度 | 把图像绘制到画布上,起点坐标为(tx,ty),绘制到画布上的图像的宽度为twidth,高度为theight |
drawImage(image,</br>sx,sy,swidth,sheight,</br>tx,ty,twidth,theight) | image:要绘制的图像</br>sx:源图像的x坐标</br>sy:源图像的y坐标</br>swidth:源图像的宽度</br>sheight:源图像的高度</br>tx:目标图像的x坐标</br>ty:目标图像的y坐标</br>twidth:目标图像的宽度</br>theight:目标图像的高度 | 先对源图像做一些处理,该处理为:以(sx,sy)为起点截取宽度为swidth,高度为sheight的新图像。处理后再把新图像绘制到画布上,起点坐标为(tx,ty),绘制到画布上的新图像的宽度为twidth,高度为theight |
7. 阴影
attribute | value | effect |
---|---|---|
shadowColor | String类型:颜色名、十六进制码、rgb等,如"#0000ff",默认为黑色 | 用CSS颜色格式表示的阴影颜色 |
shadowOffsetX | Number类型,默认为0 | 形状或路径x轴方向的阴影偏移量 |
shadowOffsetY | Number类型,默认为0 | 形状或路径y轴方向的阴影偏移量 |
shadowBlur | Number类型,默认为0,即不模糊 | 模糊的像素数 |
8. 渐变
method | param | return |
---|---|---|
createLinearGradient | 起点的x坐标</br>起点的y坐标</br>终点的x坐标</br>终点的y坐标 | 返回CanvasGradient对象的实例 |