D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
meborn
Full window
Github gist
wealth and heath
Built with
blockbuilder.org
<!DOCTYPE html> <head> <meta charset="utf-8"> <script type='text/javascript' src="https://d3js.org/d3.v4.min.js"></script> <script type='text/javascript' src="/index.js"></script> <title>My Page Title</title> <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet"> <style> .container { display: inline-block; position: relative; } h2 { font-family: 'Roboto', sans-serif; font-size: 54px; margin-left: 40px; margin-bottom: 0px; } h1 { font-family: 'Roboto', sans-serif; font-size: 200px; position: absolute; right: 0px; bottom: 20px; margin-bottom: 0px; color: #ccc; } </style> </head> <body> <h2>The Wealth & Health of Nations</h2> <div class='container'> </div> <script> var margin = {top: 40, right: 40, bottom: 40, left: 40} var width = 960 - margin.left - margin.right; var height = 540 - margin.top - margin.bottom; var loadYearMinMax = function(nations) { var nationYears = nations.map(function(nation) { var incomeMinMax = d3.extent(nation.income, function(i) {return i[0]}) var lifeMinMax = d3.extent(nation.lifeExpectancy, function(i) {return i[0]}) var popMinMax = d3.extent(nation.population, function(i) {return i[0]}) var allMinMax = d3.merge([incomeMinMax, lifeMinMax, popMinMax]) return d3.extent(allMinMax) }) return d3.extent(d3.merge(nationYears)) } // Add Year 2009 if it isn't there var addLastYear = function(nation, attr, years) { var last = nation[attr][nation[attr].length-1] var firstYear = years[0] var lastYear = years[years.length-1] if(nation[attr].length < years.length && last[0] != lastYear) { nation[attr].push([lastYear, last[1]]) } return nation[attr] } // Add Missing Year var interpolateAttr = function(nation, year, index, attr) { if(index === 0 && nation[attr][0][0] != year) { nation[attr].unshift([year, nation[attr][0][1]]) } else if(nation[attr][index] && nation[attr][index][0] != year) { var prev = index-1; var next = nation[attr].length-1 == index ? index : index+1; if(nation[attr][prev] && nation[attr][next]) { var p1 = {x: nation[attr][prev][0], y: nation[attr][prev][1]}; var p3 = {x: nation[attr][next][0], y: nation[attr][next][1]}; var p2 = {x: year}; var y = (((p2.x - p1.x)*(p3.y-p1.y))/(p3.x = p1.x))+p1.y; nation[attr].splice(index, 0, [year, y]); } } return nation[attr] } var buildNewNation = function(nation, index) { return { name: nation.name, region: nation.region, income: nation.income[index][1], lifeExpectancy: nation.lifeExpectancy[index][1], population: nation.population[index][1] } } var loadRange = function() { return { x: [0, width], y: [height, 0], radius: [1, 60], color: ['#45CCFF','#49E83E','#FFD432','#E80030','#B243FF','#080CFF'] } } var loadDomain = function(x, y, radius, color) { return { x: d3.extent(x), y: d3.extent(y), radius: d3.extent(radius), color: color } } var loadScale = function(domain, range) { return { x: d3.scaleLog().domain(domain.x).range(range.x), y: d3.scaleLinear().domain(domain.y).range(range.y), color: d3.scaleOrdinal().domain(domain.color).range(range.color), radius: d3.scaleSqrt().domain(domain.radius).range(range.radius) } } var drawAxes = function(scale, graph) { var xAxis = d3.axisBottom().ticks(10, d3.format("($.0f")).scale(scale.x); var yAxis = d3.axisLeft().scale(scale.y); graph.append('g') .attr('transform', 'translate(0,'+height+')') .call(xAxis) graph.append('g') .call(yAxis) } var drawSvg = function() { var svgWidth = width + margin.left + margin.right; var svgHeight = height + margin.top + margin.bottom var graph = d3.select('.container') .append('svg') .attr('width', svgWidth) .attr('height', svgHeight) .append('g') .attr('transform', 'translate('+margin.left+','+margin.top+')') d3.select('.container').append('h1') return graph } var draw = function(graph, nations, scale) { if(currentYear > 2009) { return clearInterval(interval) } else { d3.select('h1').text(currentYear) var t = d3.transition().duration(300); var oldCircles = graph.selectAll('circle') .data(nations, function(nation) {return nation.name}) if(currentYear === 1800 || currentYear === 2000) { console.log(oldCircles) } oldCircles.exit().remove(); var newCircles = oldCircles.enter() .append('circle') .attr('cx', function(nation) {return scale.x(nation.income)}) .attr('cy', function(nation) {return scale.y(nation.lifeExpectancy)}) var circles = newCircles.merge(oldCircles) .transition(t) .attr('cx', function(nation) {return scale.x(nation.income)}) .attr('cy', function(nation) {return scale.y(nation.lifeExpectancy)}) .attr('r', function(nation) {return scale.radius(nation.population)}) .attr('fill', function(nation) {return scale.color(nation.region)}) .attr('fill-opacity', '0.5') .attr('stroke-width', '1px') .attr('stroke', function(nation) {return scale.color(nation.region)}) } currentYear++ } var startInterval = function(graph, nations, scale) { return window.setInterval(function() { draw(graph, nations[currentYear], scale) }, 100); } var interval; var currentYear = 1800 d3.json('nations.json', function(error, nations) { var yearMinMax = loadYearMinMax(nations) var regions = d3.nest().key(function(n) { return n.region }).entries(nations).map(function(r) { return r.key }) var years = [] var incomes = [] var populations = [] var lifeExpectancies = [] var newNations = {} for(var year=yearMinMax[0]; year<=yearMinMax[1]; ++year) { years.push(year) newNations[year] = [] } nations.forEach(function(nation) { nation.income = addLastYear(nation, 'income', years) nation.lifeExpectancy = addLastYear(nation, 'lifeExpectancy', years) nation.population = addLastYear(nation, 'population', years) years.forEach(function(year, index) { nation.income = interpolateAttr(nation, year, index,'income') nation.lifeExpectancy = interpolateAttr(nation, year, index,'lifeExpectancy') nation.population = interpolateAttr(nation, year, index,'population') var newNation = buildNewNation(nation, index) incomes.push(newNation.income) populations.push(newNation.population) lifeExpectancies.push(newNation.lifeExpectancy) newNations[year].push(newNation) }) }) var domain = loadDomain(incomes, lifeExpectancies, populations, regions) var range = loadRange() var scale = loadScale(domain, range) var graph = drawSvg() drawAxes(scale, graph) interval = startInterval(graph, newNations, scale) }) </script> </body> </html>
https://d3js.org/d3.v4.min.js