38-JavaScript高级程序设计-canvas

使用 canvas 绘图

HTML5 添加 <canvas>元素,该元素负责在页面中设定一个区域,然后就可以通过 JavaScript 动态地在这个区域中绘制图形。
浏览器支持:IE9+、Firefox 1.5+、Safari 2+、Opera 9+、Chrome、iOS 版 Safari 以及 Android 版 WebKit 都在某种程度上支持。

一、基本用法

要使用<canvas>元素,必须先设置其 width 和 height 属性,指定可以绘图的区域大小。
出现在开始和结束标签中的内容是后备信息,如果浏览器不支持<canvas>元素,就会显示这些信息。
<canvas id="drawing" width=" 200" height="200">A drawing of something.</canvas>

要在这块画布(canvas)上绘图,需要取得绘图上下文。
getContext():取得绘图上下文对象的引用,传入上下文的名字,如传入"2d",就可以取得 2D 上下文对象。
注意:在使用<canvas>元素之前,首先要检测 getContext()方法是否存在。

toDataURL():导出在<canvas>元素上绘制的图像。
一个参数:图像的 MIME 类型格式,而且适合用于创建图像的任何上下文。
默认情况下,浏览器会将图像编码为 PNG 格式(除非另行指定)。
注意:如果绘制到画布上的图像源自不同的域,toDataURL()方法会抛出错误。

二、2D 上下文

2D 上下文的坐标开始于<canvas>元素的左上角,原点坐标是(0,0)。

1. 填充和描边

2D 上下文的两种基本绘图操作是填充和描边。
填充:用指定的样式(颜色、渐变或图像)填充图形;描边:只在图形的边缘画线。
fillStylestrokeStyle:属性值可以是字符串、渐变对象或模式对象,默认值"#000000"。

2. 绘制矩形

3个方法:fillRect()、strokeRect()、clearRect()。
4 个参数:矩形的 x 坐标,矩形的 y 坐标,矩形宽度,矩形高度。(单位像素)

fillRect():在画布上绘制的矩形会填充指定的颜色,颜色 fillStyle 指定。

//绘制红色矩形
context.fillStyle = "#ff0000"; 
context.fillRect(10, 10, 50, 50);

strokeRect():在画布上绘制的矩形会使用指定的颜色描边。颜色 strokeStyle 指定。
lineWidth 属性控制描边线条的宽度,值可以是任意整数。
lineCap 属性控制线条末端的形状是平头、圆头还是方头(“butt”、“round"或"square”)。
lineJoin 属性控制线条相交的方式是圆交、斜交还是斜接(“round”、“bevel"或"miter”)。

//绘制红色描边矩形
context.strokeStyle = "#ff0000"; 
context.strokeRect(10, 10, 50, 50);

clearRect():用于清除画布上的矩形区域。

//绘制红色矩形
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. 绘制路径

绘制路径,首先必须调用 beginPath() 方法,表示要开始绘制新路径。

绘制路径方法:
arc(x, y, radius, startAngle, endAngle, counterclockwise):以(x,y)为圆心绘制一条弧线,弧线半径为 radius,起始和结束角度(用弧度表示)分别为 startAngle 和 endAngle。最后一个参数表示 startAngle 和 endAngle 是否按逆时针方向计算,值为 false 表示按顺时针方向计算。
arcTo(x1, y1, x2, y2, radius):从上一点开始绘制一条弧线,到(x2,y2)为止,并且以给定的半径 radius 穿过(x1,y1)。
bezierCurveTo(c1x, c1y, c2x, c2y, x, y):从上一点开始绘制一条曲线,到(x,y)为止,并且以(c1x,c1y)和(c2x,c2y)为控制点。
lineTo(x, y):从上一点开始绘制一条直线,到(x,y)为止。
moveTo(x, y):将绘图游标移动到(x,y),不画线。
quadraticCurveTo(cx, cy, x, y):从上一点开始绘制一条二次曲线,到(x,y)为止,并且以(cx,cy)作为控制点。
rect(x, y, width, height):从点(x,y)开始绘制一个矩形,宽度和高度分别由 width 和 height 指定。这个方法绘制的是矩形路径,而不是 strokeRect()和 fillRect()所绘制的独立的形状。

绘制路径之后操作:
可以调用 closePath(),绘制一条连接到路径起点的线条。
可以调用 fill(),在路径已经完成时对路径填充,用 fillStyle 填充。
可以调用 stroke(),对路径描边,描边使用的是 strokeStyle。
可以调用 clip(),在路径上创建一个剪切区域。

