Galton board with fabric.js

Forked from jsfiddle.net/Zombo/qbntut9s/

by Chris Maloney

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
<canvas id = 'c' width='400px' height='500px'></canvas>

JavaScript

var canvas = new fabric.Canvas('c');

const cWidth = 400;
const totalRows = 20;
const spacing = 8; //Math.floor(cWidth / (totalRows + 5));
const dotRadius = 2;
const ballRadius = 3;
const cTop = ballRadius;
const totalBalls = 200;
const maxBallsInSlot = 40; //Math.floor(2 * totalBalls / totalRows);
const duration = 20;

const numBallsInSlot = new Array(totalRows).fill(0);

drawBoard();
dropBall(0);


function drawBoard() {
  _.range(totalRows).map(row => {
    _.range(row).map(dotnum => {
      var dot = new fabric.Circle ({
        originX: 'center',
        originY: 'center',
        radius: dotRadius,
        fill: 'rgba(0, 0, 0, 1)', 
        left: cWidth / 2 - row * spacing / 2 + dotnum * spacing, 
        top: cTop + row * spacing,
      });
		  canvas.add(dot);
  	});
  });
}

function dropBall(ballNum) {
  if (ballNum >= totalBalls) return;
  const hue = Math.floor(Math.random() * 360);
  const ball = new fabric.Circle ({
    originX: 'center',
    originY: 'center',
	  radius: ballRadius,
    fill: 'hsla(' + hue + ', 100%, 50%, 1)',
    left: cWidth / 2,
    top: cTop,
  });
  canvas.add(ball);
  flipcoin(0, ball, 0);

  function flipcoin(i, ball, slotNum) {
    if (i < totalRows - 1) {
      const flip =  Math.random() < 0.5 ? 'HEADS' : 'TAILS';
      const dLeft = (flip == 'HEADS' ? '+' : '-') + '=' + 
          (spacing / 2);
      const newSlotNum = slotNum + (flip == 'HEADS' ? 1 : 0);
      ball.animate(
        { top: '+=' + spacing, 
          left: dLeft }, 
        { duration: duration,
          onChange: canvas.renderAll.bind(canvas),
          onComplete: () => flipcoin(i + 1, ball, newSlotNum), }
      );
    } 
    else {
      const balls = numBallsInSlot[slotNum];
      console.log('balls: ' + balls);
      const dTop = '+=' + (maxBallsInSlot + 1 - balls) * ballRadius * 2;
      console.log('   dTop: ' + dTop);
      ball.animate(
        { top: dTop },
        { duration: duration,
          onChange: canvas.renderAll.bind(canvas),
     ...