canvas

196 阅读5分钟

基本概念

cavnas绘图技术

概念:因为JavaScript在HTML5之前缺乏实现复杂动画和几何图形的绘制技术,在HTML5版本新增了canvas绘图技术。
canvas绘图技术利用HTML5提供的canvas作为画布,利用JavaScript配套的api来实现绘制几何图形。绘制图形配合JavaScript定时器可以实现复杂动画。

画布

页面上可以使用canvas的标签来充当“画布”的角色。对于页面,canvas就是一个普通的行内标签。canvas标签本身提供了width、height属性来设置画布的尺寸大小。
不要用css设置尺寸。
<canvas width="1000" height="300"></canvas>

画笔

JavaScript会针对每个画布都会提供一个专属的画笔。在程序中,画笔会作为一个对象存在,该对象提供了一系列的api用于进行绘制操作。该画笔是原生提供,不能用jQuery进行操作。
获取画笔
1.先获取画布标签
var canvas = document.querySelector('css选择器');
var 画笔变量名 = canvas.getContext('2d');
//通过画笔来进行绘制
画笔变量名.函数名();

例子:
html
<canvas width="1000" height="300" id="demo"></canvas>
js
var canvas = document.querySelector('#demo');
var ctx = canvas.getContext('2d');
ctx.函数名();

canvas绘图技术的一般流程

1.在页面上设置画布:canvas
2.在JavaScript中获取画笔
3.利用画笔提供的api来进行绘图操作。画笔获取一次即可重复使用
3.1:调用beginPath()开始绘制路径
3.2:调用moveTo确定画笔的绘制位置
3.3:调用lineTo或arc来勾勒子路径
3.4:调用closePath来闭合子路径
3.5:调用stroke绘制路径显示在页面上。

canvas中的坐标系

以画布的左上角为原点,向右x轴为正,向下y轴为正。

canvas路径

路径:一条闭合的线条,一般一个路径是由几条子路径构成。
子路径:一个具体的线条。几条子路径进行连接闭合,就形成了一条完整的路径。
canvas是通过beginPath来表示开始绘制新的路径,closePath会将目前已绘制的子路径进行闭合,形成一条完整的路径。
即我们会在beginPath以及closePath之间进行绘制子路径。当绘制完最后一条子路径后,调用closePath,会自动将第一条子路径的起点和最后一条子路径的终点进行链接,形成一条完整的路径。

绘图操作

基本操作

beginPath():开始绘制一条路径。
closePath():关闭当前绘制的路径,会将该条路径进行闭合。

绘制几何图形-线条相关图形

moveTo(x,y):将画笔移动到指定坐标。
lineTo(x,y):勾勒出一条直线(子路径)。直线的起点就是画笔的位置,终点就是指定的x和y坐标。如果需要显示该条子路径,需要调用stroke()来进行真正的绘制子路径。
stroke():绘制当前已经勾勒出的子路径。
strokeStyle:设置线条的颜色
lineWidth:设置线条的粗细,即宽度
fill():对图形进行填充
fillStyle:设置填充颜色
``` 画笔变量名.strokeStyle = "颜色"; 画笔变量名.lineWidth = "5"; 画笔变量名.fill(); 画笔变量名.fillStyle = "pink"; 例子 ```

绘制几何图形-曲线

arc:勾勒一段曲线
画笔变量名.arc(圆心的x坐标,圆心的y坐标,半径,开始角度,结束角度,是否逆时针绘制);
例子:以100,100 半径为5生成4分之1圆,从0到90度
var canvas = document.querySelector('#demo');
var ctx = canvas.getContext('2d');
ctx.arc(100,100,5,0,Math.PI/2); //默认顺时针

在canvas中,以Math.PI作为180度。
90度为Math.PI/2
37度为37* Math.PI/180
360度为2* Math.PI

奔驰图标案例练习

奔驰图标案例
<canvas width="1000" height="300" id="demo"></canvas>
    <script>
        var canvas = document.querySelector('#demo');
        var ctx = canvas.getContext('2d');
        ctx.arc(100,100,100,0,Math.PI*2);
        ctx.moveTo(100,100);
        ctx.lineTo(100,0);
        ctx.moveTo(100,100);
        ctx.lineTo(25,165);
        ctx.moveTo(100,100);
        ctx.lineTo(175,165);
        ctx.stroke();
    </script>

粒子动画

主要思路