举例:绘制一个不带数字的时钟表盘

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();
}

isPointInPath(x, y):在路径被关闭之前确定画布上的某一点是否位于路径上。

if (context.isPointInPath(100, 100)){
  alert("Point (100, 100) is in the path.");
}
4. 绘制文本

绘制文本方法:fillText()strokeText()
4个参数:要绘制的文本字符串,x 坐 标,y 坐标,可选的最大像素宽度。
fillText()方法使用 fillStyle 属性绘制文本,strokeText()方法使用 strokeStyle 属性为文本描边。
第4个参数最大像素宽度,如果传入的字符串大于最大宽度,绘制的文本字符的高度正确,但宽度会收缩以适应最大宽度。

绘制文本前可设置3个属性(有默认值,可不设置):
font:表示文本样式、大小及字体,用 CSS 中指定字体的格式来指定,例如"10px Arial"。
textAlign:表示文本对齐方式。可能的值有"start"、“end”、“left”、“right"和"center”。(不建议使用"left"和"right")
textBaseline:表示文本的基线。可能的值有"top"、“hanging”、“middle”、“alphabetic”、“ideographic"和"bottom”。

context.font = "bold 14px Arial";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("12", 100, 20);

measureText():辅助确定文本大小。
一个参数:要绘制的文本;返回值:一个 TextMetrics 对象,对象目前只有一个 width 属性。
该方法是利用 font、textAlign 和 textBaseline 的当前值计算指定文本的大小。

5. 变换

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):直接修改变换矩阵,方式是乘以特定矩阵。(详见P453)
setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy):将变换矩阵重置为默认状态,然后再调用 transform()。

跟踪上下文的状态变化:save()restore()
调用 save(),当时的所有设置(某组属性与变换的组合)都会进入一个栈结构,得以妥善保管。然后可以对上下文进行其他修改。
调用 restore(),可以在保存设置的栈结构中向前返回一级,恢复之前的状态。
注意1:连续调用 save() 可以把更多设置保存到栈结构中,之后再连续调用 restore() 则可以一级一级返回。
注意2:save()方法保存的只是对绘图上下文的设置和变换,不会保存绘图上下文的内容。

6. 绘制图像

drawImage():将图像绘制到画布上。
参数组合1:3个,绘制图像( <img>元素/另一个<canvas>元素),以及绘制该图像的起点的 x 和 y 坐标。
参数组合2:5个,前三个同上,加上目标宽度和目标高度。
参数组合3:9个,要绘制的图像、源图像的 x 坐标、源图像的 y 坐标、源图像的宽度、源图像的高度、目标图像的 x 坐标、目标图像的 y 坐标、目标图像的宽度、目标图像的高度。

// 绘制到画布上的图像大小与原始大小一样
var image = document.images[0];
context.drawImage(image, 10, 10);
// 改变绘制后图像的大小
context.drawImage(image, 50, 10, 20, 30);
// 可以选择把图像中的某个区域绘制到上下文中
context.drawImage(image, 0, 10, 50, 50, 0, 100, 40, 60);
7. 阴影

2D 上下文会根据以下几个属性的值,自动为形状或路径绘制出阴影。
shadowColor:用 CSS 颜色格式表示的阴影颜色,默认为黑色。
shadowOffsetX:形状或路径 x 轴方向的阴影偏移量,默认为 0。
shadowOffsetY:形状或路径 y 轴方向的阴影偏移量,默认为 0。
shadowBlur:模糊的像素数,默认 0,即不模糊。

var context = drawing.getContext("2d");
//设置阴影
context.shadowOffsetX = 5; 
context.shadowOffsetY = 5;
context.shadowBlur = 4; 
context.shadowColor = "rgba(0, 0, 0, 0.5)";
//绘制红色矩形
context.fillStyle = "#ff0000"; 
context.fillRect(10, 10, 50, 50);

不同浏览器对阴影的支持有一些差异。

8. 渐变

createLinearGradient():创建一个新的线性渐变
4个参数:起点的 x 坐标、起点的 y 坐标、终点的 x 坐标、终点的 y 坐标。
调用这个方法后,会创建一个指定大小的渐变,并返回 CanvasGradient 对象的实例。

addColorStop():创建了渐变对象后,下一步使用该方法来指定色标。
2个参数:色标位置和 CSS 颜色值。色标位置是一个 0(开始的颜色)到 1(结束的颜色)之间的数字。

