Built with blockbuilder.org
Last active
June 28, 2016 00:14
-
-
Save sxywu/792a8fde4510401b63d29427f71e404f to your computer and use it in GitHub Desktop.
Chase Data: Bar Chart
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
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://npmcdn.com/babel-core@5.8.34/browser.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.11.2/lodash.js'></script> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
* { | |
font-family: Helvetica; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
#data { | |
text-align: center; | |
} | |
</style> | |
</head> | |
<body> | |
<input id="loadfile" type="file" multiple /> | |
<svg></svg> | |
<div id='data'></div> | |
<script type="text/babel"> | |
/************** | |
* This section modified from @enjalot's block: | |
http://bl.ocks.org/enjalot/63d06e2ccadad0cb30dc5f920efd1cdf | |
***************/ | |
d3.select("#loadfile").node() | |
.addEventListener('change', loadFile, false); | |
function loadFile(evt) { | |
evt.stopPropagation(); | |
evt.preventDefault(); | |
var files; | |
if(evt.dataTransfer) { | |
files = evt.dataTransfer.files; | |
} else { | |
files = evt.target.files; | |
} | |
var i = 0; | |
var reader = new FileReader(); | |
reader.onload = function(e) { | |
parseData(e.target.result); | |
// start the next | |
i += 1; | |
files[i] && reader.readAsText(files[i]); | |
} | |
reader.readAsText(files[i]); | |
} | |
var allTransactions = []; | |
function parseData(result) { | |
var transactions = d3.csv.parse(result); | |
// go through each transaction | |
_.each(transactions, transaction => { | |
if (transaction['Type'] === 'Sale') { | |
allTransactions.push({ | |
date: new Date(transaction['Trans Date']), | |
amount: -1 * parseFloat(transaction['Amount']), | |
title: transaction['Description'], | |
}); | |
} | |
}); | |
updateGraph(allTransactions); | |
} | |
// draw bar chart | |
var width = 900; | |
var height = 300; | |
var barWidth = 1; | |
var padding = {top: 40, left: 20}; | |
var linearGradient = d3.select('svg').append('defs') | |
.append("linearGradient") | |
.attr("id", "linear-gradient") | |
.attr({gradientUnits: 'userSpaceOnUse', | |
x1: 0, | |
y1: 0, | |
x2: 0, | |
y2: height - padding.top}); | |
var svg = d3.select('svg') | |
.attr({width, height}) | |
.append('g'); | |
var div = d3.select('div#data').style({width}); | |
var timeFormat = d3.time.format('%a %b %e'); | |
// do da linear gradient | |
linearGradient.append("stop") | |
.attr("offset", 0) | |
.attr("stop-color", "#ed0345"); // start at red | |
linearGradient.append("stop") | |
.attr("offset", '25%') | |
.attr("stop-color", "#fbbf45"); | |
linearGradient.append("stop") | |
.attr("offset", '75%') | |
.attr("stop-color", "#aad962"); | |
linearGradient.append("stop") | |
.attr("offset", '100%') | |
.attr("stop-color", "#03c383"); // end at green | |
// initialize scales and axis | |
var timeScale = d3.time.scale() | |
.range([0, width - padding.left]); | |
var xAxis = d3.svg.axis() | |
.orient('bottom') | |
.scale(timeScale); | |
var heightScale = d3.scale.linear() | |
.range([0, height - padding.top]); | |
var yAxis = d3.svg.axis() | |
.orient('left') | |
.scale(heightScale); | |
// initialize the containers | |
var barsG = svg.append('g') | |
.attr('transform', 'translate(' + padding.left + ',0)'); | |
var xAxisG = svg.append('g') | |
.classed('axis', true) | |
.attr('transform', | |
'translate(' + padding.left + ',' + (height - padding.top) + ')'); | |
var yAxisG = svg.append('g') | |
.classed('axis', true) | |
.attr('transform', 'translate(' + padding.left + ',0)'); | |
function updateGraph(data) { | |
// first group the data into days | |
data = _.chain(data) | |
.groupBy(d => d.date) | |
.map((transactions) => { | |
return { | |
date: transactions[0].date, | |
transactions, | |
total: _.reduce(transactions, (sum, t) => { | |
return t.amount ? sum + t.amount : sum; | |
}, 0), | |
}; | |
}).sortBy(d => d.date).value(); | |
barWidth = Math.floor((width - padding.left) / data.length) - 2; | |
// update the scales | |
timeScale.domain([data[0].date, _.last(data).date]); | |
var maxTotal = d3.max(data, d => d.total); | |
heightScale.domain([0, maxTotal]); | |
xAxisG.call(xAxis); | |
// yAxisG.call(yAxis); | |
var bars = barsG.selectAll('rect').data(data, d => d.date); | |
bars.enter().append('rect'); | |
bars.exit().remove(); | |
bars.on('mouseover', d => { | |
var html = '<h1>' + timeFormat(d.date) + ': $' + d.total + '</h1>'; | |
html += _.map(d.transactions, t => t.title + ' <b>$' + t.amount + '</b>').join('<br>'); | |
div.html(html); | |
}).style("fill", "url(#linear-gradient)") | |
.attr({stroke: '#fff'}) | |
.transition().duration(500) | |
.attr({ | |
x: d => timeScale(d.date) - barWidth / 2, | |
y: d => height - padding.top - heightScale(d.total), | |
width: barWidth, | |
height: d => heightScale(d.total), | |
}); | |
} | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment