H5+canvas动态粒子背景

首先,效果图为:

 H5代码为

<canvas id="canvas"></canvas>

样式设计CSS:

        <style>
            html {
                height: 100%
            }
            
            body {
                margin: 0;
                height: 100%;
                background: #fff;
            }

            canvas {
                display: block;
                width: 100%;
                height: 100%;
                position: absolute;
                top: 0;
                left: 0;
            }
        </style>

最重要的就是js代码了。这里一步步来实现上述粒子效果。

通过看图我们可以发现,就是由很多圆点跟线条组成的动态效果,那么要实现的就是绘制N个圆形,以及在一定距离内的两个原点之间连线。

1.首先获取到canvas对象,以及获取屏幕的宽,高,创建一个圆点列表。

            var canvas = document.getElementById('canvas');
            var ctx = canvas.getContext('2d');
            
            var w = canvas.width = canvas.offsetWidth;
            var h = canvas.height = canvas.offsetHeight;
            var circles = [];

2.绘制N个原点,这里随便多少个都可以,暂定60个。要绘制圆形,需要用到canvas的arc()方法,具体思路见canvas绘制图形,那么我们这里定义一个方法

                function drawCircle(ctx) {
                    ctx.beginPath();
                    ctx.arc(this.x, this.y, this.r, 0, 360);
                    ctx.fillStyle = 'rgba(204, 204, 204, 0.3)';
                    ctx.fill();
                }

该方法就可以通过canvas对象实现创建圆形了。那么看上述方法中的this.s, this.y表示的坐标,其实是这一方法定义在一个对象中,因为我们要创建很多圆形,所以定义了一个js对象,并且给该对象加入了画圆,画线,以及原点不断移动的方法。

            //创建对象:圆
            //x, y为坐标点, r为半径, _mx, _my为移动的距离
            function circle(x, y) {
                this.x = x;
                this.y = y;
                this.r = Math.random() * 10;
                this._mx = 1 - (Math.random() * 2);
                this._my = 1 - (Math.random() * 2);
                
                this.drawCircle = drawCircle;
                function drawCircle(ctx) {
                    ctx.beginPath();
                    ctx.arc(this.x, this.y, this.r, 0, 360);
                    ctx.fillStyle = 'rgba(204, 204, 204, 0.3)';
                    ctx.fill();
                }
                
                this.move = move;
                function move(w, h) {
                    this._mx = (this.x < w && this.x > 0) ? this._mx : (-this._mx);
                    this._my = (this.y < h && this.y > 0) ? this._my : (-this._my);
                    this.x += this._mx / 2;
                    this.y += this._my / 2;
                }
                
                this.drawLine = drawLine;
                function drawLine(ctx, _circle) {
                    var dx = this.x - _circle.x;
                    var dy = this.y - _circle.y;
                    var d = Math.sqrt(dx * dx + dy * dy);
                    if (d < 150) {
                        ctx.beginPath();
                        ctx.moveTo(this.x, this.y);
                        ctx.lineTo(_circle.x, _circle.y);
                        ctx.strokeStyle = 'rgba(204, 204, 204, 0.3)';
                        ctx.stroke();
                    }
                }
            }

由上述代码可以看到,只需要传入相应的(x, y)坐标点,就可以创建一个原点。

其中r半径是随机函数产生的随机数,所以最后生成的原点大小不一。

偏移量_mx,_my也是随机数,由1 - (Math.random() * 2)可以看出偏移范围为(-1, 1),所以我们可以看到有的点向左,有的向下,向左,向右,方向不一,能一定程度保证所有点均匀分布在屏幕中。

需要注意的是this.drawCircle = drawCircle;在对象中定义了方法之后还需要把方法添加到 JavaScript 对象。

移动方法move(),确保原点要在屏幕内移动,所以对于偏移量有个判断,当坐标超出坐标范围后,偏移量正负变换,即向之前移动方向的反方向移动。

两点之间画线的方法,这里设定两点之间连线的范围为0~150,超过150就不会再连线了。具体连线方法也可见canvas绘制图形。方法中涉及到求两点之间的直线距离,Math.sqrt(dx * dx + dy * dy),这个应该也好理解。