var gradient = context.createLinearGradient(30, 30, 70, 70);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");
//绘制渐变矩形
context.fillStyle = gradient; 
context.fillRect(30, 30, 50, 50);

为了让渐变覆盖整个矩形,而不是仅应用到矩形的一部分,矩形和渐变对象的坐标必须匹配才行。如 context.createLinearGradient(x, y, x+width, y+height);

createRadialGradient():创建径向渐变(或放射渐变)
6个参数:前三个参数指定的是起点圆的原心(x 和 y)及半径,后三个参数指定的是终点圆的原心(x 和 y)及半径。
一般情况下,将两个圆定义为同心圆,给两个圆设置不同的半径,达到从某个形状的中心点开始创建一个向外扩散的径向渐变效果。

9. 模式

模式其实就是重复的图像,可以用来填充或描边图形。
createPattern():创建一个新模式
两个参数:一个 HTML <img>元素和一个表示如何重复图像的字符串。
第一个参数也可以是一个<video>元素,或者另一个<canvas>元素。
第二个参数可选值:包括"repeat"、“repeat-x”、 “repeat-y"和"no-repeat”。

var image = document.images[0],
pattern = context.createPattern(image, "repeat");
//绘制矩形
context.fillStyle = pattern; 
context.fillRect(10, 10, 150, 150);

注意:模式与渐变一样,都是从画布的原点(0,0)开始的。将填充样式fillStyle设置为模式对象,只表示在某个特定的区域内显示重复的图像,而不是要从某个位置开始绘制重复的图像。

10. 使用图像数据

getImageData():取得原始图像数据。
4个参数:要取得其数据的画面区域的 x 和 y 坐标,以及该区域的像素宽度和高度。
返回值:一个 ImageData 的实例对象,有三个属性 width、height 和 data。data 是一个数组,保存着图像中每一个像素的数据,每一个像素用 4 个元素来保存,分别表示红、绿、蓝和透明度值。

putImageData():把图像数据绘制到画布上。

//取得图像数据
imageData = context.getImageData(0, 0, image.width, image.height); 
data = imageData.data;
// 。。。中间可以遍历图像数据的每一个像素,进行一些颜色的操作,例如灰阶过滤器。
//回写图像数据并显示结果
imageData.data = data; 
context.putImageData(imageData, 0, 0);
11. 合成

应用到 2D 上下文中所有绘制操作的属性:globalAlpha 和 globalCompositionOperation。
globalAlpha:一个介于 0 和 1 之间的值,用于指定所有绘制的透明度。默认值为 0。
globalCompositionOperation:表示后绘制的图形怎样与先绘制的图形结合。可选值:source-over(默认值)、source-in、source-out、source-atop、destination-over、destination-in、destination-out、destination-atop、lighter、copy、xor。
不同浏览器对这个属性的实现仍然存在较大的差别。

三、WebGL

WebGL 是针对 Canvas 的 3D 上下文。
WebGL 并不是 W3C 制定的标准,而是由 Khronos Group 制定的。
全面学习 WebGL,请参考 www.learningwebgl.com。

WebGL 支持比 2D 上下文更丰富和更强大的图形图像处理能力,比如:
用 GLSL(OpenGL Shading Language,OpenGL 着色语言)编写的顶点和片段着色器;
支持类型化数组,即能够将数组中的数据限定为某种特定的数值类型;
创建和操作纹理。

由于使用不多,有兴趣的自行学习:P463-P478。

支持:
浏览器实现:Firefox 4+、Chrome、Safari 5.1(默认禁用)。
WebGL 比较特别的地方在于,某个浏览器的某个版本实现了它,并不一定意味着就真能使用它。
某个浏览器支持 WebGL,至少意味着两件事:首先,浏览器本身必须实现了 WebGL API;其次,计算机必须升级显示驱动程序。
从稳妥的角度考虑,在使用 WebGL 之前,最好检测其是否得到了支持,而不是只检测特定的浏览器版本。
WebGL 还是一个正在制定和发展中的规范。不管是函数名、函数签名,还是数据类型,都有可能改变。
结论:WebGL 目前只适合实验性地学习,不适合真正开发和应用。


上一篇:37-JavaScript高级程序设计-表单序列化和富文本编辑
下一篇:39-JavaScript高级程序设计-HTML5 脚本编程

全书整理版:《Javascript高级程序设计》第3版(总结版)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值