• 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

  • 相关阅读:
    Cyclic Nacklace HDU
    Oulipo HDU
    Period HDU
    Blue Jeans POJ
    剪花布条 HDU
    最长公共前缀 CSU
    Clock Pictures CSU
    Number Sequence HDU
    Arrange the Bulls POJ
    Traveling by Stagecoach POJ
  • 原文地址:https://www.cnblogs.com/shijiaqi1066/p/4851774.html
Copyright © 2020-2023  润新知