HTML5 Canvas

作者: Lia代码猪崽 | 来源:发表于2018-10-29 17:17 被阅读1次

    一、添加一个 Canvas

    1.布置画布:通过添加<canvas>标签,添加canvas元素
    • CanvasHTML5中是透明的,是不可见的。
    • <canvas>标签中的那段文本是什么意思呢?那是一旦浏览器执行HTML页面时不支持Canvas,就会显示这段文字,换言之,只要你的浏览器支持Canvas,页面上就不会显示这个文本。
    • <canvas>中的id是标签的属性之一,在JavaScript代码中用来指定特定的<canvas>,是唯一的。
    2.获取canvas对象
    var canvas = document.getElementById("canvas");
    
    3.获得画笔(2D环境)
    var context = canvas.getContext("2d");
    

    二、绘制一条线段

    1.移动画笔(moveTo())
    • canvas画布的左上角为笛卡尔坐标系的原点,且y轴的正方向向下,x轴的正方向向右。
    • context.moveTo(100,100)。这句代码的意思是 移动画笔至(100, 100)这个点(单位是px)。
    • moveTo()方法只是表示准备状态,准备要画,还没开始画。
    笔画停点(lineTo())
    • 从上一笔的停止点绘制到这里。
    • context.lineTo(600, 600)是从 上一笔的停止点绘制到(600, 600)这里。
    • lineTo()方法只是表示准备状态,准备要画,还没开始画。
    3.选择画笔
    • context.lineWidth = 5,这句话的意思是设置画笔(线条)的粗细为 5px
    • context.strokeStyle = "#AA394C",这句话的意思是设置画笔(线条)的颜色为玫红色。

    4.确定绘制

    • 确定绘制只有两种方法,fill()stroke()
    • fill()是填充。
    • stroke()是描边。
    demo
    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>从线条开始</title>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas" style="border: 1px solid #aaaaaa; display: block; margin: 50px auto;">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
    
            context.moveTo(100,100);
            context.lineTo(600,600);
            context.lineWidth = 5;
            context.strokeStyle = "#AA394C";
            context.stroke();
        }
    </script>
    </body>
    </html>
    
    绘制一条线段

    三、多线条组成图形

    1.绘制折线

    复用lineTo()就可以了。

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>绘制折线</title>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas" style="border: 1px solid #aaaaaa; display: block; margin: 50px auto;">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
    
            context.moveTo(100,100);
            context.lineTo(300,300);
            context.lineTo(100,500);
            context.lineWidth = 5;
            context.strokeStyle = "#AA394C";
            context.stroke();
        }
    </script>
    </body>
    </html>
    
    
    折线
    2.绘制多条折线

    如果要画三条折线,分别是红色、蓝色、黑色,平移一下再改下画笔颜色就行了。

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>绘制折线</title>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas" style="border: 1px solid #aaaaaa; display: block; margin: 50px auto;">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
    
            context.moveTo(100,100);
            context.lineTo(300,300);
            context.lineTo(100,500);
            context.lineWidth = 5;
            context.strokeStyle = "red";
            context.stroke();
    
            context.moveTo(300,100);
            context.lineTo(500,300);
            context.lineTo(300,500);
            context.lineWidth = 5;
            context.strokeStyle = "blue";
            context.stroke();
    
            context.moveTo(500,100);
            context.lineTo(700,300);
            context.lineTo(500,500);
            context.lineWidth = 5;
            context.strokeStyle = "black";
            context.stroke();
        }
    </script>
    </body>
    </html>
    
    三条黑色的折线

    Canvas是基于状态的绘制。这段代码每次使用stroke()时,它都会把之前设置的状态再绘制一遍。第一次stroke()时,绘制一条红色的折线;第二次stroke()时,会再重新绘制之前的那条红色的折线,但是这个时候的画笔已经被更换成蓝色的了,所以画出的折线全是蓝色的。换言之,strokeStyle属性被覆盖了。同理,第三次绘制的时候,画笔颜色是最后的黑色,所以会重新绘制三条黑色的折线。所以,这里看到的三条折线,其实绘制了3次,一共绘制了6条折线。

    3.使用 beginPath() 开始绘制

    为了让绘制方法不重复绘制,我们可以在每次绘制之前加上beginPath(),代表下次绘制的起始之处为beginPath()之后的代码。我们在三次绘制之前分别加上context.beginPath()。

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>绘制折线</title>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas" style="border: 1px solid #aaaaaa; display: block; margin: 50px auto;">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
    
            context.beginPath();
            context.moveTo(100,100);
            context.lineTo(300,300);
            context.lineTo(100,500);
            context.lineWidth = 5;
            context.strokeStyle = "red";
            context.stroke();
    
            context.beginPath();
            context.moveTo(300,100);
            context.lineTo(500,300);
            context.lineTo(300,500);
            context.lineWidth = 5;
            context.strokeStyle = "blue";
            context.stroke();
    
            context.beginPath();
            context.moveTo(500,100);
            context.lineTo(700,300);
            context.lineTo(500,500);
            context.lineWidth = 5;
            context.strokeStyle = "black";
            context.stroke();
        }
    </script>
    </body>
    </html>
    
    三条颜色不一样的折线

    四、绘制矩形

    1.使用closePath()闭合图形

    首先我们用上节方法绘制一个矩形。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>绘制矩形</title>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas" style="border: 1px solid #aaaaaa; display: block; margin: 50px auto;">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
    
            context.beginPath();
            context.moveTo(150,50);
            context.lineTo(650,50);
            context.lineTo(650,550);
            context.lineTo(150,550);
            context.lineTo(150,50);     //绘制最后一笔使图像闭合
            context.lineWidth = 5;
            context.strokeStyle = "black";
            context.stroke();
    
        }
    </script>
    </body>
    </html>
    </body>
    </html>
    
    据说左上角会有缺口,为什么我没有?
    据说左上角有一个缺口

    这种情况是设置了lineWidth导致的。如果默认1笔触的话,是没有问题的。但是笔触越大,线条越宽,这种缺口就越明显。使用使用closePath()闭合图形来避免这种情况。

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>绘制矩形</title>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas" style="border: 1px solid #aaaaaa; display: block; margin: 50px auto;">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
    
            context.beginPath();
            context.moveTo(150,50);
            context.lineTo(650,50);
            context.lineTo(650,550);
            context.lineTo(150,550);
            context.lineTo(150,50);     //最后一笔可以不画
            context.closePath();        //使用closePath()闭合图形
    
            context.lineWidth = 5;
            context.strokeStyle = "black";
            context.stroke();
    
        }
    </script>
    </body>
    </html>
    
    image.png
    • 每次开始绘制前都务必要使用beginPath(),为了代码的完整性,每次绘制结束后使用closePath()
    • 最后一笔可以不画出来,直接使用closePath(),它会自动帮你闭合的。
    • 如果你不想绘制闭合图形就不可以使用closePath()
    2.给矩形上色
    • 这里我们要介绍一个和stroke()同等重要的方法fill()
    • 和当初描边一样,我们在填色之前,也要先用fillStyle属性选择要填充的颜色。
    • 比如我们要给上面的矩形涂上黄色,可以这样写。
    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>绘制矩形</title>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas" style="border: 1px solid #aaaaaa; display: block; margin: 50px auto;">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
    
            context.beginPath();
            context.moveTo(150,50);
            context.lineTo(650,50);
            context.lineTo(650,550);
            context.lineTo(150,550);
            context.lineTo(150,50);     //最后一笔可以不画
            context.closePath();        //使用closePath()闭合图形
    
            context.fillStyle = "yellow";   //选择油漆桶的颜色
            context.lineWidth = 5;
            context.strokeStyle = "black";
    
            context.fill();                 //确定填充
            context.stroke();
    
        }
    </script>
    </body>
    </html>
    
    中间填了黄色
    3.封装绘制方法
    • 一个矩形可以由它的左上角坐标和其长宽唯一确定。
    • 绘制矩形其实都是这样的四笔,我们可以使用JavaScript封装这些方法。
    • 还需要知道线条的颜色,宽度,填充的颜色。
    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>封装绘制矩形方法</title>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas" style="border: 1px solid #aaaaaa; display: block; margin: 50px auto;">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
    
            drawRect(context, 150, 50, 50, 50, "red", 5, "blue");
            drawRect(context, 250, 50, 50, 50, "green", 5, "red");
            drawRect(context, 350, 50, 50, 50, "yellow", 5, "black");
        }
    
        function drawRect(cxt, x, y, width, height, fillColor, borderWidth, borderColor){
            cxt.beginPath();
            cxt.moveTo(x, y);
            cxt.lineTo(x + width, y);
            cxt.lineTo(x + width, y + height);
            cxt.lineTo(x, y + height);
            cxt.lineTo(x, y);
            cxt.closePath();
    
            cxt.lineWidth = borderWidth;
            cxt.strokeStyle = borderColor;
            cxt.fillStyle = fillColor;
    
            cxt.fill();
            cxt.stroke();
        }
    </script>
    </body>
    </html>
    
    三个矩形
    4.使用rect()方法绘制矩形

    由于绘制矩形是常用的方法,所以在Canvas API中已经帮我们封装好了一个绘制矩形的方法——rect()。这个方法接收4个参数x, y, width, height,实际调用时也就是:

    context.rect(x, y, width, height);
    

    基于此,我们帮刚才封装的方法优化一下:

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>绘制魔性图形</title>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas" style="border: 1px solid #aaaaaa; display: block; margin: 50px auto;">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
    
            context.beginPath();
            context.rect(0, 0, 800, 600);
            context.fillStyle = "#AA9033";
    
            context.fill();
    
            context.beginPath();
            for(var i=0; i<20; i++){
                drawWhiteRect(context, 200 + 10 * i, 100 + 10 * i, 400 - 20 * i, 400 - 20 * i);
                drawBlackRect(context, 205 + 10 * i, 105 + 10 * i, 390 - 20 * i, 390 - 20 * i);
            }
    
            context.beginPath();
            context.rect(395, 295, 5, 5);
            context.fillStyle = "black";
            context.lineWidth = 5;
    
            context.fill();
            context.stroke();
        }
    
        function drawBlackRect(cxt, x, y, width, height){
            cxt.beginPath();
            cxt.rect(x, y, width, height);
    
            cxt.lineWidth = 5;
            cxt.strokeStyle = "black";
    
            cxt.stroke();
        }
    
        function drawWhiteRect(cxt, x, y, width, height){
            cxt.beginPath();
            cxt.rect(x, y, width, height);
    
            cxt.lineWidth = 5;
            cxt.strokeStyle = "white";
    
            cxt.stroke();
        }
    </script>
    </body>
    </html>
    
    看多了会眼花

    五、线条的属性

    1.线条的帽子lineCap

    lineCap 定义上下文中线的端点,可以有以下 3 个值:

    • butt:默认值,端点是垂直于线段边缘的平直边缘。
    • round:端点是在线段边缘处以线宽为直径的半圆。
    • square:端点是在选段边缘处以线宽为长、以一半线宽为宽的矩形。
    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>线条的帽子</title>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas" style="border: 1px solid #aaaaaa; display: block; margin: 50px auto;">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
    
            context.lineWidth = 30;
            context.strokeStyle = "#1BAAAA";
    
            context.beginPath();
            context.moveTo(100,100);
            context.lineTo(700,100);
            context.lineCap = "butt";
            context.stroke();
    
            context.beginPath();
            context.moveTo(100,300);
            context.lineTo(700,300);
            context.lineCap = "round";
            context.stroke();
    
            context.beginPath();
            context.moveTo(100,500);
            context.lineTo(700,500);
            context.lineCap = "square";
            context.stroke();
    
            //下面画两个基准线方便观察
            context.lineWidth = 3;
            context.strokeStyle = "black";
    
            context.beginPath();
            context.moveTo(100,0);
            context.lineTo(100,600);
            context.moveTo(700,0);
            context.lineTo(700,600);
            context.stroke();
        }
    </script>
    </body>
    </html>
    
    线宽为30
    2.线条的连接lineJoin

    可能有三个值:

    • miter,默认值,直接连接。
    • bevel,连接处为线宽的一半的矩形。
    • round,连接处为直径是线宽的圆。
    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>线条的连接</title>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas" style="border: 1px solid #aaaaaa; display: block; margin: 50px auto;">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
    
            context.beginPath();
            context.moveTo(100,100);
            context.lineTo(300,300);
            context.lineTo(100,500);
            context.lineJoin = "miter";
            context.lineWidth = 50;
            context.strokeStyle = "red";
            context.stroke();
    
            context.beginPath();
            context.moveTo(300,100);
            context.lineTo(500,300);
            context.lineTo(300,500);
            context.lineJoin = "bevel";
            context.lineWidth = 50;
            context.strokeStyle = "blue";
            context.stroke();
    
            context.beginPath();
            context.moveTo(500,100);
            context.lineTo(700,300);
            context.lineTo(500,500);
            context.lineJoin = "round";
            context.lineWidth = 50;
            context.strokeStyle = "black";
            context.stroke();
        }
    </script>
    </body>
    </html>
    
    线条连接处都不同
    3.线宽lineWidth

    lineWidth 定义线的宽度(默认值为 1.0)。

    4.笔触样式strokeStyle

    strokeStyle 定义线和形状边框的颜色和样式。

    六、填充颜色

    填充颜色主要分为两种:

    • 基本颜色
    • 渐变颜色(又分为线性渐变与径向渐变)
    1.填充基本颜色

    fillStyle属性用来设置画布上形状的基本颜色和填充。

    context.fillStyle = "red";
    
    2.填充渐变形状
    • 在画布上创建渐变填充有两个基本选项:线性或径向。
    • 线性渐变创建一个水平、垂直或者对角线的填充图案。
    • 径向渐变自中心点创建一个放射状填充。
    • 填充渐变形状分为三步:添加渐变线,为渐变线添加关键色,应用渐变。
    2.1.线性渐变

    三步走战略:

    2.1.1.添加渐变线:
    var grd = context.createLinearGradient(xstart,ystart,xend,yend);
    
    2.1.2.为渐变线添加关键色(类似于颜色断点):
    grd.addColorStop(stop,color);
    

    这里的stop传递的是 0 ~ 1 的浮点数,代表断点到(xstart,ystart)的距离占整个渐变色长度是比例。

    2.1.3.应用渐变:
    context.fillStyle = grd;
    context.strokeStyle = grd;
    
    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>填充线性渐变</title>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas" style="border: 1px solid #aaaaaa; display: block; margin: 50px auto;">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
    
            context.rect(200,100,400,400);
    
            //添加渐变线
            var grd = context.createLinearGradient(200,300,600,300);
    
            //添加颜色断点
            grd.addColorStop(0,"black");
            grd.addColorStop(0.5,"white");
            grd.addColorStop(1,"black");
    
            //应用渐变
            context.fillStyle = grd;
    
            context.fill();
    
        }
    </script>
    </body>
    </html>
    
    讲解图
    2.2.绘制矩形的快捷方法

    fillRect(x,y,width,height)strokeRect(x,y,width,height)这两个函数可以分别看做rect()fill()以及rect()stroke()的组合。
    因为rect()仅仅只是规划路径而已,而这两个方法实实在在的绘制。

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>填充线性渐变</title>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas" style="border: 1px solid #aaaaaa; display: block; margin: 50px auto;">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
    
            //添加渐变线
            var grd = context.createLinearGradient(100,300,700,300);
    
            //添加颜色断点
            grd.addColorStop(0,"olive");
            grd.addColorStop(0.25,"maroon");
            grd.addColorStop(0.5,"aqua");
            grd.addColorStop(0.75,"fuchsia");
            grd.addColorStop(0.25,"teal");
    
            //应用渐变
            context.fillStyle = grd;
            context.strokeStyle = grd;
    
            context.strokeRect(200,50,300,50);
            context.strokeRect(200,100,150,50);
            context.strokeRect(200,150,450,50);
    
            context.fillRect(200,300,300,50);
            context.fillRect(200,350,150,50);
            context.fillRect(200,400,450,50);
    
            context.fillRect(0,550,800,25);
    
        }
    </script>
    </body>
    </html>
    
    image.png

    这两个页面都是水平渐变,但是要清楚线性渐变不一定是水平的,方向可以是任意的,通过渐变线的端点来设置方向。

    2.3.径向渐变
    • 线性渐变是基于两个端点定义的,但是径向渐变是基于两个圆定义的。
    • 同样是三步走战略,只不过是第一步的所用方法变了。
    2.3.1.添加渐变圆:
    var grd = context.createRadialGradient(x0,y0,r0,x1,y1,r1);
    
    2.3.2.为渐变线添加关键色(类似于颜色断点):
    grd.addColorStop(stop,color);
    
    2.3.3.应用渐变:
    context.fillStyle = grd;
    context.strokeStyle = grd;
    
    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>填充径向渐变</title>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas" style="border: 1px solid #aaaaaa; display: block; margin: 50px auto;">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
    
            //添加渐变线
            var grd = context.createRadialGradient(400,300,100,400,300,200);
    
            //添加颜色断点
            grd.addColorStop(0,"olive");
            grd.addColorStop(0.25,"maroon");
            grd.addColorStop(0.5,"aqua");
            grd.addColorStop(0.75,"fuchsia");
            grd.addColorStop(1,"teal");
    
            //应用渐变
            context.fillStyle = grd;
    
            context.fillRect(100,100,600,400);
    
    
        }
    </script>
    </body>
    </html>
    
    其实只有两个圆

    createRadialGradient(x0,y0,r0,x1,y1,r1);方法规定了径向渐变开始和结束的范围,即两圆之间的渐变。

    七、填充图案

    1.createPattern()简介
    • 填充图案通过createPattern()函数进行初始化。
    • 它需要传进两个参数createPattern(img,repeat-style)
    • 第一个是Image对象实例,第二个参数是String类型,表示在形状中如何显示repeat图案。
    • createPattern()的第一个参数还可以传入一个canvas对象或者video对象。
    • 可以使用这个函数加载图像或者整个画布作为形状的填充图案。

    有以下4种图像填充类型:

    • 平面上重复:repeat;
    • x轴上重复:repeat-x;
    • y轴上重复:repeat-y;
    • 不使用重复:no-repeat;
    2.创建并填充图案

    创建Image对象,为Image对象指定图片源:

    var img = new Image();    //创建Image对象
    img.src = "8-1.jpg";    //为Image对象指定图片源
    

    填充纹理:

    var pattern = context.createPattern(img,"repeat");
    context.fillStyle = pattern;
    
    下面代码用到的图
    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>填充纹理</title>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas" style="border: 1px solid #aaaaaa; display: block; margin: 50px auto;">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
    
            var img = new Image();
            img.src = "https://img.haomeiwen.com/i7016617/395eecefc4dd4c5a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240";
            img.onload = function(){
                var pattern = context.createPattern(img, "repeat");
                context.fillStyle = pattern;
                context.fillRect(0,0,800,600);
            }
    
        }
    </script>
    </body>
    </html>
    
    铺满猪了

    这里使用了Imageonload事件,它的作用是对图片进行预加载处理,即在图片加载完成后才立即除非其后function的代码体。这个是必须的,如果不写的话,画布将会显示黑屏。因为没有等待图片加载完成就填充纹理,导致浏览器找不到图片。

    八、绘制标准圆弧

    1.使用arc()绘制圆弧

    arc()的使用方法如下:

    context.arc(x,y,radius,startAngle,endAngle,anticlockwise)
    
    • 前面三个参数,分别是圆心坐标与圆半径。
    • startAngleendAngle使用的是弧度值,不是角度值。
    • anticlockwise表示绘制的方法,是顺时针还是逆时针绘制。它传入布尔值,true表示逆时针绘制,false表示顺时针绘制,缺省值为false。
    • 弧度的规定是绝对的,如下图:


      弧度值
    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>圆</title>
        <style>
            #canvas { border: 1px solid #aaaaaa; display: block; margin: 50px auto; }
        </style>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
            context.fillStyle = "#FFF";
            context.fillRect(0,0,800,600);
    
            context.beginPath()
            context.arc(400, 300, 100, 0, 2*Math.PI, true)
    
            context.strokeStyle = "#0078AA";
            context.stroke();
        }
    </script>
    </body>
    </html>
    
    2.绘制圆角矩形

    下面,我们结合基本路径和高级路径的知识,绘制一个圆角矩形。
    圆角矩形是由四段线条和四个1/4圆弧组成,拆解如下:


    圆角矩形的组成

    因为我们要写的是函数而不是一个固定的圆角矩形,所以这里列出的是函数需要的参数。分析好之后,直接敲出代码:

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>圆角矩形</title>
        <style>
            #canvas { border: 1px solid #aaaaaa; display: block; margin: 50px auto; }
        </style>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
            context.fillStyle = "#FFF";
            context.fillRect(0,0,800,600);
    
            drawRoundRect(context, 200, 100, 400, 400, 50);
            context.strokeStyle = "#0078AA";
            context.stroke();
        }
    
        function drawRoundRect(cxt, x, y, width, height, radius){
            cxt.beginPath();
            cxt.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 3 / 2);
            cxt.lineTo(width - radius + x, y);
            cxt.arc(width - radius + x, radius + y, radius, Math.PI * 3 / 2, Math.PI * 2);
            cxt.lineTo(width + x, height + y - radius);
            cxt.arc(width - radius + x, height - radius + y, radius, 0, Math.PI * 1 / 2);
            cxt.lineTo(radius + x, height +y);
            cxt.arc(radius + x, height - radius + y, radius, Math.PI * 1 / 2, Math.PI);
            cxt.closePath();
        }
    </script>
    </body>
    </html>
    
    image.png

    九、使用切点绘制圆弧

    • arcTo()方法接收5个参数,分别是两个切点的坐标和圆弧半径。这个方法是依据切线画弧线,即由两个切线确定一条弧线。 具体如下。
    • arcTo(x1,y1,x2,y2,radius)这个函数以给定的半径绘制一条弧线,圆弧的起点与当前路径的位置到(x1, y1)点的直线相切,圆弧的终点与(x1, y1)点到(x2, y2)的直线相切。因此其通常配合moveTo()lineTo()使用。
    • 其能力是可以被更为简单的arc()替代的,其复杂就复杂在绘制方法上使用了切点。
    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>绘制弧线</title>
        <style>
            body { background: url("./images/bg3.jpg") repeat; }
            #canvas { border: 1px solid #aaaaaa; display: block; margin: 50px auto; }
        </style>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
            context.fillStyle = "#FFF";
            context.fillRect(0,0,800,600);
    
            drawArcTo(context, 200, 200, 600, 200, 600, 400, 100);
        };
    
        function drawArcTo(cxt, x0, y0, x1, y1, x2, y2, r){
            cxt.beginPath();
            cxt.moveTo(x0, y0);
            cxt.arcTo(x1, y1, x2, y2, r);
    
            cxt.lineWidth = 6;
            cxt.strokeStyle = "red";
            cxt.stroke();
    
            cxt.beginPath();
            cxt.moveTo(x0, y0);
            cxt.lineTo(x1, y1);
            cxt.lineTo(x2, y2);
    
            cxt.lineWidth = 1;
            cxt.strokeStyle = "#0088AA";
            cxt.stroke();
        }
    </script>
    </body>
    </html>
    
    结果 标注图

    arcTo()绘制的起点是(x0, y0),但(x0, y0)不一定是圆弧的切点。真正的arcTo()函数只传入(x1, y1)(x2, y2)。其中(x1, y1)称为控制点,(x2, y2)是圆弧终点的切点,它不一定在圆弧上。但(x0, y0)一定在圆弧上。

    十、二次贝塞尔曲线

    二次贝塞尔曲线
    Canvas里,二次贝塞尔曲线的方法如下:
    context.quadraticCurveTo(cpx,cpy,x,y);
    
    • 这里和acrTo()有异曲同工之妙。
    • P0是起始点,所以通常搭配moveTo()lineTo()使用。
    • P1(cpx, cpy)是控制点,P2(x, y)是终止点,它们不是相切的关系。
    • 一个工具可以简单调试直至得到你想要的效果。在线转换器

    十一、三次贝塞尔曲线

    绘制三次贝塞尔曲线代码如下。

    context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y);
    
    • 这个方法可谓是绘制波浪线的神器。
    • 根据之前的结论,n阶贝塞尔曲线就有n-1个控制点,所以三次贝塞尔曲线有1个起始点、1个终止点、2个控制点。
    • 因此传入的6个参数分别为控制点cp1 (cp1x, cp1y),控制点cp2 (cp2x, cp2y),与终止点 (x, y)
    • 这个方法也是不用大家去掌握参数具体是怎么填的,只要知道参数的意义就行。
    • quadraticCurveTo()方法一样,bezierCurveTo()的三次贝塞尔曲线网上也能找到互动的网页工具。
      这里提供一个网页:Canvas Bézier Curve Example,大家可以动手试一下。
    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>XP壁纸</title>
        <style>
            body { background: url("./images/bg3.jpg") repeat; }
            #canvas { border: 1px solid #aaaaaa; display: block; margin: 50px auto; }
        </style>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
            context.fillStyle = "#FFF";
            context.fillRect(0,0,800,600);
    
            drawPrairie(context);
            drawSky(context);
            for(var i=0; i <5; i++){
                var x0 = 500 * Math.random() + 50;
                var y0 = 200 * Math.random() + 50;
                var c0 = 100 * Math.random() + 50;
                drawCloud(context, x0, y0, c0);
    
            }
    
        };
    
        function drawSky(cxt){
            cxt.save();
    
            cxt.beginPath();
            cxt.moveTo(0, 420);
            cxt.bezierCurveTo(250, 300, 350, 550, 800, 400);
            cxt.lineTo(800,0);
            cxt.lineTo(0,0);
            cxt.closePath();
    
            var lineStyle = cxt.createRadialGradient(400, 0, 50, 400, 0, 200);
            lineStyle .addColorStop(0, "#42A9AA");
            lineStyle .addColorStop(1, "#2491AA");
    
            cxt.fillStyle = lineStyle;
    
            cxt.fill();
    
            cxt.restore();
        }
    
        function drawPrairie(cxt){
            cxt.save();
    
            cxt.beginPath();
            cxt.moveTo(0, 420);
            cxt.bezierCurveTo(250, 300, 350, 550, 800, 400);
            cxt.lineTo(800,600);
            cxt.lineTo(0,600);
            cxt.closePath();
    
            var lineStyle = cxt.createLinearGradient(0, 600, 600, 0);
            lineStyle .addColorStop(0, "#00AA58");
            lineStyle .addColorStop(0.3, "#63AA7B");
            lineStyle .addColorStop(1, "#04AA00");
    
            cxt.fillStyle = lineStyle;
            cxt.fill();
    
            cxt.restore();
        }
    
    
    
        /*渲染单个云朵
         context:  canvas.getContext("2d")对象
         cx: 云朵X轴位置
         cy: 云朵Y轴位置
         cw: 云朵宽度
         */
        function drawCloud(cxt, cx, cy, cw) {
            //云朵移动范围即画布宽度
            var maxWidth = 800;
            //如果超过边界从头开始绘制
            cx = cx % maxWidth;
            //云朵高度为宽度的60%
            var ch = cw * 0.6;
            //开始绘制云朵
    
            cxt.beginPath();
            cxt.fillStyle = "white";
            //创建渐变
            var grd = cxt.createLinearGradient(0, 0, 0, cy);
            grd.addColorStop(0, 'rgba(255,255,255,0.8)');
            grd.addColorStop(1, 'rgba(255,255,255,0.5)');
            cxt.fillStyle = grd;
    
            //在不同位置创建5个圆拼接成云朵现状
            cxt.arc(cx, cy, cw * 0.19, 0, 360, false);
            cxt.arc(cx + cw * 0.08, cy - ch * 0.3, cw * 0.11, 0, 360, false);
            cxt.arc(cx + cw * 0.3, cy - ch * 0.25, cw * 0.25, 0, 360, false);
            cxt.arc(cx + cw * 0.6, cy, cw * 0.21, 0, 360, false);
            cxt.arc(cx + cw * 0.3, cy - ch * 0.1, cw * 0.28, 0, 360, false);
            cxt.closePath();
    
            cxt.fill();
        }
    </script>
    </body>
    </html>
    
    其实每次都不一样
    保存和恢复Canvas状态

    这里还使用到了两个新方法save()restore()。之前说过了canvas是基于状态的绘制.保存(推送)当前状态到堆栈,调用以下函数:

    context.save();
    

    调出最后存储的堆栈恢复画布,使用以下函数:

    context.restore();
    

    十二、图形变换

    图形变换是指用数学方法调整所绘形状的物理属性,其实质是坐标变形。所有的变换都依赖于后台的数学矩阵运算,所以我们只要使用变换的功能即可,无需去理解这些运算。谈到图形变换,不得不得说的三个基本变换方法就是:

    • 平移变换:translate(x,y)
    • 旋转变换:rotate(deg)
    • 缩放变换:scale(sx,sy)
    • 其实坐标变形的本质是变换矩阵,所以在最后我们会谈一谈一个万能的变换方法——矩阵变换transform()。
    1.平移变换translate()

    平移变换,故名思议,就是一般的图形位移。
    比如这里我想将位于(100,100)的矩形平移至(200,200)点。
    那么我只要在绘制矩形之前加上context.translate(100,100)即可。

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>平移变换</title>
        <style>
            body { background: url("./images/bg3.jpg") repeat; }
            #canvas { border: 1px solid #aaaaaa; display: block; margin: 50px auto; }
        </style>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
            context.fillStyle = "#FFF";
            context.fillRect(0,0,800,600);
    
            context.fillStyle = "#00AAAA";
            context.fillRect(100,100,200,100);
    
            context.fillStyle = "red";
            context.translate(100,100);
            context.fillRect(100,100,200,100);
    
        };
    </script>
    </body>
    </html>
    
    为了更直观演示,宝绿色为红色平移前的位置
    平移详解
    注意使用状态保存

    其实这里有一个坑,我们如果想把矩形平移至(300,300)怎么办呢?或许我们会想,直接调用context.translate(200,200)就可以了。好,我们看看效果。

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>平移变换</title>
        <style>
            body { background: url("./images/bg3.jpg") repeat; }
            #canvas { border: 1px solid #aaaaaa; display: block; margin: 50px auto; }
        </style>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
            context.fillStyle = "#FFF";
            context.fillRect(0,0,800,600);
    
            context.fillStyle = "#00AAAA";
            context.fillRect(100,100,200,100);
    
            context.fillStyle = "red";
            context.translate(100,100);
            context.fillRect(100,100,200,100);
    
            context.fillStyle = "green";
            context.translate(200,200);
            context.fillRect(100,100,200,100);
    
        };
    </script>
    </body>
    </html>
    
    有些出乎意料

    这里的绿色矩形并没有如我们所愿在(300,300)位置处,而是跑到了(400,400)这里。为什么呢?想必大家已经知道了答案——Canvas是基于状态的绘制。在我们第一次平移之后,坐标系已经在(100,100)处了,所以如果继续平移,这个再基于新坐标系继续平移坐标系。那么要怎么去解决呢?很简单,有两个方法。

    • 第一,在每次使用完变换之后,记得将坐标系平移回原点,即调用translate(-x,-y)。
    • 第二,在每次平移之前使用context.save(),在每次绘制之后,使用context.restore()。
    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>平移变换</title>
        <style>
            body { background: url("./images/bg3.jpg") repeat; }
            #canvas { border: 1px solid #aaaaaa; display: block; margin: 50px auto; }
        </style>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
            context.fillStyle = "#FFF";
            context.fillRect(0,0,800,600);
    
            context.fillStyle = "#00AAAA";
            context.fillRect(100,100,200,100);
    
            context.save();
            context.fillStyle = "red";
            context.translate(100,100);
            context.fillRect(100,100,200,100);
            context.restore();
    
            context.save();
            context.fillStyle = "green";
            context.translate(200,200);
            context.fillRect(100,100,200,100);
            context.restore();
    
        };
    </script>
    </body>
    </html>
    
    可以了
    2.旋转变换rotate()
    • 同画圆弧一样,这里的rotate(deg)传入的参数是弧度,不是角度。
    • 同时需要注意的是,这个的旋转是以坐标系的原点(0,0)为圆心进行的顺时针旋转。
    • 所以,在使用rotate()之前,通常需要配合使用translate()平移坐标系,确定旋转的圆心。
      即,旋转变换通常搭配平移变换使用的。
    • 最后一点需要注意的是,Canvas是基于状态的绘制,所以每次旋转都是接着上次旋转的基础上继续旋转,所以在使用图形变换的时候必须搭配save()与restore()方法,一方面重置旋转角度,另一方面重置坐标系原点。
    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>旋转变换</title>
        <style>
            body { background: url("./images/bg3.jpg") repeat; }
            #canvas { border: 1px solid #aaaaaa; display: block; margin: 50px auto; }
        </style>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
            context.fillStyle = "#FFF";
            context.fillRect(0,0,800,600);
    
    
            for(var i = 0; i <= 12; i++){
                context.save();
                context.translate(70 + i * 50, 50 + i * 40);
                context.fillStyle = "#00AAAA";
                context.fillRect(0,0,20,20);
                context.restore();
    
                context.save();
                context.translate(70 + i * 50, 50 + i * 40);
                context.rotate(i * 30 * Math.PI / 180);
                context.fillStyle = "red";
                context.fillRect(0,0,20,20);
                context.restore();
            }
    
        };
    </script>
    </body>
    </html>
    
    image.png

    这里用for循环绘制了14对正方形,其中蓝色是旋转前的正方形,红色是旋转后的正方形。每次旋转都以正方形左上角顶点为原点进行旋转。每次绘制都被save()与restore()包裹起来,每次旋转前都移动了坐标系。

    3.缩放变换scale()

    缩放变换scale(sx,sy)传入两个参数,分别是水平方向和垂直方向上对象的缩放倍数。例如context.scale(2,2)就是对图像放大两倍。其实,看上去简单,实际用起来还是有一些问题的。我们来看一段代码。

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>缩放变换</title>
        <style>
            body { background: url("./images/bg3.jpg") repeat; }
            #canvas { border: 1px solid #aaaaaa; display: block; margin: 50px auto; }
        </style>
    </head>
    <body>
    <div id="canvas-warp">
        <canvas id="canvas">
            你的浏览器居然不支持Canvas?!赶快换一个吧!!
        </canvas>
    </div>
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            canvas.width = 800;
            canvas.height = 600;
            var context = canvas.getContext("2d");
            context.fillStyle = "#FFF";
            context.fillRect(0,0,800,600);
    
            context.strokeStyle = "red";
            context.lineWidth = 5;
            for(var i = 1; i < 4; i++){
                context.save();
                context.scale(i,i);
                context.strokeRect(50,50,150,100);
                context.restore();
            }
        };
    </script>
    </body>
    </html>
    
    有点奇怪哦

    看了上面的例子,大家一定对产生的结果有点奇怪。一是左上角顶点的坐标变了,而是线条的粗细也变了。因此,对于缩放变换有两点问题需要注意:

    • 缩放时,图像左上角坐标的位置也会对应缩放。
    • 缩放时,图像线条的粗细也会对应缩放。

    十三、

    参考资料

    https://airingursb.gitbooks.io/canvas/02.htmls

    相关文章

      网友评论

        本文标题:HTML5 Canvas

        本文链接:https://www.haomeiwen.com/subject/rynbtqtx.html