Canvas粒子背景效果

特效实现

浏览数:2,965

2017-12-23

  • 最近有人问我博客的背景效果怎么实现的,其实就是一个canvas效果,今天抽空写篇博客简单分享下思路
  • Demo演示

主要分为两步

  • 首先就是根据窗口缩放比例随机生成点
  • 再者就是就算点与点之间的距离,根据距离生成线段
  • 综上所述,就是画点连线的过程

实现过程

1.第一步封装个函数mainBgFullScreen初始化canvas

  • 使canvas根据窗口自适应
    width = $(':root').width();
    height = $(':root').height();
    zoom = getZoom();
    $canvas.attr('width', width);
    $canvas.attr('height', height);
    
  • 由于要做到自适应需要监听resize事件,在回调中执行mainBgFullScreen
  • 绘制Canvas,固定套路
    if ($canvas[0].getContext) {
        var ctx = $canvas[0].getContext('2d');
        ctx.fillStyle = '#ffffff';
        ctx.strokeStyle = 'rgba(255,255,255,0)';
        ctx.lineWidth = 1 * zoom;
        drawCanvas(ctx);
    }
    

2.第二步在drawCanvas函数中根据一定的逻辑画点画线
  1.画点:

  • 封装一个工厂生成不同大小,不同位置,运动速度不同的点,这些根据屏幕缩放比生成,保证各个屏幕大小下显示协调
    function creatPoint() {
        var xsKew = (Math.random() - 0.5) * zoom;//x方向速度
        var ysKew = (Math.random() - 0.5) * zoom;//y方向速度
        var r = ~~(Math.random() * 5 * zoom);
        var x = ~~(Math.random() * (width - r)) + 2 * r;
        var y = ~~(Math.random() * (height - r)) + 2 * r;
        var point = {
            x: x,
            y: y,
            xsKew: xsKew,
            ysKew: ysKew,
            r: r
        }
        return point;
    }
    
  • 在初始化Canvas时循环生成一些点,塞到数组中,画点时循环数组画点
    //初始化先放200个点
    for (var i = 0; i < ~~(200 * zoom); i++) {
        pointArry.push(creatPoint());
    }
    //drawCanvas函数中
    $.each(pointArry, function (index) {
        //绘制点
        ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI);
        ctx.fill();
    })
    
  • 由于监听resize事件所以每次初始化,先清空数组

  1.画线

  • 封装一个函数drawLine,参数是两点坐标以及ctx,根据勾股定理,大家应该都懂的,画两点之间的连线
    //画线
    function drawLine(ctx, p1x, p1y, p2x, p2y) {
        var xDistance = Math.abs(p1x - p2x);//计算两点间的x距离
        var yDistance = Math.abs(p1y - p2y);//计算两点间的y距离
        var distance = Math.sqrt(xDistance * xDistance + yDistance * yDistance);
        if (distance <= 120) {
            ctx.fillStyle = '#ffffff';//解决窗口缩放时圆点变黑
            ctx.strokeStyle = 'rgba(255,255,255,' + (1 - distance / 120) + ')';
            ctx.save();
            ctx.beginPath();
            ctx.moveTo(p1x, p1y);
            ctx.lineTo(p2x, p2y);
            ctx.stroke();
            ctx.restore();
        }
    }
    
  • 这里只有一个判断,当两点距离小于等于120时才画线,根据两点距离不同,线的粗细也在变化
  • 最后就是在drawCanvas函数中调用了,逻辑:每次画一个点的时候,循环所有的点,当其它点距离当前点距离小于等于120时,画线
    $.each(pointArry, function (index) {
        if (index != i) {
            drawLine(ctx, pointArry[i].x, pointArry[i].y, this.x, this.y);
        }
    });
    

  3.第三步就是让这些东西动起来,毫无疑问就是定时器了,这里用requestAnimationFrame递归,原因不用多说,性能好呗

if (window.requestAnimationFrame) timer = window.requestAnimationFrame(drawCanvas.bind(this, ctx));
    else if (window.msRequestAnimationFrame) timer = window.msRequestAnimationFrame(drawCanvas.bind(this, ctx));
    else if (window.mozRequestAnimationFrame) timer = window.mozRequestAnimationFrame(drawCanvas.bind(this, ctx));
    else if (window.webkitRequestAnimationFrame) timer = window.webkitRequestAnimationFrame(drawCanvas.bind(this, ctx));
  • 不要忘了在resize回调中取消动画哦!!!

  4.第四步就看需求了,鼠标移动,鼠标附近的点与鼠标连线,其实经过上面的思路,这也很容易实现了,就是或取鼠标坐标,在循环画点时,与鼠标连线就可以了

$canvas.on('mousemove', function (ev) {
    ev = ev || event;
    mouseX = ev.offsetX;
    mouseY = ev.offsetY;
});
//drawCanvas函数中
if (mouseX > 0 && mouseY > 0) {
    drawLine(ctx, mouseX, mouseY, this.x, this.y);
}

至此大功告成

  • 大家可以直接看效果
  • 小伙伴们如果有更好的方案,请分享一下,互相学习

如需转载,请注明出处:http://www.aaronxue.top/2017/12/Canvas粒子背景效果.html