<!DOCTYPE html>
<html>
  <head>
    <title>Bar Chart in D3 v5</title>
	<script src="https://d3js.org/d3.v5.min.js"></script>
  <script type='text/javascript' src="./word_wrap.js"></script>	
	<link rel="stylesheet" type="text/css" href="style.css">
  </head>
  <body>
  <h1>Bar Chart in D3 v5</h1> 
	  <div id="main"></div>
	  <script type="text/javascript" src="script.js"></script>
  </body>
</html>
/*
  TODO:
		- larger Y-numbers? Auto-Calculated margins?
		- beautiful tooltip
		- gridlines
		- actions on bar click
		- actions on body clisk
		- colors and legend
	DONE:
		- multi-line labels. 2019-07
*/


var main = d3.select('#main'); // append charts here
var allSizes = {
	big: {
		width: 960, height: 500,
		margin: {top: 20, right: 20, bottom: 130, left: 45},
		padding: 0.05 // padding is like % spaces between bars
	}
};
var x, y; // constants used by all charts

//  ______                _   _                 
// |  ____|              | | (_)                
// | |__ _   _ _ __   ___| |_ _  ___  _ __  ___ 
// |  __| | | | '_ \ / __| __| |/ _ \| '_ \/ __|
// | |  | |_| | | | | (__| |_| | (_) | | | \__ \
// |_|   \__,_|_| |_|\___|\__|_|\___/|_| |_|___/

function conversor(d) {
	// The type conversion function can also return null,
	// in which case the row will be ignored.
	// This is useful for filtering datasets on the client.

	// auto-type detect https://observablehq.com/@d3/d3-autotype
	return d3.autoType(d);
}

//    _____ _                _   
//   / ____| |              | |  
//  | |    | |__   __ _ _ __| |_ 
//  | |    | '_ \ / _` | '__| __|
//  | |____| | | | (_| | |  | |_ 
//   \_____|_| |_|\__,_|_|   \__|

// 1. Before chart data is loaded
	// chart header
	main.append('div').html("<h2>Chart Title</h2>");

	// sizes & styles & data
	var 
		sizes = allSizes.big, // change "big" and change "allsizes" to fit
		margin = 	sizes.margin,
		padding = sizes.padding;
	var 
		xClass = "axis axis--x",
		yClass = "axis axis--y",
		barClass = "bar bar_blue",
		dataSource = "data1.csv";
	var 
		width = sizes.width - margin.left - margin.right,
		height = sizes.height - margin.top - margin.bottom;

	// svg-box 
	// place for the future chart. Includes chart body, legend, and axes
	var svg = 
	main
		.append("svg")
		.attr("width", sizes.width)
		.attr("height", sizes.height)

	// scales
	// rangeRound: set range and round the resulting value to the nearest integer.
	var x = d3.scaleBand().rangeRound([0, width]).padding(padding),
			y = d3.scaleLinear().rangeRound([height, 0]);

	// chart boby
	var g = svg.append("g")
			.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

	// axes-X (object)
	var axesX = 
	g.append("g")
			.attr("class", xClass)
			.attr("transform", "translate(0," + height + ")");

	// axes-Y (object)
	var axesY = 					
	g.append("g")
		 .attr("class", yClass);
	// Y-axes text
	svg.append("text")
			.attr("transform", "rotate(-90)")
			.attr("x", -sizes.height/2 + margin.top)
			.attr("y", 0)
			.attr("dy", "0.71em")
			.attr("text-anchor", "middle");



// 3. After chart data is loaded
	// load data from csv source
	// conversor = function to modify data, runs for each data row.
	d3.csv(dataSource, conversor)
			.then((data) => {
					// scales
					x.domain(data.map(function(d) { return d.name; }));				
					var maxVal = d3.max(data, function(d) { return d.value; });
					y.domain([0, maxVal]);

					// xAxes, yAxes (axes)
					var xAxes = d3.axisBottom(x);
					var yAxes = d3.axisLeft(y);
					
					// append data to axes
					axesX.call(xAxes)
						.selectAll(".tick text")
							.call(d3.util.wrap, x.bandwidth());
					axesY.call(yAxes);

					// bar for each data element
					g.selectAll(".bar")
						.data(data)
						.enter().append("rect")
							.attr("class", barClass)
							.attr("x", function(d) { return x(d.name); })
							.attr("y", function(d) { return y(d.value); })
							.attr("width", x.bandwidth())
							.attr("height", function(d) { return height - y(d.value); });
			})
			.catch((error) => {
					throw error;
		});

// 2. Code here exacutes before 3.
body
{
  background-color: lightgray;
  font-family: Calibri, 'Trebuchet MS', sans-serif
}
#main
{
  float: left; 
  width: 100%;
  height: 100%;
}


.bar_blue {
  fill: steelblue;
  fill-opacity: 1;
}

.bar:hover {
  fill-opacity: 0.6;
}

.axis--x path {
  display: none;
}
name,value
Locke loremipsu blavlavva daa crakazavrs against megegodzillasss,400000
Reyes thebestof the best labels and even longer,800000
Ford zoommeifucan,1500000
Jarrah akalalalala op woo,1600000
Shephard zinzinzizi fii fooooofiof,2300000
Kwonn opaen bya fuu atension,4200000
// Source:
// https://gist.github.com/guypursey/f47d8cd11a8ff24854305505dbbd8c07
d3.util = d3.util || {};

d3.util.wrap = function wrap(text, width) {
  text.each(function() {
    var text = d3.select(this),
        words = text.text().split(/\s+/).reverse(),
        word,
        line = [],
        lineNumber = 0,
        lineHeight = 1.1, // ems
        y = text.attr("y"),
        dy = parseFloat(text.attr("dy")),
        tspan = text.text(null)
          .append("tspan")
          .attr("x", 0)
          .attr("y", y)
          .attr("dy", dy + "em")
    while (word = words.pop()) {
      line.push(word)
      tspan.text(line.join(" "))
      if (tspan.node().getComputedTextLength() > width) {
        line.pop()
        tspan.text(line.join(" "))
        line = [word]
        tspan = text
          .append("tspan")
          .attr("x", 0)
          .attr("y", y)
          .attr("dy", `${++lineNumber * lineHeight + dy}em`)
          .text(word)
      }
    }
  })
};