HTML5 Canvas 2D绘图
为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处。LaplaceDemon/ShiJiaqi。
http://www.cnblogs.com/shijiaqi1066/p/4851774.html
Canvas
Canvas标签,用于在web中绘制各种图形。Canvas为基于像素的绘图,绘制的图像是位图。也即Canvas绘图的基本单位是像素。Canvas是一个相当于画板的html节点,用js操作绘图。
Canvas特点
- 依赖分辨率。
- 不支持事件处理器。
- 弱的文本渲染能力。
- 能够以 .png 或 .jpg 格式保存结果图像。
- 最适合图像密集型的游戏,其中的许多对象会被频繁重绘。
一、Canvas基础
若浏览器不支持HTML5的 <canvas>标签。则把不支持信息写在<canvas></canvas>之间。
例:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <canvas id="myCanvas" width="600" height="300"> 你的浏览器还不支持哦 </canvas> </body> </html>
不建议使用CSS来制定canvas的width,height。因为canvas不光需要指定其dom的宽高,还需要指定canvas内部画布分辨率的大小。
<canvas>标签,有两个基本属性:height 与width。当两个属性的值改变时,该画布上的任何绘图都会擦除掉。
- height的默认值是 150。
- width默认值是 300。
1. Canvas绘图初步
cancas的2d绘图对象的全称为CanvasRenderingContext2D对象。CanvasRenderingContext2D理解为canvas的画笔。
使用canvas dom对象的 getContext() 方法并把"2d"作为方法参数,从而获取CanvasRenderingContext2D对象。无论调用多少次getContext()方法,获取的对象都都是相同的。
var canvas=document.getElementById("myCanvas"); var context = canvas.getContext("2d");
canvas的基本用法是:设置绘画动作,执行绘画动作。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <canvas id="myCanvas" width="800" height="800" style="border: 1px solid black"> 你的浏览器还不支持哦 </canvas> <script type="text/javascript"> var canvas=document.getElementById("myCanvas"); var context = canvas.getContext("2d"); // 状态设置 context.moveTo(100,100); context.lineTo(700,700); // 绘制 context.stroke(); </script> </body> </html>
绘图结果:
2. Canvas Context 的属性
fillStyle 属性:用来填充路径的当前的颜色、模式或渐变。这个属性可以设置为一个字符串或者一个 CanvasGradient 对象 或 CanvasPattern 对象。当设置为一个字符串时,它被解析为一个 CSS 颜色值并且用来进行实心填充。当设置为一个 CanvasGradient 或 CanvasPattern 对象,通过使用指定的渐变或模式来完成填充。
globalAlpha 属性:指定在画布上绘制的内容的不透明度。这个值的范围在 0.0(完全透明)和 1.0(完全不透明)之间。默认值为 1.0。
globalCompositeOperation 属性:指定颜色如何与画布上已有的颜色组合(合成)。
lineCap 属性:指定线条的末端如何绘制。合法的值是 "butt"、"round" 和 "square"。默认值是 "butt"。
lineJoin 属性:指定两条线条如何连接。合法的值是 "round"、"bevel" 和 "miter"。默认值是 "miter"。
lineWidth 属性:指定了画笔(绘制线条)操作的线条宽度。默认值是 1.0,并且这个属性必须大于 0.0。较宽的线条在路径上居中,每边有线条宽的一半。
miterLimit 属性:当 lineJoin 属性为 "miter" 的时候,这个属性指定了斜连接长度和线条宽度的最大比率。如需更多细节,请参阅 miterLimit 属性参考页。
shadowBlur 属性:指定羽化阴影的程度。默认值是 0。阴影效果得到 safari 的支持,但是并没有得到 FireFox 1.5 或 Opera 9 的支持。
shadowColor 属性:把阴影的颜色指定为一个 CSS 字符串或 Web 样式字符串,并且可以包含一个 alpha 部分来表示透明度。默认值是 black。阴影效果得到 Safari 的支持,但是并没有得到 FireFox 1.5 或 Opera 9 的支持。
shadowOffsetX, shadowOffsetY 属性:指定阴影的水平偏移和垂直偏移。较大的值使得阴影化的对象似乎漂浮在背景的较高位置上。默认值是 0。阴影效果得到 Safari 的支持,但是并没有得到 FireFox 1.5 或 Opera 9 的支持。
strokeStyle 属性:指定了用于画笔(绘制)路径的颜色、模式和渐变。这个属性可能是一个字符串,或者一个 CanvasGradient 对象 或 CanvasPattern 对象。如果是一个字符串,它被解析为一个 CSS 颜色值,并且画笔用所得的实色来绘制。如果这个属性的值是一个 CanvasGradient 对象或 CanvasPattern 对象,画笔使用这个渐变或模式来实现。
3. Canvas Context 实例的绘图方法
绘制路径
beginPath() :beginPath() 丢弃当前定义的路径,开始一条新的路径。
closePath() :绘制路径结束,它会绘制一个闭合的区间,添加一条起始位置到当前坐标的闭合曲线。
moveTo(x,y) :设置绘图起始坐标。
lineTo(x,y) :从最后一点到点(x,y)绘制一条直线。
arc(x,y,radius,startAngle,endAngle,anticlockwise) :绘制中心点在(x,y)的弧,半径为radius,角度在[startAngle,endAngle]之间(角度单位为弧度)。anticlockwise为布尔类型,若为true表示逆时针;若为false表示顺时针。
arcTo(x1, y1, x2, y2, radius) :创建两切线之间的弧/曲线。圆弧是半径为radius的圆的部分。该圆弧有一个点与当前位置到P1(x1,y1)的线段相切,还有一个点和从P1(x1,y1)到P2(x2,y2)的线段相切。这两个切点就是圆弧的起点和终点,圆弧绘制的方向就是连接这两个点的最短圆弧的方向。
bezierCurveTo(c1x,c1y,c2x,c2y,x,y) :使用控制点(c1x,c2y)和(c2x,c2y)从最后一点到点(x,y)绘制一条三次贝塞尔曲线。
quadraticCurveTo(cx,cy,x,y) :控制点(cx,cy)从最后一点到点(x,y),绘制一条贝塞尔曲线。
rect(x,y,width,height) :为当前路径添加一条矩形路径。矩形是路径的一个子路径,没有和路径中的任何其他子路径相连。当 rect() 方法返回时,当前位置是 (0,0)。
stroke() :渲染路径。
说明:
调用beginPath()方法表示新路径的开始。
调用closePath(),表示路径闭合。
beginPath()方法与closePath()方法不一定要成对出现。当不需要使绘图路径封闭,可以不使用closePath,仅仅可以使用beginPath开始下一段路径的绘制。
如果路径已经闭合,可以调用 fill()方法用fillStyle填充它。调用 fill()方法时,canvas会自动将未封闭的路径封闭。
调用clip(),根据路径创建一个剪裁区域。
isPointInPath(x,y) 判断路径是否存在于路径之上。该方法在路径关闭之前调用。
绘制矩形
clearRect(left,top,width,height) :清除指定的矩形区域。
strokeRect(left,top,width,height) :绘制矩形框。无填充色。框的颜色由strokeStyle属性指定。strokeStyle属性默认为黑色('#000000')。
fillRect(left,top,width,height) :绘制内部填充颜色的矩形。填充颜色由fillStyle属性指定。fillStyle属性默认为黑色('#000000')。
绘制文本
文本绘制API不一定在浏览器中有实现。
fillText(text,x,y) :绘制实心文字。
stokeText(text,x,y) :绘制空心文字。
绘制文本的context属性:
- font
- textAlign
- textBaseline
fill(),stroke(),clip() 在完成绘制的最后的填充和边界轮廓,剪辑区域。
使用图片
使用drawImage() 方法可以把图片绘制到画布上。该方法有有3个变形。
drawImage(image, x, y) :把整个图像复制到画布,将其放置到指定点的左上角,并且将每个图像像素映射到画布上。
drawImage(image, x, y, width, height) :把整个图像复制到画布,允许指定图像的宽度和高度。
drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight) :指定图像的任何矩形区域,对画布中的任何位置都可进行任何的缩放。
参数说明:
- image 所要绘制的图像。这必须是表示 <img> 标记或者屏幕外图像的 Image 对象,或者是 Canvas 元素。
- x, y 要绘制的图像的左上角的位置。
- width, height 图像所应该绘制的尺寸。指定这些参数使得图像可以缩放。
- sourceX, sourceY 图像将要被绘制的区域的左上角。这些整数参数用图像像素来度量。
- sourceWidth, sourceHeight 图像所要绘制区域的大小,用图像像素表示。
- destX, destY 所要绘制的图像区域的左上角的画布坐标。
- destWidth, destHeight 图像区域所要绘制的画布大小。
坐标变换
2D绘图环境支持所有基本绘图变换。当创建绘图环境,变换矩阵便已经初始化了默认值。
translate(dx,dy) :平移变换。将画布按向量(dx,dy)平移。也即将原点移动到坐标(dx,dy)。
rotate(a) :旋转变换,画布绕原点旋转a弧度角。
scale(scaleX,scaleY) :缩放图像,x轴放大scaleX,y轴放大scaleY。scaleX,scaleY默认都为1.0。
transform(m1_1,m1_2,m2_1,m2_2,dx,dy) :将变换矩阵乘以以下矩阵。
m1_1 m1_2 dx
m2_1 m2_2 dy
0 0 1
setTransform(m1_1,m1_2,m2_1,m2_2,dx,dy) :重置变换矩阵到默认状态,然后调用transform()。
说明:
平移 :context.translate(dx,dy) 可以使用context.transform(1,0,0,1,dx,dy) 或者 context.transform(0,1,1,0.dx,dy) 代替。
旋转 :context.rotate(a)可以使用context.transform(Math.cos(a*Math.PI/180),Math.sin(a*Math.PI/180),-Math.sin(a*Math.PI/180),Math.cos(a*Math.PI/180),0,0)
或者用
context.transform(-Math.sin(a*Math.PI/180),Math.cos(a*Math.PI/180),Math.cos(a*Math.PI/180),Math.sin(a*Math.PI/180), 0,0)代替。
缩放 :context.scale(sx, sy)可以使用context.transform(sx,0,0,sy,0,0)或者context.transform(0,sy,sx,0, 0,0)代替。
保存图形状态
save() 和 restore() 方法允许你保存和恢复一个 CanvasRenderingContext2D 对象的状态。
save() 把当前状态推入到栈中。
restore() 从栈的顶端弹出最近保存的状态,并且根据这些存储的值来设置当前绘图状态。
CanvasRenderingContext2D 对象的所有属性(除了画布的属性是一个常量)都是保存的状态的一部分。变换矩阵和剪切区域也是这个状态的一部分,但是当前路径和当前点并不是。
操作像素
createImageData
getImageData
putImageData
ImageData对象保存了图像像素值。每个对象有三个属性: width, height 和data。data 属性类型为CanvasPixelArray,用于储存width*height*4个像素值。每一个像素有RGB值和透明度alpha值(其值为 0 至255,包括alpha在内!)。像素的顺序从左至右,从上到下,按行存储。
渐变
Context对象可以通过createLinearGradient()和createRadialGradient()两个方法创建渐变对象,这两个方法的原型如下:
Object createLinearGradient(x1, y1, x2, y2) :创建一个从(x1, y1)点到(x2, y2)点的线性渐变对象。
Object createRadialGradient(x1, y1, r1, x2, y2, r2) :创建一个从以(x1, y1)点为圆心、r1为半径的圆到以(x2, y2)点为圆心、r2为半径的圆的径向渐变对象。
渐变对象创建完成之后必须使用它的addColorStop()方法来添加颜色,该方法的原型如下:
void addColorStop(position, color) :其中position表示添加颜色的位置,取值范围为[0, 1],0表示起点,1表示终点;color表示添加的颜色,取值可以是任何CSS颜色值。
渐变对象创建并配置完成之后就可以将其赋予Context对象的strokeStyle属性或者fillStyle属性,然后绘制的图形就具有了所需的渐变效果。
4. 一些简单的例子
4.1 绘制路径
例: canvas的绘制是基于状态的。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <canvas id="myCanvas" width="800" height="800" style="border: 1px solid black"> 你的浏览器还不支持哦 </canvas> <script type="text/javascript"> var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); // 状态设置 context.moveTo(100,100); context.lineTo(700,700); context.lineTo(100,700); context.lineTo(100,100); context.lineWidth = 5; context.strokeStyle = "red"; // 绘制 context.stroke(); // 状态设置 context.moveTo(200,100); context.lineTo(700,600); context.strokeStyle = "black"; // 绘制 context.stroke(); </script> </body> </html>
绘图结果:
由于stroke()方法会把当前路径中的所有线条都描一遍。所以第二段线条的黑色线的属性把第一段线条的属性覆盖掉了,从而导致了两条线段都是黑色的。
所以绘制新图像之前必须使用beginPath、closePath。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <canvas id="myCanvas" width="800" height="800" style="border: 1px solid black"></canvas> <script type="text/javascript"> var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); // 开始一段路径 context.beginPath(); // 状态设置 context.moveTo(100,100); context.lineTo(700,700); context.lineTo(100,700); context.lineTo(100,100); context.lineWidth = 5; context.strokeStyle = "red"; // 绘制 context.stroke(); // 开始一段路径 context.beginPath(); // 状态设置 context.moveTo(200,100); context.lineTo(700,600); context.strokeStyle = "black"; // 绘制 context.stroke(); </script> </body> </html>
绘图结果:
4.2 绘制七巧板
例:绘制七巧板,该例需要绘制线条而只是绘制图形,所以不需要使用stroke()方法,只需要使用fill()方法。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <canvas id="myCanvas" width="800" height="800" style="border: 1px solid black"></canvas> <script type="text/javascript"> var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); var tangram = [ {p:[{x:0,y:0},{x:800,y:0},{x:400,y:400}],color:"#caff67"}, {p:[{x:0,y:0},{x:400,y:400},{x:0,y:800}],color:"#67becf"}, {p:[{x:800,y:0},{x:800,y:400},{x:600,y:600},{x:600,y:200}],color:"#ef3d61"}, {p:[{x:600,y:200},{x:600,y:600},{x:400,y:400}],color:"#f9f51a"}, {p:[{x:400,y:400},{x:600,y:600},{x:400,y:800},{x:200,y:600}],color:"#a594c0"}, {p:[{x:200,y:600},{x:400,y:800},{x:0,y:800}],color:"#fa8ecc"}, {p:[{x:800,y:400},{x:800,y:800},{x:400,y:800}],color:"#f6ca29"}, ]; function draw(piece,ctx){ ctx.beginPath(); var p0 = piece.p[0]; ctx.moveTo(p0.x,p0.y); for(var i = 1;i<piece.p.length;i++){ var pi = piece.p[i]; ctx.lineTo(pi.x, pi.y); } ctx.lineWidth = 1; ctx.strokeStyle = "black"; ctx.fillStyle = piece.color; ctx.fill(); // 绘图,填充颜色。 ctx.closePath(); } // 绘制七巧板 for(var i=0;i<tangram.length;i++){ draw(tangram[i],context); } </script> </body> </html>
绘图结果:
4.3 绘制画圆
对于arc()方法。其圆弧的极坐标表示方法如下:
例:绘制一段圆弧。
var context = document.getElementById("myCanvas").getContext("2d"); context.lineWidth = 5; context.strokeStyle = "blue"; context.arc(300,300,200,0,1.5*Math.PI); context.stroke();
绘图结果:
arc()方法最后一个参数用于设置绘制圆弧的顺逆时针。若为true,表示逆时针,若为false,表示顺时针。但这里的顺逆时针的概念与一般的不同。具体参看示例。
var context = document.getElementById("myCanvas").getContext("2d"); context.beginPath(); context.lineWidth = 5; context.strokeStyle = "blue"; context.arc(200,400,100,0,1.5*Math.PI,true); context.stroke(); context.beginPath(); context.arc(500,400,100,0,0.5*Math.PI,true); context.stroke();
绘图结果:
二、保存canvas图形为文件
Canvas元素有一个toDataURL()方法。该方法可以将canvas中的图像数据进行base64编码。
函数:canvas.toDataURL(type, encoderOptions);
- type:图像格式,默认为"image/png"。
- encoderOptions:数值为0~1,表示图片质量,仅在type为"image/jpeg"或"image/webp"时有效。
该方法返回一串URI字符串。该字符串是canvas中图像数据的base64编码。
toDataURL()方法的浏览器兼容情况:
Chrome | Firefox(Gecko) | Internet Explorer | Opera | Safari | Android | Chrome for Android | Firefox Mobile(Gecko Mobile) | IE Mobile | Opera Mobile | Safari Mobile |
4 | 3.6(1.9.2) | 9 | 9 | 4.0 | 3.2 | 18 | 1.0(1.9.2) | (Yes) | 19 | 3.0 |
例:打印URL。
var canvas = document.getElementById("canvas"); var dataURL = canvas.toDataURL(); // 打印出URL console.log(dataURL);
例:设置图像编码的质量。
var fullQuality = canvas.toDataURL("image/jpeg", 1.0); var mediumQuality = canvas.toDataURL("image/jpeg", 0.5); var lowQuality = canvas.toDataURL("image/jpeg", 0.1);
例:将canvas的绘图结果显示到img中。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <canvas id="myCanvas" width="800" height="800" style="border: 1px solid black"></canvas> <img id="myImg" src="" width="800" height="800" alt="canvas picture" /> <script type="text/javascript"> var img = document.getElementById("myImg"); var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); // 绘图 context.beginPath(); context.arc(400,400,200,0,2*Math.PI); context.stroke(); // 设置img的src var url = canvas.toDataURL(); img.src = url; </script> </body> </html>
例:将canvas保存成图片文件。
方法一:将canvas的图形同步到image。既可以鼠标右击保存图片。
方法二:将window.location.href 赋值为DataURL 。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <canvas id="myCanvas" width="300" height="300" style="border: 1px solid black"></canvas> <input id="saveBtn" type="button" onclick="saveImg()" value="保存图片"/> <script type="text/javascript">var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); // 绘图 context.beginPath(); context.arc(150,150,50,0,2*Math.PI); context.stroke(); function saveImg(){ var url = canvas.toDataURL(); var newURL = url.replace("image/png", "image/octet-stream"); window.location.href = newURL; } </script> </body> </html>
这个方法存在问题,首先在IE10下,浏览器只是跳转到了空白页,没有下载文件。其次,在Chrome中下载文件没有文件名。Chrome中总是这样显示:
方法三:使用超链接<a></a>提供的链接进行下载。该方法可以解决下载文件名缺失的问题,但IE10中无法使用。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <canvas id="myCanvas" width="300" height="300" style="border: 1px solid black"></canvas> <input id="saveBtn" type="button" onclick="saveImg()" value="保存图片"/> <script type="text/javascript"> var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); // 绘图 context.beginPath(); context.arc(150,150,50,0,2*Math.PI); context.stroke(); function saveImg(){ var url = canvas.toDataURL(); var saveLink = document.createElement('a'); saveLink.href = url; saveLink.download = "圆弧.png"; // 触发点击事件 var clickEvent = document.createEvent('MouseEvents'); clickEvent.initEvent('click', true, true); saveLink.dispatchEvent(clickEvent); } </script> </body> </html>
绘图结果:
三、让低版本IE支持Canvas
Google提供了一个ExplorerCanvas的函数库,简称excanvas。该函数库使Canvas在低版本的IE下也可使用。
excanvas的原理是在低版本IE中使用VML绘图。需要注意的是,低版本的IE678使用VML绘图的效率比HTML5绘图的效率低很多。
例:在IE 6,7,8中使用canvas画圆。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <!--[if IE]><script type="text/javascript" src="lib/excanvas.js"></script><![endif]--> </head> <body> <canvas id="myCanvas" width="300" height="300" style="border: 1px solid black"></canvas> <script type="text/javascript"> // IE 6,7,8中必须等所有dom加载完毕才能画出图形。 window.onload = function () { var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); // 绘图 context.beginPath(); context.arc(150,150,50,0,2*Math.PI); context.stroke(); }; </script> </body> </html>
为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处。LaplaceDemon/ShiJiaqi。
http://www.cnblogs.com/shijiaqi1066/p/4851774.html