JavaScript实现液体流动效果和鼠标交互

在现代Web应用中,动态效果和交互性已经成为了不可或缺的元素。在这篇博客中,我们将使用JavaScript创建一个液体流动效果,并添加鼠标交互功能,让用户能够与页面进行互动。

创建画布和粒子
首先,我们需要创建一个画布元素,用于绘制我们的液体流动效果。在HTML中添加以下代码:

<canvas id="canvas"></canvas>
接着,在JavaScript中获取该元素,并设置其大小与浏览器窗口相同:

const canvas = document.getElementById('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

接下来,我们需要创建液体粒子。在本例中,我们将使用一个Particle类来表示每个粒子。在类中,我们需要定义粒子的位置、大小、颜色和速度等属性。在这里,我们将定义随机速度和加速度,以使每个粒子的运动轨迹都不同。以下是Particle类的示例代码:

class Particle {
  constructor(x, y, size, color) {
    this.x = x;
    this.y = y;
    this.size = size;
    this.color = color;
    this.vx = Math.random() * 2 - 1;
    this.vy = Math.random() * 2 - 1;
    this.ax = 0;
    this.ay = 0;
  }

  update() {
    this.vx += this.ax;
    this.vy += this.ay;
    this.x += this.vx;
    this.y += this.vy;
  }

  draw(ctx) {
    ctx.fillStyle = this.color;
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
    ctx.fill();
  }
}

接下来,我们需要创建一些粒子,并将它们存储在数组中。在本例中,我们将创建200个粒子,并将它们分布在画布的随机位置上。以下是示例代码:

const numParticles = 200;
const particles = [];

for (let i = 0; i < numParticles; i++) {
  const x = Math.random() * canvas.width;
  const y = Math.random() * canvas.height;
  const size = Math.random() * 10 + 5;
  const particleColor = `rgba(255, 255, 255, ${Math.random()})`;
  particles.push(new Particle(x, y, size, particleColor));
}

现在,我们已经创建了画布和粒子,并将它们存储在数组中。接下来,我们需要绘制它们。

绘制液体
在本例中,我们将使用canvas的渐变功能来绘制液体。我们将定义两种颜色,以在液体的顶部和底部之间创建渐变。以下是绘制液体的函数:

function drawLiquid() {
  const liquidWidth = canvas.width;
  const liquidHeight = 200;
  const liquidBottom = canvas.height - liquidHeight;
  const liquidColor1 = '#0A2463';
  const liquidColor2 = '#C0C0C0';

  const liquidGradient = ctx.createLinearGradient(0, liquidBottom, 0, canvas.height);
  liquidGradient.addColorStop(0, liquidColor1);
  liquidGradient.addColorStop(1, liquidColor2);

  ctx.fillStyle = liquidGradient;
  ctx.fillRect(0, liquidBottom, liquidWidth, liquidHeight);
}

在这里,我们定义了液体的宽度、高度和颜色,并使用createLinearGradient()方法创建了一个垂直渐变。最后,我们使用fillRect()方法绘制了液体矩形。

绘制粒子
现在,我们已经绘制了液体,接下来我们需要绘制粒子。我们将使用Particle类中定义的draw()方法来绘制每个粒子。以下是绘制粒子的函数:

function drawParticles() {
particles.forEach((particle) => {
particle.update();
particle.draw(ctx);
});
}

在这里,我们遍历粒子数组,并调用每个粒子的update()和draw()方法来更新和绘制它们的位置。

现在,我们已经实现了液体和粒子的绘制。接下来,我们将添加鼠标交互功能。

添加鼠标交互

在本例中,我们将创建一个鼠标粒子,它将跟随鼠标的移动而移动,并与其他粒子产生吸引力。以下是鼠标粒子的示例代码:

class MouseParticle extends Particle {
  constructor(x, y, size, color) {
    super(x, y, size, color);
    this.mass = 10;
  }

  update(mouseX, mouseY) {
    this.x = mouseX;
    this.y = mouseY;
  }

  attractionForce() {
    particles.forEach((particle) => {
      if (particle !== this) {
        const dx = particle.x - this.x;
        const dy = particle.y - this.y;
        const distance = Math.sqrt(dx * dx + dy * dy);
        const force = (this.mass * particle.mass) / (distance * distance);
        const ax = force * dx / distance;
        const ay = force * dy / distance;
        particle.ax -= ax;
        particle.ay -= ay;
      }
    });
  }
}

const mouseParticle = new MouseParticle(0, 0, 20, 'white');
在这里,我们继承了Particle类,并重写了update()方法,以便鼠标粒子可以跟随鼠标的移动而移动。我们还添加了一个attractionForce()方法,该方法将计算鼠标粒子和其他粒子之间的引力,并将其应用于其他粒子的加速度。

接下来,我们需要在动画循环中调用鼠标移动事件监听器和绘制鼠标粒子的方法。以下是动画循环的示例代码:

```javascript
let mouseX = canvas.width / 2;
let mouseY = canvas.height / 2;

canvas.addEventListener('mousemove', (event) => {
  mouseX = event.clientX;
  mouseY = event.clientY;
});

function loop() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawLiquid();
  drawParticles();
  mouseParticle.update(mouseX, mouseY);
  mouseParticle.attractionForce();
  mouseParticle.draw(ctx);
  requestAnimationFrame(loop);
}

loop();

在这里,我们添加了一个鼠标移动事件监听器,并在每次鼠标移动时更新鼠标的坐标。接下来,我们在动画循环中调用了绘制鼠标粒子的方法,并在每次循环中更新鼠标粒子的位置和其他粒子的加速度。

现在,我们已经实现了一个具有液体流动效果和鼠标交互的动态效果。您可以将下面的代码保存到文件,在浏览器打开查看效果。

总结
在本文中,我们使用JavaScript实现了一个液体流动效果和鼠标交互的动态效果。我们创建了画布和粒子,并使用canvas的渐变功能绘制了液体。我们还添加了鼠标粒子,并在每次循环中更新了粒子的位置和加速度。这个例子展示了JavaScript在动态效果和交互性方面的强大能力,希望对您有所帮助。

完整代码

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Liquid Flow Page</title>
  <style>
    body {
      background-color: #000;
      overflow: hidden;
    }

    canvas {
      position: absolute;
      top: 0;
      left: 0;
      z-index: -1;
    }

    h1 {
      font-size: 80px;
      color: #fff;
      text-align: center;
      margin-top: 200px;
    }
  </style>
</head>
<body>
  <h1>Liquid Flow Page</h1>
  <canvas id="canvas"></canvas>
  <script>
    // 创建canvas并设置大小
    const canvas = document.getElementById('canvas');
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    // 获取canvas上下文
    const ctx = canvas.getContext('2d');

    // 定义液体粒子的数量
    const numParticles = 200;

    // 定义液体粒子的颜色
    const particleColor = '#ff00ff';

    // 定义液体粒子的速度和加速度
    const particleSpeed = 2;
    const particleAcceleration = 0.05;

    // 定义液体的颜色
    const liquidColor1 = '#ff00ff';
    const liquidColor2 = '#00ffff';

    // 定义液体的高度和波动幅度
    const liquidHeight = 200;
    const liquidAmplitude = 50;

    // 定义鼠标粒子对象
    class MouseParticle {
      constructor(x, y, size, color) {
        this.x = x;
        this.y = y;
        this.size = size;
        this.color = color;
        this.vx = 0;
        this.vy = 0;
      }

      // 更新粒子的位置和速度
      update(x, y) {
        this.vx = (x - this.x) / 10;
        this.vy = (y - this.y) / 10;
        this.x += this.vx;
        this.y += this.vy;
      }

      // 绘制粒子
      draw() {
        ctx.fillStyle = this.color;
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
        ctx.fill();
      }
    }

    // 创建鼠标粒子对象
    const mouseParticle = new MouseParticle(canvas.width / 2, canvas.height / 2, 20, particleColor);

    // 创建液体粒子对象
    class Particle {
      constructor(x, y, size, color) {
        this.x = x;
        this.y = y;
        this.size = size;
        this.color = color;
        this.vx = Math.random() * particleSpeed - particleSpeed / 2;
        this.vy = Math.random() * particleSpeed - particleSpeed / 2;
      }

      // 更新粒子的位置和速度
      update() {
        this.x += this.vx;
        this.y += this.vy;
        this.vy += particleAcceleration;
      }

      // 绘制粒子
      draw() {
        ctx.fillStyle = this.color;
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
        ctx.fill();
      }

      // 计算粒子和鼠标粒子之间的距离
      distanceToMouse() {
        const dx = this.x - mouseParticle.x;
        const dy = this.y - mouseParticle.y;
        return Math.sqrt(dx * dx + dy * dy);
      }

      // 计算粒子和鼠标粒子之间的吸引力
      attractionForce() {
        const distance = this.distanceToMouse();
        const maxDistance = 100;
        const minDistance = 20;
        if (distance < maxDistance) {
          const force = (maxDistance - distance) / (maxDistance - minDistance);
          this.vx += (mouseParticle.vx * force) / 2;
          this.vy += (mouseParticle.vy * force) / 2;
        }
      }
    }

    // 创建液体粒子数组
    const particles = [];
    for (let i = 0; i < numParticles; i++) {
      const x = Math.random() * canvas.width;
      const y = Math.random() * canvas.height;
      const size= Math.random() * 10 + 5;
particles.push(new Particle(x, y, size, particleColor));
}

// 绘制液体
function drawLiquid() {
  const waveOffset = performance.now() / 1000;
  const liquidWidth = canvas.width;
  const liquidBottom = canvas.height - liquidHeight;

  const liquidGradient = ctx.createLinearGradient(0, liquidBottom, 0, canvas.height);
  liquidGradient.addColorStop(0, liquidColor1);
  liquidGradient.addColorStop(1, liquidColor2);

  ctx.fillStyle = liquidGradient;
  ctx.beginPath();
  ctx.moveTo(0, liquidBottom);
  for (let x = 0; x <= liquidWidth; x += 10) {
    const waveX = x / liquidWidth * Math.PI * 2;
    const waveY = Math.sin(waveX + waveOffset) * liquidAmplitude + liquidBottom;
    ctx.lineTo(x, waveY);
  }
  ctx.lineTo(canvas.width, canvas.height);
  ctx.lineTo(0, canvas.height);
  ctx.closePath();
  ctx.fill();
}

// 绘制粒子和鼠标粒子
function drawParticles() {
  particles.forEach((particle) => {
    particle.update();
    particle.attractionForce();
    particle.draw();
  });
  mouseParticle.update(mouseX, mouseY);
  mouseParticle.draw();
}

// 动画循环
let mouseX = canvas.width / 2;
let mouseY = canvas.height / 2;
canvas.addEventListener('mousemove', (event) => {
  mouseX = event.clientX;
  mouseY = event.clientY;
});

function loop() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawLiquid();
  drawParticles();
  requestAnimationFrame(loop);
}

loop();
</script> </body> </html>
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值