3. 定义了绘制圆点的方法,那么我们要再定义一个方法将所有的点画出来。这里就要用到最开始定义的圆点列表circles。

<body onload="init(60)">
    ...
</body>
            function init(num) {
                for(var i = 0; i < num; i ++) {
                    circles.push(new circle(Math.random() * w, Math.random() * h));
                }
                draw();
            }

body上的onload方法表示网页进入时触发的方法,一打开网页就要马上加载init方法。

init方法,可以看到,是创建了60个circle实例push进原点列表中了,而创建的实例的坐标点都是随机的范围再(0, 0) ~ (w, h)。创建好实例后就要开始画点了啊!调用draw方法。

            function draw() {
                ctx.clearRect(0, 0, w, h);
                for(var i = 0; i < circles.length; i ++) {
                    circles[i].move(w, h);
                    circles[i].drawCircle(ctx);
                    for(var j = i + 1; j < circles.length; j++) {
                        circles[i].drawLine(ctx, circles[j]);
                    }
                }
                requestAnimationFrame(draw);
            }

在上述方法中,遍历所有原点,调用circle对象的方法,画圆以及移动,里面的for循环表示每个当前点都与数组后面的点相连即可,即不需要考虑后面的点与前面的点相连问题,因为两点之间连一次就可以了,所以j从1 + 1开始。

这里更新页面用requestAnimationFrame替代setTimeout。

window.requestAnimationFrame = window.requestAnimationFrame 
                                        || window.mozRequestAnimationFrame 
                                        || window.webkitRequestAnimationFrame 
                                        || window.msRequestAnimationFrame;

 

4. 到目前为止,就实现了60个点在屏幕上移动,且150距离内的两点会有连线,那么为了更好的体验效果,我们可以加入鼠标进入屏幕的互动效果。

鼠标进入后会生成一个半径确定的(这里假定8,都可以)不同颜色的原点,且该点在与任意点距离在150以内时要有连线。

那么,需要创建一个对象继承circle,重写画圆方法。

            function currentCircle(x, y) {
                circle.call(this, x, y);
                
                this.drawCircle = drawCircle;
                function drawCircle(ctx) {
                    ctx.beginPath();
                    ctx.arc(this.x, this.y, 8, 0, 360);
                    ctx.fillStyle = 'rgba(255, 77, 54, 0.6)';
                    ctx.fill();
                }
            }

其实,这里也可以不定义这个对象,可以把circle对象改一下,将颜色也定为参数即可。

好了,对象定义好了,那么就要创建实例了,初始状态为

            var current_circle = new currentCircle(0, 0);

 

在屏幕中移动以及离开屏幕的事件响应也可以有了。clientX为鼠标指针向对于浏览器页面(或客户区)的水平坐标。

            window.onmousemove = function(e) {
                e = e || window.event;
                current_circle.x = e.clientX;
                current_circle.y = e.clientY;
            }
            window.onmouseout = function() {
                current_circle.x = null;
                current_circle.y = null;
             }

最后,鼠标点与其他点的连线,修改draw方法

            function draw() {
                ctx.clearRect(0, 0, w, h);
                for(var i = 0; i < circles.length; i ++) {
                    circles[i].move(w, h);
                    circles[i].drawCircle(ctx);
                    for(var j = i + 1; j < circles.length; j++) {
                        circles[i].drawLine(ctx, circles[j]);
                    }
                } 
                if (current_circle.x) {
                    current_circle.drawCircle(ctx);
                    for (var k = 0; k < circles.length; k++) {
                        current_circle.drawLine(ctx, circles[k])
                    }
                }
                requestAnimationFrame(draw);
            }

加了一个判断,如果current_circle的x坐标不为0了(初始状态为0,见实例创建),那么就要画鼠标点了,且遍历所有的圆点,能连线的都连线。到这里,开头的动图上的效果都实现了。

最后,原码下载地址GitHub:https://github.com/sakurayj/canvas

 

posted @ 2019-01-23 16:48  _yj  阅读(3609)  评论(0编辑  收藏  举报