D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
jinlong25
Full window
Github gist
Stacked bar chart for easy comparison
Built with
blockbuilder.org
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>stacked bar chart</title> <style> * { font-family: sans-serif; } .axis path, .axis line { fill: none; stroke: #888; shape-rendering: crispEdges; } .axis text { font-size: 10px; fill: #222; } .y.axis line { stroke: #bbb; opacity: 0.7; } .y.axis path { stroke-width: 0; } </style> </head> <body> <div class="chart"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> <script> //define layout vars var width = 800, height = 200, margin = { top: 100, right: 10, bottom: 200, left: 50 } //define range for x/y scales var x = d3.scale.ordinal().rangeRoundBands([0, width], 0.2); var y = d3.scale.linear().rangeRound([height, 0]); //define color scale var colors = d3.scale.ordinal().range(['#a93790', '#ec6e8d', '#f9c7a8']); //define x/y axes var xAxis = d3.svg.axis().scale(x).orient('bottom'); var yAxis = d3.svg.axis().scale(y).orient('left').ticks(5); //define svg var svg = d3.select('.chart').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 + ')'); //load data d3.csv('data.csv', function(err, data) { if (err) throw err; //get the keys for x scale keys = d3.keys(data[0]).filter(function(d) { return d != 'Quarter'; }); //define the domain for colors scale colors.domain(keys); //parse data data.forEach(function(d) { d.Mac = parseFloat(d.Mac); d.iPad = parseFloat(d.iPad); d.iPhone = parseFloat(d.iPhone); var y0 = 0; d.values = keys.map(function(key) { return { key: key, quarter: d.Quarter, y0: y0, y1: y0 += +d[key] }; }); }); //define the domain for x/y scale x.domain(data.map(function(d) { return d.Quarter; })); y.domain([0, d3.max(data, function(d) { return Math.round((d.Mac + d.iPad + d.iPhone) * 1.35); })]); //append a group for each quarter var quarters = svg.selectAll('g.quarter') .data(data) .enter().append('g') .attr('class', 'quarter'); //plot bars for each series quarters.selectAll('rect.bar') .data(function(d) { return d.values; }) .enter().append('rect') .attr('class', function(d) { return 'bar ' + d.key; }) .attr('name', function(d) { return d.key; }) .attr('cursor', 'pointer') .attr('x', function(d) { return x(d.quarter); }) .attr('y', function(d) { return y(d.y1); }) .attr('y0', function(d) { return d.y0; }) .attr('width', x.rangeBand()) .attr('height', function(d) { return y(d.y0) - y(d.y1); }) .attr('fill', function(d) { return colors(d.key); }); //draw x/y axes svg.append('g') .attr('class', 'x axis') .attr('pointer-events', 'none') .attr('transform', 'translate(0, ' + height + ')') .call(xAxis); svg.append('g') .attr('class', 'y axis') .call(yAxis) .append('text') .attr('x', -26) .attr('y', 0) .text('Unit: million'); //draw legend groups var legends = svg.selectAll('g.legend') .data(keys) .enter().append('g') .attr('class', 'legend') .attr('transform', function(d, i) { return 'translate(0, ' + ((keys.length - 1 - i) * 18 - 10) + ')'; }); //draw legend rects legends.append('rect') .attr('class', function(d) { return 'bar ' + d; }) .attr('name', function(d) { return d; }) .attr('cursor', 'pointer') .attr('x', width - 44) .attr('y', -10) .attr('width', 34) .attr('height', 15) .style('fill', function(d) { return colors(d); }); //draw legend labels legends.append('text') .attr('x', width - 28) .attr('y', 1) .attr('pointer-events', 'none') .style('text-anchor', 'middle') .style('font-size', 10) .style('fill', '#fff') .text(function(d) { return d; }); //draw legend indicator var indicator = svg.append('text') .attr('class', 'legend-indicator') .attr('x', width - 96) .attr('y', -8) .style('font-size', 10) .style('opacity', 0) .text('comparing'); //draw title svg.append('text') .attr('x', (width + margin.left + margin.right) / 2) .attr('y', -20) .style('text-anchor', 'middle') .style('font-size', 20) .text('Apple product unit sales'); //draw note svg.append('a') .attr('href', 'https://barefigur.es/companies/apple/products/') .append('text') .attr('x', -16) .attr('y', height + 60) .style('font-size', 12) .text('Data source: Bare Figures') //add user interaction d3.selectAll('.bar').on('click', function() { //vertically translate bars for comparison var selected = d3.select(this).attr('name'); quarters.transition() .duration(200) .attr('transform', function(d) { var y0 = d.values.filter(function(k) { return k.key === selected; })[0].y0; return 'translate(0, ' + (height - y(y0)) + ')'; }); //conditionally style x axis label color if (selected === keys[0]) { d3.selectAll('.x.axis text') .transition() .duration(200) .style('fill', '#222'); } else { d3.selectAll('.x.axis text') .transition() .duration(200) .style('fill', '#fff'); } //show legend indicator indicator.style('opacity', 1); //position legend indicator var index = keys.indexOf(selected); indicator.transition() .duration(200) .attr('transform', 'translate(0, ' + (keys.length - 1 - index) * 18 + ')') }); d3.selectAll('.bar').on('mouseover', function() { //change opacity of selected series var selected = d3.select(this).attr('name'); d3.selectAll('.bar.' + selected).style('fill-opacity', 0.75); }); d3.selectAll('.bar').on('mouseout', function() { //change opacity of selected series var selected = d3.select(this).attr('name'); d3.selectAll('.bar.' + selected).style('fill-opacity', 1); }); }); </script> </body> </html>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js