# canvas创建一个炫酷背景

怎么能让页面上的元素动起来呢:

  • gif 图
  • CSS3 动画
  • js 控制
  • svg
  • Canvas

# 效果

这里主要是与鼠标之间的交互效果。

与鼠标之间有互动的效果主要是产生用户行为的反馈,比如在网页制作中,使用 hover 变色表示用户的鼠标在元素上方悬停,这就是用户行为的一种反馈。

我们经常使用的与鼠标之间的交互效果主要有两种:

  • 鼠标跟随
  • 视觉差

总结一下,炫酷的网页背景特效有哪些特点:

  • 背景
    • 单一颜色
    • 渐变
    • 平铺
  • 炫酷
    • 随机
  • 特效
    • 鼠标跟随
    • 视觉差

# 实现随机粒子特效

# 创建全屏 Canvas

首先,需要一个全屏的 Canvas 画布。

    var ctx = document.getElementById('canvas'),
        content = ctx.getContext('2d'),
        WIDTH,
        HEIGHT;
    WIDTH = document.documentElement.clientWidth;
    HEIGHT = document.documentElement.clientHeight;
    ctx.width = WIDTH;
    ctx.height = HEIGHT;

使用 WIDTHHEIGHT 两个常量储存屏幕宽度和高度信息。

# 设置 Round_item 类

在创建了一个全屏的 Canvas 之后,创建单个的 Round_item 类。

首先 Round_item 类需要有什么参数呢?设置的是位置随机、透明度随机、半径随机的圆。为了区分不同的圆,我们还应该设置一个唯一的 index 参数。

需要的参数有:

  • x 坐标
  • y 坐标
  • 半径
  • 透明度
  • index
    function Round_item(index,x,y) {
        this.index = index;
        this.x = x;
        this.y = y;
        this.r = Math.random() * 2 + 1;
        var alpha = (Math.floor(Math.random() * 10) + 1) / 10 / 2;
        this.color = "rgba(255,255,255," + alpha + ")";
    }

这里我们使用了构造函数的方式来创建单个的圆,我们还需要一个变量 initRoundPopulation 来设置 round 的个数,然后我们便可以通过 for 循环创建出 initRoundPopulation 个圆。

# 设置 draw() 方法

在设置了单个的 Round_item 类之后,我们还要给每一个 round 设置 draw() 方法,所以我们需要将 draw() 方法设置在 Round_item 的原型中,这样我们创建出来的每一个 Round_item 实例对象都拥有了 draw() 方法。

    Round_item.prototype.draw = function () {
        content.fillStyle = this.color;
        content.shadowBlur = this.r * 2;
        content.beginPath();
        content.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
        content.closePath();
        content.fill();
    };

# 设置初始化 init() 函数

然后就需要设置初始化 init() 函数了,在 init() 函数中,我们的主要任务是创建单个的 round,然后使用其 draw() 方法。

    function init() {
        for(var i = 0; i < initRoundPopulation; i++ ){
            round[i] = new Round_item(i,Math.random() * WIDTH,Math.random() * HEIGHT);
            round[i].draw();
        }

    }

至此,已经完成了随机粒子的实现,完整的代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        html,body {
            margin:0;
            overflow:hidden;
            width:100%;
            height:100%;
            cursor:none;
            background:black;
        }
    </style>
</head>
<body>
<canvas id="canvas"></canvas>

<script>
    var ctx = document.getElementById('canvas'),
        content = ctx.getContext('2d'),
        round = [],
        WIDTH,
        HEIGHT,
        initRoundPopulation = 100;


    WIDTH = document.documentElement.clientWidth;
    HEIGHT = document.documentElement.clientHeight;

    ctx.width = WIDTH;
    ctx.height = HEIGHT;

    function Round_item(index,x,y) {
        this.index = index;
        this.x = x;
        this.y = y;
        this.r = Math.random() * 2 + 1;
        var alpha = (Math.floor(Math.random() * 10) + 1) / 10 ;
        let a=parseInt(255*Math.random());
        let b=parseInt(255*Math.random());
        let c=parseInt(255*Math.random());
        this.color = `rgba(${a},${b},${c},${alpha} )`;
    }

    Round_item.prototype.draw = function () {
        content.fillStyle = this.color;
        content.shadowBlur = this.r * 2;
        content.beginPath();
        content.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
        content.closePath();
        content.fill();
    };
		
	

    function init() {
        for(var i = 0; i < initRoundPopulation; i++ ){
            round[i] = new Round_item(i,Math.random() * WIDTH,Math.random() * HEIGHT);
            round[i].draw();
        }

    }

    init();

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

# 随机粒子动起来

