# 使你的鼠标和屏幕互动

在第 5 节,我们实现了随机粒子;第 6 节,我们让随机粒子动了起来,并且简单介绍了 Canvas 制作动画的原理。

本节我们一起来看一下 Canvas 是怎么和我们的鼠标互动的。

我们先来看一下这个效果。 鼠标互动效果

然后我们分析一下这个效果:鼠标移动,会在经过的地方创建一个圆,圆的半径由小变大,达到某个固定大小时该圆消失。圆的颜色也是在随机变化的(gif 图片时间较短,效果不明显)。

# 创建 Canvas 元素

首先我们还是要创建并获取 Canvas 元素,相信大家对此步骤应该很熟悉了吧。

这里也顺带将需要的参数直接写好了,我们将一些可以控制的变量直接写在参数中,这样在后面就可以获取参数直接使用。设置参数主要是为了更改方便。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        #canvas {
            background: #000;
        }
    </style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
        var canvas = document.getElementById('canvas'),
            ctx = canvas.getContext('2d'),
            WIDTH = canvas.width = document.documentElement.clientWidth,
            HEIGHT = canvas.height = document.documentElement.clientHeight,
            para = {
                num: 100,
                color: false,    //  颜色  如果是false 则是随机渐变颜色
                r: 0.9,          //   圆每次增加的半径 
                o: 0.09,         //      判断圆消失的条件,数值越大,消失的越快
                a: 1
            },
            color,
            color2,
            round_arr = [];     // 存放圆的数组 
</script>
</body>
</html>

我们就创建一个黑色的全屏 Canvas 元素。

# onmousemove 事件

在创建完了 Canvas 元素之后,我们要写鼠标移动的事件了,我们要考虑一下鼠标事件怎么写。

观察一下刚刚的 gif 图片,可以看出,在鼠标移动的过程中,不断地在鼠标滑过的位置产生一个逐渐变大的圆。

那么怎么让效果动起来呢?这就用到第 6 节讲到的知识了,我们在 Canvas 中创建动画的方式就是不断地清除屏幕内容然后重绘。

我们可以看出来,移动的轨迹是由一个一个的圆构成的,如果移动的速度过快的话,那么就可以明显看出一个一个的圆。

既然轨迹是由很多圆构成,那么我们就应该使用数组储存圆的信息(坐标、半径),然后在鼠标移动的时候将鼠标的位置信息储存在数组中。

所以在鼠标移动的过程我们首先要获得鼠标的坐标,然后将鼠标的坐标以及其他信息 push 到数组中去:

   
    window.onmousemove = function (event) {

        mouseX = event.clientX;
        mouseY = event.clientY;

        round_arr.push({
            mouseX: mouseX,
            mouseY: mouseY,
            r: para.r,  // 设置半径每次增大的数值        
            o: 1,    //  判断圆消失的条件,数值越大,消失得越快
        })
    };

# 设置 color

我们已经将圆的相关信息储存在 round_arr 数组中了,现在要在 animate() 函数中将圆显示出来。animate() 函数我们稍后再介绍。

创建圆需要的坐标信息以及半径,我们在鼠标移动的事件中都已经将其 push 到 round_arr 数组中了,还有一个条件是需要设置的,那就是颜色。

怎么对颜色进行处理呢?在 para 参数中,我们可以看出,其中有设置 color 值。如果 color 值不为 false,那么设置的圆的颜色就是设置的 color 值;如果设置的 color 值为 false,那么圆的颜色就是随机的。


if (para.color) {
    color2 = para.color;
} else {
    color = Math.random() * 360;
}

那么怎么设置颜色的渐变呢?我们将 color 的颜色值依次增加一个增量。


if (!para.color) {
    color += .1;
    color2 = 'hsl(' + color + ',100%,80%)';
}

要让颜色一直改变,我们要将上面颜色改变的代码放在一个一直执行的函数。我们将上面改变颜色的代码放在下面我们要介绍的 animate() 函数中。

# animate() 函数

