block by enjalot 77cfa8eb62e34833ae7c

hilbert grid marching

Full Screen

Responding to the challenge of recreating this animation!

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

Built with blockbuilder.org

forked from enjalot‘s block: hilbert grid

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 = 15;
    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)
      */
    .attr("stroke-dashoffset", revealAlong)
    
    g.selectAll("circle.point")
      .data(d3.range(testGrid.length))
      .enter()
      .append("circle").classed("point", true)
      .attr({
        cx: function(d,i) { return testGrid[d].x },
        cy: function(d,i) { return testGrid[d].y },
        r: 6,
        fill: function(d,i) { return color(testGrid[d].j) },
        opacity: 0,
      })
      //.transition().duration(revealDuration)
      //.delay(function(d) { return testGrid[d].j * revealOffset })
      .attr({
        opacity: 1
      })
    
    function transition(offset) {
      function getI(d) {
        return (d + offset) % testGrid.length
      }
      function getNode(d) {
        return testGrid[getI(d)]
      }
      g.selectAll("circle.point").transition()
        .ease("cubic")
      .ease("linear")
        .duration(function(d) {
        if(getI(d) === 0) {
          return 0
        } else {
          return 500
        }
        })
        .delay(function(d,i) { 
        	if(getI(d) === 0) return 450
        	return 0
        })
        .attr({
          cx: function(d,i) { return getNode(d).x },
          cy: function(d,i) { return getNode(d).y },
        })
        .each("end", function(d,i) {
          //if(i !== testGrid.length - 1) return;
          if(i !== 0) return;
          transition(offset+1);
        })
    }
    transition(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;
}