前端canvas粒子动画背景(带鼠标跟随和点击散开)

本文详细介绍了一款基于canvas的互动粒子动画的实现过程,包括粒子移动、鼠标跟随、点击散开等功能,以及代码细节。
该文章已生成可运行项目,

目录

闲聊

看下效果

先贴下代码吧

大概说一下流程

下面让我来详细说一下

1、初始化基础属性 

2、添加鼠标移动事件并实时更新鼠标坐标 

3、通过随机数生成粒子的坐标和横纵轴速度

4、渲染粒子并将粒子对象保存在数组中

5、调用requestAnimationFrame启动动画,使粒子移动起来

6、通过横纵坐标和速度计算粒子位置

7、计算与鼠标距离进行坐标的修正

8、计算与鼠标距离并进行连线

9、计算粒子直接的距离并进行连线

10、添加鼠标点击事件并调用粒子的散开事件

11、通过与鼠标的距离和相对位置进行计算来重新给粒子添加速度

12、监听页面大小变化来初始化画布

总结


闲聊

一年前觉得别人写的贼酷贼神奇的canvas粒子动画背景,一年后自己写了一个更nb的,hahahaha!

好吧,其实也没啥难的,前后大概花了俩小时,只不过是最近才正儿八经学了一下canvas,写个东西来练练手。

言归正传,这个粒子背景的粒子移动和粒子直接的连线以及和鼠标的连线都很简单,两个难点在于鼠标跟随和点击散开,下面的介绍中我将重点说一下这两个功能点。

看下效果

没有鼠标?截图给隐藏掉了,位置就不用我说了吧。

gif好糊啊= =

先贴下代码吧

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Starry</title>
</head>
<body>
  <div style="position: fixed;top: 0;left:0;bottom: 0;right: 0;z-index: 0">
    <canvas id="canvas" style="background-color: rgb(50,64,87);"></canvas>
  </div>

<script type="text/javascript">
  const canvas = document.getElementById('canvas')
  const ctx = canvas.getContext('2d')
  let width = window.innerWidth
  let height = window.innerHeight

  let dotsNum = 80 // 点的数量
  let radius = 1 // 圆的半径,连接线宽度的一半
  let fillStyle = 'rgba(255,255,255,0.5)' // 点的颜色
  let lineWidth = radius * 2
  let connection = 120 // 连线最大距离
  let followLength = 80 // 鼠标跟随距离

  let dots = []
  let animationFrame = null
  let mouseX = null
  let mouseY = null

  function addCanvasSize () { // 改变画布尺寸
    width = window.innerWidth
    height = window.innerHeight
    canvas.width = width
    canvas.height = height
    ctx.clearRect(0, 0, width, height)
    dots = []
    if (animationFrame) window.cancelAnimationFrame(animationFrame)
    initDots(dotsNum)
    moveDots()
  }

  function mouseMove (e) {
    mouseX = e.clientX
    mouseY = e.clientY
  }

  function mouseOut (e) {
    mouseX = null
    mouseY = null
  }

  function mouseClick () {
    for (const dot of dots) dot.elastic()
  }

  class Dot {
    constructor(x, y) {
      this.x = x
      this.y = y
      this.speedX = Math.random() * 2 - 1
      this.speedY = Math.random() * 2 - 1
      this.follow = false
    }
    draw () {
      ctx.beginPath()
      ctx.arc(this.x, this.y, radius, 0, 2 * Math.PI)
      ctx.fill()
      ctx.closePath()
    }
    move () {
      if (this.x >= width || this.x <= 0) this.speedX = -this.speedX
      if (this.y >= height || this.y <= 0) this.speedY = -this.speedY
      this.x += this.speedX
      this.y += this.speedY
      if (this.speedX >= 1) this.speedX--
      if (this.speedX <= -1) this.speedX++
      if (this.speedY >= 1) this.speedY--
      if (this.speedY <= -1) this.speedY++
      this.correct()
      this.connectMouse()
      this.draw()
    }
    correct () { // 根据鼠标的位置修正
      if (!mouseX || !mouseY) return
      let lengthX = mouseX - this.x
      let lengthY = mouseY - this.y
      const distance = Math.sqrt(lengthX ** 2 + lengthY ** 2)
      if (distance <= followLength) this.follow = true
      else if (this.follow === true && distance > followLength && distance <= followLength + 8) {
        let proportion = followLength / distance
        lengthX *= proportion
        lengthY *= proportion
        this.x = mouseX - lengthX
        this.y = mouseY - lengthY
      } else this.follow = false
    }
    connectMouse () { // 点与鼠标连线
      if (mouseX && mouseY) {
        let lengthX = mouseX - this.x
        let lengthY = mouseY - this.y
        const distance = Math.sqrt(lengthX ** 2 + lengthY ** 2)
        if (distance <= connection) {
          opacity = (1 - distance / connection) * 0.5
          ctx.strokeStyle = `rgba(255,255,255,${opacity})`
          ctx.beginPath()
          ctx.moveTo(this.x, this.y)
          ctx.lineTo(mouseX, mouseY);
          ctx.stroke();
          ctx.closePath()
        }
      }
    }
    elastic () { // 鼠标点击后的弹射
      let lengthX = mouseX - this.x
      let lengthY = mouseY - this.y
      const distance = Math.sqrt(lengthX ** 2 + lengthY ** 2)
      if (distance >= connection) return
      const rate = 1 - distance / connection // 距离越小此值约接近1
      this.speedX = 40 * rate * -lengthX / distance
      this.speedY = 40 * rate * -lengthY / distance
    }
  }

  function initDots (num) { // 初始化粒子
    ctx.fillStyle = fillStyle
    ctx.lin
本文章已经生成可运行项目
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值