|
<!DOCTYPE html> |
|
<head> |
|
<meta charset="utf-8"> |
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
<link href="//fonts.googleapis.com/css?family=.|Oswald:light,normal,bold|Oswald:light,normal,bold|Oswald:light,normal,bold|Raleway:light,normal,bold|Roboto:light,normal,bold" rel="stylesheet" type="text/css" /> |
|
<style> |
|
body { color:#3288e2;background:#fbf7ef;margin:0;top:0;right:0;bottom:0;left:0; } |
|
|
|
svg { |
|
font: 10px sans-serif; |
|
} |
|
|
|
.orange { |
|
fill: black |
|
} |
|
|
|
.normal{ |
|
opacity: 0.1 |
|
} |
|
|
|
.highlighted { |
|
opacity: 1 |
|
} |
|
|
|
.rect { |
|
background:#3288e2; |
|
width: 50px; |
|
height: 50px |
|
} |
|
|
|
.line { |
|
fill: none; |
|
stroke: #3288e2; |
|
/* stroke-width: 2px; */ |
|
} |
|
|
|
.title { |
|
font-family: Raleway; |
|
text-align: center; |
|
margin-top: 3%; |
|
font-weight: 600; |
|
font-size: 22px; |
|
letter-spacing: 0.15em; |
|
} |
|
|
|
.container { |
|
background: #ece5d6; |
|
margin-right: 5%; |
|
margin-left: 5%; |
|
margin-top: 24px; |
|
margin-bottom: 24px; |
|
text-align: center; |
|
padding-bottom: 24px; |
|
padding-top: 24px; |
|
overflow: scroll; |
|
} |
|
|
|
.todos { |
|
border: 2px solid #ece5d6; |
|
text-align: left; |
|
font-family: roboto; |
|
margin-top: 16px; |
|
padding-left: 5%; |
|
padding-right: 5%; |
|
} |
|
|
|
.todo { |
|
line-height: 24px; |
|
background: #3288e2; |
|
color: #fbf7ef; |
|
padding-top: 0%; |
|
padding-left: 2%; |
|
font-family: raleway; |
|
width: 50%; |
|
} |
|
|
|
.first { |
|
padding-top:8px |
|
} |
|
|
|
.last { |
|
padding-bottom:8px |
|
} |
|
|
|
.label { |
|
width: 8%; |
|
height: 36px; |
|
padding-top: 4px; |
|
display: inline-block; |
|
margin-right: 2%; |
|
margin-left: 2%; |
|
text-align: center; |
|
color: #636363; |
|
font-family: 'Oswald'; |
|
font-size: 21px; |
|
min-width: 74px; |
|
margin-bottom: 18px; |
|
} |
|
|
|
.visualization { |
|
text-align:left |
|
} |
|
|
|
.legend{ |
|
color: red |
|
} |
|
|
|
</style> |
|
</head> |
|
|
|
<body> |
|
<div class="title">EU Terrorism 1970-2014</div> |
|
<div class="container"> |
|
<div class="legend"></div> |
|
<div class="visualization"></div> |
|
<div class="todos"> |
|
<div class="first todo">1. Redo the transition to add/remove with d3</div> |
|
<div class="todo">2. Work out how to redraw axis</div> |
|
<div class="todo">3. Group numbers by decade</div> |
|
<div class="todo">4. Transition the opacity</div> |
|
<div class="todo">5. Sort the lines to put the smaller ones first</div> |
|
<div class="todo">6. Get different date (EU Migration?) at click of button</div> |
|
<div class="last todo">7. Responsive width</div> |
|
</div> |
|
</div> |
|
<script> |
|
|
|
//country colours |
|
var colours = { |
|
Spain: '#f7ecab', |
|
Italy: '#96dfd1', |
|
UnitedKingdom: '#f5c8c8', |
|
France:'#badeb5', |
|
Belgium:'#9dbece', |
|
Denmark:'pink', |
|
Germany: 'orange', |
|
Greece: 'green', |
|
Ireland: '#d6ecd8', |
|
Italy: 'yellow', |
|
Luxembourg:'rebeccapurple', |
|
Netherlands:'blue', |
|
Portugal:'red' |
|
} |
|
|
|
//Margin Convention |
|
var margin = {top: 20, right: 30, bottom: 20, left: 60}, |
|
width = 900 - margin.left - margin.right, |
|
height = 500 - margin.top - margin.bottom; |
|
labelHeight = 45 |
|
|
|
//Container |
|
var svg = d3.select(".visualization").append("svg") |
|
.attr("width", width + margin.left + margin.right) |
|
.attr("height", height + margin.top + margin.bottom) |
|
.append("g") |
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); |
|
|
|
var legend = d3.select(".legend").append("svg") |
|
.attr("width", width) |
|
.attr("height", labelHeight) |
|
.append('g'); |
|
|
|
//Saving the correct time format for D3 |
|
var parseDate = d3.timeParse("%b %Y"); |
|
|
|
//Saving the correct time format for the axis lables |
|
var formatTime = d3.timeFormat("%b %Y"); |
|
|
|
//Defining the range for the time scale |
|
var x = d3.scaleTime().range([0, width]); |
|
|
|
//Defining the range for the linear scaling |
|
var y = d3.scaleLinear().range([height, 0]); |
|
|
|
//Creating the line generator, defing by using accessor functions the date being the x variable and the price being the y variable |
|
var line = d3.line() |
|
.x(function(d) { return x(d.date); }) |
|
.y(function(d) { return y(d.price); }); |
|
|
|
////Creating the area generator, defing by using accessor functions the date being the x variable and the price being the y1 variable and the height being the y0 in order to avoid that the area that at the left up corner. |
|
var area = d3.area() |
|
.x(function(d) { return x(d.date); }) |
|
.y0(height) |
|
.y1(function(d) { return y(d.price); }); |
|
|
|
//Connecting to the belgium set |
|
d3.text('EU_Terrorism.csv', function(error, raw) { |
|
|
|
var dsv = d3.dsvFormat(',') |
|
var orig_data = dsv.parse(raw); |
|
var data = []; |
|
orig_data.forEach( function(row) { |
|
|
|
Object.keys(row).forEach( function(colname) { |
|
// Ignore 'State' and 'Value' columns |
|
if(colname == "iyear" || colname == "price") { |
|
return |
|
} |
|
data.push({"date": row["iyear"], "price": row[colname], "country": colname}); |
|
}); |
|
}); |
|
|
|
var symbols = d3.nest() |
|
.key(function(d) { return d.country; }) |
|
.entries(data); |
|
|
|
// Parse and caculate some values for each countries |
|
symbols.forEach(function(s) { |
|
s.key = s.key.replace(/\s+/g, ''); |
|
// changes eg "United Kingdom to UnitedKingdom" |
|
s.colour = colours[s.key] |
|
s.values.forEach(function(d) { |
|
d.date = d.date; |
|
d.price = +d.price; |
|
}); |
|
|
|
s.maxPrice = d3.max(s.values, function(d) { return d.price; }); |
|
s.sumPrice = d3.sum(s.values, function(d) { return d.price; }); |
|
}); |
|
console.table(orig_data) |
|
console.table(data) |
|
|
|
//Defining the domain for the linear scaling using D3 extent which return the min and max |
|
x.domain(d3.extent(data, function(d) { return d.date; })); |
|
|
|
y.domain([0, d3.max(symbols.map(function(d) { return d.maxPrice; }))]) |
|
|
|
svg.selectAll(".line") |
|
.data(symbols) |
|
.enter() |
|
.append("path") |
|
.attr("class", "line") |
|
.attr("d", function(d) { return line(d.values); }) |
|
.style("stroke", function(d) { return (d.colour); }); |
|
|
|
svg.selectAll(".area") |
|
.data(symbols) |
|
.enter() |
|
.append("path") |
|
.attr("class", "normal") |
|
.attr("id", function(d) { return (d.key); }) |
|
.attr("d", function(d) { return area(d.values); }) |
|
.style("class", "normal") |
|
.style("fill", function(d) { return (d.colour); }); |
|
|
|
|
|
// Calling and defining the x axis at the same time |
|
svg.append("g") |
|
.attr("class", "axis--x") |
|
.attr("transform", "translate(0," + height + ")") |
|
.call(d3.axisBottom(x) |
|
.ticks(8) |
|
.tickFormat(formatTime)); |
|
|
|
//Calling and defining the y axis at the same time |
|
svg.append("g") |
|
.attr("class", "axis--y") |
|
.call(d3.axisLeft(y) |
|
.ticks(4)); |
|
|
|
// Legend |
|
legend.selectAll("rect") |
|
.data(symbols) |
|
.enter() |
|
.append("g") |
|
.append("rect") |
|
.attr("height", labelHeight) |
|
.attr("width", width / symbols.length) |
|
.attr("fill", function(d) { return (d.colour); }) |
|
.attr("transform", function(d, i){ |
|
return "translate(" + (width / symbols.length*i) + ",0)" |
|
}); |
|
|
|
legend.selectAll("g") |
|
.append("text") |
|
.attr("transform", |
|
function(d, i){ return "translate(" + (width / symbols.length*i) + ",30)"; |
|
}) |
|
.attr("font-size", "2em") |
|
.attr("color", "black") |
|
.text(function(d){ return d.key;}) |
|
.on("click", function(d) { |
|
var opacity = d3.selectAll(`#${d.key}`).attr('class') === 'normal' ? 'highlighted' : 'normal' |
|
d3.selectAll(`#${d.key}`).attr('class', opacity) |
|
}); |
|
}) |
|
|
|
</script> |
|
</body> |