Earth's climate.
Drag to rotate, mousewheel to zoom. Click a play/pause to animate. Click a country for details.
Built with d3gl
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>D3GL Earth Climate</title> | |
<link rel="stylesheet" href="http://dcpos.ch/d3gl/css/demo.css" /> | |
<link rel="stylesheet" href="http://dcpos.ch/d3gl/css/demo-countries.css" /> | |
</head> | |
<body> | |
<ul id="picker"> | |
</ul> | |
<div id="climate-globe-labels"> | |
<div id="pr"> | |
Precipitation <br /> | |
<img src="http://dcpos.ch/d3gl/demos/pr_scale.png" /> | |
</div> | |
<div id="tas"> | |
Temperature <br /> | |
<img src="http://dcpos.ch/d3gl/demos/tas_scale.png" /> | |
</div> | |
</div> | |
<script type="text/javascript" src="http://dcpos.ch/d3gl/js/d3gl.min.js"></script> | |
<script type="text/javascript" src="http://dcpos.ch/d3gl/data/country_code_map.js"></script> | |
<script type="text/javascript"> | |
var climateDataTypes = ["pr", "tas"]; | |
var months = ["Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sep", "Oct", "Nov", "Dec"]; | |
var monthIdx = 0; // jan displays by default | |
function createControls(){ | |
var selected, hovered, active, playing = false; | |
d3.select("#picker").selectAll("li") | |
.data(months) | |
.enter().append("li") | |
.text(function(d){ return d; }) | |
.attr("id", function(d, i) { | |
return d; | |
}) | |
.on('mouseover', function(d) { | |
if(hovered) $(hovered).removeClass("hovered"); | |
$(hovered = this).addClass("hovered"); | |
}) | |
.on('mouseout', function(d) { | |
$(this).removeClass("hovered"); | |
hovered = null; | |
}) | |
.on('mousedown', function(d) { | |
if(active) $(active).removeClass("active"); | |
$(active = this).addClass("active"); | |
}) | |
.on('mouseup', function(d) { | |
$(this).removeClass("active"); | |
}) | |
.on('click', function(d) { | |
if(selected) $(selected).removeClass("selected"); | |
$(selected = this).addClass("selected"); | |
monthIdx = months.indexOf(selected.id); | |
}); | |
d3.select("#picker").append("li") | |
.attr("class", "play") | |
.html(" ") | |
.on('click', function(){ | |
playing = !playing; | |
$(this).attr("class", playing ? "play pause" : "play"); | |
}); | |
setInterval(function(){ | |
if(!playing) return; | |
monthIdx = (monthIdx+1)%12; | |
if(selected) $(selected).removeClass("selected"); | |
selected = $("#"+months[monthIdx]).addClass("selected"); | |
}, 90); | |
selected = $("#Jan").addClass("selected"); | |
} | |
function loadData(callback) { | |
var data = {}; | |
var nLoaded = 0; | |
d3.json("http://dcpos.ch/d3gl/data/pr.json", function(datum){ | |
var domain = [0, 100, 200, 300, 400, 500]; | |
data["pr"] = {}; | |
data["pr"].scale = d3.scale.linear() | |
.domain(domain) | |
.range([ | |
"#ffffff", // [-INF, 100) | |
"#00cc99", // [100, 200) | |
"#008f6b", // [200, 300) | |
"#00644b", // [300, 400) | |
"#004634" // [400, INF] | |
]); | |
data["pr"].data = datum; | |
if(++nLoaded==2) { | |
callback(data); | |
} | |
}); | |
d3.json("http://dcpos.ch/d3gl/data/tas.json", function(datum){ | |
data["tas"] = {}; | |
data["tas"].scale = d3.scale.quantile() | |
.domain([-40, 40]) | |
.range([ | |
"#000000", // [-40, -30) | |
"#000099", // [-30, -20) | |
"#0033cc", // [-20, -10) | |
"#0066ff", // [-10, 0) | |
"#0099ff", // [0, 10) | |
"#00cc66", // [10, 20) | |
"#ffcc00", // [20, 30) | |
"#ff6600" // [30, 40] | |
]); | |
data["tas"].data = datum; | |
if(++nLoaded==2) { | |
callback(data); | |
} | |
}); | |
} | |
function createGlobes(data) { | |
// create the globe | |
var globe = d3.gl.globe() | |
.width(360).height(360) | |
.texture("http://dcpos.ch/d3gl/img/earth-blank.png") | |
.transparency(function(body){ | |
return 0.6; | |
}); | |
var mouseoverPoint; | |
globe.shapes("countries") | |
.data(function(climateDataT) { | |
return data[climateDataT]["data"]; | |
}) | |
.id(function(d){ | |
// the id returned here must match the color in the shape texture | |
// such that r*10*10 + g*10 + b = id | |
return country_code_map["alpha_code_to_country"][d["ISO_code"]]["country-code"]; | |
}) | |
.color(function(d){ | |
if(d==mouseoverPoint) return [50, 50, 50, 255]; | |
var values = d["monthly_data"]; | |
if(values.length>0) { | |
var value = parseInt(d["monthly_data"][monthIdx]["data"]); | |
var color = data[d["var"]].scale(value); | |
color = color.slice(1); | |
var sr = parseInt(color.substring(0, 2), 16); | |
var sg = parseInt(color.substring(2, 4), 16); | |
var sb = parseInt(color.substring(4), 16); | |
return [sr, sg, sb, 255]; | |
} | |
return [0, 0, 0, 0]; | |
}) | |
.on("mousemove", function(evt) { | |
if(evt.shape) { | |
mouseoverPoint = evt.shape; | |
} else { | |
mouseoverPoint = null; | |
} | |
}) | |
.on("click", function(evt) { | |
if(evt.shape) { | |
showDetails(evt, evt.shape); | |
} else { | |
$("#bubble").hide(); | |
} | |
}); | |
d3.select("body").selectAll(".climate-globe") | |
.data(climateDataTypes).enter() | |
.append("span").attr("class", "climate-globe") | |
.call(globe); | |
} | |
function showDetails(mouseEvent, data) { | |
var name = country_code_map["alpha_code_to_country"][data["ISO_code"]]["name"]; | |
var value = months[monthIdx]+": "; | |
if(data["monthly_data"].length==0){ | |
value += "N/A"; | |
} else { | |
value += Math.round(data["monthly_data"][monthIdx]["data"]); | |
value += data["var"]=="pr" ? " mm" : " °C"; | |
} | |
var size = name.length > 15 ? "10pt" : "12pt"; | |
var height = name.length > 15 ? 60 : 40; | |
$("#bubble").show() | |
.css("font-size", size) | |
.css("height", height + "px") | |
.css("left", mouseEvent.clientX) | |
.css("top", mouseEvent.clientY + height/3) | |
.html(name + "<br />" + value); | |
} | |
$(function(){ | |
// create the ui | |
createControls(); | |
loadData(createGlobes); | |
}); | |
</script> | |
<div id="bubble"></div> | |
</body> | |
</html> |