block by sxywu 792a8fde4510401b63d29427f71e404f

Chase Data: Bar Chart

Full Screen

Built with blockbuilder.org

index.html

<!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: 
    //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>