Skip to content

Instantly share code, notes, and snippets.

@sdbernard
Created November 22, 2015 16:33
Show Gist options
  • Save sdbernard/cc7edf60f57fc407c621 to your computer and use it in GitHub Desktop.
Save sdbernard/cc7edf60f57fc407c621 to your computer and use it in GitHub Desktop.
d3 module 4
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
<!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>
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