Calculator of PI

by maxell4o

HTML

<axis>
  <collisions>Click on Document to RUN</collisions>
</axis>

CSS

body {
  margin: 0;
}

axis {
  display: flex;
  align-items: flex-end;
  height: 250px;
  box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
}

collisions {
  display: inline-block;
  position: absolute;
  top: 10px;
  font-size: 18px;
  left: 10px;
}

collisions.done {
  color: green;
}

block {
  display: flex;
  background: #ccc;
  border: 2px #999 solid;
  box-sizing: border-box;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  color: #333;
  position: absolute;
}

JavaScript

// You can define number of digits that will be generated
// At the last line in CalculatePi constructor param
// The Animation will stop 1 second after complete

class Block {
  constructor(x, w, v, m) {
    this.x = x;
    this.w = w;
    this.v = v;
    this.m = m;

    this.el = null;
    this.display();
  }

  display() {
    let block = document.createElement('block');
    block.style.left = `${Math.floor(this.x)}px`;
    block.style.width = `${this.w}px`;
    block.style.height = `${this.w}px`;
    block.innerText = `${this.m.toLocaleString()} kg`;
    this.el = block;
    document.querySelector('axis').append(block);
  }

  update() {
    this.x += this.v;
  }

  updateView() {
    this.el.style.left = `${this.x}px`;
  }

  collide(b) {
    return !(this.x + this.w < b.x);
  }

  bounce(b) {
    return (this.m - b.m) / (this.m + b.m) * this.v +
      (2 * b.m / (this.m + b.m)) * b.v;
  }

  wall() {
    return this.x <= 0;
  }

  reverse() {
    this.v = this.v * -1;
  }
}

class CalculatePI {
  constructor(digits = 1) {
    this.steps = Math.pow(10, Math.floor(digits) - 1);
    this.b1 = new Block(50, 50, 0, 1);
    this.b2 = new Block(150, 160, -1 / this.steps, Math.pow(100, Math.floor(digits) - 1));

    this.animation = null;
    this.collisions = 0;
    this.collisionsRef = document.querySelector('collisions');
    document.addEventListener('click', this.run.bind(this));
  }

  run(e) {
    if (this.animation && e && e.type == 'click') {
      window.cancelAnimationFrame(this.animation);
      this.animation = null;
    } else {
      for (let i = 0; i < this.steps; i++) {
        this.render();
      }

      this.updateView();
      this.b1.updateView();
      this.b2.updateView();

      if (this.b1.v >= 0 && this.b2.v >= 0 && this.b1.v < this.b2.v) {
        this.collisionsRef.className = 'done';
        setTimeout(() => {
        	window.cancelAnimationFrame(this.animation);
        }, 1000)
      }

      this.animation =...