利用随机圆心位置批量生成小圆,然后利用定时器不断改变每个小圆点的圆心位置,达到随机移动的目的。再判断两个点的圆心是否小于指定的一个数字,是就针对这两个点的圆心来绘制线条。给鼠标设置移动事件,保存鼠标移动的x和y坐标,以此为圆心,指定一个半径。判断所有的点,是否是在这个圆以内,如果是,则以两个点的圆心为坐标生成线条。

随机点绘制

每个点的状态需要保存。每个点需要使用一个原生对象来保存,并把所有的点保存到数组中,统一绘制。

点随机移动

随机移动的原理就是不断的改变点的圆心位置。
再利用定时器不断的绘制(清屏)。
边界的判断:点移动范围不能超过边界。
在移动之前对当前点的位置进行判断,如果超出指定范围,那么就速度取反。

绘制两点间线条

如果两个点之间的距离小于指定值,那么就针对这两个点进行连线。
创建一个函数,需要传入一个点对象,里面遍历整个dots数组,判断遍历的点和传入的点的距离是否小于指定值,如果小于,则用画笔进行连线。

设置鼠标移动事件,规定线条生成范围

思路:对鼠标设置move事件,获取鼠标的x和y坐标。然后指定一个半径,表示以鼠标为圆心的一个圆。处于该圆以内的两个点进行连线。(实际上就是在第三阶段的函数中额外加一个判断条件,即点在该圆内(与圆心的距离小于半径))。

其他常用api

clearRect:清理画布中的指定区域。即清理绘制痕迹。
画笔变量名.clearRect(清理区域的左上角x坐标,清理区域的左上角y坐标,清理区域的宽度,清理区域的高度)
例子:清理整个画布,假设画布变量是canvas
ctx.clearRect(0,0,canvas.width,canvas.height)

练习

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body{
            overflow: hidden;
        }
    </style>
</head>
<body>
    <canvas id="dot"></canvas>
    <script>
        var canvas = document.querySelector('#dot');
        var ctx = canvas.getContext('2d');
        //配置粒子动画的参数
        var dotCount = 100; //屏幕粒子的数量
        var dotRadius = 5; //粒子的半径
        //定义保存点的数组
        var dots = [];
        //设置canvas的宽高
        // canvas.setAttribute('width',innerWidth);
        // canvas.setAttribute('height',innerHeight);
        //快捷设置宽高
        canvas.width = innerWidth;
        canvas.height = innerHeight;
        //随机点绘制:点就是一个小圆
       for(var i=0;i<dotCount;i++){
        ctx.beginPath();
        //随机的圆心的坐标
        var random_x = parseInt(Math.random()*canvas.width);
        var random_y = parseInt(Math.random()*canvas.height);
        //随机点的速度,随机-1 1 x和y轴速度独立
        var randomArr = [1,-1];
        var speedX = randomArr[parseInt(Math.random()*2)];
        var speedY = randomArr[parseInt(Math.random()*2)];
        //勾勒圆
        ctx.arc(random_x,random_y,dotRadius,0,Math.PI*2);
        ctx.closePath();
        ctx.fillStyle = "pink";
        ctx.fill();

        //把点的信息保存到对象,并把对象放入数组中
        var dot = {
            //圆心坐标
            x:random_x,
            y:random_y,
            speedX:speedX,
            speedY:speedY
        };
        //放入数组
        dots.push(dot);
       }

       

       //随机移动
       /*
       每个点用一个原生对象来保存,圆心坐标
       var dot = {
        x:578
        y:234
       }
       var arr=[dot1,dot2,dot3...,dot100]
       */
      //改变点的圆心位置,比如再原来的基础上-4
    //   for(var i=0;i<dots.length;i++){
    //     var dot = dots[i];
    //     dot.x -=4;
    //     dot.y -=4;
    //   }
    //利用定时器不断的改变
    setInterval(()=>{
        //清理
        ctx.clearRect(0,0,canvas.width,canvas.height);
        for(var i=0;i<dots.length;i++){
        var dot = dots[i];
        dot.x -=dot.speedX;
        dot.y -=dot.speedY;
        //需要把新的圆心坐标更新到画布中,重新绘制点
        ctx.beginPath();
        ctx.arc(dot.x,dot.y,dotRadius,0,Math.PI*2);
        ctx.closePath();
        ctx.fillStyle = "pink";
        ctx.fill();
        }

    },10);

    </script>
</body>
</html>