|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script> |
|
<title>stacked bar</title> |
|
<style> |
|
.axis text { |
|
font: 10px sans-serif; |
|
} |
|
.axis path, .axis line { |
|
fill: none; |
|
stroke: #000; |
|
shape-rendering: crispEdges; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<script> |
|
/* |
|
an iteration on this bl.ock |
|
http://bl.ocks.org/ZJONSSON/2975320 |
|
barStack - stacking with negative values |
|
*/ |
|
|
|
function barStack(seriesData) { |
|
var l = seriesData[0].length |
|
while (l--) { |
|
var posBase = 0; // positive base |
|
var negBase = 0; // negative base |
|
|
|
seriesData.forEach(function(d) { |
|
d = d[l] |
|
d.size = Math.abs(d.y) |
|
if (d.y < 0) { |
|
d.y0 = negBase |
|
negBase -= d.size |
|
} else |
|
{ |
|
d.y0 = posBase = posBase + d.size |
|
} |
|
}) |
|
} |
|
seriesData.extent = d3.extent( |
|
d3.merge( |
|
d3.merge( |
|
seriesData.map(function(e) { |
|
return e.map(function(f) { return [f.y0,f.y0-f.size] }) |
|
}) |
|
) |
|
) |
|
) |
|
} |
|
|
|
/* Here is an example */ |
|
|
|
// each series is an array of objects |
|
// our data is in turn an array of those series arrays |
|
// which is to say |
|
// an array of arrays of objects |
|
var data = [ |
|
[ {y:3}, {y:6}, {y:-3} ], |
|
[ {y:4}, {y:-2}, {y:-9} ], |
|
[ {y:10}, {y:-3}, {y:4} ] |
|
] |
|
|
|
var h = 500; |
|
var w = 500; |
|
var margin = 20; |
|
var color = d3.scale.category10(); |
|
|
|
var x = d3.scale.ordinal() |
|
.domain(['abc', 'abc2', 'abc3']) |
|
.rangeRoundBands([ margin, w - margin ], .1) |
|
|
|
var y = d3.scale.linear() |
|
.range([h-margin,0+margin]); |
|
|
|
var xAxis = d3.svg.axis() |
|
.scale(x) |
|
.orient("bottom") |
|
.tickSize(6, 0); |
|
|
|
var yAxis = d3.svg.axis() |
|
.scale(y) |
|
.orient("left"); |
|
|
|
barStack(data); |
|
y.domain(data.extent); |
|
|
|
svg = d3.select("body") |
|
.append("svg") |
|
.attr("height", h) |
|
.attr("width", w) |
|
|
|
svg.selectAll(".series") |
|
.data(data) |
|
.enter() |
|
.append("g") |
|
.classed("series", true) |
|
.style("fill", function(d,i) { return color(i) }) |
|
.style("opacity", 0.8) |
|
.selectAll("rect") |
|
.data(Object) |
|
.enter() |
|
.append("rect") |
|
.attr("x", function(d, i) { return x(x.domain()[i]) }) |
|
.attr("y", function(d) { return y(d.y0) }) |
|
.attr("height", function(d) { return y(0) - y(d.size) }) |
|
.attr("width", x.rangeBand()) |
|
.on("mouseover", function() { tooltip.style("display", null); }) |
|
.on("mouseout", function() { tooltip.style("display", "none"); }) |
|
.on("mousemove", function(d) { |
|
var xPosition = d3.mouse(this)[0] - 35; |
|
var yPosition = d3.mouse(this)[1] - 5; |
|
tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")"); |
|
tooltip.select("text").text(d.y); |
|
}); |
|
|
|
console.log("y(0)", y(0)); |
|
console.log("margin", margin); |
|
|
|
svg.append("g") |
|
.attr("class", "axis x") |
|
.attr("transform", "translate(0 " + y(0) + ")") |
|
.call(xAxis); |
|
|
|
svg.append("g") |
|
.attr("class", "axis y") |
|
.attr("transform", "translate(" + margin + " 0)") |
|
.call(yAxis); |
|
|
|
/* Here we add tooltips */ |
|
|
|
// Prep the tooltip bits, initial display is hidden |
|
var tooltip = svg.append("g") |
|
.attr("class", "tooltip") |
|
.style("display", "none"); |
|
|
|
tooltip.append("rect") |
|
.attr("width", 30) |
|
.attr("height", 20) |
|
.attr("fill", "white") |
|
.style("opacity", 0.5); |
|
|
|
tooltip.append("text") |
|
.attr("x", 15) |
|
.attr("dy", "1.2em") |
|
.style("text-anchor", "middle") |
|
.attr("font-size", "12px") |
|
.attr("font-weight", "bold"); |
|
|
|
</script> |
|
</body> |