|
<!DOCTYPE html> |
|
<head> |
|
<meta charset="utf-8"> |
|
<script src="https://d3js.org/d3.v3.min.js"></script> |
|
<style> |
|
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } |
|
</style> |
|
</head> |
|
<div id='container'></div> |
|
<body> |
|
<script> |
|
var url = 'data.csv' |
|
|
|
d3.csv(url, function(error, data){ |
|
|
|
// major dimension |
|
var margin = {top: 70, bottom: 40, left: 40, right: 120}, axisPadding = 5; |
|
var WIDTH = 450, HEIGHT = 300; |
|
var svgWidth = WIDTH + margin.left + margin.right, |
|
svgHeight = HEIGHT + margin.top + margin.bottom; |
|
|
|
var svg = d3.select('#container') |
|
.append('svg') |
|
.attr({width: svgWidth, height: svgHeight}); |
|
var items = d3.keys(data[0]).filter(function(d){ return d !== 'Country'; }) |
|
|
|
// Country,Electronics,Software,Mechanics |
|
var nest = d3.nest() |
|
.key(function(d){ return d.Country; }) |
|
.sortKeys(d3.ascending) |
|
.rollup(function(leave){ |
|
return items.map(function(e){return {name: e, value: +leave[0][e]}}) |
|
}) |
|
.entries(data); |
|
var maxIncome = d3.max(nest, function(d0){ |
|
return d3.max(d0.values, function(d1){return d1.value; }); |
|
}); |
|
|
|
|
|
// create scales and axises |
|
var xScale = d3.scale.ordinal() |
|
.domain(nest.map(function(d){ return d.key; })) |
|
.rangeBands([0, WIDTH], 0.15); |
|
var xInner = d3.scale.ordinal() |
|
.domain(items) |
|
.rangeBands([0, xScale.rangeBand()], 0); |
|
var color = d3.scale.category10() |
|
.domain(items); |
|
// console.log(xScale.domain()) |
|
var yScale = d3.scale.linear() |
|
.domain([0, maxIncome]) |
|
.range([0, HEIGHT]); |
|
|
|
|
|
var xAxis = d3.svg.axis() |
|
.orient('bottom') |
|
.tickSize(6,0) |
|
.scale(xScale); |
|
var yAxis = d3.svg.axis() |
|
.orient('left') |
|
.ticks(5) |
|
.scale(yScale.copy().domain(yScale.domain().slice().reverse())); |
|
// console.log(yScale.domain()); |
|
|
|
|
|
var xGroup = svg.append('g') |
|
.attr('transform', 'translate(' + |
|
[margin.left, margin.top + HEIGHT + axisPadding] + |
|
')'); |
|
xGroup.call(xAxis); |
|
styleAxis(xGroup); |
|
|
|
var yGroup = svg.append('g') |
|
.attr('transform', 'translate(' + |
|
[margin.left - axisPadding, margin.top] + |
|
')') |
|
yGroup.call(yAxis); |
|
styleAxis(yGroup); |
|
|
|
|
|
// create the body graph |
|
var mainGroup = svg.append('g') |
|
.attr('transform', 'translate(' + |
|
[margin.left, margin.top + HEIGHT] + |
|
')'); |
|
var countries = mainGroup.selectAll('g') |
|
.data(nest) |
|
.enter() |
|
.append('g') |
|
.attr('transform', function(d){ |
|
return 'translate(' + [xScale(d.key), 0] + ')'; |
|
}); |
|
var rects = countries.selectAll('rect') |
|
.data(function(d){return d.values;}) |
|
.enter() |
|
.append('rect') |
|
.each(function(d,i){ |
|
d3.select(this).attr({ |
|
fill: color(d.name), |
|
x: xInner(d.name), |
|
y: 0, |
|
height: yScale(d.value), |
|
width: xInner.rangeBand(), |
|
}); |
|
}); |
|
// animation |
|
rects |
|
.transition() |
|
.duration(600) |
|
.each('end', function(d){ |
|
d3.select(this) |
|
.transition() |
|
.attr('y', -yScale(d.value)) |
|
}) |
|
.attr('y', function(d){ return -yScale(d.value); }); |
|
// add interactive behavious |
|
rects |
|
.on('mouseover', function(){ |
|
d3.select(this) |
|
.transition() |
|
.attr('fill', 'yellow') |
|
}) |
|
.on('mouseout', function(){ |
|
d3.select(this) |
|
.transition() |
|
.delay(200) |
|
.attr('fill', function(d){ return color(d.name); }) |
|
}); |
|
// text label |
|
countries.selectAll('text') |
|
.data(function(d){return d.values;}) |
|
.enter() |
|
.append('text') |
|
.each(function(d,i){ |
|
d3.select(this).text(d.value); |
|
d3.select(this).attr({ |
|
x: xInner(d.name) + xInner.rangeBand() / 2, |
|
y: -yScale(d.value) - 3, |
|
'text-anchor': 'middle', |
|
}); |
|
}); |
|
|
|
// create legend |
|
var legendGroup = svg.append('g') |
|
.attr('transform', 'translate(' + |
|
[margin.left + WIDTH + axisPadding, margin.top] + |
|
')'); |
|
var legends = legendGroup.selectAll('g') |
|
.data(items) |
|
.enter() |
|
.append('g') |
|
.attr('transform', function(d,i){return 'translate(' + [0, i * 25] + ')'}); |
|
legends.append('rect') |
|
.attr({ |
|
fill: function(d){return color(d)}, |
|
rx: 10, |
|
ry: 10, |
|
width: 20, |
|
height: 20, |
|
}); |
|
legends.append('text') |
|
.text(function(d){return d;}) |
|
.attr({ |
|
fill: 'black', |
|
x: 25, |
|
y: 16, |
|
}); |
|
}) |
|
|
|
|
|
function styleAxis(axis){ |
|
// style path |
|
axis.select('.domain').attr({ |
|
fill: 'none', |
|
stroke: '#888', |
|
'stroke-width': 1 |
|
}); |
|
// style tick |
|
axis.selectAll('.tick line').attr({ |
|
stroke: '#000', |
|
'stroke-width': 1, |
|
}) |
|
} |
|
|
|
</script> |
|
</body> |