我们需要一个一直在执行的函数,这个函数主要负责动画的 animate() 函数。从函数名就可以看出这个函数的作用,的确,我们需要在该函数中写动画。

第 6 节写动画的主要思想是 —— 清除屏幕再重新绘制,这里的 animate() 函数也是这样的。

我们先来清除屏幕。


ctx.clearRect(0, 0, WIDTH, HEIGHT);

接着使用 round_arr 数组中的数据将一个一个的圆绘制出来。

for (var i = 0; i < round_arr.length; i++) {

    ctx.fillStyle = color2;
    ctx.beginPath();
    ctx.arc( round_arr[i].mouseX ,round_arr[i].mouseY,round_arr[i].r,0, Math.PI * 2);
    ctx.closePath();
    ctx.fill();
    round_arr[i].r += para.r;
    round_arr[i].o -= para.o;

    if( round_arr[i].o <= 0){
        round_arr.splice(i,1);
        i--;
    }
    
}

然后我们还需要一直执行这个函数:

window.requestAnimationFrame(animate);

我们来看下完整的 animate() 函数:


function animate() {

    if (!para.color) {
        color += .1;
        color2 = 'hsl(' + color + ',100%,80%)';
    }

    ctx.clearRect(0, 0, WIDTH, HEIGHT);

    for (var i = 0; i < round_arr.length; i++) {

        ctx.fillStyle = color2;
        ctx.beginPath();
         ctx.arc( round_arr[i].mouseX ,round_arr[i].mouseY,round_arr[i].r,0, Math.PI * 2);
        ctx.closePath();
        ctx.fill();
        round_arr[i].r += para.r;
        round_arr[i].o -= para.o;

        if( round_arr[i].o <= 0){
            round_arr.splice(i,1);
            i--;
        }
    }

    window.requestAnimationFrame(animate);
};

# 小结

以上,我们就写完了一个完整的鼠标跟随效果的例子,让我们来看一下主要的有哪些步骤:

  1. 创建 Canvas 元素,设置参数
  2. 鼠标移动事件,将坐标信息 push 到数组
  3. 设置颜色
  4. 设置动画 animate() 函数

我们来看一下这个例子的完整代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        #canvas {
            background: #000;
        }
    </style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>


        var canvas = document.getElementById('canvas'),
            ctx = canvas.getContext('2d'),
            WIDTH = canvas.width = document.documentElement.clientWidth,
            HEIGHT = canvas.height = document.documentElement.clientHeight,
            para = {
                num: 100,
                color: false,    //  颜色  如果是false 则是随机渐变颜色
                r: 0.9,
                o: 0.09,         //  判断圆消失的条件,数值越大,消失的越快
                a: 1,

            },
            color,
            color2,
            round_arr = [];





        window.onmousemove = function (event) {

            mouseX = event.clientX;
            mouseY = event.clientY;

            round_arr.push({
                mouseX: mouseX,
                mouseY: mouseY,
                r: para.r,
                o: 1
            })
        };


        // 判断参数中是否设置了 color,如果设置了 color,就使用该值、
        // 如果参数中的 color 为 false,那么就使用随机的颜色
        if (para.color) {
            color2 = para.color;
        } else {
            color = Math.random() * 360;
        }

        function animate() {

            if (!para.color) {
                color += .1;
                color2 = 'hsl(' + color + ',100%,80%)';
            }

            ctx.clearRect(0, 0, WIDTH, HEIGHT);

            for (var i = 0; i < round_arr.length; i++) {

                ctx.fillStyle = color2;
                ctx.beginPath();
                ctx.arc( round_arr[i].mouseX ,round_arr[i].mouseY,round_arr[i].r,0, Math.PI * 2);
                ctx.closePath();
                ctx.fill();
                round_arr[i].r += para.r;
                round_arr[i].o -= para.o;

                if( round_arr[i].o <= 0){
                    round_arr.splice(i,1);
                    i--;
                }
            }

            window.requestAnimationFrame(animate);
        };

        animate();
</script>
</body>
</html>