# animate() 函数

其实,Canvas 制作动画是一个不断擦除再重绘的过程。

实现动画需要在很短的时间内不断的清除内容再重新绘制,新的图形和原先清除的图形之间有某种位置关系,速度足够快的话,就会看到动画的效果。

需要一个 animate() 函数,在这个函数中首先需要清除当前屏幕,这里的清除函数用到的是 content.clearRect() 方法。

先来看一下 canvas 的 content.clearRect() 方法:

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

  • x:要清除的矩形左上角的 x 坐标
  • y:要清除的矩形左上角的 y 坐标
  • width:要清除的矩形的宽度
  • height:要清除的矩形的高度

在刚刚的分析中可以得出,需要清除的区域是整个屏幕,所以 content.clearRect() 的参数就是 content.clearRect(0, 0, WIDTH, HEIGHT);,这里就用到了之前获取的屏幕宽度和高度的常量:WIDTHHEIGHT。这样就将屏幕上的所有内容都清除了。

清除了屏幕内容之后就要重新绘制图形,重新绘制的图形是需要和原图形之间有一定的关系,先制作一个简单的效果 —— 粒子匀速上升。粒子匀速上升,也就是 y 坐标在不断地变化,既然是匀速的,那么也就是在相同的时间位移是相同的。

可以将粒子位移的变化函数 move() 写在 Round_item 的原型上。

requestAnimationFrame 采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使动画卡顿不流畅,让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果。

所以我们就使用 requestAnimationFrame() 函数递归的调用 animate() 函数来实现动画的效果。

    function animate() {
        content.clearRect(0, 0, WIDTH, HEIGHT);

        for (var i in round) {
            round[i].move();
        }
        requestAnimationFrame(animate);
    }

# 创建 move() 函数

使用 move() 函数来改变 round 的 y 坐标。

move() 方法中,我们只需要改变 round 的 y 坐标即可,并且设置边界条件,当 y 坐标的值小于 -10(也可以是其他负值),代表该 round 已经超出了屏幕,这个时候我们要将其移动到屏幕的最底端,这样才能保证我们创建的粒子数不变,一直是 initRoundPopulation 的值。

这样就是一个粒子在不断地上升,上升到了最顶端再移动到最底端的循环过程,看起来像是有源源不断的粒子,但其实总数是不变的。

在 y 坐标的变化之后,我们还需要使用新的 y 坐标再来重新绘制一下该 round。

经过上面的分析,move() 写起来是不是很简单呢?

    Round_item.prototype.move = function () {
        this.y -= 0.15;
        if (this.y <= -10) {
            this.y = HEIGHT + 10;
        }
        this.draw();
    };

#init() 中加入 animate()

想要实现动画的效果,还需要在 init() 中加入 animate() 函数。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        html, body {
            margin: 0;
            overflow: hidden;
            width: 100%;
            height: 100%;
            cursor: none;
            background: black;
        }
    </style>
</head>
<body>
<canvas id="canvas"></canvas>

<script>
    var ctx = document.getElementById('canvas'),
        content = ctx.getContext('2d'),
        round = [],
        WIDTH,
        HEIGHT,
        initRoundPopulation = 60;


    WIDTH = document.documentElement.clientWidth;
    HEIGHT = document.documentElement.clientHeight;

    ctx.width = WIDTH;
    ctx.height = HEIGHT;

    function Round_item(index, x, y) {
        this.index = index;
        this.x = x;
        this.y = y;
        this.r = Math.random() * 2 + 2;
        var alpha = (Math.floor(Math.random() * 10) + 1) / 12 ;
        let a=parseInt(255*Math.random());
       let b=parseInt(255*Math.random());
       let c=parseInt(255*Math.random());
       this.color = `rgba(${a},${b},${c},${alpha})`;
    }

    Round_item.prototype.draw = function () {
        content.fillStyle = this.color;
        content.shadowBlur = this.r * 2;
        content.beginPath();
        content.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
        content.closePath();
        content.fill();
    };

    function animate() {
        content.clearRect(0, 0, WIDTH, HEIGHT);

        for (var i in round) {
            round[i].move();
        }
        requestAnimationFrame(animate)
    }

    Round_item.prototype.move = function () {
        this.y -= 0.2;
        if (this.y <= -10) {
            this.y = HEIGHT + 10;
        }
        this.draw();
    };


    function init() {
        for (var i = 0; i < initRoundPopulation; i++) {
            round[i] = new Round_item(i, Math.random() * WIDTH, Math.random() * HEIGHT);
            round[i].draw();
        }
        animate();

    }

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


uigradients (opens new window)

最后更新: 1/28/2021, 4:11:50 PM