Created
November 22, 2015 16:33
-
-
Save sdbernard/cc7edf60f57fc407c621 to your computer and use it in GitHub Desktop.
d3 module 4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>EU Migration Crisis</title> | |
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script> | |
<script src="http://d3js.org/topojson.v1.min.js"></script> | |
<link href="https://fonts.googleapis.com/css?family=Roboto+Condensed:300normal,300italic,400normal,400italic,700normal,700italic|Roboto:400normal|Open+Sans:400normal|Oswald:400normal|Lato:400normal|Roboto+Slab:400normal|Open+Sans+Condensed:300normal|Source+Sans+Pro:400normal|Raleway:400normal|PT+Sans:400normal|Ubuntu:400normal&subset=all" rel="stylesheet" type="text/css"> | |
<style type="text/css"> | |
body { | |
background-color: #fff1e0; | |
margin-top: 3em; | |
font-family: 'Roboto Condensed', sans-serif; | |
font-weight: 400; | |
} | |
svg { | |
background-color: #ecf8fe; | |
} | |
h1 { | |
font-weight: 300; | |
font-size: 36px; | |
color: #333333; | |
margin-top: 0; | |
margin-bottom: 0; | |
margin-left: -2px; | |
} | |
h6 { | |
font-size: 12px; | |
margin-bottom: 0.2em; | |
margin-top: 6px; | |
font-weight: 800; | |
text-transform: uppercase; | |
color: #af516c; | |
} | |
.contentHolder { | |
background: #fff9f1; | |
padding: 20px 20px 14px; | |
width: 640px; | |
box-sizing: border-box; | |
margin: 0 auto; | |
box-shadow: 0px 2px 5px 0px rgba(0,0,0,0.3); | |
position: relative; | |
} | |
.coast { | |
stroke: #a7a592; | |
fill: none; | |
stroke-width: 1px; | |
} | |
.schengen-yes { | |
fill: #bddacd; | |
} | |
.schengen-no { | |
fill: #dfb3ae; | |
} | |
.subjectCountry{ | |
font-weight: 700; | |
font-size: 1.5em; | |
fill: #706F6F; | |
letter-spacing: 2px; | |
} | |
.place-label { | |
font-size: 11px; | |
text-transform: uppercase; | |
text-anchor: middle; | |
fill: #74736c | |
} | |
.subject.place-label { | |
font-weight: 800; | |
font-size: 14px; | |
fill: #000000; | |
} | |
.legendLabel { | |
font-size: 13px; | |
} | |
.border { | |
stroke-linejoin: round; | |
stroke-linecap: round; | |
} | |
.border.additional { | |
stroke: #000000; | |
stroke-width: 3px; | |
} | |
.border.partial { | |
stroke: #f26522; | |
stroke-width: 3px; | |
} | |
.border.fence { | |
stroke: #ad1c21; | |
stroke-width: 3px; | |
} | |
.disputed { | |
stroke: #a7a592; | |
stroke-width: 1px; | |
stroke-dasharray:1, 2; | |
fill: none; | |
} | |
.arrowsHolder{ | |
position: absolute; | |
bottom: 28px; | |
left: 12px; | |
opacity: 0; | |
} | |
.relief { | |
position: absolute; | |
bottom: 25px; | |
left: 20px; | |
opacity: 0; | |
} | |
.refugees circle, .legend.refugees { | |
fill: #af516c; | |
fill-opacity: 0; | |
stroke: #af516c; | |
stroke-width: 1px; | |
} | |
.refugees text{ | |
font-weight: 400; | |
text-anchor: middle; | |
fill: #ffffff; | |
font-size: 13px; | |
letter-spacing: 1px; | |
opacity: 0; | |
} | |
.source { | |
font-size: 11px; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="contentHolder"> | |
<h6>EU Migration Crisis</h6> | |
<h1>How many refugees enter the EU via the Western Balkans route?</h1> | |
<p>Over the summer of 2015, an increasing number of migrants and asylum seekers escaping war, take the Western Balkans route, which stretches from Greece to northern Europe</p> | |
<div class="arrowsHolder"><img src="https://image.webservices.ft.com/v1/images/raw/ftcms:39099228-9130-11e5-bd82-c1fb87bef7af?source=test" alt=""></div> | |
<!-- <div class="relief"><img src="images/relief.png" alt=""></div> --> | |
<div class="mapHolder"></div> | |
<div class="source">Source: UNHCR; Acaps</div> | |
</div> | |
<script type="text/javascript"> | |
//Width and height | |
var w = 600; | |
var h = 689; | |
//Define map projection | |
var projection = d3.geo.mercator() | |
.center([17.5, 47.4 ]) | |
.translate([ w/2, h/2 ]) | |
.scale([ w * 2.0]); | |
//Define path generator | |
var path = d3.geo.path() | |
.projection(projection); | |
//Create SVG | |
var svg = d3.select('.mapHolder') | |
.append('svg') | |
.attr('width', w) | |
.attr('height', h) | |
.attr('opacity', 0) | |
var numFormat = d3.format(',') | |
//Load in GeoJSON data | |
d3.json('eumigration.json', function(migration) { | |
// //Bind data and create one path per GeoJSON feature | |
var countryFills = svg.append('g'); | |
var relief = svg.append('g'); | |
var coast = svg.append('g'); | |
var boundaryLines = svg.append('g'); | |
var disputed = svg.append('g'); | |
var refugees = svg.append('g'); | |
var countryNames = svg.append('g'); | |
var legend = svg.append('g'); | |
countryFills.selectAll('path') | |
.data(topojson.feature(migration, migration.objects.countries).features) | |
.enter() | |
.append('path') | |
.attr({ | |
'd': path, | |
'id': function(d) { return d['SOV_A3']; }, | |
'class': 'country', | |
// 'opacity': 0.6, | |
'fill': function(d) { | |
if(d.properties.schengen === 'yes') { | |
return '#bddacd' | |
} else if (d.properties.schengen === 'no'){ | |
return '#dfb3ae'; | |
} else { | |
return '#f8f7f4'; | |
} | |
}, | |
}); | |
boundaryLines.selectAll('path') | |
.data(topojson.feature(migration, migration.objects.boundaries).features) | |
.enter() | |
.append('path') | |
.attr({ | |
'd': path, | |
'id': function(d) { return d['SOV_A3']; }, | |
'class': function(d) { return 'boundary ' + d.properties.type; }, | |
// 'fill-opacity': 0.4, | |
'fill': 'none', | |
'stroke-width': function(d) { | |
if(d.properties.type === 'additional' || d.properties.type === 'fence' || d.properties.type === 'partial') { | |
return 3; | |
} else { | |
return 1; | |
} | |
}, | |
'stroke': '#a7a592', | |
'stroke-linejoin': 'round', | |
'stroke-linecap': 'round', | |
'stroke-width': '1px' | |
}) | |
.transition().delay(5000).duration(1000).attr('stroke', | |
function(d) { | |
if(d.properties.type === 'additional') { | |
return '#000000' | |
} else if (d.properties.type === 'fence'){ | |
return '#ad1c21'; | |
} else if (d.properties.type === 'partial'){ | |
return '#f26522'; | |
} else { | |
return '#a7a592'; | |
} | |
} | |
).attr('stroke-width', | |
function(d) { | |
if(d.properties.type === 'additional') { | |
return 3 | |
} else if (d.properties.type === 'fence'){ | |
return 3; | |
} else if (d.properties.type === 'partial'){ | |
return 3; | |
} else { | |
return 1; | |
} | |
} | |
); | |
d3.selectAll('.additional').transition().delay(8000).duration(500).style('opacity', 0.3); | |
d3.selectAll('.partial').transition().delay(8000).duration(500).style('opacity', 0.3); | |
d3.selectAll('.fence').transition().delay(8000).duration(500).style('opacity', 0.3); | |
countryNames.selectAll('.place-label') | |
.data(topojson.feature(migration, migration.objects.clabels).features) | |
.enter().append('text') | |
.attr('class', | |
function(d) { | |
if(d.properties.feature === 'yes') { | |
return 'subject place-label'; | |
} else { | |
return 'place-label'; | |
} | |
}) | |
.attr('transform', function(d) { return 'translate(' + projection(d.geometry.coordinates) + ')'; }) | |
.text(function(d) { return d.properties.name; }); | |
disputed.selectAll('path') | |
.data(topojson.feature(migration, migration.objects.disputed).features) | |
.enter() | |
.append('path') | |
.attr({ | |
'd': path, | |
'class': 'disputed' | |
}) | |
coast.selectAll('path') | |
.data(topojson.feature(migration, migration.objects.ocean).features) | |
.enter() | |
.append('path') | |
.attr({ | |
'd': path, | |
'class': 'coast' | |
}) | |
// add circle groups for refugee numbers | |
var refugeeData = refugees.selectAll('g') | |
.data(topojson.feature(migration, migration.objects.refugees).features) | |
.enter() | |
.append('g') | |
.attr({ | |
'class': 'refugees' | |
}) | |
.attr('transform', function(d) { return 'translate(' + projection(d.geometry.coordinates) + ')'; }); | |
//add circles | |
refugeeData.append('circle') | |
// .attr('r', function(d) { return Math.sqrt(d.properties.refugees) / Math.PI / 8; }) | |
.attr('r', 0) | |
.transition().delay(function(d, i) { return (i * 50) + 9000 ; }).duration(500).attr('r', function(d) { return Math.sqrt(d.properties.refugees) / Math.PI / 5; }).style('fill-opacity', 0.7); | |
//add data values | |
refugeeData.append('text') | |
.text(function(d) { return numFormat(d.properties.refugees); }) | |
.attr('dy', 6) | |
.transition().delay(function(d, i) { return (i * 50) + 9000 ; }).duration(500).style('opacity', 1);; | |
legend.attr('transform', 'translate(' + (w - 200) + ',' + 10 + ')') | |
legend.append('rect') | |
.attr({ | |
'width': 190, | |
'height': 150, | |
'fill': '#ffffff', | |
'opacity': 0 | |
}) | |
.transition().delay(1000).duration(500).attr('opacity', 1); | |
var borders = legend.append('g'); | |
borders | |
.attr('transform', 'translate(' + 10 + ',' + 50 + ')') | |
.attr('opacity', 0) | |
borders.append('line') | |
.attr({ | |
'x1': 0, | |
'x2': 30, | |
'y1': 5, | |
'y2': 5, | |
'class': 'border additional' | |
}) | |
borders.append('line') | |
.attr({ | |
'x1': 0, | |
'x2': 30, | |
'y1': 25, | |
'y2': 25, | |
'class': 'border fence' | |
}) | |
borders.append('line') | |
.attr({ | |
'x1': 0, | |
'x2': 30, | |
'y1': 45, | |
'y2': 45, | |
'class': 'border partial' | |
}) | |
borders.append('text') | |
.attr('class', 'legendLabel') | |
.attr('transform', 'translate(' + 35 + ',' + 10 + ')') | |
.text('Additional border controls') | |
borders.append('text') | |
.attr('class', 'legendLabel') | |
.attr('transform', 'translate(' + 35 + ',' + 30 + ')') | |
.text('Fences') | |
borders.append('text') | |
.attr('class', 'legendLabel') | |
.attr('transform', 'translate(' + 35 + ',' + 50 + ')') | |
.text('Partial fences planned') | |
borders | |
.transition().delay(5000).duration(1000).attr('opacity', 1); | |
legend.append('rect') | |
.attr('transform', 'translate(' + 10 + ',' + 10 + ')') | |
.attr({ | |
'width': 30, | |
'height': 10, | |
'class': 'legend schengen-yes', | |
'opacity': 0 | |
}) | |
.transition().delay(1000).duration(800).attr('opacity', 1); | |
legend.append('rect') | |
.attr('transform', 'translate(' + 10 + ',' + 30 + ')') | |
.attr({ | |
'width': 30, | |
'height': 10, | |
'class': 'legend schengen-no', | |
'opacity': 0 | |
}) | |
.transition().delay(1000).duration(800).attr('opacity', 1); | |
legend.append('circle') | |
.attr('transform', 'translate(' + 25 + ',' + 125 + ')') | |
.attr({ | |
'r': 15, | |
'class': 'legend refugees', | |
'opacity': 0 | |
}) | |
.transition().delay(9000).duration(800).attr('opacity', 1).style('fill-opacity', 0.7); | |
legend.append('text') | |
.attr('transform', 'translate(' + 45 + ',' + 20 + ')') | |
.attr('class', 'legendLabel') | |
.attr('opacity', 0) | |
.text('Schengen countries') | |
.transition().delay(1000).duration(800).attr('opacity', 1); | |
legend.append('text') | |
.attr('transform', 'translate(' + 45 + ',' + 40 + ')') | |
.attr('class', 'legendLabel') | |
.attr('opacity', 0) | |
.text('Non-Schengen countries') | |
.transition().delay(1000).duration(800).attr('opacity', 1); | |
var legendRefugeeLabel = legend.append('text') | |
.attr('transform', 'translate(' + 45 + ',' + 122 + ')') | |
.attr('class', 'legendLabel') | |
.attr('opacity', 0); | |
legendRefugeeLabel.append('tspan') | |
.text('Estimated arrivals'); | |
legendRefugeeLabel.append('tspan') | |
.text('since Sept 1 2015') | |
.attr('x', 0) | |
.attr('y', 15); | |
// <image xlink:href="firefox.jpg" x="0" y="0" height="50px" width="50px"/> | |
relief.append('image') | |
.attr({ | |
'xlink:href': 'https://image.webservices.ft.com/v1/images/raw/ftcms:ccbe9dec-9135-11e5-bd82-c1fb87bef7af?source=test', | |
'width': 600, | |
'height': 690 | |
}) | |
/* transitions*/ | |
svg.transition().delay(200).duration(800).attr('opacity', 1); | |
// d3.select('.arrowsHolder').transition().delay(3000).duration(800).attr('opacity', 1); | |
d3.select('.arrowsHolder').transition().delay(3000).duration(800).style('opacity', 1); | |
d3.select('.arrowsHolder').transition().delay(7000).duration(800).style('opacity', 0.3); | |
legendRefugeeLabel.transition().delay(9000).duration(800).attr('opacity', 1); | |
}); | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
topojson \ | |
-o eumigration.json \ | |
--id-property SOV_A3 \ | |
--properties name=NAME \ | |
--properties iso=SOV_A3 \ | |
--properties type=type \ | |
--properties schengen=schengen \ | |
--properties feature=isFeature \ | |
--properties refugees=refugees \ | |
-- \ | |
countries.json \ | |
boundaries.json\ | |
ocean.json\ | |
sweden.json\ | |
bordercontrols.json\ | |
disputed.json\ | |
clabels.json\ | |
refugees.json | |
ogr2ogr \ | |
-f GeoJSON \ | |
bordercontrols.json \ | |
_clippedborder-controls.shp | |
ogr2ogr \ | |
-f GeoJSON \ | |
boundaries.json \ | |
boundaries.shp | |
ogr2ogr \ | |
-f GeoJSON \ | |
sweden.json \ | |
_clippedsweden-border.shp | |
ogr2ogr \ | |
-f GeoJSON \ | |
countries.json \ | |
_clippedcountry-labels_10m.shp | |
ogr2ogr \ | |
-f GeoJSON \ | |
disputed.json \ | |
_clippeddisputed-boundaries_10m.shp | |
ogr2ogr \ | |
-f GeoJSON \ | |
ocean.json \ | |
_clippedne_10m_ocean.shp | |
ogr2ogr \ | |
-f GeoJSON \ | |
clabels.json \ | |
cLabels.shp | |
ogr2ogr \ | |
-f GeoJSON \ | |
refugees.json \ | |
refugees.shp |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment