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
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
<!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> |
// 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; | |
} |