HTML5简单入门系列(七)
前言
本篇详细介绍canvas画布的API。说是详细介绍,也只是一些常用的API及简单实例和说明。LZ本人也还没有看完全部,下篇会介绍剩余的一些内容。
本篇的示例中,LZ加入了注释,为的是只简单介绍API确实挺无聊,也不那么容易理解,看代码看效果才最直接。
canvas APIs
canvas 基础api 介绍
在初始化Javascript函数中,用canvas标签的id获得canvas的DOM对象,并用getContext() 方法获得这个canvas的“2d”上下文对象,之后使用上下文对象调用canvas API 画图。
直线
画直线的功能可以用 beginPath(), moveTo(), lineTo() 和 stroke() 几个方法的组合来实现。
方法 beginPath() 定义了一个新的路径绘制动作的开始。
方法 moveTo() 为指定点创建了一个新的子路径,我们可以把
moveTo() 方法看成用来定位绘图鼠标用的(直线的起点,因为所有画线都和它相关,我们称之为上下文点)。
方法 lineTo() 从鼠标定位点,到方法参数中指定的点之间画一条直线。
方法 stroke() 为所画的线赋予颜色,并使其可见。如果没有特别的指定颜色的话,则默认使用黑色画直线。
上下文对象context的属性
context.lineWidth = 5; //设置宽度
context.strokeStyle = 'blue'; //设置颜色
context.lineCap = 'round'; //设置直线终点样式,可选值butt(默认值),round,和square。
示例如下
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>直线</title> <script> window.onload = function () { var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); // 最上面的线是butt样式 context.beginPath(); context.moveTo(200, canvas.height / 2 - 50); context.lineTo(canvas.width - 200, canvas.height / 2 - 50); context.lineWidth = 10; context.strokeStyle = "#ff0000"; context.lineCap = "butt"; context.stroke(); // 中间的线是round样式 context.beginPath(); context.moveTo(200, canvas.height / 2); context.lineTo(canvas.width - 200, canvas.height / 2); context.lineWidth = 15; context.strokeStyle = "#00ff00"; context.lineCap = "round"; context.stroke(); // 最下面的是square样式 context.beginPath(); context.moveTo(200, canvas.height / 2 + 50); context.lineTo(canvas.width - 200, canvas.height / 2 + 50); context.lineWidth = 20; context.strokeStyle = "#0000ff"; context.lineCap = "square"; context.stroke(); }; </script> </head> <body> <canvas id="myCanvas" width="578" height="200"></canvas> </body> </html>
效果如图:
弧线
画弧线的方法是 arc()。每条弧线都需要由中心点、半径、起始角度(弧度n*Math.PI)、结束角度(弧度m*Math.PI)和绘图方向(顺时针 false 还是逆时针true)这几个参数来确定。如context.arc(x, y, radius, startAngle, endAngle, antiClockwise);
二次曲线
二次曲线使用quadraticCurveTo()方法来绘制。每条二次曲线要由上下文点、一个控制点和一个终止点来定义。
context.quadraticCurveTo(controlX, controlY, endX, endY);
贝塞尔曲线
绘制贝塞尔曲线使用方法bezierCurveTo() 。每条贝塞尔曲线需要由上下文点、两个控制点和一个终止点来确定。如:
context.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, endX, endY);
圆角
画圆角使用方法 arcTo() 。此方法需要一个控制点、一个终止点和半径作为必要的参数。如:
context.arcTo(controlX,controlY,endX,endY,radius);
画路径
路径是由多条子路径连接构成的。每条子路径的终止点就将作为新的上下文点。我们可以使用lineTo(), arcTo(), quadraticCurveTo() 和 bezierCurveTo() 创建新的子路径。每次要开始画一条路径的时候就要使用 beginPath() 方法。
canvas支持3种线条的连接样式,包括: miter, round, 和 bevel。 设定连接样式是用 lineJoin 属性设定。缺省情况下,将使用 miter 样式。
上边几个的代码示例如下:
1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <title></title> 6 <script> 7 window.onload = function () { 8 ords(); 9 arc(); 10 //quadratic(); 11 //bezier(); 12 //arcTo(); 13 //path(); 14 }; 15 //弧线 16 function arc() { 17 var canvas = document.getElementById("myCanvas"); 18 var context = canvas.getContext("2d"); 19 var x = canvas.width / 2, y = canvas.height / 2;//圆心坐标 20 var radius = 75; //半径 21 var startAngle = 0.5 * Math.PI, //开始弧度 22 endAngle = 2 * Math.PI, //结束弧度 23 counterClockwise = false; //画图方向,false-顺时针,true-逆时针,注意对绘画效果的影响!! 24 context.beginPath(); 25 context.arc(x, y, radius, startAngle, endAngle, counterClockwise); 26 //context.lineWidth = 15; 27 //context.strokeStyle = "black"; 28 //context.stroke(); 29 context.fillStyle = "blue"; 30 context.fill(); 31 } 32 //二次曲线 33 function quadratic() { 34 var canvas = document.getElementById("myCanvas"); 35 var context = canvas.getContext("2d"); 36 37 context.beginPath(); 38 context.moveTo(188, 150);//起始点 39 context.quadraticCurveTo(328, 50, 388, 150);//控制点和结束点 40 context.lineWidth = 10; 41 context.strokeStyle = "black"; 42 context.stroke(); 43 } 44 //贝赛尔曲线 45 function bezier() { 46 var canvas = document.getElementById("myCanvas"); 47 var context = canvas.getContext("2d"); 48 context.beginPath(); 49 context.moveTo(188, 130); 50 context.bezierCurveTo(80, 10, 188, 10, 388, 170);//控制点1,控制点2和结束点 51 context.lineWidth = 10; 52 context.strokeStyle = "black"; 53 context.stroke(); 54 } 55 //圆角 56 function arcTo() { 57 var canvas = document.getElementById("myCanvas"); 58 var context = canvas.getContext("2d"); 59 var rectWidth = 200,//矩形框宽度 60 rectHeight = 100,//高度 61 rectX = 189,//起点 62 rectY = 50, 63 cornerRadius = 50;//圆角半径 64 context.beginPath(); 65 context.moveTo(rectX, rectY); 66 context.lineTo(rectX + rectWidth - cornerRadius, rectY);//直线坐标点,x坐标减去圆角半径 67 context.arcTo(rectX + rectWidth, rectY, rectX + rectWidth, rectY + cornerRadius, cornerRadius);//圆角起始点坐标和半径 68 context.lineTo(rectX + rectWidth, rectY + rectHeight);//此时起点y坐标是圆角结束点rectY + cornerRadius 69 context.lineWidth = 5; 70 context.stroke(); 71 } 72 //路径 73 function path() { 74 var canvas = document.getElementById("myCanvas"); 75 var context = canvas.getContext("2d"); 76 77 context.beginPath(); 78 context.lineJoin = "round";//线间链接样式:可选值miter(默认), round, 和 bevel。 79 context.moveTo(100, 20); 80 context.lineTo(220, 60); 81 // 第一条直线 82 context.lineTo(200, 160); 83 // 二次曲线 84 context.quadraticCurveTo(230, 200, 250, 120); 85 // 贝塞尔曲线 86 context.bezierCurveTo(290, -40, 300, 200, 400, 150); 87 // 第二条直线 88 context.lineTo(500, 90); 89 context.lineWidth = 15; 90 context.strokeStyle = "blue"; 91 context.closePath(); 92 context.stroke(); 93 94 } 95 //坐标系 96 function ords() { 97 for (var i = 0; i < 50; i++) { 98 drawDirectedLine(i * 20, 0, false);//纵向,只关心横坐标 99 drawDirectedLine(0, i * 20, true);//横向,只关心纵坐标 100 } 101 } 102 //起点坐标,直线方向:true-横向,false-纵向 103 function drawDirectedLine(x1, y1, d) { 104 var canvas = document.getElementById("myCanvas"); 105 var context = canvas.getContext("2d"); 106 context.beginPath(); 107 context.strokeStyle = "#ff3333"; 108 if (d) { 109 context.moveTo(0, y1); 110 context.lineTo(1000, y1); 111 } 112 else { 113 context.moveTo(x1, 0); 114 context.lineTo(x1, 1000); 115 } 116 context.stroke(); 117 } 118 </script> 119 </head> 120 <body> 121 <canvas id="myCanvas" width="578" height="250"></canvas> 122 </body> 123 </html>
线性渐变
要使用线性渐变效果填充图形,首先要使用 createLinearGradient() 方法从上下文对象中创建线性渐变对象。
createLinearGradient() 方法的四个参数确定一条虚拟线段,渐变就沿着此条线段的方向。
然后用 addColorStop 方法为线性渐变对象设置渐变线上的关键点的颜色,offset 表示关键点是在渐变虚拟线段的什么位置, offset 的取值范围是0到1,其中0表示是起始点,1表示是终止点,0到1之间的值表示是此虚拟线段中间的某一位置。
再将此线性渐变对象作为填充类型赋值给上下文对象的 fillStyle 属性。canvas将根据渐变虚拟线段上关键点的颜色变化填充图形。
示例代码:
1 function linear() { 2 var canvas = document.getElementById("myCanvas"); 3 var context = canvas.getContext("2d"); 4 5 var grd = context.createLinearGradient(0, 0, 450, 400);//渐变路径从(0,0) 到(450,300) 6 7 8 grd.addColorStop(0, "#000000"); 9 grd.addColorStop(0.5, "#ff0000"); 10 grd.addColorStop(1, "#ffffff"); 11 12 ////查看渐变效果。 13 //context.beginPath(); 14 //context.fillStyle = grd; 15 //context.fillRect(0, 0, 450, 400); 16 17 context.beginPath(); 18 context.moveTo(170, 80);//起点 19 context.bezierCurveTo(130, 100, 130, 150, 230, 150);//两个控制点,一个终结点(下一个路径的起点) 20 context.bezierCurveTo(250, 180, 320, 180, 340, 150); 21 context.bezierCurveTo(420, 150, 420, 120, 390, 100); 22 context.bezierCurveTo(430, 40, 370, 30, 340, 50); 23 context.bezierCurveTo(320, 5, 250, 20, 250, 50); 24 context.bezierCurveTo(200, 5, 150, 20, 170, 80); 25 context.closePath(); 26 27 //圆周 28 context.strokeStyle = "blue"; 29 context.lineWidth = 15; 30 context.closePath(); 31 context.stroke(); 32 //填充 33 context.fillStyle = grd; 34 context.fill(); 35 36 }
效果如图:
径向渐变
径向渐变与线性渐变类似,只不过渐变方向不是线段,而是两个圆之间。使用 createRadialGradient() 方法创建渐变对象,参数是渐变起始圆和终止圆。如:
context.createRadialGradient(startX, startY, startRadius, endX, endY, endRadius);
示例代码:
1 function Radial() { 2 var canvas = document.getElementById("myCanvas"); 3 var context = canvas.getContext("2d"); 4 context.beginPath(); 5 6 //三处注释效果不一样,可对比查看 7 //注释一 示例作图 8 context.moveTo(170, 80); 9 context.bezierCurveTo(130, 100, 130, 150, 230, 150);//两个控制点,一个终结点 10 context.bezierCurveTo(250, 180, 320, 180, 340, 150); 11 context.bezierCurveTo(420, 150, 420, 120, 390, 100); 12 context.bezierCurveTo(430, 40, 370, 30, 340, 50); 13 context.bezierCurveTo(320, 5, 250, 20, 250, 50); 14 context.bezierCurveTo(200, 5, 150, 20, 170, 80); 15 context.closePath(); 16 // 创建径向渐变对象 17 var grd = context.createRadialGradient(238, 50, 10, 238, 50, 200);//两个圆心+半径 18 // 设置渐变起始圆处的颜色 19 grd.addColorStop(0, "#FF0000"); 20 // 设置渐变终止圆处的颜色 21 grd.addColorStop(1, "#00FF00"); 22 23 ////注释二 查看渐变效果 24 //context.arc(238, 50, 10, 0, Math.PI * 2, true); 25 ////同心圆效果 26 ////context.arc(238, 50, 200, 0, Math.PI * 2, true); 27 ////非同心圆效果 28 //context.arc(238, 200, 200, 0, Math.PI * 2, true); 29 30 ////注释三 拉开距离 查看两个圆的效果 31 //context.arc(800, 50, 10, 0, Math.PI * 2, true); 32 //context.arc(800, 400, 200, 0, Math.PI * 2, true); 33 34 context.strokeStyle = "blue"; 35 context.lineWidth = 2; 36 context.closePath(); 37 context.stroke(); 38 context.fillStyle = grd; 39 context.fill(); 40 }
效果如图:
绘制图像
绘制图像需要使用 drawImage() 方法。此方法需要一个图像对象和一个起始点坐标作为参数,其中起始点坐标是相对于canvas的左上角的位置。如:
context.drawImage(imageObj, x, y);
由于 drawImage() 方法需要一个图像对象作为参数,所以我们需要在实际调用 drawImage() 之前就加载图像。这一要求可以通过图像对象的 onload 事件来实现。不过要注意的是, onload 应该在用图像对象的src属性指定图像来源之前就进行赋值。
方法 drawImage() 还可以接受 destWidth 和 destHeight 两个参数用来以任意指定的尺寸显示图像:
context.drawImage(imageObj, x, y, width, height);
方法 drawImage() 还可以增加另六个参数来实现对图像的裁剪。这六个参数是, sourceX,sourceY, sourceWidth, sourceHeight, destWidth 和 destHeight。这六个参数对应的含义可以参阅示意图。 context.drawImage(imageObj, sx, sy, sw, sh, dx, dy, dw, dh);
图片来源(https://developer.mozilla.org/zh-CN/docs/Web/Guide/HTML/Canvas_tutorial/Using_images#Using_images_which_are_on_the_same_page)
示例代码:
1 function drawImg() { 2 var canvas = document.getElementById("myCanvas"); 3 var context = canvas.getContext("2d"); 4 var img = new Image(); 5 //为保证图片加载,在其load方法中添加绘图方法 6 img.onload = function () { 7 context.drawImage(img, 0, 200);//原图输出在位置(0,300) 8 context.drawImage(img, 0, 0, 100, 100);//在位置(0,0)将图画成(缩放) 100*100 9 context.drawImage(img, 50, 50, 150, 150, 0, 120, 100, 130);//将原图从左上角(50,50)到右下角(150,150)裁剪下来,在位置(0,120)缩放成100*130的图片 10 11 var pattern = context.createPattern(img, "repeat"); 12 context.fillStyle = pattern; 13 context.fillRect(0, 400, canvas.width - 20, canvas.height - 20);//填充一个矩形 14 } 15 img.src = "http://w3school.com.cn/i/ct_html5_canvas_image.gif"; 16 }
效果图如下:
文本的字体、大小和样式
友情提醒:这里介绍文字略多,可先运行示例,查看效果再回头看介绍,那样就一目了然了。
要设置字体、大小和样式,需要用到上下文对象的 font 属性。样式可以是 normal, italic 或 bold 。默认情况是 normal 。
context.font = 'italic 40px Calibri';
文本的颜色用 fillStyle 属性设置
要描绘字体边缘的效果,要使用 strokeText() 方法替代fillText(),同时要用strokeStyle 属性替代 fillStyle 属性。
文本的对齐功能设定使用 textAlign 属性。其可用的选项包括 start, end, left, center和 right 。对齐的位置是相对于一条虚拟的垂直线,这条线是由 fillText() 或 strokeText() 定义的文本x位置。
垂直对齐文本需要用到 textBaseline 属性。此属性可用的选项包括:top, hanging,middle, alphabetic, ideographic 和 bottom 。默认情况下是alphabetic 。
要获取有关文本的尺度信息,可以使用 measureText() 方法。此方法需要一个文本字符串组为参数,并返回一个尺度对象。尺度对象中的数据是基于所提供的字符串参数和当前的文本字体信息而来的。注意:由于文本的像素高度等于字体尺寸的磅值,所以,从 measureText() 返回的尺度对象并不包含高度数据。如:
var metrics = context.measureText("text");
var width = metrics.width;
示例代码如下:
1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <title></title> 6 <script> 7 8 9 window.onload = function () { 10 font(); 11 wrapText(); 12 }; 13 14 function font() { 15 var c = document.getElementById("myCanvas"); 16 var ctx = c.getContext("2d"); 17 18 // 在位置 300 创建蓝线 19 ctx.strokeStyle = "blue"; 20 ctx.moveTo(300, 20); 21 ctx.lineTo(300, 200); 22 ctx.stroke(); 23 24 ctx.font = "15px Arial"; 25 26 // 显示不同的 textAlign 值 27 ctx.textAlign = "start"; 28 ctx.fillText("textAlign=start", 300, 60); 29 ctx.textAlign = "end"; 30 ctx.fillText("textAlign=end", 300, 80); 31 ctx.textAlign = "left"; 32 ctx.fillText("textAlign=left", 300, 100); 33 ctx.textAlign = "right"; 34 ctx.fillText("textAlign=right", 300, 140); 35 ctx.textAlign = "center"; 36 ctx.fillText("textAlign=center", 300, 120); 37 38 //在位置 y=300 绘制蓝色线条 39 ctx.strokeStyle = "blue"; 40 ctx.moveTo(5, 300); 41 ctx.lineTo(395, 300); 42 ctx.stroke(); 43 44 ctx.font = "20px Arial" 45 46 //在 y=300 以不同的 textBaseline 值放置每个单词 47 ctx.textBaseline = "top"; 48 ctx.fillText("Top", 25, 300); 49 ctx.textBaseline = "bottom"; 50 ctx.fillText("Bottom", 50, 300); 51 ctx.textBaseline = "middle"; 52 ctx.fillText("Middle", 120, 300); 53 ctx.textBaseline = "alphabetic"; 54 ctx.fillText("Alphabetic", 200, 300); 55 ctx.textBaseline = "hanging"; 56 ctx.fillText("Hanging", 290, 300); 57 58 } 59 60 function wrapText() { 61 62 var canvas = document.getElementById("myCanvas"); 63 var context = canvas.getContext("2d"); 64 var maxWidth = 300; 65 var lineHeight = 25; 66 var x = (canvas.width - maxWidth) / 2; 67 var y = 400; 68 var text = "All the world 's a stage, and all the men and women merely players. They have their exits and their entrances; And one man in his time plays many parts."; 69 context.font = "16pt Calibri"; 70 //context.fillStyle = "#333"; 71 72 // 创建渐变 73 var gradient = context.createLinearGradient(0, 0, canvas.width, 0); 74 gradient.addColorStop("0", "magenta"); 75 gradient.addColorStop("0.5", "blue"); 76 gradient.addColorStop("1.0", "red"); 77 // 用渐变填色 78 context.fillStyle = gradient; 79 context.textBaseline = 'bottom'; 80 81 82 var words = text.split(" "); 83 var line = ""; 84 for (var n = 0; n < words.length; n++) { 85 var testLine = line + words[n] + " "; 86 var metrics = context.measureText(testLine); 87 var testWidth = metrics.width; 88 if (testWidth > maxWidth) {//大于最大长度 则将当前行输出,然后换行(y增加)并将换行后的首字母赋值给line 89 context.fillText(line, x, y); 90 line = words[n] + " "; 91 y += lineHeight; 92 } else { 93 line = testLine; 94 } 95 } 96 context.fillText(line, x, y);//最后一行 97 } 98 </script> 99 </head> 100 <body> 101 <canvas id="myCanvas" width="1000" height="600"></canvas> 102 </body> 103 </html>
效果如图(由于LZ截图问题,设置的居中在图中是不居中的):
小结
本篇介绍了线、路径、渐变和文本,下篇将介绍阴影、状态储存和恢复等。
由于LZ现在不如之前清闲了,可能会耽误进度,但是我会尽量坚持写完该系列,谢谢支持。