Last active
August 29, 2015 13:59
-
-
Save jayrambhia/10473767 to your computer and use it in GitHub Desktop.
Multibar transition using d3
This file contains 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
axis = function(){ | |
var ldomain = 0, rdomain = 0, lrange = 0, rrange = 0; | |
var orientation = "left", ticks = 0; | |
var xpadding = 10, ypadding = 10; | |
var plotted = false; | |
var scale, Axis, AxisGroup; | |
function chart(selection){} | |
chart.ticks = function(_) { | |
if (!arguments.length) return ticks; | |
ticks = _; | |
chart.update(); | |
return chart; | |
} | |
chart.ldomain = function(_) { | |
if (!arguments.length) return ldomain; | |
ldomain = _; | |
chart.update(); | |
return chart; | |
} | |
chart.rdomain = function(_) { | |
if (!arguments.length) return rdomain; | |
rdomain = _; | |
chart.update(); | |
return chart; | |
} | |
chart.lrange = function(_) { | |
if (!arguments.length) return lrange; | |
lrange = _; | |
chart.update(); | |
return chart; | |
} | |
chart.rrange = function(_) { | |
if (!arguments.length) return rrange; | |
rrange = _; | |
chart.update(); | |
return chart; | |
} | |
chart.orientation = function(_) { | |
if (!arguments.length) return orientation; | |
orientation = _; | |
chart.update(); | |
return chart; | |
} | |
chart.xpadding = function(_) { | |
if (!arguments.length) return xpadding; | |
xpadding = _; | |
chart.update(); | |
return chart; | |
} | |
chart.ypadding = function(_) { | |
if (!arguments.length) return ypadding; | |
ypadding = _; | |
chart.update(); | |
return chart; | |
} | |
chart.change_rrange = function(_){ | |
if(!arguments.length) return rrange; | |
rrange = _; | |
chart.update(); | |
return chart; | |
} | |
chart.plot = function(svg) { | |
plotted = true; | |
scale = d3.scale.linear() | |
.domain([ldomain, rdomain]) | |
.range([lrange, rrange]); | |
Axis = d3.svg.axis() | |
.scale(scale) | |
.orient(orientation) | |
.ticks(ticks); | |
AxisGroup = svg.append("g") | |
.attr("class", "axis") | |
.attr("transform", "translate(" + xpadding + "," + ypadding + ")") | |
.call(Axis); | |
return svg; | |
} | |
chart.update = function(){ | |
if (!plotted) {return chart;} | |
scale = d3.scale.linear() | |
.domain([ldomain, rdomain]) | |
.range([lrange, rrange]); | |
Axis = d3.svg.axis() | |
.scale(scale) | |
.orient(orientation) | |
.ticks(ticks); | |
AxisGroup.transition().duration(1000) | |
.attr("transform", "translate(" + xpadding + "," + ypadding + ")") | |
.call(Axis); | |
} | |
return chart; | |
} | |
barChart = function() { | |
var width = 600 | |
, height = 300 | |
, colorPalette = d3.scale.category20c() | |
, barWidth = 40 | |
, separation = 5 | |
, xpadding = 30 | |
, ypadding = 10 | |
, textXOffset = 15 | |
, textYOffset = 15 | |
, textYPosition = 300 | |
, yTicks = 5 | |
, xTicks = 0 | |
, maxData = 0 | |
, xrange = 0 | |
, yrange = 0 | |
, cols = 0 | |
, rows = 0 | |
, maxData = 0 | |
, xrange = 0 | |
, yrange = 0 | |
, barHeightMultiplier = 1 | |
, showAxis = true | |
, showYText = false | |
, showXText = false | |
, textSpace = 50 | |
, plotted = false; | |
var xAxis = axis() , yAxis = axis(); | |
function chart(selection) { | |
//selection.each | |
} | |
chart.plot = function() { | |
plotted = true; | |
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height); | |
if (showAxis) | |
{ | |
xAxis.ldomain(0) | |
.rdomain(rows) | |
.lrange(0) | |
.rrange(xrange) | |
.xpadding(10) | |
.ypadding(height - textSpace) | |
.orientation("bottom") | |
.ticks(xTicks) | |
.plot(svg); | |
yAxis.ldomain(0) | |
.rdomain(maxData) | |
.lrange(0) | |
.rrange(height - textSpace - ypadding) | |
.ticks(yTicks) | |
.ypadding(ypadding) | |
.xpadding(10) | |
.orientation("left") | |
.plot(svg); | |
} | |
var dataEnter = svg.selectAll("rect").data(data).enter(); | |
dataEnter.append("rect").attr("x", function(d, i) | |
{ | |
return (xpadding + (i)*(barWidth+separation)); | |
}).attr("y", function(d) | |
{ | |
return height - textSpace - d[1] * barHeightMultiplier - 1; | |
}).attr("width", function(d) | |
{ | |
return barWidth; | |
}).attr("height", function(d) | |
{ | |
return d[1] * barHeightMultiplier; | |
}).style("fill", function(d, i) {return colorPalette(i);}); | |
if (showXText) | |
{ | |
dataEnter.append("text").text(function(d) | |
{ | |
return d[0]; | |
})/* | |
.attr("x", function(d, i) | |
{ | |
return (xpadding + 20 + (i)*(barWidth+separation));; | |
}).attr("y", textYPosition)*/ | |
.attr("font-family", "sans-serif") | |
.attr("font-size", "12px") | |
.attr("fill", function(d, i){return colorPalette(i);}) | |
.attr("transform", function(d, i) | |
{ | |
var xvar = (xpadding + 20 + (i)*(barWidth+separation)); | |
var yvar = textYPosition ; | |
return "rotate(-90," + xvar + "," + yvar + ")"; | |
}); | |
} | |
return chart; | |
} | |
chart.load = function(indata) { | |
data = indata; | |
rows = data.length; | |
cols = data[0].length; | |
for(var s=0; s<rows; s++) | |
{ | |
if (maxData < Number(data[s][1])) | |
{ | |
maxData = Number(data[s][1]); | |
} | |
} | |
xrange = rows * (barWidth + separation) + xpadding; | |
yrange = maxData; | |
barHeightMultiplier = (height - ypadding - textSpace) / maxData; | |
textYPosition = height - 1; | |
return chart; | |
} | |
chart.width = function(_) { | |
if (!arguments.length) return width; | |
width = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.height = function(_) { | |
if (!arguments.length) return height; | |
height = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.separation = function(_) { | |
if (!arguments.length) return separation; | |
separation = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.xpadding = function(_) { | |
if (!arguments.length) return xpadding; | |
xpadding = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.ypadding = function(_) { | |
if (!arguments.length) return ypadding; | |
ypadding = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.xTicks = function(_) { | |
if (!arguments.length) return xTicks; | |
xTicks = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.yTicks = function(_) { | |
if (!arguments.length) return yTicks; | |
yTicks = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.barWidth = function(_) { | |
if (!arguments.length) return barWidth; | |
barWidth = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.showAxis = function(_) { | |
if (!arguments.length) return showAxis; | |
showAxis = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.showXText = function(_) { | |
if (!arguments.length) return showXText; | |
showXText = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.changeBarWidth = function(_){ | |
if (!arguments.length) return barWidth; | |
barWidth = _; | |
if (!plotted) return chart; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.changeSeparation = function(_){ | |
if (!arguments.length) return separation; | |
separation = _; | |
//if (!plotted) return chart; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.changeHeight = function(_){ | |
if (!arguments.length) return height; | |
height = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.updatePlotValues = function(){ | |
xrange = rows * (barWidth + separation) + xpadding; | |
yrange = maxData; | |
barHeightMultiplier = (height - ypadding - textSpace) / maxData; | |
textYPosition = height - 1; | |
} | |
chart.update = function(_){ | |
if (!plotted) { return chart; } | |
if(showAxis) | |
{ | |
xAxis.ldomain(0) | |
.rdomain(rows) | |
.lrange(0) | |
.rrange(xrange) | |
.xpadding(10) | |
.ypadding(height - textSpace) | |
.orientation("bottom") | |
.ticks(xTicks) | |
.update(); | |
yAxis.ldomain(0) | |
.rdomain(maxData) | |
.lrange(0) | |
.rrange(height - textSpace - ypadding) | |
.ticks(yTicks) | |
.ypadding(ypadding) | |
.xpadding(10) | |
.orientation("left") | |
.update(); | |
} | |
var barNodes = document.querySelectorAll("svg"); | |
d3.select("svg").attr("height", height).attr("width", width); | |
for(var n=0; n<barNodes.length; n++) { | |
d3.select(barNodes.item(n)).selectAll("rect").transition().duration(1000) | |
.attr("x", function(d, i) | |
{ | |
return (xpadding + (i)*(barWidth+separation)); | |
}).attr("y", function(d) | |
{ | |
return height - textSpace - d[1] * barHeightMultiplier - 1; | |
}).attr("width", function(d) | |
{ | |
return barWidth; | |
}).attr("height", function(d) | |
{ | |
return d[1] * barHeightMultiplier; | |
}).style("fill", function(d, i) {return colorPalette(i);}); | |
if (showXText) | |
{ | |
d3.select(barNodes.item(n)).selectAll("text") | |
/* | |
.attr("x", function(d, i) | |
{ | |
return (xpadding + barWidth/2 + (i)*(barWidth+separation)); | |
}).attr("y", textYPosition) | |
*/ | |
.attr("transform", function(d, i) | |
{ | |
var xvar = (xpadding + barWidth/2 + (i)*(barWidth+separation)); | |
var yvar = textYPosition ; | |
return "translate("+ (xvar) +","+(yvar)+")rotate(-90)"; | |
}); | |
} | |
} | |
} | |
//return this; | |
return chart; | |
} | |
multibarChart = function() { | |
var width = 600 | |
, height = 300 | |
, colorPalette = d3.scale.category20() | |
, barWidth = 40 | |
, separation = 5 | |
, xpadding = 10 | |
, ypadding = 10 | |
, textXOffset = 15 | |
, textYOffset = 15 | |
, textYPosition = 300 | |
, yTicks = 5 | |
, xTicks = 0 | |
, maxData = 0 | |
, xrange = 0 | |
, yrange = 0 | |
, cols = 0 | |
, rows = 0 | |
, maxData = 0 | |
, xrange = 0 | |
, yrange = 0 | |
, barHeightMultiplier = 1 | |
, showAxis = true | |
, showYText = false | |
, showXText = false | |
, textSpace = 50 | |
, plotted = false | |
, stacked = true; | |
var xAxis = axis() , yAxis = axis(); | |
function chart(selection) { | |
//selection.each | |
} | |
chart.plot = function() { | |
plotted = true; | |
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height); | |
if (showAxis) | |
{ | |
xAxis.ldomain(0) | |
.rdomain(rows) | |
.lrange(0) | |
.rrange(xrange) | |
.xpadding(10) | |
.ypadding(height) | |
.orientation("bottom") | |
.ticks(xTicks) | |
.plot(svg); | |
yAxis.ldomain(0) | |
.rdomain(maxData) | |
.lrange(0) | |
.rrange(height - ypadding) | |
.ticks(yTicks) | |
.ypadding(ypadding) | |
.xpadding(10) | |
.orientation("left") | |
.plot(svg); | |
} | |
var dataEnter = svg.selectAll("rect").data(data).enter(); | |
if(stacked) | |
{ | |
// stacked bars | |
for(var n=0; n<cols-1; n++) | |
{ | |
dataEnter.append("rect").attr("x", function(d, i) | |
{ | |
if (i == 0) { return 0; } | |
return (xpadding + 5 + (i-1)*(barWidth+separation)); | |
}).attr("y", function(d, i) | |
{ | |
if (i == 0) { return 0; } | |
var ytop = 0; | |
for(var m = cols - 1; m > n; m--) | |
{ | |
ytop += Number(d[m]); | |
} | |
return height - 1 - ytop * barHeightMultiplier; | |
}).attr("width", function(d, i) | |
{ | |
if (i == 0) { return 0; } | |
return barWidth; | |
}).attr("height", function(d, i) | |
{ | |
if (i == 0) { return 0; } | |
return d[n+1] * barHeightMultiplier; | |
}).style("fill", function(d, i) {return colorPalette(n);}) | |
.attr("row",function(d,i){if (i == 0) { return 0; }return i;}) | |
.attr("col", function(d,i){if (i == 0) { return 0; }return n+1;}); | |
} | |
} | |
else | |
{ | |
// grouped bars | |
var sBarWidth = barWidth/cols; | |
for(var n=0; n < cols - 1; n++) | |
{ | |
dataEnter.append("rect").attr("x", function(d, i) | |
{ | |
if (i == 0) { return 0; } | |
return (xpadding + 5 + (n*sBarWidth) + (i-1)*(cols-1)*(sBarWidth) + (i-1)*(separation)); | |
//return ((i-1) + 0.5) * horizontalBarDistance + (n * barWidth) + xpadding; | |
}).attr("y", function(d, i) | |
{ | |
if (i == 0) { return 0; } | |
return height - 1 - d[n+1] * barHeightMultiplier; | |
}).attr("width", function(d, i) | |
{ | |
if (i == 0) { return 0; } | |
return sBarWidth; | |
}).attr("height", function(d, i) | |
{ | |
if (i == 0) { return 0; } | |
return d[n+1] * barHeightMultiplier; | |
}).style("fill", function(d, i) {return colorPalette(n);}) | |
.attr("row",function(d,i){if (i == 0) { return 0; }return i;}) | |
.attr("col", function(d,i){if (i == 0) { return 0; }return n+1;}); | |
} | |
} | |
return chart; | |
} | |
chart.load = function(indata) { | |
data = indata; | |
rows = data.length; | |
cols = data[0].length; | |
var cData = 0; | |
for(var i=1; i<rows; i++) | |
{ | |
for(var j=1; j<cols; j++) | |
{ | |
cData += Number(data[i][j]); | |
} | |
if(cData > maxData) | |
{ | |
maxData = cData; | |
} | |
cData = 0; | |
} | |
xrange = (rows - 1) * (barWidth) + (rows - 2)*separation + xpadding; | |
yrange = maxData; | |
barHeightMultiplier = (height - ypadding) / maxData; | |
textYPosition = height - 1; | |
return chart; | |
} | |
chart.width = function(_) { | |
if (!arguments.length) return width; | |
width = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.stacked = function(_) { | |
if (!arguments.length) return stacked; | |
stacked = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.height = function(_) { | |
if (!arguments.length) return height; | |
height = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.separation = function(_) { | |
if (!arguments.length) return separation; | |
separation = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.xpadding = function(_) { | |
if (!arguments.length) return xpadding; | |
xpadding = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.ypadding = function(_) { | |
if (!arguments.length) return ypadding; | |
ypadding = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.xTicks = function(_) { | |
if (!arguments.length) return xTicks; | |
xTicks = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.yTicks = function(_) { | |
if (!arguments.length) return yTicks; | |
yTicks = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.barWidth = function(_) { | |
if (!arguments.length) return barWidth; | |
barWidth = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.showAxis = function(_) { | |
if (!arguments.length) return showAxis; | |
showAxis = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.showXText = function(_) { | |
if (!arguments.length) return showXText; | |
showXText = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.changeBarWidth = function(_){ | |
if (!arguments.length) return barWidth; | |
barWidth = _; | |
if (!plotted) return chart; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.changeSeparation = function(_){ | |
if (!arguments.length) return separation; | |
separation = _; | |
//if (!plotted) return chart; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.changeHeight = function(_){ | |
if (!arguments.length) return height; | |
height = _; | |
chart.updatePlotValues(); | |
chart.update(); | |
return chart; | |
} | |
chart.updatePlotValues = function(){ | |
if (stacked) | |
{ | |
var cData = 0; | |
maxData = 0; | |
for(var i=1; i<rows; i++) | |
{ | |
for(var j=1; j<cols; j++) | |
{ | |
cData += Number(data[i][j]); | |
} | |
if(cData > maxData) | |
{ | |
maxData = cData; | |
} | |
cData = 0; | |
} | |
} | |
else | |
{ | |
maxData = 0; | |
for(var i=1; i<rows; i++) | |
{ | |
for(var j=1; j<cols; j++) | |
{ | |
if(Number(data[i][j]) > maxData) | |
{ | |
maxData = Number(data[i][j]); | |
} | |
} | |
} | |
} | |
xrange = (rows - 1) * (barWidth) + (rows - 2)*separation + xpadding;; | |
yrange = maxData; | |
barHeightMultiplier = (height - ypadding) / maxData; | |
textYPosition = height - 1; | |
} | |
chart.update = function(_){ | |
if (!plotted) { return chart; } | |
if(showAxis) | |
{ | |
xAxis.ldomain(0) | |
.rdomain(rows) | |
.lrange(0) | |
.rrange(xrange) | |
.xpadding(10) | |
.ypadding(height) | |
.orientation("bottom") | |
.ticks(xTicks) | |
.update(); | |
yAxis.ldomain(0) | |
.rdomain(maxData) | |
.lrange(0) | |
.rrange(height - ypadding) | |
.ticks(yTicks) | |
.ypadding(ypadding) | |
.xpadding(10) | |
.orientation("left") | |
.update(); | |
} | |
var barNodes = document.querySelectorAll("svg"); | |
d3.select("svg").attr("height", height).attr("width", width); | |
if(stacked) | |
{ | |
//replot stacked bars | |
for(var m=0; m<barNodes.length; m++) { | |
var rect = d3.select(barNodes.item(m)).selectAll("rect"); | |
var rowval = 0; | |
var colval = 0; | |
rect.transition().duration(1000) | |
.attr("x", function(d, i) | |
{ | |
rowval = d3.select(this).attr("row"); | |
colval = d3.select(this).attr("col"); | |
if (rowval == 0) {return 0;} | |
return (xpadding + 5 + (rowval-1)*(barWidth+separation)); | |
}).attr("y", function(d, i) | |
{ | |
if (rowval == 0) { return 0; } | |
var ytop = 0; | |
for(var s = cols - 1; s >= colval; s--) | |
{ | |
ytop += Number(d[s]); | |
} | |
return height - 1 - (ytop * barHeightMultiplier); | |
}).attr("width", function(d, i) | |
{ | |
if (rowval == 0) { return 0; } | |
return barWidth; | |
}).attr("height", function(d, i) | |
{ | |
if (rowval == 0) { return 0; } | |
return d[colval] * barHeightMultiplier; | |
}); | |
} | |
} | |
else | |
{ | |
// replot grouped bars | |
var sBarWidth = barWidth/(cols-1); | |
for(var m=0; m<barNodes.length; m++) { | |
var rect = d3.select(barNodes.item(m)).selectAll("rect"); | |
var rowval = 0; | |
var colval = 0; | |
rect.transition() | |
.delay(function(d,i){return i * 20;}) | |
.attr("y", function(d, i) | |
{ | |
rowval = d3.select(this).attr("row"); | |
colval = d3.select(this).attr("col"); | |
if (rowval == 0) { return 0; } | |
return height - 1 - (d[colval] * barHeightMultiplier); | |
}).attr("height", function(d, i) | |
{ | |
if (rowval == 0) { return 0; } | |
return d[colval] * barHeightMultiplier; | |
}).transition().duration(500) | |
.attr("x", function(d, i) | |
{ | |
if (rowval == 0) {return 0;} | |
return (xpadding + 5 + ((colval - 1)*sBarWidth) + (rowval-1)*(cols-1)*(sBarWidth) + (rowval-1)*(separation)); | |
}).transition() | |
.attr("width", function(d, i) | |
{ | |
if (rowval == 0) { return 0; } | |
return sBarWidth; | |
}); | |
} | |
} | |
} | |
return chart; | |
} | |
function draw() { | |
var data = generateData(60, 6); | |
console.log(data); | |
var chart = multibarChart().width(800).height(300).barWidth(10).separation(2).showAxis(false).load(data).plot(); | |
chart.stacked(false).separation(3); | |
return chart; | |
} | |
function generateData(n, o) { | |
var data = [] | |
for (var i=0; i<n; i++) | |
{ | |
var coldata = []; | |
for(var j=0; j<o; j++) | |
{ | |
coldata.push(Math.random()); | |
} | |
data.push(coldata); | |
} | |
return data; | |
} |
This file contains 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
<html> | |
<head> | |
<style type="text/css"> | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: black; | |
shape-rendering: crispEdges; | |
} | |
.axis text { | |
font-family: sans-serif; | |
font-size: 11px; | |
} | |
.xaxis path, | |
.xaxis line { | |
fill: none; | |
stroke: black; | |
shape-rendering: crispEdges; | |
} | |
.slice text { | |
font-size: 16pt; | |
font-family: Arial; | |
} | |
</style> | |
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.v2.js"></script> | |
<script type="text/javascript" src="barChart.js"></script> | |
</head> | |
<body> | |
<form> | |
<label><input type="radio" name="mode" value="grouped"> Grouped</label> | |
<label><input type="radio" name="mode" value="stacked" checked> Stacked</label> | |
</form> | |
<script type="text/javascript"> | |
var data = generateData(46, 6); // for 50 rows and 5 cols of data. I'm skipping first col and first row | |
var chart = multibarChart().width(900).height(300).barWidth(15).separation(5).showAxis(false).load(data).plot(); | |
d3.selectAll("input").on("change", change); | |
function change() { | |
if (this.value == "grouped") | |
{ | |
chart.stacked(false); | |
} | |
else | |
{ | |
chart.stacked(true); | |
} | |
} | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment