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),
...