Skip to content

Instantly share code, notes, and snippets.

@Pabloska
Last active November 18, 2016 12:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Pabloska/d1a90ccc5371c624e1df881047374732 to your computer and use it in GitHub Desktop.
Save Pabloska/d1a90ccc5371c624e1df881047374732 to your computer and use it in GitHub Desktop.
Migrant Deaths
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();
});
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
<!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>
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