block by enjalot 5109a9fbd5f9a7230f17

hilbert grid

Full Screen

Working towards a Hilbert Curve based grid layout

LSystem code lifted from this block by nitaku who has many fascinating d3 experiments

TODO: more pointAlongPath blocks.

Built with blockbuilder.org

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
  <script src="lsystem.js"></script>
  <style>
    body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
    svg { width: 100%; height: 100%; }
    
    .curve {
      fill: none;
      stroke: #b5b5b5;
    }
  </style>
</head>

<body>
  <svg></svg>
  <script>
    var side = 20;
    var revealDuration = 500;
    var revealOffset = 150;
    var steps = 4

    var hilbertConfig = {
      steps: steps,
      axiom: 'A',
      rules: {
        A: '-BF+AFA+FB-',
        B: '+AF-BFB-FA+'
      }
    }
    var test = LSystem.fractalize(hilbertConfig);
    
    var angle = -Math.PI / 2;
    var testCurve = LSystem.path({
      fractal: test,
      side: side,
      angle: angle,
    })
    
    var testGrid = LSystem.grid({
      fractal: test,
      side: side,
      angle: angle
    })
    
    var color = d3.scale.linear()
      .domain([0, testGrid.length])
      .range(["#65a0ff", "#cc4e00"])
      .interpolate(d3.interpolateHcl)
    
    var svg = d3.select("svg")
    
    var g = svg.append("g")
    .attr("transform", "translate(330, 40)")
    
    var duration = testGrid.length * revealOffset;
    g.append("path").classed("curve", true)
    .attr({
      d: testCurve,
      "stroke-dasharray": function() {
        var tracklength = this.getTotalLength();
        return tracklength + " " + tracklength;
      },
      "stroke-dashoffset": function() {
        return this.getTotalLength();
      },
    })
    .transition()
      .duration(duration).delay(revealDuration/2)
      .ease("linear")
      .attrTween("stroke-dashoffset", revealAlong)
    
    g.selectAll("circle.point")
      .data(testGrid)
      .enter()
      .append("circle").classed("point", true)
      .attr({
        cx: function(d,i) { return d.x },
        cy: function(d,i) { return d.y },
        r: 4,
        fill: function(d,i) { return color(d.j) },
        opacity: 0,
      })
      .transition().duration(revealDuration)
      .delay(function(d) { return d.j * revealOffset })
      .attr({
        opacity: 1
      })
    

function revealAlong(d, i, a) {
  var l = this.getTotalLength();
  return function(t) {
    if(t > 1) { t = 1}
    return l * (1-t);
  };
};

    
  </script>
</body>

lsystem.js

// from http://bl.ocks.org/nitaku/8947871

var LSystem = window.LSystem = {}


LSystem.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 SVG path string
*/
LSystem.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;
};

LSystem.grid = function(config) {
  var angle, char, i, j, len, ref, x, y;
  angle = 0.0;
  j = 1;
  var grid = [{x: 0, y: 0, j: 0}];
  ref = config.fractal;
  for (i = 0, len = ref.length; i < len; i++) {
    //if(j >= config.data.length) return grid;
    char = ref[i];
    if (char === '+') {
      angle += config.angle;
    } else if (char === '-') {
      angle -= config.angle;
    } else if (char === 'F') {
      x = config.side * Math.cos(angle);
      y = config.side * Math.sin(angle);
      x += grid[j-1].x;
      y += grid[j-1].y;
      grid.push({
        x: x,
        y: y,
        //data: config.data[j],
        j: j
      });
      j++
    }
  }
  return grid;
}