Confetti explosion

https://ko-fi.com/simren https://www.buymeacoffee.com/simren

by Simon

HTML

<body style="display: flex;align-items: center;justify-content: center">
  <div id="explodeEl" class="button">Explode</div>
</body>

CSS

* {
  box-sizing: border-box;
}

body,
html {
  font: 'SegoeUI-Light', Candara, "Bitstream Vera Sans", "DejaVu Sans", "Bitstream Vera Sans", "Trebuchet MS", Verdana, "Verdana Ref", sans-serif;
  font-family: 'SegoeUI-Light', Candara, "Bitstream Vera Sans", "DejaVu Sans", "Bitstream Vera Sans", "Trebuchet MS", Verdana, "Verdana Ref", sans-serif;
  margin: 0;
  padding: 0;
  height: 100%;
}

.button {
  display: inline-block;
  text-transform: uppercase;
  text-align: center;
  padding: 5px;
  font-size: 2em;
  font-weight: 700;
  text-decoration: none;
  border-radius: 5px;
  color: #999;
  background: #ffffff;
  background: linear-gradient(to bottom, #ffffff 0%, #f1f1f1 50%, #e1e1e1 51%, #f6f6f6 100%);
  box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.5);
  cursor: pointer;
  white-space: nowrap;
}

JavaScript

class Confetti {
  constructor(colours, particles, velocity, gravity) {
    if (typeof(colours) == 'object') {
      this.colours = colours;
    } else {
      this.colours = ['#ffc000', '#ff3b3b', '#ff8400'];
    }
    if (typeof(particles) == 'number') {
      this.particles = particles;
    } else {
      this.particles = 25;
    }
    if (typeof(velocity) == 'number') {
      this.velocity = velocity
    } else {
      this.velocity = 1
    }
    if (typeof(gravity) == 'number') {
      this.gravity = gravity
    } else {
      this.gravity = 0.1
    }
  }
  explode = (x, y) => {
    let particles = [];
    let ratio = window.devicePixelRatio;
    let c = document.createElement('canvas');
    let ctx = c.getContext('2d');

    c.style.position = 'fixed';
    c.style.left = (x - 250) + 'px';
    c.style.top = (y - 250) + 'px';
    c.style.pointerEvents = 'none';
    c.style.width = 500 + 'px';
    c.style.height = 500 + 'px';
    c.style.zIndex = 100;
    c.width = 500 * ratio;
    c.height = 500 * ratio;
    document.body.appendChild(c);

    for (var i = 0; i < this.particles; i++) {
      particles.push({
        x: c.width / 2,
        y: c.height / 2,
        width: this.r(3, 10),
        height: this.r(3, 10),
        colour: this.colours[Math.floor(Math.random() * this.colours.length)],
        direction: this.r(0, 360),
        rotation: this.r(0, 360),
        speed: this.r(5, 15),
        friction: 0.9,
        opacity: 1,
        yVel: this.velocity,
        gravity: this.gravity
      });
    }
    this.render(particles, ctx, c.width, c.height);
    setTimeout(() => document.body.removeChild(c), 1500);
  }
  render = (particles, ctx, width, height) => {
    requestAnimationFrame(() => this.render(particles, ctx, width, height));
    ctx.clearRect(0, 0, width, height);
    particles.forEach((p, i) => {

      p.x += p.speed * Math.cos(p.direction * Math.PI / 180);
      p.y += p.speed * Math.sin(p.direction * Math.PI / 180);

      let...