var w = 960 // bl.ocks.org viewport width , h = 500 // bl.ocks.org viewport height , cw = 8 // cellWidth , ch = 8 // cellHeight , m = false // toggle mode on mousedown/mouseup , ccx = w/cw // cell count x , ccy = h/ch // cell count y , del = 100 // ms between generations , xs = d3.scale.linear().domain([0, ccx]).rangeRound([0, ccx * cw]) , ys = d3.scale.linear().domain([0, ccy]).rangeRound([0, ccy * ch]) , states = [] ; d3.range(ccx * ccy).forEach(function(c) { states[c] = Math.random() > .8; }); var vis = d3.select('body').append('svg:svg') .attr('width', w) .attr('height', h); vis.selectAll('rect') .data(states) .enter().append('svg:rect') .attr('width', cw) .attr('height', ch) .attr('x', function(d, i) { return xs(i % ccx); }) .attr('y', function(d, i) { return ys(i / ccx | 0); }) .on('mouseup', function() { m = false; }) .on('mousedown', function() { m = true; }) .on('mousemove', function(d, i) { if (m) states[i] = !states[i]; }) .classed('life', function(d) { return d; }); function createNewGeneration() { var c, x, y, t, r, b, l, n, nextState = []; for (x = 0; x < ccx; x++) { l = x - 1; r = x + 1; for (y = 0; y < ccy; y++) { t = y - 1; b = y + 1; n = states[coord(l,t)] + states[coord(x,t)] + states[coord(r,t)] + states[coord(l,y)] + states[coord(r,y)] + states[coord(l,b)] + states[coord(x,b)] + states[coord(r,b)]; nextState[c = coord(x,y)] = states[c] ? n == 2 || n == 3 : n == 3; } } return nextState; } function coord(x, y) { return coord[x +','+ y] || (coord[x +','+ y] = ccx * ((ccy + y) % ccy) + ((ccx + x) % ccx)); } function animate() { d3.selectAll('rect') .data(states = createNewGeneration()) .classed('life', function(d) { return d; }); } setInterval(animate, del);