Created
August 2, 2012 06:11
-
-
Save mbecica/3234310 to your computer and use it in GitHub Desktop.
Stacked Bar d3 transition in canvas
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE HTML> | |
<head> | |
<title>Stacked bar d3 canvas transition</title> | |
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/d3/2.8.1/d3.v2.min.js"></script> | |
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js"></script> | |
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/zepto/1.0rc1/zepto.min.js"></script> | |
</head> | |
<body> | |
<div id="graphs"></div> | |
<button id="switch">Switch</button> | |
<script type="text/javascript"> | |
$(function() { | |
var w = 720, | |
h = 300, | |
p = [0, 25, 15, 0], | |
transition_count = 0, | |
last = [], | |
x = d3.scale.ordinal().rangeRoundBands([0, w - p[1] - p[3]]), | |
y = d3.scale.linear().range([0, h - p[0] - p[2]]), | |
z = d3.scale.ordinal().range(["darkgray", "lightblue"]), | |
parse = d3.time.format("%b %e").parse, | |
format = d3.time.format("%b %e"), | |
swap = true; | |
$("#graphs").append("<canvas width="+w+" height="+h+" id='canvas'></canvas"); | |
var canvas = document.getElementById("canvas"); | |
var ctx = canvas.getContext('2d'); | |
d3.json("revenue.json", function(json) { | |
//Draw graph on load | |
var data = d3.layout.stack()(_(json[0]).map(function(row) { | |
return row; | |
})); | |
render(data); | |
last = data; | |
}); | |
$('#switch').click(function() { | |
if (swap) { | |
transition("rev-two.json", ++transition_count); | |
swap = false; | |
} else { | |
transition("revenue.json", ++transition_count); | |
swap = true; | |
} | |
}); | |
function render(data) { | |
// Compute the x-domain and y-domain. | |
y.domain([0, d3.max(data.map(function(d) { | |
return d3.max(d, function(e, i) { | |
return data[1][i].y + data[0][i].y | |
})}))*1.1]); | |
x.domain(data[1].map(function(d) { return d.x; })); | |
// y axis | |
y.ticks(4).map(drawAxis); | |
// Draw bars | |
_(data).each(function(row, i) { | |
_(row).each(function(d, j) { | |
drawBar(i, j, d); | |
}); | |
}); | |
}; | |
function drawBar(i, j, d) { | |
ctx.fillStyle = z(i); | |
ctx.fillRect(p[1]+x(d.x)+1, h-p[2]-y(d.y0)-y(d.y), x.rangeBand()-1, y(d.y)); | |
// x axis | |
if (j%7 == 0 || j==0) { | |
ctx.fillStyle = "#999"; | |
ctx.fillText(format(new Date(d.x)), x(d.x) + x.rangeBand(), h-2); | |
} | |
}; | |
function drawAxis(a) { | |
//draw y axis | |
ctx.fillStyle = "#999"; | |
if (a != 0) { | |
ctx.fillText(a, 0, h-p[2]-y(a)+12); | |
ctx.lineWidth = .1; | |
ctx.beginPath(); | |
ctx.moveTo(0, h-p[2]-y(a)); | |
ctx.lineTo(w, h-p[2]-y(a)); | |
ctx.stroke(); | |
} else { | |
ctx.lineWidth = 1; | |
ctx.beginPath(); | |
ctx.moveTo(0, h-p[2]-y(a)+1); | |
ctx.lineTo(w, h-p[2]-y(a)+1); | |
ctx.stroke(); | |
} | |
}; | |
function transition(file, count) { | |
d3.json(file, function(json) { | |
var data = d3.layout.stack()(_(json[0]).map(function(row) { return row; })); | |
// find next positions by interpolating arrays | |
var transition = d3.interpolate(position(last), position(data)); | |
// run transition | |
d3.timer(function(t) { | |
// abort old transition | |
if (count < transition_count) return true; | |
clear(); | |
if (t > 1000) { | |
last = data; | |
render(last); | |
return true | |
}; | |
last = transition(t/1000); | |
render(resumeData(last)); | |
}); | |
}); | |
}; | |
function resumeData(data) { | |
return data.map(function(d) { | |
return d.map(function(e) { | |
return {"x":e[0],"y":e[1],"y0":e[2]} | |
}) | |
}); | |
} | |
function position(data) { | |
return data.map(function(d) { | |
return d.map(function(e) { | |
return [e.x,e.y,e.y0] | |
}) | |
}); | |
}; | |
// clear canvas | |
function clear() { | |
ctx.clearRect(0,0,w,h); | |
}; | |
}); | |
</script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[{ | |
"gross":[{"x":1340938902744,"y":478},{"x":1341025302744,"y":487},{"x":1341111702744,"y":473},{"x":1341198102744,"y":241},{"x":1341284502744,"y":10},{"x":1341370902744,"y":293},{"x":1341457302744,"y":254},{"x":1341543702744,"y":165},{"x":1341630102744,"y":223},{"x":1341716502744,"y":69},{"x":1341802902744,"y":432},{"x":1341889302744,"y":328},{"x":1341975702744,"y":27},{"x":1342062102744,"y":273},{"x":1342148502744,"y":248},{"x":1342234902744,"y":105},{"x":1342321302744,"y":418},{"x":1342407702744,"y":320},{"x":1342494102744,"y":355},{"x":1342580502744,"y":303},{"x":1342666902744,"y":155},{"x":1342753302744,"y":89},{"x":1342839702744,"y":54},{"x":1342926102744,"y":475},{"x":1343012502744,"y":138},{"x":1343098902744,"y":436},{"x":1343185302744,"y":73},{"x":1343271702744,"y":404},{"x":1343358102744,"y":434},{"x":1343444502744,"y":327}], | |
"total":[{"x":1340938902744,"y":736},{"x":1341025302744,"y":440},{"x":1341111702744,"y":1089},{"x":1341198102744,"y":566},{"x":1341284502744,"y":1385},{"x":1341370902744,"y":1420},{"x":1341457302744,"y":1471},{"x":1341543702744,"y":724},{"x":1341630102744,"y":860},{"x":1341716502744,"y":392},{"x":1341802902744,"y":670},{"x":1341889302744,"y":1395},{"x":1341975702744,"y":373},{"x":1342062102744,"y":659},{"x":1342148502744,"y":169},{"x":1342234902744,"y":850},{"x":1342321302744,"y":1409},{"x":1342407702744,"y":1070},{"x":1342494102744,"y":1138},{"x":1342580502744,"y":32},{"x":1342666902744,"y":1169},{"x":1342753302744,"y":594},{"x":1342839702744,"y":79},{"x":1342926102744,"y":337},{"x":1343012502744,"y":988},{"x":1343098902744,"y":1435},{"x":1343185302744,"y":169},{"x":1343271702744,"y":17},{"x":1343358102744,"y":1181},{"x":1343444502744,"y":1268}] | |
}] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[{ | |
"gross":[{"x":1340938902744,"y":69},{"x":1341025302744,"y":450},{"x":1341111702744,"y":350},{"x":1341198102744,"y":591},{"x":1341284502744,"y":283},{"x":1341370902744,"y":18},{"x":1341457302744,"y":115},{"x":1341543702744,"y":345},{"x":1341630102744,"y":302},{"x":1341716502744,"y":412},{"x":1341802902744,"y":224},{"x":1341889302744,"y":463},{"x":1341975702744,"y":566},{"x":1342062102744,"y":444},{"x":1342148502744,"y":402},{"x":1342234902744,"y":295},{"x":1342321302744,"y":586},{"x":1342407702744,"y":549},{"x":1342494102744,"y":564},{"x":1342580502744,"y":398},{"x":1342666902744,"y":326},{"x":1342753302744,"y":476},{"x":1342839702744,"y":15},{"x":1342926102744,"y":428},{"x":1343012502744,"y":566},{"x":1343098902744,"y":519},{"x":1343185302744,"y":393},{"x":1343271702744,"y":448},{"x":1343358102744,"y":42},{"x":1343444502744,"y":336}], | |
"total":[{"x":1340938902744,"y":3972},{"x":1341025302744,"y":1052},{"x":1341111702744,"y":2768},{"x":1341198102744,"y":2607},{"x":1341284502744,"y":341},{"x":1341370902744,"y":362},{"x":1341457302744,"y":1357},{"x":1341543702744,"y":3611},{"x":1341630102744,"y":2133},{"x":1341716502744,"y":270},{"x":1341802902744,"y":4624},{"x":1341889302744,"y":3666},{"x":1341975702744,"y":993},{"x":1342062102744,"y":4573},{"x":1342148502744,"y":4580},{"x":1342234902744,"y":3261},{"x":1342321302744,"y":4842},{"x":1342407702744,"y":3786},{"x":1342494102744,"y":554},{"x":1342580502744,"y":740},{"x":1342666902744,"y":1382},{"x":1342753302744,"y":2851},{"x":1342839702744,"y":1605},{"x":1342926102744,"y":1828},{"x":1343012502744,"y":1612},{"x":1343098902744,"y":2482},{"x":1343185302744,"y":3854},{"x":1343271702744,"y":1239},{"x":1343358102744,"y":2282},{"x":1343444502744,"y":3141}] | |
}] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE HTML> | |
<head> | |
<title>Stacked bar d3 svg transition</title> | |
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/d3/2.8.1/d3.v2.min.js"></script> | |
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js"></script> | |
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/zepto/1.0rc1/zepto.min.js"></script> | |
</head> | |
<body> | |
<button id="switch">Switch</button> | |
<script type="text/javascript"> | |
$(function() { | |
var w = 700, | |
h = 300, | |
p = [20, 50, 30, 20], | |
x = d3.scale.ordinal().rangeRoundBands([0, w - p[1] - p[3]]), | |
y = d3.scale.linear().range([0, h - p[0] - p[2]]), | |
z = d3.scale.ordinal().range(["darkgray", "lightblue"]), | |
parse = d3.time.format("%b %e").parse, | |
format = d3.time.format("%b %e"), | |
swap = true; | |
var svg = d3.select("body").append("svg:svg") | |
.attr("width", w) | |
.attr("height", h) | |
.append("svg:g") | |
.attr("transform", "translate(" + p[3] + "," + (h - p[2]) + ")"); | |
var renderOne = function(file) { | |
d3.json(file, function(rData) { | |
var data = rData[0]; | |
var stacks = d3.layout.stack()(_(data).map(function(row) { | |
return row; | |
})); | |
rerender(data, stacks); | |
}); | |
}; | |
d3.json("revenue.json", function(rData) { | |
var data = rData[0]; | |
var stacks = d3.layout.stack()(_(data).map(function(row) { | |
return row; | |
})); | |
render(data, stacks); | |
}); | |
$('#switch').click(function() { | |
if (swap) { | |
renderOne("rev-two.json"); | |
swap = false; | |
} else { | |
renderOne("revenue.json"); | |
swap = true; | |
} | |
}); | |
var render = function(data, stacks) { | |
// Compute the x-domain and y-domain. | |
y.domain([0, d3.max($.map(data, function(d) { | |
return d3.max(d, function(e, i) { | |
return data["total"][i].y + data["gross"][i].y | |
})}))*1.1]); | |
x.domain(data["total"].map(function(d) { return d.x; })); | |
// Add a group for each bar. | |
var bar = svg.selectAll("g.bar") | |
.data(stacks) | |
.enter().append("svg:g") | |
.attr("class", "bar") | |
.style("fill", function(d, i) { return z(i); }); | |
// Add a rect for each date. | |
var rect = bar.selectAll("rect") | |
.data(Object) | |
.enter().append("svg:rect") | |
.attr("x", function(d) { return x(d.x) + 1; }) | |
.attr("y", function(d) { return -y(d.y) - y(d.y0); }) | |
.attr("height", function(d) { return y(d.y); }) | |
.attr("width", x.rangeBand()-1); | |
// Add a label per date. | |
var label = svg.selectAll("text.xlabel") | |
.data(x.domain()) | |
.enter().append("svg:text") | |
.attr("x", function(d) { return x(d) + x.rangeBand() / 2; }) | |
.attr("y", 6) | |
.attr("text-anchor", "middle") | |
.attr("dy", ".71em") | |
.attr("class", "xlabel") | |
.text(function(d) { return format(new Date(d)) }); | |
// Add y-axis rules. | |
var rule = svg.selectAll("g.rule") | |
.data(y.ticks(3)) | |
.enter().append("svg:g") | |
.attr("class", "rule") | |
.attr("transform", function(d) { return "translate(0," + -y(d) + ")"; }); | |
rule.append("svg:line") | |
.attr("x2", w - p[1] - p[3]) | |
.attr("class", "yline") | |
.style("stroke", function(d) { return d ? "#ccc" : "#000"; }) | |
.style("stroke-opacity", function(d) { return d ? .7 : null; }); | |
rule.append("svg:text") | |
.attr("x", 0) | |
.attr("dy", "1em") | |
.attr("class", "ylabel") | |
.text(d3.format(",d")); | |
}; | |
var rerender = function(data, stacks) { | |
// Compute the x-domain and y-domain. | |
y.domain([0, d3.max($.map(data, function(d) { | |
return d3.max(d, function(e, i) { | |
return data["total"][i].y + data["gross"][i].y | |
})}))*1.1]); | |
x.domain(data["total"].map(function(d) { return d.x; })); | |
// Add a group for each bar. | |
var bar = svg.selectAll("g.bar") | |
.data(stacks); | |
// Add a rect for each date. | |
bar.selectAll("rect") | |
.data(Object) | |
.transition() | |
.duration(1000) | |
.attr("x", function(d) { return x(d.x) + 1; }) | |
.attr("y", function(d) { return -y(d.y) - y(d.y0); }) | |
.attr("height", function(d) { return y(d.y); }) | |
.attr("width", x.rangeBand()-1); | |
// Add a label per date. | |
svg.selectAll("text.xlabel") | |
.data(x.domain()) | |
.transition() | |
.duration(1000) | |
.attr("x", function(d) { return x(d) + x.rangeBand() / 2; }) | |
.attr("y", 6) | |
.text(function(d) { return format(new Date(d)) }); | |
// Add y-axis rules. | |
svg.selectAll("g.rule") | |
.data(y.ticks(3)) | |
.transition() | |
.duration(1000) | |
.attr("transform", function(d) { return "translate(0," + -y(d) + ")"; }); | |
svg.selectAll("line.yline") | |
.attr("x2", w - p[1] - p[3]) | |
.style("stroke", function(d) { return d ? "#ccc" : "#000"; }) | |
.style("stroke-opacity", function(d) { return d ? .7 : null; }); | |
svg.selectAll("text.ylabel") | |
.text(d3.format(",d")); | |
}; | |
}); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment