Skip to content

Instantly share code, notes, and snippets.

@jrzief
Last active July 31, 2019 17:52
Show Gist options
  • Save jrzief/b4626d5bd41b338279b175ddae3a5cd8 to your computer and use it in GitHub Desktop.
Save jrzief/b4626d5bd41b338279b175ddae3a5cd8 to your computer and use it in GitHub Desktop.
Health and Wealth with tooltip
license: mit
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.9.1/d3-tip.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<style>
#chart-area svg {
margin-left: auto;
margin-right: auto;
display: block;
}
#reset-button, #play-button {
float: left;
margin-right:10px;
}
#reset-button, #play-button {
margin-top: 5px;
margin-bottom:10px;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6">
<button id="play-button" class="btn btn-primary">Play</button>
<button id="reset-button" class="btn btn-primary">Reset</button>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div id="chart-area"></div>
</div>
</div>
</div>
<script>
var margin = { left:80, right:20, top:50, bottom:100 };
var height = 600 - margin.top - margin.bottom,
width = 900 - margin.left - margin.right;
var g = d3.select("#chart-area")
.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 + ")");
var time = 0;
// Tooltip
var tip = d3.tip().attr('class', 'd3-tip')
.html(function(d) {
var text = "<strong>Country:</strong> <span style='color:red'>" + d.country + "</span><br>";
text += "<strong>Continent:</strong> <span style='color:red;text-transform:capitalize'>" + d.continent + "</span><br>";
text += "<strong>Life Expectancy:</strong> <span style='color:red'>" + d3.format(".2f")(d.life_exp) + "</span><br>";
text += "<strong>GDP Per Capita:</strong> <span style='color:red'>" + d3.format("$,.0f")(d.income) + "</span><br>";
text += "<strong>Population:</strong> <span style='color:red'>" + d3.format(",.0f")(d.population) + "</span><br>";
return text;
});
g.call(tip);
var interval;
var formattedData;
//Labels
var xLabel = g.append("text")
.attr("y", height + 50)
.attr("x", width / 2)
.attr("font-size", "20px")
.attr("text-anchor", "middle")
.text("GDP Per Capita ($)");
var yLabel = g.append("text")
.attr("transform", "rotate(-90)")
.attr("y", -40)
.attr("x", -170)
.attr("font-size", "20px")
.attr("text-anchor", "middle")
.text("Life Expectancy (Years)")
var timeLabel = g.append("text")
.attr("y", height -10)
.attr("x", width - 40)
.attr("font-size", "40px")
.attr("opacity", "0.4")
.attr("text-anchor", "middle")
.text("1800");
//Scales
var x = d3.scaleLog()
.base(10)
.domain([142, 150000])
.range([0, width]);
var y = d3.scaleLinear()
.domain([0, 90])
.range([height, 0]);
var area = d3.scaleLinear()
.range([25*Math.PI, 1500*Math.PI])
.domain([2000, 1400000000]);
// X Axis
var xAxisCall = d3.axisBottom(x)
.tickValues([400, 4000, 40000])
.tickFormat(d3.format("$"));
g.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height +")")
.call(xAxisCall);
// Y Axis
var yAxisCall = d3.axisLeft(y)
.tickFormat(function(d){ return +d; });
g.append("g")
.attr("class", "y axis")
.call(yAxisCall);
var continentColor = d3.scaleOrdinal(d3.schemeCategory20);
//Building the Legend
var continents = ["europe", "asia", "americas", "africa"];
var legend = g.append("g")
.attr("transform", "translate(" + (width - 10) +
"," + (height - 125) + ")");
continents.forEach(function(continent, i){
var legendRow = legend.append("g")
.attr("transform", "translate(0, " + (i * 20) + ")");
legendRow.append("rect")
.attr("width", 10)
.attr("height", 10)
.attr("fill", continentColor(continent));
legendRow.append("text")
.attr("x", -10)
.attr("y", 10)
.attr("text-anchor", "end")
.style("text-transform", "capitalize")
.text(continent);
});
//GET THE DATA
d3.json("data.json", function(data){
console.log(data);
// Clean data
formattedData = data.map(function(year){
return year["countries"].filter(function(country){
var dataExists = (country.income && country.life_exp);
return dataExists
}).map(function(country){
country.income = +country.income;
country.life_exp = +country.life_exp;
return country;
})
});
// First run of the visualization
update(formattedData[0]);
});
$("#play-button")
.on("click", function(){
var button = $(this);
if (button.text() == "Play"){
button.text("Pause");
interval = setInterval(step, 100);
}
else {
button.text("Play");
clearInterval(interval);
}
})
$("#reset-button")
.on("click", function(){
time = 0;
update(formattedData[0]);
})
function step(){
// At the end of our data, loop back
time = (time < 167) ? time+1 : 0
update(formattedData[time]);
}
function update(data) {
var t = d3.transition()
.duration(100);
// JOIN new data with old elements.
var circles = g.selectAll("circle")
.data(data, function(d) {return d.country; });
// EXIT old elements not present in new data.
circles.exit()
.attr("class", "exit")
.remove();
// ENTER new elements present in new data.
var enter = circles.enter()
.append("circle")
//.filter(function(year) {return year === "1800"})
.attr("class", "enter")
.attr("fill", function(d) { return continentColor(d.continent); })
.on("mouseover", tip.show)
.on("mouseout", tip.hide)
.merge(circles)
.transition(t)
.attr("cy", function(d){ return y(d.life_exp); })
.attr("cx", function(d){ return x(d.income) })
.attr("r", function(d){ return Math.sqrt(area(d.population) / Math.PI) });
// Update the time label
timeLabel.text(+(time + 1850))
}
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment