|
<!DOCTYPE html> |
|
<head> |
|
<meta charset="utf-8"> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> |
|
<style> |
|
.axis path, .axis line { |
|
fill: none; |
|
stroke: #000; |
|
shape-rendering: crispEdges; |
|
} |
|
|
|
text { |
|
font-family: avenir, sans-serif; |
|
font-size: 11px; |
|
} |
|
</style> |
|
</head> |
|
|
|
<body> |
|
|
|
<script> |
|
var zeroHeight = 4; |
|
var margin = {top: 12, right: 10, bottom: 30+zeroHeight, left: 25}; |
|
|
|
var width = 960 - margin.left - margin.right, |
|
height = 500 - margin.top - margin.bottom; |
|
|
|
var svg = d3.select("body").append("svg") |
|
.attr("width", width + margin.left + margin.right) |
|
.attr("height", height + margin.top + margin.bottom) |
|
.append("g") |
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); |
|
|
|
var x = d3.scale.ordinal() |
|
.domain([0,1]) |
|
.rangeBands([0, width]); |
|
|
|
var y = d3.scale.linear() |
|
.domain([0,1]) |
|
.range([height, 0]); |
|
|
|
var colorRange = |
|
["#3182bd", "#6baed6", "#9ecae1", "#c6dbef", "#31a354", "#74c476", "#a1d99b", "#c7e9c0", |
|
"#e6550d", "#fd8d3c", "#fdae6b", "#fdd0a2", "#843c39", "#ad494a", "#d6616b", "#e7969c"] |
|
|
|
var colors = function(i){ |
|
var denom = Math.pow(2, 4-iteration) |
|
return colorRange[Math.floor(i*denom)] |
|
} |
|
|
|
var maxIter = 4; |
|
var iteration = 0; |
|
var values = [0]; |
|
|
|
var yAxis = d3.svg.axis() |
|
.orient("left") |
|
.ticks(1) |
|
.scale(y); |
|
|
|
var xAxis = d3.svg.axis() |
|
.orient("bottom") |
|
.ticks(1) |
|
.scale(x); |
|
|
|
svg.append("g") |
|
.attr("class", "y axis") |
|
.call(yAxis); |
|
|
|
svg.append("g") |
|
.attr("class", "x axis") |
|
.attr("transform", "translate(0," + (height+zeroHeight) + ")") |
|
.call(xAxis); |
|
|
|
|
|
var transDur = 1200 |
|
var shrink = function(){ |
|
y.domain([0, Math.pow(2, iteration+1)-1]) |
|
|
|
svg.select(".y.axis") |
|
.transition().duration(transDur) |
|
.call(yAxis.ticks(Math.min(32, y.domain()[1]))); |
|
|
|
var bars = svg.selectAll("rect.bar") |
|
.transition().duration(transDur) |
|
.attr("y", y) |
|
.attr("height", function(d){ return height - y(d) + zeroHeight}) |
|
|
|
setTimeout(subdivide, 1.1*transDur) |
|
} |
|
|
|
var subdivide = function(){ |
|
var rise = Math.pow(2, iteration); |
|
iteration++; |
|
values = values.map(function(d){ |
|
return [ d, d+rise ]; |
|
}).reduce(function(a, b) { // flatten the pairs into a single list |
|
return a.concat(b); |
|
}); |
|
|
|
x.domain(d3.range(Math.pow(2, iteration))); |
|
svg.select(".x.axis") |
|
.transition().duration(transDur) |
|
.call(xAxis.ticks(Math.min(20,x.domain()[1]))); |
|
|
|
var bars = svg.selectAll("rect.bar") |
|
.data(values, function(d){return d}) |
|
|
|
bars.enter() |
|
.append("rect") |
|
.attr("class", "bar") |
|
.attr("x", function(d,i){return x(i)}) |
|
.each(function(d,i){ |
|
var value = iteration === 1 ? d : values[i-1]; |
|
d3.select(this) |
|
.attr("y", y(value)) |
|
.attr("height", height - y(value) + zeroHeight) |
|
}) |
|
.style("fill", function(d,i){ |
|
if (iteration === 1){ |
|
return colors(i); |
|
}else{ |
|
return colors(i - i%2); // start with neightbor's color |
|
} |
|
}) |
|
.transition().duration(transDur) |
|
.attr("y", y) |
|
.attr("height", function(d){ return height - y(d) + zeroHeight}) |
|
.style("fill", function(d,i){ |
|
return colors(i); |
|
}) |
|
|
|
bars.attr("width", Math.ceil(x.rangeBand())); |
|
|
|
if (iteration <= maxIter){ |
|
setTimeout(shrink, 1.1*transDur) |
|
}else{ |
|
setTimeout(finalize, 1.1*transDur) |
|
} |
|
} |
|
|
|
var finalize = function(){ |
|
svg.selectAll() |
|
.data(values) |
|
.enter() |
|
.append("text") |
|
.text(function(d){return d}) |
|
.attr("transform", function(d, i){return "translate("+(x(i)+x.rangeBand()/2)+","+(y(d)-3)+")"}) |
|
.style("opacity", 0) |
|
.style("text-anchor", "middle") |
|
.transition().duration(transDur) |
|
.style("opacity", 1) |
|
} |
|
|
|
subdivide(); |
|
|
|
</script> |
|
</body> |