(function() { var fractalize, global, hex_coords, new_hex; global = {}; /* compute a Lindenmayer system given an axiom, a number of steps and rules */ fractalize = function(config) { var char, i, input, output, _i, _len, _ref; input = config.axiom; for (i = 0, _ref = config.steps; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) { output = ''; for (_i = 0, _len = input.length; _i < _len; _i++) { char = input[_i]; 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 coords, dx, dy, e, gosper, height, hexes, i, path_generator, radius, seq, 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(540,10)'); /* create the input sequence (random length between 1000 and 2401) */ /* give the element a random value (random choice between uniform and triangular distribution) */ seq = (function() { var _ref, _results; _results = []; for (i = 0, _ref = 1000 + Math.floor(Math.random() * 1401); 0 <= _ref ? i <= _ref : i >= _ref; 0 <= _ref ? i++ : i--) { _results.push(Math.random() > 0.5 ? Math.random() : (Math.random() + Math.random()) / 2); } return _results; })(); /* sort the sequence by value */ seq.sort(); /* create the Gosper curve */ gosper = fractalize({ axiom: 'A', steps: 4, rules: { A: 'A+BF++BF-FA--FAFA-BF+', B: '-FA+BFBF++BF+FA--FA-B' } }); /* convert the curve into coordinates of hex cells */ coords = hex_coords({ fractal: gosper }); /* create the GeoJSON hexes */ hexes = { type: 'FeatureCollection', features: (function() { var _len, _results; _results = []; for (i = 0, _len = seq.length; i < _len; i++) { e = seq[i]; _results.push(new_hex(coords[i], e)); } return _results; })() }; /* custom projection to make hexagons appear regular (y axis is also flipped) */ radius = 5; dx = radius * 2 * Math.sin(Math.PI / 3); dy = radius * 1.5; 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); } })); /* draw the cells */ global.vis.selectAll('.hex').data(hexes.features).enter().append('path').attr('class', 'hex').attr('d', path_generator).append('title'); recolor(false); return document.getElementById('default').focus(); }; /* color the cells according to the selected quantization */ window.recolor = function(quantization) { /* define a quantize scale */ var colorify, perc, quantize; if (quantization !== false) { quantize = d3.scale.quantize().domain([0, 1]).range(d3.range(0, 1, 1.0 / quantization)); } else { quantize = function(x) { return x; }; } /* define a linear color scale */ colorify = d3.scale.linear().domain([0, 1]).range(['rgb(247,251,255)', 'rgb(8,48,107)']).interpolate(d3.interpolateHcl); /* define a percentage format */ perc = d3.format('.4p'); return global.vis.selectAll('.hex').attr('fill', function(d) { return colorify(quantize(d.properties['value'])); }).attr('stroke', function(d) { return colorify(quantize(d.properties['value'])); }).select('title').text(function(d) { return "" + (perc(d.properties['value'])) + " > " + (perc(quantize(d.properties['value']))); }); }; /* create a new hexagon */ new_hex = function(c, e) { /* conversion from hex coordinates to rect */ var x, y; x = 2 * (c.x + c.z / 2.0); y = 2 * c.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]]] }, properties: { 'value': e } }; }; }).call(this);