Skip to content

Instantly share code, notes, and snippets.

@renecnielsen
Forked from mbostock/.block
Last active August 29, 2015 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save renecnielsen/9549823 to your computer and use it in GitHub Desktop.
Save renecnielsen/9549823 to your computer and use it in GitHub Desktop.
Post-2015 World Tour with Category Menu and Bar Chart
<!DOCTYPE html>
<html>
<head>
<title>Post-2015 Globe | UN Global Pulse</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:300,600' rel='stylesheet' type='text/css'>
<link href="style.css" rel="stylesheet" type="text/css">
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/queue.v1.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.min.js"></script>
</head>
<body>
<?php
$topics = array(
"education" => "A good education",
"water" => "Access to clean water and sanitation",
"climate" => "Action taken on climate change",
"food" => "Affordable and nutritious food",
"government" => "An honest and responsive government",
"health" => "Better healthcare",
"job" => "Better job opportunities",
"transport" => "Better transport and roads",
"equality" => "Equality between men and women",
"discrimination" => "Freedom from discrimination",
"phone" => "Phone and internet access",
"politicalfreedoms" => "Political freedoms",
"forests" => "Protecting forests rivers and oceans",
"crime" => "Protection against crime and violence",
"energy" => "Reliable energy at home",
"support" => "Support for people who can't work"
);
?>
<div id="theglobe">
<div id="header">
<h1>Talking about <span id="topicDescription">A good education</span>: </h1><h2></h2><br />
<span class="subtitle"></span>
</div> <!-- #header -->
<div id="left">
<p>The globe spins to show the 20 countries that have proportionately talked the most about the highlighted Post-2015 topic on Twitter from August 2012 to now.</p>
<h3>Pick a topic below</h3>
<div id="navigation-container">
<nav class="navigation">
<ul id="navigation">
<?
$tCount = 1;
foreach ($topics as $topicKey => $topicDesc) {
echo "<li class=\"navigation-{$topicKey}\"><a href=\"#\" onclick=\"setTopic(".$tCount.");\">{$topicDesc}</a></li>";
$tCount++;
}
?>
</ul>
</nav>
</div> <!-- #navigation-container -->
</div> <!-- #left -->
<div id="globe"></div>
<div id="right">
<h3>Ranking</h3>
<p>The ranking shows the countries with the highest proportion of tweets about the highlighted topic. The percentages refer to the proportion of tweets about the highlighted topic, in relation to tweets about all the other Post-2015 topics, that were generated by that country.</p>
</div> <!-- #right -->
<div id="chart"></div>
</div> <!-- #theglobe -->
<!-- Globe Javascript -->
<script type="text/javascript">
var topics = new Array();
topics[ 1] = "education";
topics[ 2] = "water";
topics[ 3] = "climate";
topics[ 4] = "food";
topics[ 5] = "government";
topics[ 6] = "health";
topics[ 7] = "job";
topics[ 8] = "transport";
topics[ 9] = "equality";
topics[10] = "discrimination";
topics[11] = "phone";
topics[12] = "politicalfreedoms";
topics[13] = "forests";
topics[14] = "crime";
topics[15] = "energy";
topics[16] = "support";
var topicDescriptions = new Array();
topicDescriptions[ 1] = "A good education";
topicDescriptions[ 2] = "Access to clean water and sanitation";
topicDescriptions[ 3] = "Action taken on climate change";
topicDescriptions[ 4] = "Affordable and nutritious food";
topicDescriptions[ 5] = "An honest and responsive government";
topicDescriptions[ 6] = "Better healthcare";
topicDescriptions[ 7] = "Better job opportunities";
topicDescriptions[ 8] = "Better transport and roads";
topicDescriptions[ 9] = "Equality between men and women";
topicDescriptions[10] = "Freedom from discrimination";
topicDescriptions[11] = "Phone and internet access";
topicDescriptions[12] = "Political freedoms";
topicDescriptions[13] = "Protecting forests rivers and oceans";
topicDescriptions[14] = "Protection against crime and violence";
topicDescriptions[15] = "Reliable energy at home";
topicDescriptions[16] = "Support for people who can't work";
var colors = new Array();
colors[ 1] = "#47c0be";
colors[ 2] = "#97d3c9";
colors[ 3] = "#fcb749";
colors[ 4] = "#b0d256";
colors[ 5] = "#2da9e1";
colors[ 6] = "#ca3a28";
colors[ 7] = "#e8168b";
colors[ 8] = "#fbe792";
colors[ 9] = "#c84699";
colors[10] = "#dec0ca";
colors[11] = "#7cb5d6";
colors[12] = "#723390";
colors[13] = "#71be45";
colors[14] = "#387195";
colors[15] = "#a01c40";
colors[16] = "#233884";
var atTopic = 0;
var i = -1;
function markTopicActive(tId) {
for(var x=1; x<=16; x++) {
var liClass = "navigation-"+topics[x];
var liElement = d3.select("."+liClass);
if (x == tId) {
liElement.attr("class", liClass + " active");
} else {
liElement.attr("class", liClass);
}
}
}
function setTopic(tId) {
i = -1;
atTopic = tId;
topic = topics[atTopic];
color = colors[atTopic];
topicDescription = topicDescriptions[atTopic];
tD = d3.select("#topicDescription");
tD.attr("class", "topic-"+topic);
tD.text(topicDescription);
markTopicActive(tId);
renderBarGraph();
}
function nextTopic() {
goToTopic = atTopic + 1;
if (goToTopic >16) goToTopic = 1;
setTopic(goToTopic);
}
if (window.innerWidth < 768)
{
var width = window.innerWidth,
height = width,
barwidth = width * 0.35,
barheight = height;
}
else
{
var width = 750,
height = 750,
barwidth = 300,
barheight = 450;
}
var projection = d3.geo.orthographic()
.scale(height*0.35)
.translate([width/2,height/2])
.clipAngle(90);
var canvas = d3.select("#globe").append("canvas")
.attr("class", "globe")
.attr("width", width)
.attr("height", height);
var c = canvas.node().getContext("2d");
var path = d3.geo.path()
.projection(projection)
.context(c);
var title = d3.select("h2");
var subtitle = d3.select(".subtitle");
var margin = {top: 5, right: 40, bottom: 5, left: 160};
var x = d3.scale.linear()
.range([barwidth, 0]);
var y = d3.scale.ordinal()
.rangeRoundBands([0, barheight], .75);
var xAxis = d3.svg.axis()
.scale(x)
.orient("top")
.tickFormat(function(d){return d + "%";});
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var tip = d3.tip()
.attr('id', "d3-tip")
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<h3>" + d.place + ". " + d.name + "</h3>" + "Tweets about " + topicDescription + ": " + "<b>" + numberWithCommas(d.counttopic) + "</b>" + "<br/>" + "Tweets about Post-2015: <b>" + numberWithCommas(d.counttotal) + "</b>" + "<br/>" + "% about " + topicDescription + ": " + "<b>" + d.share + "</b>";
})
popup = d3.tip()
.attr('id', "d3-popup")
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<h3>HI</h3>";
});
var svg;
var countries;
var globalNames;
function fixedHide() {
tip.hide();
tip.attr("style", "position: absolute; opacity: 0; top: 0px; left: 0px;");
}
function renderBarGraph() {
d3.select("#barGraph").remove();
svg = d3.select("#chart").append("svg")
.attr("id", "barGraph")
.attr("width", barwidth + margin.left + margin.right)
.attr("height", barheight + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(tip);
topicCountries = countries.filter(function(d) {
return globalNames.some(function(n) {
if (d.id == n.id && n.topic == topic) {
d.topic = n.topic;
d.share = n.share;
d.counttotal = n.counttotal;
d.counttopic = n.counttopic;
d.place = n.place;
return d.name = n.name;
}
});
}).sort(function(a, b) {
return a.place - b.place;
});
y.domain(topicCountries.map(function(d) { return d.name; }));
x.domain([d3.max(topicCountries, function(d) { return Number(d.share); }), 0]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(" + barheight + "), 0")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.selectAll(".bar")
.data(topicCountries)
.enter().append("rect")
.attr("class", "bar")
.attr("fill", color)
.attr("y", function(d) { return y(d.name); })
.attr("height", y.rangeBand())
.attr("x", function(d) { return 0; })
.attr("width", function(d) { return x(d.share); })
.on('mouseover', tip.show)
.on('mouseout', fixedHide);
svg.selectAll(".barvalue")
.data(topicCountries)
.enter().append("text")
.attr("class", "barvalue")
.attr("x", function(d) { return x(d.share); })
.attr("y", function(d) { return y(d.name); })
.attr("dx", 3)
.attr("dy", ".5em")
.attr("text-anchor", "start")
.text(function(d) { return d.share + "%"; });
}
queue()
.defer(d3.json, "world-110m.json")
.defer(d3.tsv, "combined_countries.tsv")
.await(ready);
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
function boldCountryName(i) {
yAx = d3.select("svg").select("g").select("g.y.axis")
yAx.selectAll("g.tick").select("text").style("font-weight","normal");
yAx.select("g.tick:nth-of-type("+(i+1)+")").select("text").style("font-weight","bold");
}
function ready(error, world, names) {
globalNames = names;
countries = topojson.feature(world, world.objects.countries).features;
var globe = {type: "Sphere"},
land = topojson.feature(world, world.objects.land),
borders = topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; });
countries = countries.filter(function(d) {
return names.some(function(n) {
if (d.id == n.id) {
d.topic = n.topic;
d.share = n.share;
d.counttotal = n.counttotal;
d.counttopic = n.counttopic;
d.place = n.place;
return d.name = n.name;
}
});
})/*.sort(function(a, b) {
return a.place - b.place;
})*/;
nextTopic();
(function transition() {
n = topicCountries.length;
if (i >= n-1) {
nextTopic();
}
d3.transition()
.duration(2000)
.each("start", function() {
i = i + 1;
country = topicCountries[i];
title.text(country.name);
//subtitle.text("Of " + numberWithCommas(country.counttotal) + " Post-2015 tweets from " + country.name + ", " + country.share + "% are about " + topic);
boldCountryName(i);
})
.tween("rotate", function() {
var p = d3.geo.centroid(topicCountries[i]),
r = d3.interpolate(projection.rotate(), [-p[0], -p[1]]);
return function(t) {
projection.rotate(r(t));
c.clearRect(0, 0, width, height);
c.fillStyle = "#bbb", c.beginPath(), path(land), c.fill();
c.fillStyle = color, c.beginPath(), path(topicCountries[i]), c.fill();
c.strokeStyle = "#fff", c.lineWidth = .2, c.beginPath(), path(borders), c.stroke();
};
})
.transition()
.each("end", transition);
})();
}
</script>
</body>
</html>
html, body {
height: 100%;
font: 12px 'Open Sans';
}
#theglobe {
position: relative;
z-index: 20;
width: 1400px;
height: 700px;
margin-left: auto;
margin-right: auto;
}
#theglobe h1, #theglobe h2 {
font-size: 2.3em;
display: inline;
font-weight: normal;
}
#theglobe h3 {
font-size: 1.4em;
margin: 0;
font-weight: normal;
}
#header {
position: absolute;
top: 0px;
left: 20px !important;
}
#left
{
position: absolute;
top: 50px;
width: 450px;
left: 20px;
}
#left h3
{
margin-top: 10px;
}
#navigation {
position: relative;
}
#navigation ul
{
margin: 0 !important;
padding: 0 !important;
list-style-type: none !important;
-webkit-padding-start: 0 !important;
}
#navigation li
{
margin: 0.5em 0 0 0 !important;
text-indent: -1.7em !important;
list-style-type: none !important;
color: #bbb !important;
font-size: 1.25em !important;
line-height: 1.3em !important;
}
#navigation li a
{
display: block !important;
color: rgba(0,0,0,0.7) !important;
display: inline !important;
text-decoration: none !important;
}
#navigation li.active a
{
color: #000 !important;
font-weight: bold !important;
}
li.navigation-education:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
margin: 0 .5em 0 0;
color: #47c0be;
background: #47c0be;
}
li.navigation-water:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
margin-right: .5em;
color: #97d3c9;
background: #97d3c9;
}
li.navigation-climate:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
margin-right: .5em;
color: #fcb749;
background: #fcb749;
}
li.navigation-food:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
margin-right: .5em;
color: #b0d256;
background: #b0d256;
}
li.navigation-government:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
margin-right: .5em;
color: #2da9e1;
background: #2da9e1;
}
li.navigation-health:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
margin-right: .5em;
color: #ca3a28;
background: #ca3a28;
}
li.navigation-job:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
margin-right: .5em;
color: #e8168b;
background: #e8168b;
}
li.navigation-transport:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
margin-right: .5em;
color: #fbe792;
background: #fbe792;
}
li.navigation-equality:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
margin-right: .5em;
color: #c84699;
background: #c84699;
}
li.navigation-discrimination:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
margin-right: .5em;
color: #dec0ca;
background: #dec0ca;
}
li.navigation-phone:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
margin-right: .5em;
color: #7cb5d6;
background: #7cb5d6;
}
li.navigation-politicalfreedoms:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
margin-right: .5em;
color: #723390;
background: #723390;
}
li.navigation-forests:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
margin-right: .5em;
color: #71be45;
background: #71be45;
}
li.navigation-crime:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
margin-right: .5em;
color: #387195;
background: #387195;
}
li.navigation-energy:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
margin-right: .5em;
color: #a01c40;
background: #a01c40;
}
li.navigation-support:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
margin-right: .5em;
color: #233884;
background: #233884;
}
#theglobe li.active:before
{
content: "√";
padding: 0 0.5em 0 0.5em;
color: #fff;
}
.topic-education
{
color: #47c0be;
}
.topic-water
{
color: #97d3c9;
}
.topic-climate
{
color: #fcb749;
}
.topic-food
{
color: #b0d256;
}
.topic-government
{
color: #2da9e1;
}
.topic-health
{
color: #ca3a28;
}
.topic-job
{
color: #e8168b;
}
.topic-transport
{
color: #fbe792;
}
.topic-equality
{
color: #c84699;
}
.topic-discrimination
{
color: #dec0ca;
}
.topic-phone
{
color: #7cb5d6;
}
.topic-politicalfreedoms
{
color: #723390;
}
.topic-forests
{
color: #71be45;
}
.topic-crime
{
color: #387195;
}
.topic-energy
{
color: #a01c40;
}
.topic-support
{
color: #233884;
}
#globe {
position: absolute;
left: 270px;
}
#right {
position: absolute;
left: 1050px;
top: 80px;
width: 320px;
}
#right h3 {
margin-bottom: 0;
}
#right p {
margin-top: 0;
margin-bottom: 0.5em;
font-size: 0.9em;
}
#chart {
position: absolute;
left: 890px;
top: 190px;
}
.x.axis path, .y.axis path {
display: none;
}
.y {
font-size: 0.9em;
}
.bar:hover {
fill: rgba(0, 0, 0,0.75);
}
text.barvalue {
fill: #000;
font-size: 0.7em;
}
.x.axis {
display: none;
}
.x.axis path {
display: none;
}
.d3-tip {
position: absolute;
line-height: 1;
font-weight: 200;
padding: 12px;
background: rgba(0,0,0,0.75);
color: #fff;
border-radius: 2px;
z-index: 100;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 15px;
width: 100%;
line-height: 0.75;
color: rgba(0, 0, 0,0.75);
content: "\25BC";
position: absolute;
text-align: center;
z-index: 100;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
/*height: 700px;*/
z-index: 100;
}
#theglobe .globe {
text-align: left !important;
padding: 20px 0;
position: relative;
}
.globe.multipage {
text-align: left;
padding: 30px 0 0;
}
.globe.multipage .copyright {
text-align: center;
}
/* ------------------------------------------------------------------------ */
/* Screensize specifics
/* ------------------------------------------------------------------------ */
@media only screen and (max-width: 767px) {
#theglobe {
width: 100%;
height: auto;
margin-left: auto;
margin-right: auto;
}
#theglobe h1, #theglobe h2 {
font-size: 1.3em !important;
display: inline !important;
font-weight: normal !important;
}
#theglobe h3 {
font-size: 1.1em !important;
}
#header {
position: static !important;
width: 95% !important;
margin-left: auto !important;
margin-right: auto !important;
margin-top: 10px;
}
#left {
position: static !important;
top: 0 !important;
width: 95% !important;
margin-left: auto !important;
margin-right: auto !important;
}
#globe {
position: static;
left: 0;
z-index:-6000;
overflow:hidden;
}
#right {
position: static !important;
width: 95% !important;
margin-left: auto !important;
margin-right: auto !important;
margin-bottom: 5px;
}
#right p {
margin-top: 0.5em;
margin-bottom: 0.5em;
font-size: 0.9em;
}
#chart {
position: static !important;
width: 95% !important;
margin-left: auto !important;
margin-right: auto !important;
}
.navigation {
position: relative;
min-height: 40px;
}
.navigation ul {
width: 90% !important;
margin-left: auto !important;
margin-right: auto !important;
padding: 5px 0;
position: relative;
top: 0;
border: solid 1px #bbb;
border-radius: 5px;
box-shadow: 0 1px 2px rgba(0,0,0,.3);
}
.navigation li {
display: none; /* hide all <li> items */
margin: 0;
}
.navigation .active {
display: block; /* show only current <li> item */
}
.navigation a {
display: block;
padding: 5px 5px 5px 5px;
text-align: left;
}
/* on nav hover */
.navigation ul:hover {
background-image: none;
}
.navigation ul:hover li {
display: block;
margin: 0 0 5px;
}
/* right nav */
.navigation.right ul {
left: auto;
right: 0;
}
/* center nav */
.navigation.center ul {
left: 50%;
margin-left: -90px;
}
}
@elsherbini
Copy link

Really incredible. Thank you for sharing the code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment