Introduction - Random Number Distribution
Random number generators are algorithmic and usually also deterministic. If they’re started from the same initial state (given the same seed, input or whatever), they’ll create the same random numbers.
Processing and JavaScript both have random number generators exhibiting this property. They also exhibit roughly uniform spread of probabilities. Over time, the proprotions of numbers picked evens out. They both generate random numbers between 0 and 1, with many decimal points of precision, so the picks are rarely the same but they’re close enough that approximations or dividing into ranges will demonstrate the uniformity.
In Processing
The tutorial shows a simple graph-drawing sketch. It divides the random number generator’s output into twenty equal sized ranges and plots a graph showing the count of picks within this range. The heights of the columns in the graph grow over time, but roughly evenly. I just copied the code from the tutorial so it’s not included here.
In JavaScript
The tutorial doesn’t directly invite play with the Processing version of the random number distribution graph, and so it seems a little odd to recreate it as-is in JavaScript. However, I want to get my head around using the Canvas for data-visualisation as well as simulation, making this totally relevant.
Frames
I decided to begin modularising the code. I created a namespace called Frames
and gave it a couple of useful functions (just the setupCanvas
and a clearContext
methods). Internally, Frames’s closure keeps a hold of the drawing context to be used from call to call (avoiding the need to pass the context in from other objects, which would be a weird interface). I did this simply to begin the idea of a helper module for the code. It’ll mutate over time. This is almost certainly premature.
var Frames = ( function () {
var context;
//
// helper functions
//
function setupCanvas(width, height) {
var canvas = document.createElement( 'canvas' );
context = canvas.getContext( '2d' );
canvas.width = width || window.innerWidth;
canvas.height = width || window.innerHeight;
document.body.appendChild( canvas );
return context;
}
function clearContext () {
context.clearRect( 0, 0, context.canvas.width, context.canvas.height );
}
return {
setupCanvas: setupCanvas,
clearContext: clearContext
};
})();
The graph
Then I reimplemented the random number generator’s distribution graph.
(function( Frames ){
var RANDOMS_COUNT = 20;
var context, randomCounts;
//
// implement these functions so the "framework" will run
//
function setup () {
var loop = RANDOMS_COUNT;
randomCounts = [];
while( loop-- ) randomCounts.push( 0 );
context = Frames.setupCanvas( 640, 240 );
}
function draw () {
var columnWidth = context.canvas.width / RANDOMS_COUNT;
var columnHeight = context.canvas.height;
var index = parseInt( Math.random() * RANDOMS_COUNT, 10 );
var step;
Frames.clearContext();
randomCounts[ index ] += 1;
context.fillStyle = 'rgb(175, 175, 175)';
context.strokeStyle = 'black';
for( step = 0; step < RANDOMS_COUNT; step++ ) {
context.fillRect( step * columnWidth, columnHeight - randomCounts[ step ], columnWidth - 1, randomCounts[ step ] );
}
}
//
// the framework/helpers/etc
// setup and draw loop
//
setup();
requestAnimationFrame( function drawLoop () {
draw();
requestAnimationFrame( drawLoop );
});
})( Frames );
Continuing to modularise the code, I wrapped the “program” in an IIFE[1], passing in the Frames
object.
(function( Frames ){
// module code
})( Frames );
This pattern forces Frames
to be defined before it’s consumed. If you don’t do this, the code will throw an error. A more rigorous build process, module system (like (RequireJS)[http://requirejs.org]) or dependancy injector would allow me to be looser with the order of definitions, but I don’t want to get into a build process at this of the learning.
I knew I’d be using the number of range divisions multiple times, so I put the total count of ranges into a variable RANDOMS_COUNT
. Capitalising the name this way hints that the value should remain constant.
Douglas Crockford’s The Good Parts encourages developers to always use braces, {
and }
, where they are optional. In his view this avoids bugs. The recommendation has become JavaScript community best practice. They’re certainly helpful. Over time, and through exposure to Ruby and CoffeeScript, I’ve grown fond of dropping them where I can. My preference now is that if I can put a loop or an if()
statement into one line, I’ll drop the braces. For example:
// from the listing above
while( loop-- ) randomCounts.push( 0 );
… or …
if( someErrorCondition ) throw "Some error message";
Also, here, the loop counts down rather than up. I did this to keep the code really short and because the ordering wasn’t important. When ordering is important, a more explicit loop (and usually a for()
) is more appropriate, in my view.