<div class="wrapper">
  <canvas id="canvas"></canvas>
  <h1 class="title">Particle</h1>
</div>

/* #7EC2C2 #9DDCDC #FFF4E1 #E67A7A */
* {
  margin: 0;
  padding: 0;
}

body {
  background-color: #a0d8ef;
}

.wrapper {
  width: 100vw;
  height: 100vh;
  position: relative;
}

.title {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 100px;
  font-weight: bold;
  color: #fff4e14d;
}
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

window.requestAnimationFrame = 
  window.requestAnimationFrame ||
  window.mozRequestAnimationFrame ||
  window.weblitRequestAnimationFrame ||
  window.msRequestAnimationFrame ||
  function (cb) { setTimeout(cb, 17); };

const NUM = 50; // 表示数
const particles = [];
const mouse = {
  x: null,
  y: null,
  radius: 50,
}

window.addEventListener('mousemove', (event) => {
  mouse.x = event.x;
  mouse.y = event.y;
});
window.addEventListener('resize', (event) => {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
});


class Particle {
  constructor(x, y, radius, directionX, directionY, index) {
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.baseRadius = radius;
    this.maxRadius = radius * 2;
    this.directionX = directionX;
    this.directionY = directionY;
    this.index = index;
  }
  _setColor () {
    if(this.index % 3 === 0) {
      ctx.fillStyle = "#fff";
      ctx.fill();
    } else if(this.index % 3 === 1) {
      ctx.strokeStyle = "#fff";
      ctx.lineWidth = 1;
      ctx.stroke()
    }else {
      ctx.globalAlpha = 0.8;
      ctx.fillStyle = "#0f0091";
      ctx.fill();
    }
  }
  render() {
    this._setColor();

    // 円をかく
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
  }
  update() {
    this._changeSpeed();
    this._setPosition();
    this.render();
  }
  _changeSpeed () {
    if (this._detectCollision() && this.radius < this.maxRadius) {
      this.radius += 1;
    } else {
      if (this.baseRadius < this.radius) this.radius -= 1;
    }
  }
  _setPosition () {
    this.x += this.directionX;
    if(this.x > canvas.width + this.radius) {
      this.x = -this.radius;
    }
  }
  _detectCollision () {
    // 衝突しているかどうか
    const dx = mouse.x - this.x;
    const dy = mouse.y - this.y;
    const distance = Math.sqrt(dx * dx + dy * dy);
    return distance < mouse.radius + this.radius;
  }
}

init();
render();

function init() {
  for(let i = 0; i < NUM; i++) {
    // particles 
    const x = Math.random() * canvas.width;
    const y = Math.floor(Math.random() * canvas.height);
    const radius = Math.floor(Math.random() * 40);
    const directionX = Math.random() * 2;
    const directionY = Math.random() * 2 - 1;
    const particle = new Particle(x, y, radius, directionX, directionY, i);
    particles.push(particle);
  }
}

function render() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  for(let i = 0; i < particles.length; i++) {
    particles[i].update();
  }
  requestAnimationFrame(render);
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.