Skip to content

Instantly share code, notes, and snippets.

@emepyc
Created December 17, 2012 17:00
Show Gist options
  • Save emepyc/4319822 to your computer and use it in GitHub Desktop.
Save emepyc/4319822 to your computer and use it in GitHub Desktop.
Horizontal stacked bar with update
{"description":"Horizontal stacked bar with update","endpoint":"","display":"svg","public":true,"require":[],"fileconfigs":{"gistfile1.txt":{"default":true,"vim":false,"emacs":false,"fontSize":12},"inlet.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"config.json":{"default":true,"vim":false,"emacs":false,"fontSize":12},"_.md":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"tab":"edit","display_percent":0.414969725755848,"play":false,"loop":false,"restart":false,"autoinit":true,"pause":true,"loop_type":"period","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"hidepanel":false}
// This snippet implements a reusable stacked bar chart with transitions.
// Its purpose is to experiment with reusable charts (and transitions)
// as explained in:
// http://bost.ocks.org/mike/chart/
var g = d3.select("svg")
.append("g")
var data1 = {jobs_counts : { counts : [2,6,7,2,1],
colors : ["green", "yellow", "red", "blue", "cyan"]
},
total_job_count : 18,
logic_name : "analysis1"
};
var data2 = {jobs_counts : { counts : [1,1,1,10,2],
colors : ["green", "yellow", "red", "blue", "cyan"]
},
total_job_count : 15,
logic_name : "analysis1"
};
var max_counts = 20;
// pChart is the reusable stacked bar chart implementation.
// In this example only a few methods are defined (API):
// -data: to update the data used by the pie chart (here this is internally used by the update method)
// -update: to update the pie chart with new data + transition
// -transition: returns a transition closure that is used to pudate the pie-chart (via its update method)
// -height: to update the height of the horizontal stacked bar.
// -barsmargin: to update the left space, used for the analysis label
var pChart = hStackedBarChart().data(data1).height(50).barsmargin(100);
pChart(g);
var t = pChart.transition();
pChart.update(data1, t);
setTimeout(function(){console.log("ch1"); pChart.update(data2, t)}, 2000);
setTimeout(function(){console.log("ch2"); pChart.update(data1, t)}, 4000);
setTimeout(function(){console.log("ch3"); pChart.update(data2, t)}, 6000);
// The reusable horizontal stacked bar
function hStackedBarChart() {
var barsmargin = 80;
var stack = d3.layout.stack();
  var margin = {top: 10, right: 10, bottom: 10, left: 10},
      width = 460 - margin.left - margin.right,
height = 50;
 var fontsize = 16;
var raw_data = {total_job_count : 4,
jobs_counts : { counts : [0,0,0,0,0],
colors : ["green", "yellow", "blue", "red", "cyan"]
},
logic_name : "analysis1"
};
var bChart = function(g){
var data = bChart.transformData(raw_data);
var layers = stack(data);
// Only 1 layer
var gLayer = g.selectAll(".layer")
                 .data(layers)
                 .enter().append("svg:g")
                 .attr("class", "layer")
                 .style("fill", function(d, i) { return raw_data.jobs_counts.colors[i] })
console.log(gLayer);
var gRects = gLayer.selectAll("g")
        .data(function(d) {return d})
         .enter().append("g")
         .attr("class", function(d,i){return "analysis" + (i+1)})
         .classed("bar", true);
gRects.append("svg:rect")
         .attr("x", barsmargin)
     //    .attr("y", function(d) {console.log(d); return x(d.x)})
.attr("y", 0) // at the top
         .attr("height", height)
         .attr("width", 0)
         .each(function(d,i){this._type = "stacked"});
// analysis label
g
.append("svg:g")
.attr("class", "analysis_label")
.attr("to_id", raw_data.logic_name)
.on("click", bChart.switch_type)
.append("svg:text")
.attr("x", 0)
.attr("y", bChart.height()/2 + bChart.fontsize()/2.5)
.attr("fill", "black")
.attr("font-size", fontsize)
.text(raw_data.logic_name);
// general counts label
g
      .append("svg:text")
      .attr("class", "count_label")
      .attr("x", barsmargin + 10)
      .attr("y", bChart.height()/2 + bChart.fontsize()/2.5)
      .attr("fill", "black")
      .attr("font-size", fontsize)
      .text("0");
    gRects.append("svg:text")          
        .attr("x", barsmargin)
        .attr("y", 0)
        .attr("font-size", 10)
        .attr("fill", "red")
        .text(0)
        .each(function(d,i){this._type = "stacked"});
bChart.transition = function () {
var duration = 1000;
var delay = 0;
var newT = function (newlayers) {
y = bChart.new_scale(g, newlayers);
var layer = g.selectAll(".layer")
               .data(newlayers);
var rect = layer.selectAll("rect")
        .data(function(d) {return d});
var text = layer.selectAll("text")
         .data(function(d) {return d});
layer.selectAll(".bar").call(bChart.redrawBars, duration, delay);
g.selectAll(".count_label")
        .data(newlayers)
        .transition()
        .delay(function(d,i){return i*100})
        .duration(1000)
.attr("x", function(d,i){var l=layers.slice(-1)[0][0]; return(y(l.y0+l.y) + barsmargin + 10)})
        .text(function(d,i){var l=layers.slice(-1)[0][0]; return (l.y0 + l.y)});
};
return newT;
};
bChart.update = function(new_raw_data, trans) {
bChart.data(new_raw_data);
var new_data = bChart.transformData(new_raw_data);
var new_layers = stack(new_data);
trans(new_layers);
layers = new_layers;
return;
};
// live_overview(g, layers);
return gRects;
};
bChart.fontsize = function (value) {
if (!arguments.length) return fontsize;
fontsize = value;
return bChart;
};
bChart.data = function (value) {
if (!arguments.length) return raw_data;
raw_data = value;
return bChart;
};
bChart.height = function (value) {
if (!arguments.length) return height;
height = value;
return bChart;
};
bChart.barsmargin = function (value) {
if (!arguments.length) return barsmargin;
barsmargin = value;
return bChart;
};
bChart.switch_type = function () {
console.log(d3.select(this).attr("to_id"));
d3.selectAll("." + d3.select(this).attr("to_id")) // these are g with rects
.each(function(d,i) {
if($(this).children("rect")[0]._type=="grouped"){
$(this).children("rect")[0]._type="stacked";
$(this).children("text")[0]._type="stacked";
} else {
$(this).children("rect")[0]._type="grouped";
$(this).children("text")[0]._type="grouped";
}
$(this).children("rect")[0]._column=i;
$(this).children("text")[0]._column=i;
})
.call(bChart.redrawBars, 300, 10);
};
bChart.redrawBars = function (bar, time, delay) {
var height = bChart.height();
var n = bChart.data().jobs_counts.counts.length;
var indHeight = height/n;
var barsmargin = bChart.barsmargin();
var rect = bar.selectAll("rect");
rect
.transition()
.delay(function(d,i) {return i*delay})
.duration(time)
.attr("x",function(d) {if (this._type == "stacked") {return barsmargin+y(d.y0)} else {return barsmargin}})
.attr("y", function(d,i) {if (this._type == "stacked") {return 0} else {return this._column * indHeight}})
.attr("width", function(d) {return y(d.y)})
.attr("height", function() {if (this._type == "stacked") { return height } else {return indHeight}});
var counts_labels = bar.selectAll("text");
counts_labels
.transition()
.delay(function(d,i) {return i*delay})
.duration(time)
.attr("x", function(d) {if (this._type == "stacked") {return barsmargin+y(d.y0+d.y)} else {return barsmargin+y(d.y)}})
.attr("y", function(d,i) { if (this._type == "stacked") { return 0 } else { return this._column * indHeight + indHeight/2 + (16/2.5)}})
.text(function(d){return (d.y)})
};
bChart.transformData = function (data) {
var transfData = [];
for (var i=0; i<data.jobs_counts.counts.length; i++) {
transfData[i] = [];
}
for (var j=0; j<data.jobs_counts.counts.length; j++) {
transfData[j].push({x:0, y:data.jobs_counts.counts[j]})
  }
    return transfData;
};
bChart.new_scale = function(svg, layers) {
var yStackMax = d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.y0 + d.y; }); });
var width = 440;
var y = d3.scale.linear()
.domain([0, yStackMax])
.range([0,width]);
return y;
}
return bChart;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment