Canvas粒子背景效果

4,526 阅读2分钟
原文链接: aaronxue.top

Canvas粒子背景效果

 canvas |  2017年12月21日 |

  • 最近有人问我博客的背景效果怎么实现的,其实就是一个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事件所以每次初始化,先清空数组
    2. 画线
      • 封装一个函数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);
     }
    

    至此大功告成

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

HTML JavaScript canvas