canvas小球连线

html部分

  <canvas id="canvas">浏览器不支持</canvas>

css部分

 * {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
  }

  html,
  body {
    width: 100%;
    height: 100%;
  }

javascript部分

   const canvas = document.querySelector('#canvas')
    const ctx = canvas.getContext('2d')
    canvas.width = document.documentElement.clientWidth
    canvas.height = document.documentElement.clientHeight
    window.addEventListener('resize', () => {
      canvas.width = document.documentElement.clientWidth
      canvas.height = document.documentElement.clientHeight
    })
    // 控制小球
    let ballArr = [];
    class Ball {
      x = Math.floor(Math.random() * canvas.width) //小球生成位置,坐标是圆心
      y = Math.floor(Math.random() * canvas.height) //小球生成位置,坐标是圆心
      r = 10 //小球的半径
      color = 'gray'
      dx = (Math.floor(Math.random() * 10) - 5) || 1
      dy = (Math.floor(Math.random() * 10) - 5) || 1
      constructor() {
        ballArr.push(this)
      }
      // 小球渲染
      render() {
        // 创建一个路径
        ctx.beginPath()
        // 透明度
        ctx.globalAlpha = 1 //小球透明度
        // 画小球
        ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, false)
        ctx.fillStyle = this.color
        ctx.fill();
      }
      //小球更新
      update() {
        this.x += this.dx; //x轴更新
        // 纠正x,因为x是画布最左边到圆心距离,r是圆半径,所以左边距离不能小于圆半径,否则小球就会超出画布
        if (this.x <= this.r) {
          this.x = this.r;
        } else if (this.x >= canvas.width - this.r) { //如果左边距离大于画布减去半径距离,那么左边x就等于画布宽度减半径
          this.x = canvas.width - this.r
        }
        this.y += this.dy;
        // 纠正y,同上,也是防止超出画布
        if (this.y <= this.r) {
          this.y = this.r
        } else if (this.y >= canvas.height - this.r) { //如果画布y距离大于画布高度减去半径距离,那么y就等于画布高度减半径
          this.y = canvas.height - this.r
        }
        // 碰壁返回
        //左边距离加半径等于或超过画布宽度就让速度变相反数(右边反弹)    或者左边距离(画布左到圆心)减去半径(左边反弹))
        if (this.x + this.r >= canvas.width || this.x - this.r <= 0) {
          this.dx *= -1;
        }
        // 最下方反弹                              上方反弹
        if (this.y + this.r >= canvas.height || this.y - this.r <= 0) {
          this.dy *= -1;
        }
      }
    }
    // 创建20个小球
    for (let i = 0; i < 20; i++) {
      new Ball()
    }

    let x, y;
    canvas.addEventListener('mousemove', (e) => {
      x = e.offsetX
      y = e.offsetY
    })
    canvas.addEventListener('mouseout', (e) => {
      console.log('鼠标移出页面');
      x = null
      y = null
    })
    // 生成线
    function makeLine(distance, moveTo, lineTo) {
      // 两个小球距离小于150,就画上直线。超过150不需要清除线,因为画布每次都会清空
      if (distance <= 150) {
        ctx.strokeStyle = "#000"
        ctx.beginPath();
        /* 
          线的透明度,根据当前已经连线的小球距离进行线的透明度设置
          距离越近透明度越大,越远越小
        */
        ctx.globalCompositeOperation = 'destination-over' //让线在小球下面盖住
        ctx.globalAlpha = 1 - distance / 150; //这里是线透明度
        ctx.moveTo(moveTo.x, moveTo.y)
        ctx.lineTo(lineTo.x, lineTo.y)
        ctx.closePath();
        ctx.stroke();
      }
    }
    setInterval(() => {
      // 清除画布
      ctx.clearRect(0, 0, canvas.width, canvas.height)
      // 小球渲染更新
      ballArr.forEach(ballObj => {
        ballObj.update();
        ballObj.render();
      });
      // 画线逻辑
      for (let i = 0; i < ballArr.length; i++) {
        for (let j = i + 1; j < ballArr.length; j++) {
          // 计算第i个小球和其他小球的距离,这里使用勾股定理。sqrt求平方根,pow是一个底数的几次方,这里是平方
          let distance = Math.sqrt(Math.pow(ballArr[i].x - ballArr[j].x, 2) + Math.pow(ballArr[i].y - ballArr[j].y,
            2))
          // 两个小球距离小于150,就画上直线。超过150不需要清除线,因为画布每次都会清空
          makeLine(distance, ballArr[i], ballArr[j])
        }
        // 鼠标到每个希求距离
        let mouseDistance = Math.sqrt(Math.pow(ballArr[i].x - x, 2) + Math.pow(ballArr[i].y - y, 2))
        makeLine(mouseDistance, ballArr[i], {
          x,
          y
        })
      }
    }, 1000 / 60);

效果图

图一

图二

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值