Last active
November 18, 2016 12:47
-
-
Save Pabloska/d1a90ccc5371c624e1df881047374732 to your computer and use it in GitHub Desktop.
Migrant Deaths
This file contains 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
var aspect = 2.5; | |
var width = $("#map").width(); | |
var height = width/ aspect; | |
var infoWidth = 100; | |
var margin = { | |
top: 20, | |
left: 35, | |
bottom: 30, | |
right: 50 | |
} | |
//colors for deaths | |
var colors = ['red','#ff4d4d'] | |
colors.reverse() | |
//temporary empty color that will be used for mouseover and mouseout events | |
var tempColor; | |
var mouseBool = false; | |
//add BaseMap | |
var map = L.map('map', {center: [33.348885,-11.074219], | |
zoom: 3, | |
reuseTiles: false, | |
trackResize: false}) | |
.addLayer(new L.TileLayer("http://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Dark_Gray_Base/MapServer/tile/{z}/{y}/{x}")); | |
var infoLoc = width - (width*.20) | |
//Attach empty SVG to the basemap | |
var svg = d3.select(map.getPanes().overlayPane).append("svg"); | |
svg.attr('width',width).attr('height',height) | |
//hide phantom svg on zoom | |
var g = svg.append("g").attr("class", "leaflet-zoom-hide"); | |
var infoLeft = width - (width*.25); | |
var graphHeight = height*.35; | |
//var infoLeft = width - (width*.25); | |
var graphW = width - margin.left - margin.right; | |
var graphH = graphHeight - margin.top - margin.bottom; | |
var infoHeight = graphHeight*2 | |
var xTrans = -graphW/11/2 | |
console.log(height,graphHeight,infoHeight) | |
var infoSVG = d3.select('#infoPane').append('svg') | |
.attr('width',infoWidth) | |
.attr('height',infoHeight) | |
.attr('transform','translate('+infoLeft+',0)') | |
//place graph svg | |
var graph = d3.select('#graph').append('svg') | |
.attr('width', width) | |
.attr('height',graphHeight) | |
graph = graph.append('g') | |
.attr('transform','translate('+margin.left+','+margin.top+')') | |
//var dateTime = d3.time.format('%Y-%m-%d %H:%M:%S') | |
var timeISO = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ") | |
var format = d3.time.format('%d %b %Y') | |
//var timeFormat = d3.time.format('%I:%M ') | |
//var tempTime = d3.time.hour('15:32') | |
var hr = '15:32:00' | |
hr = d3.time.format('%I:%M:%L').parse(hr) | |
var hrFormat = d3.time.format('%I:%M %p') | |
hr = hrFormat(hr) | |
Start = ('2016-01-03T00:00:000Z') | |
projectStart = timeISO.parse(Start) | |
function drawData(){ | |
d3.json('deaths.topojson', function(error, deaths){ | |
var collection = topojson.feature(deaths,deaths.objects.collection); | |
/*add LatLng to each point in dataset*/ | |
collection.features.forEach(function(d){ | |
d.LatLng = new L.LatLng(d.geometry.coordinates[1],d.geometry.coordinates[0]) | |
}) | |
var transform = d3.geo.transform({point: projectPoint}), | |
path = d3.geo.path().projection(transform) | |
var min = d3.min(collection.features,function(d){ | |
return d.properties.Length | |
}) | |
var max = d3.max(collection.features, function(d){ | |
return d.properties.Length | |
}) | |
var deathTotal = d3.sum(collection.features, function(d){ | |
return d.properties.Length | |
}) | |
var totalIncidents = collection.features.length | |
var totalScale = d3.scale.linear() | |
.domain([(deathTotal*1.15),0]) | |
.range([0,(infoHeight*.80)]) | |
/**************** | |
create cirlce scale for deaths | |
*****************/ | |
var deathScale = d3.scale.linear() | |
.domain([min,max]) | |
.range([1.5,15]) | |
//create Incidents/deaths chart | |
metaBars = infoSVG.append('g') | |
infoSVG.append('rect') | |
.attr('x',0) | |
.attr('y',totalScale(totalIncidents)) | |
.attr('width',infoWidth/2) | |
.attr('class','totalBar') | |
.attr('id','incidentTotal') | |
.attr('height',infoHeight - totalScale(totalIncidents)) | |
.style('fill','grey') | |
.style('opacity',0.90) | |
infoSVG.append('text') | |
.attr('x',infoWidth*.25) | |
.attr('text-anchor','middle') | |
.attr('y',infoHeight*.98) | |
.attr("transform", "translate(-250,275) rotate(-90)") | |
.style('fill','white') | |
.text('Incidents') | |
infoSVG.append('text') | |
.attr('x',infoWidth*.25) | |
.attr('text-anchor','middle') | |
.attr('y',totalScale(totalIncidents) -5) | |
.style('fill','white') | |
.attr('class','barTotal') | |
.attr('id','IncidentBarTotal')//ID allows changig number dynamically --> see secton "updating of total bars" | |
.text(totalIncidents) | |
infoSVG.append('rect') | |
.attr('x',infoWidth/2) | |
.attr('y',totalScale(deathTotal)) | |
.attr('width',infoWidth/2) | |
.attr('class','totalBar') | |
.attr('id','deathTotal') | |
.attr('height',infoHeight - totalScale(deathTotal)) | |
.style('fill','red') | |
.style('opacity',0.90) | |
infoSVG.append('text') | |
.attr('x',infoWidth*.75) | |
.attr('text-anchor','middle') | |
//.attr("dy", ".0em") | |
.attr("transform", "translate(-200,330) rotate(-90)") | |
.attr('y',infoHeight*.98) | |
.style('fill','white') | |
.text('Deaths') | |
infoSVG.append('text') | |
.attr('x',infoWidth*.75) | |
.attr('text-anchor','middle') | |
.attr('y',totalScale(deathTotal)-5) | |
.style('fill','white') | |
.attr('class','barTotal') | |
.attr('id','deathBarTotaltext')//ID allows changig number dynamically --> see secton "updating of total bars" | |
.text(deathTotal) | |
/* | |
var mileTotal = d3.round(d3.sum(collection.features,function(d){ return d.properties.Length}),2) | |
d3.selectAll('#Distance').text('Distance (Miles): ' + mileTotal) | |
d3.selectAll('#tripCount').text('Trips: '+ collection.features.length) | |
*/ | |
var colorScale = d3.scale.linear() | |
.domain([min,max]) | |
.range(colors) | |
//sort the trips by date andd time | |
function sortTrips(a,b){ | |
console.log() | |
return new Date(a.properties.DateTime) - new Date(b.properties.DateTime) | |
} | |
data = collection.features | |
data = data.sort(sortTrips) | |
//activate mouse interactivity | |
setTimeout(function(){ | |
mouseBool = true; | |
},(data.length+1)*100) | |
//update infoPane data | |
//d3.select('#totalDeaths').text(d3.format(',')(deathTotal)) | |
//d3.select('#totalIncidents').text(data.length) | |
//var day1 = new Date(data[0].properties.Name) | |
//var day30 = new Date(data[data.length-1].Name) | |
//xScale.domain([day1, day30]) | |
// .ticks(d3.time.days,1) | |
// .tickFormat(d3.time.format('%a')) | |
// | |
//graph.select('.xAxis') | |
// .call(xAxis) | |
//************************************** | |
//setup graph scales and axes. | |
//************************************** | |
var begin = new Date(data[0].properties.Name) | |
//var end = timeISO.parse(data[data.length - 1].properties.Name) | |
var end = new Date(data[data.length - 1].properties.Name) | |
console.log(begin,end) | |
//var utcRange = d3.time.day.range(begin,end) | |
var xScale = d3.time.scale.utc() | |
.domain([begin,end]) | |
.range([0,graphW]) | |
.nice() | |
var xAxis = d3.svg.axis() | |
.scale(xScale) | |
.orient('bottom') | |
.ticks(d3.time.month.utc) | |
.tickFormat(d3.time.format('%b')) | |
//.tickSize(10,2.5,0) | |
//.tickSubdivide(5) | |
// .ticks(16) | |
.tickPadding(10) | |
//var xTimeAxis = d3.svg.axis() | |
// .scale(xScale) | |
// .orient('bottom') | |
// .ticks(d3.time.hours,4) | |
// .tickFormat(d3.time.format('%I:%M %p')) | |
// .ticks(15) | |
var yScale = d3.scale.linear() | |
.domain([0,600]) | |
.range([graphH,0]) | |
var yAxis = d3.svg.axis() | |
.scale(yScale) | |
.orient('left') | |
.ticks(4) | |
graph.append('g') | |
.attr('class','axis') | |
.attr('id','xAxis') | |
.attr('transform','translate(0,'+ graphH +')') | |
.call(xAxis) | |
.style('fill','white') | |
//translate month axis ticks to center of bin | |
d3.select('#xAxis').selectAll('text') | |
.attr('transform','translate('+xTrans+')') | |
/********************* | |
*add text to graph | |
**********************/ | |
graph.append('g') | |
.attr('class','axis') | |
.call(yAxis) | |
.style('fill','white') | |
.style('stroke','') | |
.style('stroke-width','2.0px') | |
graph.append('text') | |
.attr('text-anchor','middle') | |
.attr('transform','translate('+(graphW/2)+','+(-margin.top/2.25)+')') | |
.text('Migrant Deaths 2016') | |
.style('fill','white') | |
graph.append('text') | |
.attr('text-anchor','left') | |
.attr('transform','translate('+(graphW*.05)+','+(-margin.top/2.25)+')') | |
.attr('id','date') | |
.text('Date:') | |
.style('fill','white') | |
graph.append('text') | |
.attr('text-anchor','middle') | |
.attr('id','deathCount') | |
.text('') | |
.style('fill','white') | |
//Add deaths to the map | |
var deaths = g.append('g').selectAll("circle") | |
.data(data) | |
.enter() | |
.append('circle') | |
.attr('class','deaths') | |
.attr('id',function(d,i){ | |
return 'incidentLoc' + i | |
}) | |
.attr('fill', function(d){ | |
return colorScale(d.properties.Length) | |
}) | |
.attr('cx',function(d){ | |
return map.latLngToLayerPoint(d.LatLng).x | |
}) | |
.attr('cy',function(d){ | |
return map.latLngToLayerPoint(d.LatLng).y | |
}) | |
//.attr('r',function(d){ | |
// return deathScale(d.properties.Length) | |
//}) | |
.style('opacity',0.75); | |
deaths.transition() | |
.ease('linear') | |
.duration(1500) | |
.delay(1500) | |
.attr("r", function(d){ | |
return deathScale(d.properties.Length) | |
}); | |
/********************* | |
*death location interactivity | |
**********************/ | |
deaths.on('mouseover',function(d,i){ | |
d3.select(this).transition() | |
.style('opacity',1) | |
.attr('r',function(){ | |
return deathScale(max*2) | |
}) | |
var barID = '#barID'+i | |
console.log(barID) | |
d3.select(barID).transition() | |
.style('opacity',1) | |
.attr('width',10) | |
}); | |
deaths.on('mouseout',function(d,i){ | |
d3.select(this).transition() | |
.style('opacity',0.75) | |
.attr('r',function(d){ | |
return deathScale(d.properties.Length) | |
}) | |
var barID = '#barID'+i | |
d3.select(barID).transition() | |
.style('opacity',1) | |
.attr('width',10) | |
}) | |
//Draw bars on the bar graph | |
var bars = graph.selectAll('rect') | |
.data(data) | |
.enter() | |
.append('rect') | |
.attr('class','bars') | |
.attr('id',function(d,i){ | |
return 'barID'+i | |
}) | |
.attr('x',function(d){ | |
return xScale(new Date(d.properties.Name)) | |
}) | |
.attr('y',function(d){ | |
return yScale(0) | |
}) | |
.attr('height',0) | |
.attr('width',5) | |
.style('fill',function(d){ | |
return colorScale(d.properties.Length) | |
}) | |
.style('opacity',0.50); | |
bars.transition().ease('linear') | |
.duration(1500) | |
.delay(1000) | |
.attr('height',function(d){ | |
return graphHeight-margin.top-margin.bottom - yScale(d.properties.Length) | |
}) | |
.attr('y',function(d){ | |
return yScale(d.properties.Length) | |
}) | |
//bar interactivity | |
bars.on('mouseover',function(d,i){ | |
//if (mouseBool == true){ | |
var length = d.properties.Length; | |
var date = new Date(d.properties.Name); | |
var loc = '#incidentLoc' + i | |
var dateText = format(date); | |
var tripNo = i+1; | |
d3.select(this) | |
//.style('fill','#FA8D34') | |
.style('width',10) | |
.style('opacity',1) | |
d3.select('#deathCount') | |
.style('opacity',1) | |
.attr('x',xScale(date) + 2.5) | |
.attr('y',yScale(length)- 2.5) | |
.text(length) | |
//location interactivity | |
var loc = '#incidentLoc'+i | |
d3.select(loc).transition() | |
.style('opacity',1) | |
.attr('r',function(){ | |
return deathScale(max*2) | |
}) | |
//.style('stroke-width',7) | |
d3.select('#deathCount').text(length) | |
d3.select('#date').text('Date: ' + dateText) | |
//}; | |
}) | |
bars.on('mouseout',function(d,i){ | |
//if (mouseBool == true){ | |
d3.select(this) | |
.style('fill',function(d){ | |
return colorScale(d.properties.Length) | |
}) | |
.style('width',5) | |
.style('opacity',0.75) | |
d3.select('#deathCount').transition() | |
.style('opacity',0) | |
//transition corresponding location | |
var loc = '#incidentLoc'+ i | |
d3.select(loc).transition() | |
.style('opacity',0.50) | |
//.style('stroke','#2892C7') | |
.attr('r',function(d){ | |
return deathScale(d.properties.Length) | |
}) | |
.style('fill',function(d){ | |
return colorScale(d.properties.Length) | |
}) | |
//text transitions | |
d3.select('#date').text("Date: ") | |
d3.select('#deaths').text(0) | |
//}; | |
}) | |
/*********************** | |
*Animdate function | |
***********************/ | |
//Trip Animation | |
d3.select('#play').on('click',function(d,i){ | |
d3.select('#play').classed('disabled',true); | |
deaths.transition().ease('linear').duration(500).attr('r',0) | |
bars.transition().ease('linear').duration(500).attr('y',yScale(0)) | |
.attr('height',0) | |
d3.selectAll('.totalBar').transition() | |
.attr('y',infoHeight) | |
.attr('height',0) | |
d3.selectAll('.barTotal').transition() | |
.attr('y',infoHeight) | |
.style('opacity',0) | |
var tempBars = d3.selectAll('.bars').data() | |
var tempLocs = d3.selectAll('.deaths').data() | |
var runningdeathSum = 0 | |
function animate(data,index){ | |
var barID = '#barID' + index; | |
var locID = '#incidentLoc' + index | |
var date = new Date(data[index].properties.Name) | |
var deaths = data[index].properties.Length | |
runningdeathSum += deaths | |
console.log(index,runningdeathSum, deaths) | |
/*********************** | |
*updating of total bars | |
***********************/ | |
infoSVG.select('rect#incidentTotal').transition() | |
.attr('y',totalScale(index)) | |
.attr('height',infoHeight - totalScale(index)) | |
d3.select('#IncidentBarTotal').transition() | |
.attr('y',totalScale(index) -5) | |
.text(index) | |
infoSVG.select('rect#deathTotal').transition() | |
.attr('y',totalScale(runningdeathSum)) | |
.attr('height',infoHeight - totalScale(runningdeathSum)) | |
d3.select('#deathBarTotaltext').transition() | |
.attr('y',totalScale(runningdeathSum) -5) | |
.text(runningdeathSum) | |
//bar and location animation | |
var dateText = format(date) | |
if (index < data.length){ | |
var timer = setTimeout(function(){ | |
d3.select(barID).transition().duration(450) | |
.attr('height', graphHeight-margin.top-margin.bottom - yScale(deaths)) | |
.attr('y',yScale(deaths)); | |
d3.select('#deathCount').transition() | |
.style('opacity',1) | |
.attr('x',xScale(date) + 2.5) | |
.attr('y',yScale(deaths)- 2.5) | |
.text(deaths); | |
d3.select('#date').text('Date: ' + dateText); | |
d3.select(locID).transition().duration(450) | |
.attr('r',deathScale(max*2)) | |
.transition().duration(200) | |
.attr('r',deathScale(deaths)); | |
if (index == totalIncidents) { | |
d3.select('#deathCount').transition().style('opacity',0) | |
} | |
animate(data,++index) | |
},250)//end timer function | |
}//end conditional checking index against data length | |
}//end animate function | |
animate(tempBars,0) | |
})//end of play button function | |
//map zoom/rest functionality | |
map.on('viewreset', reset); | |
//this will put stuff on the map | |
reset(); | |
// Reposition the SVG to cover the features. | |
function reset() { | |
var bounds = path.bounds(collection); | |
var topLeft = bounds[0], | |
bottomRight = bounds[1]; | |
svg.attr("width", bottomRight[0] - topLeft[0]) | |
.attr("height", bottomRight[1] - topLeft[1]) | |
.style("left", topLeft[0] + "px") | |
.style("top", topLeft[1] + "px"); | |
g.attr("transform", "translate(" + -topLeft[0] + "," + -topLeft[1] + ")"); | |
deaths.attr('cx',function(d){ | |
return map.latLngToLayerPoint(d.LatLng).x | |
}) | |
.attr('cy',function(d){ | |
return map.latLngToLayerPoint(d.LatLng).y | |
}) | |
.attr('r',function(d){ | |
return deathScale(d.properties.Length) | |
}) | |
} // end reset | |
function projectPoint(x,y){ | |
var point = map.latLngToLayerPoint(new L.LatLng(y,x)); | |
this.stream.point(point.x,point.y); | |
}// end projectPoint function | |
});//end d3 callback | |
};// end drawEmp | |
$(document).ready(function(){ | |
drawData(); | |
}); |
This file contains 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 class="no-js" lang="en"> | |
<head> | |
<meta charset="utf-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<meta name="keywords" content=""/> | |
<meta name="description" content=""/> | |
<title>Migrant Deaths Around the World</title> | |
<!--<link rel="stylesheet" href="css/app.css"/>--> | |
<link rel="stylesheet" href="styles_cycling.css"/> | |
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" /> | |
<!--<script src="../../bower_components/modernizr/modernizr.js"></script>--> | |
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="http://d3js.org/topojson.v1.min.js"></script> | |
</head> | |
<body> | |
<div class="toppadding" id="info"> | |
<div class="small-4 columns toppadding end" id='buttonDiv'> | |
<button align="middle" class="button expand" id="play">Animate Incidents</button> | |
</div> | |
</div> | |
<div class="small-12 columns" id="map"> | |
<div id="infoPane"> | |
<!--h3>Date</h3> | |
<h5 id="date"></h5> | |
<h3>Deaths</h3> | |
<h5 id="deaths">0</h5> | |
<h3>Total Deaths</h3> | |
<h5 id="totalDeaths"></h5> | |
<h3>Total Incidents</h3> | |
<h5 id="totalIncidents">000</h5--> | |
</div> | |
</div> | |
<div id='graph'></div> | |
<br> </br> | |
<br> </br> | |
<script src='https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js'></script> | |
<!--<script src="../../bower_components/foundation/js/foundation.min.js"></script> | |
<script src="../js/app.js"></script> | |
<script src="../D3\src_code\d3.min.js"></script--> | |
<script src="https://d3js.org/queue.v1.min.js"></script> | |
<script src="https://d3js.org/topojson.v1.min.js"></script> | |
<script src="app_1.js"></script> | |
<script> | |
//$(document).foundation(); | |
</script> | |
</body> | |
</html> |
This file contains 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
body { | |
background-color: #111111; | |
} | |
footer p { | |
color: white; | |
} | |
#name { | |
margin-left: 1em; | |
color: white; | |
font-size: 1.25em; | |
margin-bottom: 2px; | |
} | |
.badge { | |
color: white; | |
background: #111111; | |
} | |
#badge p { | |
font-size: 0.95em; | |
} | |
#buttonDiv { | |
padding-top: 1em; | |
vertical-align: middle !important; | |
} | |
.button { | |
display: block !important; | |
vertical-align: middle !important; | |
} | |
#info h3 { | |
padding-top: 0em; | |
padding-bottom: 0em; | |
} | |
#info p { | |
font-size: .95em; | |
background: #111111; | |
padding-bottom: 0em !important; | |
padding-top: 0em; | |
} | |
#map { | |
width: 100%; | |
height: 75%; | |
background-color: #111111; | |
position: relative; | |
} | |
.fullwidth { | |
width:80%; | |
} | |
.leaflet-container{ | |
cursor: default; | |
} | |
#infoPane h3, h4{ | |
color: white; | |
} | |
#infoPane { | |
position: relative; | |
/*left: 500px;*/ | |
z-index: 2; | |
float: right ; | |
padding: 5px; | |
background-color: #111111; | |
opacity: 0.85; | |
} | |
#infoPane h3, h5 { | |
color: white; | |
font-weight: .5rem !important; | |
} | |
#graph { | |
position: absolute; | |
bottom: 0; | |
z-index: 1000; | |
padding:5px; | |
background-color: #111111; | |
/*opacity: .75;*/ | |
} | |
.axis line, | |
.axis path { | |
fill: none; | |
stroke: white; | |
shape-rendering: cripsEdges; | |
} | |
/*iPad stylings*/ | |
/*landscape*/ | |
@media (min-width: 850px) and (max-width: 1100px){ | |
div.overlay p {font-size: 0.75em !important} | |
div.overlay h2 {font-size: 1.5em;} | |
#infoPane h3 {font-size: 1.5em;} | |
#infoPane h5 {font-size: .95em;} | |
#title h3 {font-size: 1.65em} | |
#info p {font-size: .95em;} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment