(function() { // noprotect; /* compute a Lindenmayer system given an axiom, a number of steps and rules */ var curve, d, fractalize, height, svg_path, transition, tweenDash, vis, width; 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 SVG path string */ svg_path = function(config) { var angle, char, path, _i, _len, _ref; angle = 0.0; path = 'M0 0'; _ref = config.fractal; for (_i = 0, _len = _ref.length; _i < _len; _i++) { char = _ref[_i]; if (char === '+') { angle += config.angle; } else if (char === '-') { angle -= config.angle; } else if (char === 'F') { path += "l" + (config.side * Math.cos(angle)) + " " + (config.side * Math.sin(angle)); } } return path; }; /* animate the path */ /* from Mike Bostock's stroke dash interpolation example http://bl.ocks.org/mbostock/5649592 */ tweenDash = function() { var i, l; l = this.getTotalLength(); i = d3.interpolateString('0,' + l, l + ',' + l); return function(t) { return i(t); }; }; transition = function(path) { return path.transition().duration(20000).attrTween('stroke-dasharray', tweenDash); }; curve = fractalize({ axiom: 'FY', steps: 4, rules: { Y: 'Y+RFR+FLF+RFRFR+FLFLF', L: 'LF+RFR+FL-F-LFLFL-FRFR+', R: '-LFLF+RFRFR+F+RF-LFL-FR' } }); d = svg_path({ fractal: curve, side: 5, angle: Math.PI / 2 }); width = 960; height = 500; vis = d3.select('body').append('svg').attr({ width: width, height: height }).append('g').attr({ transform: "translate(" + (width / 2) + "," + (height / 2) + ")" }); vis.append('path').attr('class', 'curve shadow').attr('d', d); vis.append('path').attr('class', 'curve').attr('d', d).call(transition); vis.append('circle').attr({ r: 2, fill: 'red' }); }).call(this);