|
<!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> |