// Generated by CoffeeScript 1.4.0 (function() { var color, fractalize, global, hex_coords, new_hex, redraw; global = {}; /* compute a Lindenmayer system given an axiom, a number of steps and rules */ fractalize = function(config) { var char, i, input, output, _i, _j, _len, _ref; input = config.axiom; for (i = _i = 0, _ref = config.steps; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { output = ''; for (_j = 0, _len = input.length; _j < _len; _j++) { char = input[_j]; if (char in config.rules) { output += config.rules[char]; } else { output += char; } } input = output; } return output; }; /* convert a Lindenmayer string into an array of hexagonal coordinates */ hex_coords = function(config) { var char, current, dir, dir_i, directions, path, _i, _len, _ref; directions = [ { x: +1, y: -1, z: 0 }, { x: +1, y: 0, z: -1 }, { x: 0, y: +1, z: -1 }, { x: -1, y: +1, z: 0 }, { x: -1, y: 0, z: +1 }, { x: 0, y: -1, z: +1 } ]; /* start the walk from the origin cell, facing east */ path = [ { x: 0, y: 0, z: 0 } ]; dir_i = 0; _ref = config.fractal; for (_i = 0, _len = _ref.length; _i < _len; _i++) { char = _ref[_i]; if (char === '+') { dir_i = (dir_i + 1) % directions.length; } else if (char === '-') { dir_i = dir_i - 1; if (dir_i === -1) { dir_i = 5; } } else if (char === 'F') { dir = directions[dir_i]; current = path[path.length - 1]; path.push({ x: current.x + dir.x, y: current.y + dir.y, z: current.z + dir.z }); } } return path; }; window.main = function() { var d, data, dx, dy, gosper, height, hexes, radius, svg, width; width = 960; height = 500; svg = d3.select('body').append('svg').attr('width', width).attr('height', height); global.vis = svg.append('g').attr('transform', 'translate(660,360)'); /* create the Gosper curve */ gosper = fractalize({ axiom: 'A', steps: 3, rules: { A: 'A-FB--FB-F++AF++A-F+AF+B-', B: '+A-FB-F+B--FB--F+AF++AF+B' } }); /* convert the curve into coordinates of hex cells */ data = hex_coords({ fractal: gosper }); /* create the GeoJSON hexes */ hexes = { type: 'FeatureCollection', features: (function() { var _i, _len, _results; _results = []; for (_i = 0, _len = data.length; _i < _len; _i++) { d = data[_i]; _results.push(new_hex(d)); } return _results; })() }; /* custom projection to make hexagons appear regular (y axis is also flipped) */ radius = 12; dx = radius * 2 * Math.sin(Math.PI / 3); dy = radius * 1.5; global.path_generator = d3.geo.path().projection(d3.geo.transform({ point: function(x, y) { return this.stream.point(x * dx / 2, -(y - (2 - (y & 1)) / 3) * dy / 2); } })); /* start the animation */ redraw(hexes.features, 1); /* draw the origin */ return global.vis.append('circle').attr('cx', 0).attr('cy', 0).attr('r', 3); }; /* create a new hexagon */ new_hex = function(d) { /* conversion from hex coordinates to rect */ var x, y; x = 2 * (d.x + d.z / 2.0); y = 2 * d.z; return { type: 'Feature', geometry: { type: 'Polygon', coordinates: [[[x, y + 2], [x + 1, y + 1], [x + 1, y], [x, y - 1], [x - 1, y], [x - 1, y + 1], [x, y + 2]]] } }; }; /* update the drawing, then call again this function till data ends */ color = function(i) { var i_49, i_7; i_7 = Math.floor(i / 7); i_49 = Math.floor(i / 49); return d3.hcl((i_7 % 7) * 360 / 7, 30, (function() { switch (i_49) { case 0: return 80; case 1: return 55; case 2: return 30; case 3: return 55; case 4: return 80; case 5: return 55; case 6: return 80; } })()); }; redraw = function(data, size) { return global.vis.selectAll('.hex').data(data.slice(0, size)).enter().append('path').attr('class', 'hex').attr('d', global.path_generator).attr('fill', function(d, i) { return color(i); }).transition().duration(60).each('end', (function() { if (size > data.length) { return; } return redraw(data, size + 1); })); }; }).call(this);