D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
kcsluis
Full window
Github gist
Incomes and Countries
<!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>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js