block by nitaku e2af207bc46782aa460c

Hilbert sequence (L-system)

Full Screen

A Lindenmayer system that draws a sequence of growing Hilbert curves. To obtain a sequence, a repetition rule (Y -> YAF) is added to the Hilbert rules (A and B).

index.js

/* compute a Lindenmayer system given an axiom, a number of steps and rules
*/


(function() {
  var curve, d, fractalize, height, svg, svg_path, transition, tweenDash, 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: 'YA',
    steps: 5,
    rules: {
      Y: 'YAF',
      A: '-BF+AFA+FB-',
      B: '+AF-BFB-FA+'
    }
  });

  d = svg_path({
    fractal: curve,
    side: 12,
    angle: Math.PI / 2
  });

  width = 960;

  height = 500;

  svg = d3.select('body').append('svg').attr('width', width).attr('height', height);

  svg.append('path').attr('class', 'curve shadow').attr('d', d).attr('transform', 'translate(100,430)');

  svg.append('path').attr('class', 'curve').attr('d', d).attr('transform', 'translate(100,430)').call(transition);

}).call(this);

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="description" content="Hilbert sequence (L-system)" />
    <title>Hilbert sequence (L-system)</title>
    <link rel="stylesheet" href="index.css">
    <script src="//d3js.org/d3.v3.min.js"></script>
</head>
<body>
  <script src="index.js"></script>
</body>
</html>

index.coffee

### compute a Lindenmayer system given an axiom, a number of steps and rules ###
fractalize = (config) ->
    input = config.axiom
    
    for i in [0...config.steps]
        output = ''
        
        for char in input
            if char of config.rules
                output += config.rules[char]
            else
                output += char
                
        input = output
        
    return output
    
### convert a Lindenmayer string into an SVG path string ###
svg_path = (config) ->
    angle = 0.0
    path = 'M0 0'
    
    for char in config.fractal
        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 = () ->
    l = this.getTotalLength()
    i = d3.interpolateString('0,' + l, l + ',' + l)
    return (t) -> i(t)
    
transition = (path) ->
    path.transition()
        .duration(20000)
        .attrTween('stroke-dasharray', tweenDash)
        
        
curve = fractalize
    axiom: 'YA'
    steps: 5
    rules:
        Y: 'YAF'
        A: '-BF+AFA+FB-'
        B: '+AF-BFB-FA+'
        
d = svg_path
    fractal: curve
    side: 12
    angle: Math.PI/2
    
width = 960
height = 500

svg = d3.select('body').append('svg')
    .attr('width', width)
    .attr('height', height)
    
svg.append('path')
    .attr('class', 'curve shadow')
    .attr('d', d)
    .attr('transform', 'translate(100,430)')
    
svg.append('path')
    .attr('class', 'curve')
    .attr('d', d)
    .attr('transform', 'translate(100,430)')
    .call(transition)
    

index.css

svg {
  background: white;
}
.curve {
  fill: none;
  stroke: black;
  stroke-width: 1.5px;
}

.shadow {
  opacity: 0.1;
}