A reconstruction of the chart from the Recent Attacks Demonstrate Islamic State’s Ability to Both Inspire and Coordinate Terror article in The New York Times, created during the course on data visualization held at the Charles University's New Media Studies department in winter 2015.
Last active
January 9, 2016 18:06
-
-
Save karmi/61fac7da4c29f712913b to your computer and use it in GitHub Desktop.
NYT ISIS Attacks Chart
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
[ | |
{ | |
"date" : "2015-12-02", | |
"fatalities" : 14, | |
"location" : "California", | |
"region" : "North America", | |
"description" : "Shooting", | |
"link" : "http://www.nytimes.com/interactive/2015/12/02/us/california-mass-shooting-san-bernardino.html" | |
}, | |
{ | |
"date" : "2015-11-26", | |
"fatalities" : 1, | |
"location" : "Bangladesh", | |
"region" : "Asia", | |
"description" : "Attack on mosque", | |
"link" : "http://www.nytimes.com/2015/11/27/world/asia/gunmen-strike-shiite-mosque-in-bangladesh.html" | |
}, | |
{ | |
"date" : "2015-11-24", | |
"fatalities" : 7, | |
"location" : "Egypt", | |
"region" : "Middle East", | |
"description" : "Attack on hotel", | |
"link" : null | |
}, | |
{ | |
"date" : "2015-11-24", | |
"fatalities" : 12, | |
"location" : "Tunisia", | |
"region" : "Middle East", | |
"description" : "Suicide bomb", | |
"link" : "http://www.nytimes.com/2015/11/26/world/middleeast/tunisia-suicide-bombing-presidenital-guard.html" | |
}, | |
{ | |
"date" : "2015-11-13", | |
"fatalities" : 130, | |
"location" : "Paris", | |
"region" : "Europe", | |
"description" : "Attacks on club and restaurants", | |
"link" : "http://www.nytimes.com/2015/11/15/world/europe/paris-terrorist-attacks.html" | |
}, | |
{ | |
"date" : "2015-11-12", | |
"fatalities" : 43, | |
"location" : "Lebanon", | |
"region" : "Middle East", | |
"description" : "Suicide bombing", | |
"link" : "http://www.nytimes.com/2015/11/13/world/middleeast/lebanon-explosions-southern-beirut-hezbollah.html" | |
}, | |
{ | |
"date" : "2015-11-04", | |
"fatalities" : 4, | |
"location" : "Egypt", | |
"region" : "Middle East", | |
"description" : "Suicide bombing", | |
"link" : "http://www.nytimes.com/2015/11/05/world/middleeast/egypt-bombing-sinai-police.html" | |
}, | |
{ | |
"date" : "2015-11-04", | |
"fatalities" : 1, | |
"location" : "Bangladesh", | |
"region" : "Asia", | |
"description" : "Stabbing and shooting", | |
"link" : "http://www.nytimes.com/2015/11/06/world/asia/isis-bangladesh-police-attack.html" | |
}, | |
{ | |
"date" : "2015-10-31", | |
"fatalities" : 224, | |
"location" : "Egypt", | |
"region" : "Middle East", | |
"description" : "Russian plane downed", | |
"link" : "http://www.nytimes.com/2015/11/10/world/middleeast/suspects-in-russian-jet-crash-risk-exposing-their-isis-allies-to-a-backlash.html" | |
}, | |
{ | |
"date" : "2015-10-24", | |
"fatalities" : 1, | |
"location" : "Bangladesh", | |
"region" : "Asia", | |
"description" : "Bombings", | |
"link" : "http://www.nytimes.com/2015/10/25/world/asia/isis-claims-responsibility-for-attack-in-bangladesh-targeting-shias.html" | |
}, | |
{ | |
"date" : "2015-10-10", | |
"fatalities" : 102, | |
"location" : "Ankara", | |
"region" : "Middle East", | |
"description" : "Bombing of a peace rally", | |
"link" : "http://www.nytimes.com/2015/10/11/world/europe/ankara-turkey-explosion-deaths.html" | |
}, | |
{ | |
"date" : "2015-10-06", | |
"fatalities" : 25, | |
"location" : "Yemen", | |
"region" : "Middle East", | |
"description" : "Bombings", | |
"link" : "http://www.nytimes.com/2015/10/07/world/middleeast/yemen-aden-hotel-explosion.html" | |
}, | |
{ | |
"date" : "2015-10-03", | |
"fatalities" : 1, | |
"location" : "Bangladesh", | |
"region" : "Asia", | |
"description" : "Shooting", | |
"link" : "http://www.nytimes.com/2015/10/04/world/asia/in-bangladesh-a-second-foreigner-is-violently-killed.html" | |
}, | |
{ | |
"date" : "2015-09-28", | |
"fatalities" : 1, | |
"location" : "Bangladesh", | |
"region" : "Asia", | |
"description" : "Shooting", | |
"link" : "http://www.nytimes.com/2015/09/30/world/asia/-isis-bangladesh-cesare-tavella.html" | |
}, | |
{ | |
"date" : "2015-09-24", | |
"fatalities" : 25, | |
"location" : "Yemen", | |
"region" : "Middle East", | |
"description" : "Bombings", | |
"link" : "http://www.nytimes.com/2015/09/25/world/middleeast/sana-yemen-mosque-suicide-attack.html" | |
}, | |
{ | |
"date" : "2015-09-02", | |
"fatalities" : 20, | |
"location" : "Yemen", | |
"region" : "Middle East", | |
"description" : "Bombings", | |
"link" : "http://www.nytimes.com/2015/09/03/world/middleeast/yemen-red-cross-workers-shot-dead.html" | |
}, | |
{ | |
"date" : "2015-08-26", | |
"fatalities" : 2, | |
"location" : "Egypt", | |
"region" : "Middle East", | |
"description" : "Shooting of police officers", | |
"link" : null | |
}, | |
{ | |
"date" : "2015-08-12", | |
"fatalities" : 1, | |
"location" : "Egypt", | |
"region" : "Middle East", | |
"description" : "Beheading of Croatian worker", | |
"link" : "http://www.nytimes.com/2015/08/13/world/middleeast/isis-egypt-croatian-beheading.html" | |
}, | |
{ | |
"date" : "2015-08-07", | |
"fatalities" : 15, | |
"location" : "Saudi Arabia", | |
"region" : "Middle East", | |
"description" : "Sucide bombing at a mosque", | |
"link" : "http://www.nytimes.com/2015/08/07/world/middleeast/suicide-bombing-saudi-arabia.html" | |
}, | |
{ | |
"date" : "2015-07-20", | |
"fatalities" : 32, | |
"location" : "Turkey", | |
"region" : "Middle East", | |
"description" : "Suicide bombing", | |
"link" : "http://www.nytimes.com/2015/07/23/world/europe/turkey-suruc-bombing.html" | |
}, | |
{ | |
"date" : "2015-07-11", | |
"fatalities" : 1, | |
"location" : "Egypt", | |
"region" : "Middle East", | |
"description" : "Embassy explosion", | |
"link" : "http://www.nytimes.com/2015/07/12/world/middleeast/egypt-bombing-at-italian-consulate-in-cairo.html" | |
}, | |
{ | |
"date" : "2015-07-01", | |
"fatalities" : 21, | |
"location" : "Egypt", | |
"region" : "Middle East", | |
"description" : "Attacks on military bases", | |
"link" : "http://www.nytimes.com/2015/07/02/world/middleeast/sinai-isis-attack.html" | |
}, | |
{ | |
"date" : "2015-06-26", | |
"fatalities" : 38, | |
"location" : "Tunisia", | |
"region" : "Middle East", | |
"description" : "Shooting at beach resort", | |
"link" : "http://www.nytimes.com/2015/06/27/world/africa/gunmen-attack-hotel-in-sousse-tunisia.html" | |
}, | |
{ | |
"date" : "2015-06-26", | |
"fatalities" : 27, | |
"location" : "Kuwait", | |
"region" : "Middle East", | |
"description" : "Suicide bombing at a mosque", | |
"link" : "http://www.nytimes.com/2015/06/27/world/middleeast/terror-attacks-france-tunisia-kuwait.html" | |
}, | |
{ | |
"date" : "2015-06-26", | |
"fatalities" : 70, | |
"location" : "Somalia", | |
"region" : "Africa", | |
"description" : "Attack on African Union base", | |
"link" : "http://www.nytimes.com/2015/06/27/world/africa/somalia-shabab-militants-attack-african-union-base.html" | |
}, | |
{ | |
"date" : "2015-06-17", | |
"fatalities" : 30, | |
"location" : "Yemen", | |
"region" : "Middle East", | |
"description" : "Car bombings", | |
"link" : "http://www.nytimes.com/2015/06/18/world/middleeast/isis-claims-responsibility-for-deadly-bombings-in-yemen.html" | |
}, | |
{ | |
"date" : "2015-06-05", | |
"fatalities" : 2, | |
"location" : "Turkey", | |
"region" : "Middle East", | |
"description" : "Explosion", | |
"link" : "http://www.nytimes.com/2015/06/06/world/europe/days-before-election-in-turkey-blasts-at-rally-kill-2.html" | |
}, | |
{ | |
"date" : "2015-06-03", | |
"fatalities" : 10, | |
"location" : "Afghanistan", | |
"region" : "Asia", | |
"description" : "Beheading of Taliban members", | |
"link" : "http://www.nytimes.com/2015/06/05/world/asia/afghanistan-taliban-face-insurgent-threat-from-isis.html" | |
}, | |
{ | |
"date" : "2015-05-31", | |
"fatalities" : 4, | |
"location" : "Libya", | |
"region" : "Middle East", | |
"description" : "Suicide bomber", | |
"link" : "http://www.nytimes.com/2015/06/01/world/africa/western-officials-alarmed-as-islamic-state-expands-territory-in-libya.html" | |
}, | |
{ | |
"date" : "2015-05-29", | |
"fatalities" : 3, | |
"location" : "Saudi Arabia", | |
"region" : "Middle East", | |
"description" : "Suicide bombing at a mosque", | |
"link" : "http://www.nytimes.com/2015/05/30/world/middleeast/mosque-bombing-saudi-arabia-shiites-dammam.html" | |
}, | |
{ | |
"date" : "2015-05-22", | |
"fatalities" : 21, | |
"location" : "Saudi Arabia", | |
"region" : "Middle East", | |
"description" : "Suicide bombing at a mosque", | |
"link" : "http://www.nytimes.com/2015/05/23/world/middleeast/suicide-bombing-saudi-arabia-shiites-sunnis-yemen-mosque.html" | |
}, | |
{ | |
"date" : "2015-04-30", | |
"fatalities" : 15, | |
"location" : "Yemen", | |
"region" : "Middle East", | |
"description" : "Killing of soldiers", | |
"link" : null | |
}, | |
{ | |
"date" : "2015-04-19", | |
"fatalities" : 28, | |
"location" : "Libya", | |
"region" : "Middle East", | |
"description" : "Beheading and shooting", | |
"link" : "" | |
}, | |
{ | |
"date" : "2015-04-12", | |
"fatalities" : 12, | |
"location" : "Egypt", | |
"region" : "Middle East", | |
"description" : "Attack on police and military", | |
"link" : "http://www.nytimes.com/2015/04/13/world/middleeast/sinai-group-kills-officers-in-bombings.html" | |
}, | |
{ | |
"date" : "2015-04-12", | |
"fatalities" : 2, | |
"location" : "Libya", | |
"region" : "Middle East", | |
"description" : "Shooting at embassy", | |
"link" : "http://www.nytimes.com/2015/04/13/world/middleeast/fatal-shooting-at-south-korean-embassy-in-libya.html" | |
}, | |
{ | |
"date" : "2015-04-08", | |
"fatalities" : 2, | |
"location" : "Saudi Arabia", | |
"region" : "Middle East", | |
"description" : "Shooting", | |
"link" : null | |
}, | |
{ | |
"date" : "2015-04-05", | |
"fatalities" : 4, | |
"location" : "Libya", | |
"region" : "Middle East", | |
"description" : "Attack at security checkpoint", | |
"link" : null | |
}, | |
{ | |
"date" : "2015-04-02", | |
"fatalities" : 13, | |
"location" : "Egypt", | |
"region" : "Middle East", | |
"description" : "Car bombs", | |
"link" : "http://www.nytimes.com/2015/04/03/world/middleeast/egypt-militants-attack-sinai-checkpoints.html" | |
}, | |
{ | |
"date" : "2015-03-20", | |
"fatalities" : 130, | |
"location" : "Yemen", | |
"region" : "Middle East", | |
"description" : "Suicide bombing at a mosque", | |
"link" : "http://www.nytimes.com/2015/03/21/world/middleeast/suicide-attacks-at-shiite-mosques-in-yemen.html" | |
}, | |
{ | |
"date" : "2015-03-18", | |
"fatalities" : 22, | |
"location" : "Tunisia", | |
"region" : "Middle East", | |
"description" : "Shooting at a museum", | |
"link" : "http://www.nytimes.com/2015/03/20/world/africa/miltants-isis-included-claim-tunisia-museum-attack.html" | |
}, | |
{ | |
"date" : "2015-02-20", | |
"fatalities" : 40, | |
"location" : "Libya", | |
"region" : "Middle East", | |
"description" : "Car bombs", | |
"link" : "http://www.nytimes.com/2015/02/21/world/middleeast/militants-claiming-isis-ties-say-they-carried-out-libya-bombings.html" | |
}, | |
{ | |
"date" : "2015-02-15", | |
"fatalities" : 21, | |
"location" : "Libya", | |
"region" : "Middle East", | |
"description" : "Beheading of Egyptian Christians", | |
"link" : "http://www.nytimes.com/2015/02/16/world/middleeast/islamic-state-video-beheadings-of-21-egyptian-christians.html" | |
}, | |
{ | |
"date" : "2015-02-15", | |
"fatalities" : 2, | |
"location" : "Denmark", | |
"region" : "Europe", | |
"description" : "Shooting", | |
"link" : "http://www.nytimes.com/2015/02/16/world/europe/copenhagen-attacks-suspect-is-killed-police-say.html" | |
}, | |
{ | |
"date" : "2015-02-03", | |
"fatalities" : 12, | |
"location" : "Libya", | |
"region" : "Middle East", | |
"description" : "Attack on air field", | |
"link" : "http://www.nytimes.com/2015/02/05/world/middleeast/people-are-killed-in-attack-on-libyan-oil-field.html" | |
}, | |
{ | |
"date" : "2015-01-29", | |
"fatalities" : 44, | |
"location" : "Egypt", | |
"region" : "Middle East", | |
"description" : "Bombings", | |
"link" : "http://www.nytimes.com/2015/01/30/world/middleeast/bombings-of-security-facilities-in-sinai-kill-at-least-26.html" | |
}, | |
{ | |
"date" : "2015-01-27", | |
"fatalities" : 8, | |
"location" : "Libya", | |
"region" : "Middle East", | |
"description" : "Armed assualt on Hotel", | |
"link" : "http://www.nytimes.com/2015/01/28/world/middleeast/islamic-state-tripoli-libya-terror-attack.html" | |
}, | |
{ | |
"date" : "2015-01-07", | |
"fatalities" : 12, | |
"location" : "France", | |
"region" : "Europe", | |
"description" : "Shootings", | |
"link" : "http://www.nytimes.com/2015/01/08/world/europe/charlie-hebdo-paris-shooting.html" | |
}, | |
{ | |
"date" : "2015-01-09", | |
"fatalities" : 5, | |
"location" : "France", | |
"region" : "Europe", | |
"description" : "Shootings", | |
"link" : "http://www.nytimes.com/2015/03/14/world/europe/kosher-supermarket-attacked-in-paris-to-reopen.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
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>NYT ISIS Attacks Chart</title> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> | |
<style> | |
body { | |
font-family: 'Helvetica Neue', sans-serif; | |
padding: 0; | |
margin: 40px; | |
} | |
#chart { | |
position: relative; | |
} | |
#chart circle { | |
fill: orange; | |
stroke: #bf3e05; | |
stroke-width: 2px; | |
opacity: 0.7; | |
} | |
#chart circle.hidden { | |
display: none; | |
} | |
#chart circle:hover { | |
fill: #bf3e05; | |
opacity: 1; | |
} | |
#chart circle.has_link:hover { | |
cursor: pointer; | |
} | |
.x.axis path.domain { | |
display: none; | |
} | |
.x.axis line { | |
stroke: #c1c1c1; | |
shape-rendering: crispEdges; | |
} | |
.x.axis text { | |
fill: #999; | |
font-weight: 100; | |
} | |
div.legend { | |
color: #444; | |
background-color: #fff; | |
position: absolute; | |
display: none; | |
border-left: 1px solid #bf3e05; | |
z-index: -1; | |
padding: 10px 0px 1px 10px; | |
} | |
div.legend.visible { | |
display: block; | |
} | |
div.legend p { | |
font-size: 80%; | |
padding: 0; | |
margin: 0 0 0.25em 0; | |
} | |
div.legend p:last-child { | |
padding-top: 0.28em; | |
margin-bottom: -0.20em; | |
} | |
div.legend small { | |
color: #878787; | |
font-size: 70%; | |
font-weight: 200; | |
text-transform: uppercase; | |
} | |
div.legend .fatalities { | |
font-size: 140%; | |
} | |
div.legend .link { | |
color: #666; | |
font-size: 65%; | |
} | |
.region-switch { | |
position: absolute; | |
top: 1.75em; | |
right: 40px; | |
} | |
a.switch { | |
color: #444; | |
background: #ccc; | |
font-size: 80%; | |
text-decoration: none; | |
margin: 0 0.25em 0.2em 0; | |
padding: 0.25em 0.5em 0.25em 0.5em; | |
border-radius: 0.4em; | |
display: block; | |
} | |
a.switch.active { | |
color: #ccc; | |
background: #444; | |
} | |
div.total { | |
color: #666; | |
font-size: 80%; | |
text-transform: uppercase; | |
font-weight: 100; | |
letter-spacing: -0.05em; | |
position: absolute; | |
top: 0; | |
right: 40px; | |
} | |
div.total p { | |
margin: 0 0.45em 0 0; | |
padding: 0; | |
} | |
div.total strong { | |
font-size: 140%; | |
font-weight: 900; | |
padding-right: 0.1em; | |
} | |
.footer { | |
color: #bfbfbf; | |
font-size: 65%; | |
font-weight: 200; | |
text-align: left; | |
position: absolute; | |
bottom: 0em; | |
right: 42px; | |
width: 8.75em; | |
} | |
.footer small:after { content:"\A"; white-space:pre; } { | |
} | |
.footer p { | |
margin: 0; padding: 0; | |
} | |
.footer a { | |
color: #bfbfbf; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="chart"></div> | |
<script> | |
d3.json('data.json', function(error, json) { | |
var data = json.sort(function(a, b) { return b.fatalities - a.fatalities }); | |
var width = 1200, | |
height = 200, | |
margin = { top: 0, right: 100, bottom: 0, left: 50 }; | |
var svg = d3.select('#chart') | |
.style({ width: (width+margin.right) + 'px' }) | |
.append('svg') | |
.attr('width', width) | |
.attr('height', height); | |
var xScale = d3.time.scale(); | |
var rScale = d3.scale.sqrt(); | |
var xAxis = d3.svg.axis(); | |
xScale | |
.domain( d3.extent( json, function(d) { return d3.time.format('%Y-%m-%d').parse(d.date) } ) ) | |
.range([margin.left, width-margin.right]) | |
rScale | |
.domain( [0, d3.max(json, function(d) { return d.fatalities })] ) | |
.range([0, height/3]) | |
xAxis.scale(xScale); | |
svg.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + (height-25) + ")") | |
.call(xAxis); | |
svg.selectAll('.x.axis line') | |
.attr('y1', -height) | |
.attr('y2', 0) | |
var circle = svg.selectAll('circle') | |
.data(data) | |
.enter() | |
.append('circle') | |
.attr('id', function(d, i) { return ('circle-'+i) }) | |
.attr('cx', function(d) { return xScale(d3.time.format('%Y-%m-%d').parse(d.date)) }) | |
.attr('cy', height/2) | |
.attr('r', function(d) { return rScale(d.fatalities) }) | |
.attr('class', function(d, i) { | |
c = !!d.link ? 'has_link' : '' | |
c += !!d.region ? (' ' + d.region.toLowerCase().replace(/\s/, '-')) : '' | |
return c | |
}) | |
.on('mouseover', function(d, i) { | |
d3.select('#legend-'+i).classed('visible', true) | |
d3.select('.x.axis').style('opacity', '0.5') | |
}) | |
.on('mouseout', function(d, i) { | |
d3.select('#legend-'+i).classed('visible', false) | |
d3.select('.x.axis').style('opacity', '1') | |
}) | |
.on('click', function(d, i) { | |
return !!d.link ? window.open(d.link, '_blank') : null | |
}) | |
.append('title') | |
.text(function(d) { return d.link ? 'Click for more info' : '' }); | |
var legend = d3.select('#chart').selectAll('div.legend') | |
.data(data) | |
.enter() | |
.append('div') | |
.attr('id', function(d, i) { return ('legend-'+i) }) | |
.attr('class', 'legend') | |
.attr('style', function(d) { | |
return 'top: ' + ((height/2)) + 'px; left:' + xScale(d3.time.format('%Y-%m-%d').parse(d.date)) + 'px;' + 'padding-top: ' + ((height/2)+20) + 'px' | |
}) | |
.html(function(d) { | |
var format = d3.time.format('%B %d, %Y'); | |
html = '<p class="fatalities"><strong>' + d.fatalities + '</strong> <small>fatalities</small></p> ' + | |
'<p class="description">' + d.description + '</p>' + | |
'<p class="location"><small>Location </small>' + d.location + '</p> ' + | |
'<p class="date"><small>Date </small>' + format(d3.time.format('%Y-%m-%d').parse(d.date)) + '</p> '; | |
if ( d.link ) { | |
html += '<p class="link">' + d.link + '</p>'; | |
} | |
return html | |
}); | |
d3.select('#chart') | |
.insert('div', ':first-child') | |
.attr('class', 'region-switch') | |
.selectAll('a.switch') | |
.data(['All', 'Middle East', 'Africa', 'Europe', 'North America', 'Asia']) | |
.enter() | |
.append('a') | |
.attr('href', function(d) { return '#' + d.toLowerCase().replace(/\s/, '-') }) | |
.attr('class', function(d) { return 'switch ' + d.toLowerCase().replace(/\s/, '-') }) | |
.text(function(d) { return d }) | |
.on('click', function(d) { | |
if ( 'All' === d ) { | |
svg.selectAll('circle') | |
.transition().duration(150) | |
.style('opacity', 0.7) | |
.each('end', function() { d3.select(this).classed('hidden', false) }) | |
d3.select('#chart .total strong').text( d3.sum(data, function(d) { return d.fatalities }) ) | |
} else { | |
svg.selectAll('circle') | |
.filter(function(e) { return e.region != d }) | |
.transition().duration(150) | |
.style('opacity', 0) | |
.each('end', function() { d3.select(this).classed('hidden', true) }) | |
svg.selectAll('circle') | |
.filter(function(e) { return e.region == d }) | |
.transition().duration(150) | |
.style('opacity', 0.7) | |
.each('end', function() { console.log(d3.select(this)); d3.select(this).classed('hidden', false) }) | |
d3.select('#chart .total strong').text( d3.sum(data.filter(function(e) { return e.region == d }), function(e) { return e.fatalities }) ) | |
} | |
d3.selectAll('a.switch').classed('active', false) | |
d3.select(this).classed('active', true) | |
}); | |
d3.select('a.switch.all').classed('active', true); | |
var total = d3.select('#chart') | |
.insert('div', ':first-child') | |
.datum(d3.sum(data, function(d) { return d.fatalities })) | |
.attr('class', 'total') | |
.html(function(d) { | |
return '<p><strong>' + d + '</strong> fatalities</p>' | |
}); | |
d3.select('#chart') | |
.append('div') | |
.attr('class', 'footer') | |
.html('<p><small>Data sources</small> <a href="http://www.nytimes.com/interactive/2015/06/17/world/middleeast/map-isis-attacks-around-the-world.html?_r=3">NYT</a>, <a href="https://en.wikipedia.org/wiki/List_of_Islamist_terrorist_attacks#2015.E2.80.93present">Wikipedia</a></p>'); | |
if (document.location.hash.length > 0) { | |
var path = d3.select('.' + document.location.hash.replace('#', '')) | |
path.on('click').call(path.node(), path.datum()) | |
}; | |
}); | |
</script> | |
<script> | |
// Make the canvas wider on http://bl.ocks.org | |
if (document.location.hostname.indexOf("bl.ocks.org") > -1) { | |
d3.select(parent.document).select('iframe').style('width', '1325px').style('height', '400px'); | |
d3.select(parent.document).select('body').style('width', '1325px').style('margin', '2em'); | |
d3.select(parent.document).select('.gist-source pre').style('border-left', 'none'); | |
} | |
</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
task :default => :server | |
# Serving files via Rack | |
desc "Serve the files via Rack and Thin" | |
task :server => [:dependencies] do | |
port = ENV['PORT'] || 8000 | |
puts "Launching local webserver at <http://localhost:#{port}> ...", "-"*80 | |
begin | |
Thin::Logging.silent = true | |
Thin::Server.start port, lambda { |env| | |
if env['PATH_INFO'] == '/' | |
[200, {'Content-Type' => 'text/html'}, File.new('index.html')] | |
else | |
Rack::Directory.new('.').(env) | |
end | |
} | |
rescue Exception => e | |
if e.message =~ /no acceptor/ | |
puts "[!] Port #{port} not available, trying next one...", "" | |
port += 1 | |
puts "Launching local webserver at <http://localhost:#{port}> ...", "-"*80 | |
retry | |
end | |
raise | |
end | |
end | |
task :dependencies do | |
%w| rack thin |.each do |lib| | |
begin | |
require lib | |
rescue LoadError | |
puts "[!] Required gem '#{lib}' not found, please install it with:", "", | |
" $ gem install #{lib}", "", | |
"-"*80 | |
raise | |
end | |
end | |
end | |
# Stepping through the tutorial | |
begin | |
require 'term/ansicolor' | |
class String | |
include Term::ANSIColor | |
end | |
rescue LoadError | |
class String | |
def black; self; end | |
def on_green; self; end | |
def on_yellow; self; end | |
end | |
end | |
_ = '-'*80 | |
desc "List the steps of this tutorial" | |
task :steps do | |
puts _, "Steps of this tutorial", _ | |
current = GitSteps.current_step | |
GitSteps.steps.each_with_index do |step, i| | |
is_current = step.sha == current.sha ? "*" : " " | |
puts "#{is_current} #{(i+1).to_s.rjust(3).bold} | #{step.subject.gsub(/^\[\d+\] /, '')}" | |
end; puts | |
end | |
desc "Display current step" | |
task :step => [:check] do | |
step = GitSteps.current_step | |
puts _, "#{step.sha} | #{step.subject.bold}", | |
_, "#{step.body}" | |
end | |
desc "Start the tutorial or switch back to first step" | |
task :start => [:check] do | |
puts _, "Starting the tutorial with the first step".white.on_magenta, _ | |
step = GitSteps.steps.first | |
puts "#{step.sha} | #{step.subject.bold}", | |
"#{step.body}" | |
exec "git checkout #{step.sha} > /dev/null 2>&1 " | |
end | |
desc "Step to the next step of tutorial" | |
task :next => [:check] do | |
if step = GitSteps.next_step | |
puts _, "#{step.sha} | #{step.subject.bold}", | |
_, "#{step.body}" | |
exec "git checkout #{step.sha} > /dev/null 2>&1 " | |
else | |
puts "You have reached the end of the tutorial".white.on_green, | |
"Start again with: rake start" | |
end | |
end | |
desc "Step to the previous step of tutorial" | |
task :previous => [:check] do | |
if step = GitSteps.previous_step | |
puts _, "#{step.sha} | #{step.subject.bold}", | |
_, "#{step.body}" | |
exec "git checkout #{step.sha} > /dev/null 2>&1 " | |
else | |
puts "You are at the beginning of the tutorial".white.on_green, | |
"Follow the tutorial with: rake next" | |
end | |
end | |
desc "Show differences between the current step and the previous step" | |
task :diff do | |
current = GitSteps.current_step | |
previous = GitSteps.previous_step | |
(puts "[!] Cannot find previous step".white.on_red; exit(1)) unless previous | |
puts _, "Previous : #{previous.subject}", | |
"Current : #{current.subject}", _ | |
exec "git diff --color --ignore-all-space --minimal HEAD^ HEAD | cat" | |
end | |
desc "Reset the tutorial and switch to master branch" | |
task :reset => [:check] do | |
exec "git checkout master > /dev/null" | |
end | |
task :check do | |
if `which git` == '' | |
puts "[!] ERROR: You need Git installed to step through the tutorial.".white.on_red | |
exit(1) | |
end | |
end | |
module GitSteps | |
class Commit | |
attr_reader :sha, :subject, :body | |
def initialize(commit) | |
@sha, @subject = commit.split('|||', 2) | |
@body = %x[git log -n 1 --format='%b' #{sha}].chomp | |
end | |
def step?; subject =~ /^\[\d+\]/; end | |
end | |
def steps | |
%x[git log --reverse --format='%h|||%s' master] | |
.chomp | |
.split("\n") | |
.map { |commit| Commit.new(commit) } | |
.select { |commit| commit.step? } | |
end | |
def current_step | |
Commit.new( %x[git log -n 1--reverse --format='%h|||%s'].chomp ) | |
end | |
def next_step | |
steps.select { |step| step.subject > current_step.subject }.first | |
end | |
def previous_step | |
steps.select { |step| step.subject < current_step.subject }.last | |
end | |
extend self | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment