block by enjalot e662bb2e2c0783ee82f9

hilbert grid creeping

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

forked from enjalot‘s block: hilbert grid marching

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: 4,
        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("sin")
        .duration(function(d) {
        if((d + offset) % testGrid.length === testGrid.length -1) {
          return 1000
        } else {
          return 500
        }
        })
        .delay(function(d,i) { return d * 50 })
        .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;
}