Built with blockbuilder.org
xxxxxxxxxx
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<style>
body {
margin: 0;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.title {
font-family: "Georgia";
font-size: 32px;
fill: #000;
}
.axis {
font-family: "Arial";
font-size: 11px;
fill: #808080;
}
.circle {
fill-opacity: 0.75;
stroke: #c0c0c0;
}
.domain {
stroke: #c0c0c0;
}
.tick > line {
stroke: #c0c0c0;
}
.line1 {
fill: none;
stroke: pink;
stroke-width: 3px;
}
.line2 {
fill: none;
stroke: darkseagreen;
stroke-width: 3px;
}
</style>
</head>
<body>
<div class="container" style="width: 960px;">
<div class="row">
<div class="col-md-4 col-xs-4">
<p>Country 1</p>
<select id="x-menu"></select>
</div>
<div class="col-md-4 col-xs-4">
<p>Country 2</p>
<select id="y-menu"></select>
</div>
<div class="col-md-4 col-xs-4">
<form id="series">
<input type="radio" id="income" name="series" value="income" checked /> Income<br/>
<input type="radio" id="lifeExpectancy" name="series" value="lifeExpectancy" /> Life Expectancy<br/>
<input type="radio" id="population" name="series" value="population" /> Population<br/>
</form>
</div>
</div>
<div class="row">
<div class="col-md-12 col-xs-12 graph">
</div>
</div>
</div>
<script>
var scales = {};
var series = ["income", "lifeExpectancy", "population"];
var populateMenus = function(data, menuID, defaultVal) {
var dropdown = d3.select(menuID);
dropdown.selectAll("option")
.data(data)
.enter()
.append("option")
.attr("value", function(d) { return d.name })
.attr("selected", function(d) {
if (d.name == defaultVal) {
return "selected";
}
})
.text(function(d) { return d.name });
}
var appendRadioButtons = function(input) {
var form = d3.select("#series");
form.selectAll("input")
.data(input)
.enter()
.append("input")
.attr("type", "radio")
.attr("id", function(d) { return d })
.attr("value", function(d) { return d })
.attr("name", "series")
.attr("checked", function(d, i) {
if (i === 0) {
return "checked"
}
})
.text(function(d) { return d });
}
var processData = function(data, yrExtent) {
var result = [];
for (yr = yrExtent[0]; yr <= yrExtent[1]; yr++) {
var yrResult = [];
data.forEach(function(d) {
var nation = {
income: null,
lifeExpectancy: null,
name: null,
population: null,
region: null
}
var incomeData = getAttrByYear(d, nation, yr, "income");
var lifeExpData = getAttrByYear(d, nation, yr, "lifeExpectancy");
var populationData = getAttrByYear(d, nation, yr, "population");
nation.name = d.name;
nation.region = d.region;
yrResult.push(nation);
});
result[yr] = yrResult;
}
return result;
}
var getMinMax = function(input, attr) {
var min = 99999999;
var max = 0;
input.forEach(function(d) {
d[attr].forEach(function(i) {
if (i[1] < min) {
min = i[1];
}
if (i[1] > max) {
max = i[1];
}
});
});
return [min, max];
}
var update = function(data, svg, nation1, nation2, series) {
var selection = svg.selectAll("circle")
.data(newData);
selection.enter()
.append("circle")
.merge(selection)
.transition()
.attr("cx", function(d) {
if (d.income != null) {
return scales.xSca(d.income)
}})
.attr("cy", function(d) {
if (d.lifeExpectancy != null) {
return scales.ySca(d.lifeExpectancy)
}
})
.attr("r", function(d) {
if ((d.income && d.lifeExpectancy && d.population) != null) {
return scales.rSca(d.population)
}
})
.attr("id", function(d) { return d.name })
.attr("fill", function(d) { return scales.cSca(d.region) })
.attr("class", "circle");
d3.select(".year").text(year);
selection.exit().remove();
}
var getExtent = function(data, offset) {
var minYear;
var maxYear;
data.forEach(function(d) {
var inc = d.income.sort();
var incMin = inc.slice(0)[0][offset];
if (minYear > incMin | !(minYear)) {
minYear = incMin;
}
var incMax = inc.slice(-1)[0][offset];
if (maxYear < incMax | !(maxYear)) {
maxYear
}
var life = d.lifeExpectancy.sort();
var lifeMin = inc.slice(0)[0][offset];
if (minYear > lifeMin | !(minYear)) {
minYear = lifeMin;
}
var lifeMax = inc.slice(-1)[0][offset];
if (maxYear < lifeMax | !(maxYear)) {
maxYear = lifeMax;
}
var pop = d.population.sort();
var popMin = inc.slice(0)[0][offset];
if (minYear > popMin | !(minYear)) {
minYear = popMin;
}
var popMax = inc.slice(-1)[0][offset];
if (maxYear < popMax | !(maxYear)) {
maxYear = popMax;
}
})
return [minYear, maxYear];
}
var getAttrByYear = function(input, output, year, attr) {
input[attr].forEach(function(d) {
if (d[0] === year) {
return output[attr] = d[1];
}
});
}
d3.json("nations.json", function(error, data) {
if (error) return error;
console.log(data); // original data
// input: old data => output: min/max years of all data
yrExtent = getExtent(data, 0);
newData = processData(data, yrExtent);
minData = newData[1800];
console.log(newData); // filtered data
// populate menus
populateMenus(minData, "#x-menu", "United States");
populateMenus(minData, "#y-menu", "Canada");
// refactor to getNationData()
var nation1Data = d3.nest()
.key(function(d) { return d.name == "United States" })
.object(data);
var nation2Data = d3.nest()
.key(function(d) { return d.name == "Canada" })
.object(data);
var nation1Series = nation1Data["true"][0].income;
var nation2Series = nation2Data["true"][0].income;
console.log("nation1Series", nation1Series);
console.log("nation2Series", nation2Series);
// vars -----------------------------------------------------------
var margin = { top: 20, right: 20, bottom: 20, left: 50 };
var width = 930 - margin.left - margin.right;
var height = 430 - margin.top - margin.bottom;
// min-max
var xExtent = yrExtent;
var yExtent = getExtent(data, 1);
// var rExtent = getMinMax(data, "population");
var colorDomain = d3.nest().key(function(d) { return d.region }).object(minData);
// console.log("colorDomain", colorDomain);
// console.log("xExtent = ", xExtent, "yExtent = ", yExtent);
// scales
var xScale = d3.scaleTime()
.domain([new Date(1800), new Date(2009)])
.range([0, width]);
var yScale = d3.scaleLinear()
.domain(yExtent)
.range([height, 0]);
// var rScale = d3.scaleSqrt()
// .domain(rExtent)
// .range([0,90]);
var colorScale = d3.scaleOrdinal()
.domain(colorDomain)
.range(["Pink", "LightCyan", "Gainsboro", "Thistle", "MintCream", "LemonChiffon"]);
// axes
var x = d3.axisBottom()
.scale(xScale)
.tickFormat(d3.timeFormat("%Y"));
var y = d3.axisLeft()
.scale(yScale);
// graph ----------------------------------------------------------
// svg
var svg = d3.select(".graph")
.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 + ")");
// axes
var xAxis = svg.append("g")
.call(x)
.attr("transform", "translate(0, " + height + ")");
var yAxis = svg.append("g")
.call(y);
// labels
var yLabel = yAxis.append("text")
.text("income (dollars)")
.attr("class", "axis")
.attr("transform", "translate(15, 0) rotate(-90)")
.attr("text-anchor", "end");
var gNation1 = svg.append("g")
.attr("id", "nation1");
var gNation2 = svg.append("g")
.attr("id", "nation2");
var line = d3.line()
.x(function(d) { return xScale(d[0]) })
.y(function(d) { return yScale(d[1]) });
var path1 = svg
.append("path")
.attr("class", "line1")
.datum(nation1Series)
.attr("d", line);
var path2 = svg
.append("path")
.attr("class", "line2")
.datum(nation2Series)
.attr("d", line);
});
</script>
</body>
</html>
https://d3js.org/d3.v4.min.js