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>

绘图结果:

wps9B3C.tmp

由于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>

绘图结果:

wps9B5D.tmp

 

 

 

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

 

posted @ 2015-10-02 00:02  LaplaceDemon  阅读(9397)  评论(1编辑  收藏  举报