block by kcsluis e873b0e611994b2d4fe2

Incomes and Countries

Full Screen

index.html

<!DOCTYPE html>
<meta charset="utf-8">

<style type="text/css">
	svg {
		border: 1px solid #f0f;
	}
	body {
		font-family: 'arial', sans-serif;
		font-size: 9px;
		width: 960px;
		margin: 40px auto;
	}
	h1 {
		font-size: 24px;
	}
	.axis path {
		display: none;
	}
	.axis line {
		stroke-width: 1px;
		stroke: #ccc;
		stroke-dasharray: 2px 2px;
	}
	g.tick text {
		fill: #aaa;
	}
	path {
		stroke-width: 2px;
	}
	.g-update {
		fill: none;
		stroke: steelblue;
	}
	.numLabel {
		font-weight: bold;
		vertical-align: middle;
	}
	.copLabel {		
		vertical-align: middle;
		text-anchor: end;
		font-size: 6px;
	}
	select {
		margin-bottom: 12px;
	}

	.cop95 { opacity: 1.0 }
	.cop90 { opacity: 0.95 }
	.cop80 { opacity: 0.9 }
	.cop70 { opacity: 0.85 }
	.cop60 { opacity: 0.8 }
	.cop50 { opacity: 0.75 }
	.cop40 { opacity: 0.7 }
	.cop30 { opacity: 0.65 }
	.cop20 { opacity: 0.6 }
	.cop10 { opacity: 0.55 }
	.cop5 { opacity: 0.5 }

</style>

<body>
	<h1 class="chartTitle"></h1>
	<select></select>
</body>

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js" charset="utf-8"></script>

<script>

function addCommas(nStr)
{
    nStr += '';
    var x = nStr.split('.');
    var x1 = x[0];
    var x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
        x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }
    return x1 + x2;
};

var margin = {top: 40, right: 60, bottom: 40, left: 60};
var width = 960 - margin.left - margin.right,
	height = 500 - margin.top - margin.bottom;

var headline = d3.select("h1");

var xScale = d3.scale.linear()
	.range([0, width]);
var yScale = d3.scale.linear()
	.range([height, 0]);

var line = d3.svg.line()
  .x(function(d) { return xScale(d.year); })
  .y(function(d) { return yScale(d.val); });

var xAxis = d3.svg.axis()
	.scale(xScale)
	.tickSize(-height)
	.tickPadding(8)
	.orient("bottom")
	.tickFormat(d3.round);
var yAxis = d3.svg.axis()
	.scale(yScale)
	.tickSize(-width)
	.tickPadding(8)
	.orient("left");

var svg = d3.select("body").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 + ")");

d3.tsv("incomes.tsv", function (error, data) {
	if (error) throw error;

	// format your data
	data.forEach( function (d) {
		d.val = +d.val;
		d.year = +d.year;
		d.unique = d.cutoff + "-" + d.year;
	});

	// create the dropdown menu
	var countryList = d3.set(data.map( function (d) { return d.country; } )).values();
	d3.select("select").selectAll("option")
		.data(countryList)
		.enter()
		.append("option")
		.text( function (d) { return d; });
	// the event listener has to be associated with the select, not the option
	d3.select('select')
      .on('change', function (d) { drawChartForCountry(this.value); });

	xScale.domain(d3.extent(data, function(d) { return d.year; }));
	yScale.domain(d3.extent(data, function(d) { return d.val; }));

	var xAxisGroup = svg.append("g")
		.call(xAxis)
		.attr("class", "axis")
		.attr("transform", "translate(0," + height + ")");
	var yAxisGroup = svg.append("g")
		.call(yAxis)
		.attr("class", "axis");

	function drawChartForCountry(countryName) {

		headline.text("Incomes, "+ countryName);

		// filter data by passed-in country name
		var thisCountry = data.filter( function (d) { return d.country === countryName; });
		// get the last year of the data
		var firstYear = d3.min(thisCountry.map( function (d) { return d.year; }));
		// get the length of values in each line
		var lastYear = d3.max(thisCountry.map( function (d) { return d.year; }));
		// get the length of values in each line
		var valuesLength = d3.set(thisCountry.map( function (d) { return d.year; })).values().length-1;

		// nest data by COP
		var nestedData = d3.nest()
		  .key(function(d) { return d.cutoff; })
		  .entries(thisCountry);

		// select data, add class
		var countryLineGroup = svg.selectAll(".country-line-group")
        .data(nestedData);
    countryLineGroup.attr("class", "country-line-group update");
    
    // ENTER 
    var countryLineGroupEnter = countryLineGroup.enter()
        .append("g")
        .attr("class", "country-line-group enter")

    // IF THERE ARE NEW G ELEMENTS, APPEND LINES AND TEXT FOR THEM
    countryLineGroupEnter.append("path")
    		.attr("class", function (d) { return "g-update " + d.key; })
        .attr("d", function(d) { return line(d.values) });
    countryLineGroupEnter
			.append("text")
			.attr("class", "numLabel")
			.text( function (d) { return "$" + addCommas(d.values[valuesLength].val); })
			.attr("dx", function (d) { return xScale(lastYear)+3; })
			.attr("dy", function (d) { return yScale(d.values[valuesLength].val)+3; });
		countryLineGroupEnter
			.append("text")
			.attr("class", "copLabel")
			.text( function (d) { return d.key; })
			.attr("dx", function (d) { return xScale(firstYear)-3; })
			.attr("dy", function (d) { return yScale(d.values[0].val)+3; });
    
    // UPDATE ALL MY ELEMENTS
    var updateSelection = svg.selectAll(".country-line-group")
        .transition()
        .duration(250);


    // this is the crazy part
    // you have to use .select to propigate changes down to child elements
    // the selectAll above points at the svg g
    // now the one below points at the children

    updateSelection.select("path")
				.attr("d", function(d) { return line(d.values); });
		updateSelection.select("text.numLabel")
			.text( function (d) { return "$" + addCommas(d.values[valuesLength].val); })
			.attr("dx", function (d) { return xScale(lastYear)+3; })
			.attr("dy", function (d) { return yScale(d.values[valuesLength].val)+3; });
		updateSelection.select("text.copLabel")
			.text( function (d) { return d.key; })
			.attr("dx", function (d) { return xScale(firstYear)-3; })
			.attr("dy", function (d) { return yScale(d.values[0].val)+3; });


		// NOW, REMOVE ELEMENTS NO LONGER BOUND TO DATA
    countryLineGroup.exit()
        .attr("class", ".country-line-group exit")
        .transition()
        .duration(250)
        .style("opacity", 0)
        .remove();

	};

	drawChartForCountry("Australia");
	window.drawChartForCountry = drawChartForCountry;

});

// </script>