HTML

HTML5 Canvas

2018-10-29  本文已影响1人  Lia代码猪崽

一、添加一个 Canvas

1.布置画布:通过添加<canvas>标签,添加canvas元素
2.获取canvas对象
var canvas = document.getElementById("canvas");
3.获得画笔(2D环境)
var context = canvas.getContext("2d");

二、绘制一条线段

1.移动画笔(moveTo())
笔画停点(lineTo())
3.选择画笔

4.确定绘制

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
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.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.封装绘制方法
<!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 个值:

<!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

可能有三个值:

<!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()简介

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

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)
<!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

九、使用切点绘制圆弧

<!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);

十一、三次贝塞尔曲线

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

context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y);
<!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();

十二、图形变换

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

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)处了,所以如果继续平移,这个再基于新坐标系继续平移坐标系。那么要怎么去解决呢?很简单,有两个方法。

<!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()
<!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

上一篇下一篇

猜你喜欢

热点阅读