-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.html
601 lines (552 loc) · 21.9 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Sealed Cities</title>
<link rel="icon" type="image/png" href="img/favicon.ico">
<script type="text/javascript" src="d3/d3.v3.min.js"></script>
<script type="text/javascript" src="d3/d3-legend.min.js"></script>
<script type="text/javascript" src="js/jQuery.js"></script>
<link rel="stylesheet" type="text/css" href="css/style.css">
<link href='https://fonts.googleapis.com/css?family=Oswald' rel='stylesheet' type='text/css'>
</head>
<body>
<h1>Soil Sealing in European Cities</h1>
<header>
<div class="introduction">
Our soils are extremely valuable, but often not enough taken care of. Especially in cities it is very common to seal the ground with impervious materials for housing, streets, and car parks. <a href="http://esdac.jrc.ec.europa.eu/themes/soil-sealing"><strong class="highlight" target="_blank">Soil sealing</strong></a> contributes to global warming, promotes water scarcity and flooding at the same time, and puts biodiversity at risk.
<hr>
European cities show a varying degree of soil sealing.
Here you can explore the degrees of soil sealing in Europe's cities, grouped per country.
</div>
<div class="top-description">
<p class="description-item">
<strong class="highlight">Scroll over a country</strong> to see how many cities have at least half of their soil sealed.
</p>
<p class="description-item">
<strong class="highlight">Click on a country</strong> to see the average amount of soil sealing across its cities.
</p>
</div>
</header>
<div class="info-box">
<a href="http://esdac.jrc.ec.europa.eu/themes/soil-sealing">
<strong class="highlight" target="_blank">SOIL SEALING</strong></a> is the loss of soil resources
<br>due to the covering of land for housing,<br>roads or other construction work.
</div>
<!-- body of main script moved to the left edge for easier reading -->
<script type="text/javascript">
// use strict globally
"use strict";
////
//// PART 0 - LOADING AND CLEANING THE DATA
////
// will contain countries with available soil sealing data;for later comparison
var allCountriesWithData = [];
/* names of countries constituting the United Kingdom, Belgium,
Italy, France, Spain; the map lists them as separate countries,
the dataset as unified countries so I'll need this array to compare */
var uk = ["N. Ireland", "England", "Scotland", "Wales", "Faeroe Is."];
var belgium = ["Walloon", "Flemish"];
var italy = ["Sicily", "Sardinia"];
var france = ["Corsica"];
var spain = ["Balearic Is.", "Canary Is."];
// defining the vars to refer to both loaded datasets
var geo_data;
var data0;
/* importing the geoJSON file for drawing the map
Resource: http://grokbase.com/t/gg/d3-js/1372gq18j9/geojson-maps - Thanks :) */
d3.json("data/region_un_Europe_subunits.json", function(error, geo_data) {
// saving the data
geo_data = geo_data;
// importing the json file
d3.json('data/soil_sealing_cities.json', function(error, data) {
// perform some data wrangling for each row
data.forEach(function(d) {
d.country = d.country;
// transform strings to integers
d.cat_below_25_percent = +d.cat_below_25_percent;
d.cat_25_to_49_percent = +d.cat_25_to_49_percent;
d.cat_50_to_74_percent = +d.cat_50_to_74_percent;
d.cat_75_and_above_percent = +d.cat_75_and_above_percent;
d.sum_of_cities = +d.sum_of_cities;
d.percentage_cities_50_and_above_percent =
+d.percentage_cities_50_and_above_percent;
d.total_sealed_in_percent = +d.total_sealed_in_percent;
});
// saving the data as 'data0' to avoid confusion with 'data'
data0 = data;
// USING BOTH LOADED DATABASES
createGraphic(geo_data, data0);
// closing the inner data loading function
});
// closing the outer data loading function
});
// HERE COMES THE FUNCTION HOLDING ALL THE MAIN LOGIC
function createGraphic(geo_data, data) {
/* this function is a wrapper for all parts that collectively draw the
map and populate it with data-driven graphics */
//
// gathering data in the defined variables
//
/* adding to the countries-array those countries that have
soil sealing data available */
data0.forEach(function(d) {
allCountriesWithData.push(d.country);
});
// adding also the conglomerate that constitutes the UK
uk.forEach(function(p) {
allCountriesWithData.push(p);
});
// adding the comglomerate that constitutes Belgium
belgium.forEach(function(p) {
allCountriesWithData.push(p);
});
// adding the comglomerate that constitutes Italy
italy.forEach(function(p) {
allCountriesWithData.push(p);
});
// adding the comglomerate that constitutes France
france.forEach(function(p) {
allCountriesWithData.push(p);
});
// adding the comglomerate that constitutes Spain
spain.forEach(function(p) {
allCountriesWithData.push(p);
});
////
//// PART 1 - BUILDING THE MAP
////
// setting the margin etc. (specifications taken from the course)
// Resource: https://www.udacity.com/course/viewer#!/c-ud507-nd/l-3066258748/m-3105808656
var margin = 75;
var width = 1920 - margin;
var height = 1080 - margin;
var svg = d3.select('body')
.append('svg')
.attr('width', width + margin)
.attr('height', height + margin)
.append('g')
.attr('class', 'map');
debugger;
var projection = d3.geo.mercator()
// arranging the map so that it fits on the page
.scale(700)
.translate([width / 2 - 600, height + 250]);
var path = d3.geo.path().projection(projection);
var map = svg.selectAll('path')
.data(geo_data.features)
.enter()
.append('path')
.attr('d', path)
// adding an ID to each country, defined by country code
.attr('id', function(d) {
var country_id = d.properties.brk_a3;
return country_id;
})
/* additionally adding a class to each country
to make it possible to address the UK as a whole */
.attr('class', function(d) {
var country_id = d.properties.brk_a3;
// unifying the United Kingdom
if (country_id == "SCT" ||
country_id == "ENG" ||
country_id == "FRO" ||
country_id == "WLS" ||
country_id == "NIR") {
return "UK";
// unifying Belgium
} else if (country_id == "BFR" ||
country_id == "BWR") {
return "BEL";
// unifying Italy
} else if (country_id == "ITX" ||
country_id == "ITY" ||
country_id == "ITD") {
return "IT";
// unifying Spain
} else if (country_id == "ESX" ||
country_id == "ESI" ||
country_id == "ESC") {
return "ES";
// unifying France
} else if (country_id == "FXX" ||
country_id == "FXC") {
return "FRA";
} else {
// assign the 'entitiy' class if the country is only one
return "entity";
}
})
// coloring the countries according to their data
.style('fill', function(d) {
// when there is no soil sealing data, gray the country
if (noDataCountry(d) == true) {
return "lightgray";
} else {
/* color according to an ordinal progression
in traffic light scheme */
var color;
data0.forEach(function(c) {
if (c.country == d.properties.name ||
/* accounting for some alternative spelling
and organization between the two datasets */
(c.country == "Belgium"
&& belgium.indexOf(d.properties.name) != -1) ||
(c.country == "Italy"
&& italy.indexOf(d.properties.name) != -1) ||
(c.country == "Spain"
&& spain.indexOf(d.properties.name) != -1) ||
(c.country == "France"
&& france.indexOf(d.properties.name) != -1) ||
(c.country == "The Netherlands" &&
d.properties.name == "Netherlands") ||
(c.country == "Czech Republic" &&
d.properties.name == "Czech Rep.") ||
(c.country == "United Kingdom"
&& uk.indexOf(d.properties.name) != -1)) {
// coloring the countries according to a traffic light scheme
if (c.percentage_cities_50_and_above_percent < 25) {
color = "#5DC74C"; // green
return color;
}
else if (c.percentage_cities_50_and_above_percent < 50) {
color = "orange";
return color;
}
else if (c.percentage_cities_50_and_above_percent < 75) {
color = "#FF3232"; // lightred
return color;
} else {
color = "#E50000"; // darkred
return color;
}
}
// closing data0.forEach()
});
// give back the respective color for each country
return color;
}
// end of the logic assigning the 'fill' style
})
.style("stroke", "white")
// assigning the callbacks to the country paths
.on("mouseover", mapMouseOver)
.on("mouseout", mapMouseOut)
.on("click", showDetails);
// adding a legend for the color coding of the countries
// Reference: http://d3-legend.susielu.com/#color-examples
var ordinal = d3.scale.ordinal()
.domain(["< 25%", "25% - 49%", "50% - 74%", "> 75%"])
// #5DC74C is a shade of green, #FF3232 light-red, and #E50000 dark-red
.range([ "#5DC74C", "orange", "#FF3232", "#E50000"]);
// svg variable declared in line 68, appending a g element here
svg.append("g")
.attr("class", "legendOrdinal")
.attr("transform", "translate(5, 30)");
var legendOrdinal = d3.legend.color()
.title("% of cities per country with at least half their soil sealed")
.shape("path", d3.svg.symbol().type("circle").size(150)())
.shapePadding(10)
.scale(ordinal);
svg.select(".legendOrdinal")
.call(legendOrdinal);
//end of the legend
svg.append("g")
.text("Hellouhellooooehheooe");
function noDataCountry(d) {
/* returns 'true' when the country on the map is not present
in the dataset (meaning there's no available soil sealing data) */
if (allCountriesWithData.indexOf(d.properties.name) == -1 &&
d.properties.name != "Walloon" &&
d.properties.name != "Netherlands" &&
d.properties.name != "Czech Rep.") {
return true;
} else {
return false;
}
};
////
//// PART 2 - ADDING INTERACTIVITY
////
// adding the tooltip div to the DOM
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
function mapMouseOver(d) {
// "seals" the countries on mouseover by highlighting them gray
var country_id = d.properties.brk_a3;
/* Assigning classes to unify the associated countries and
chaining them in order so that they discolor at the same time */
var country = d3.selectAll($("#" + country_id));
// United Kingdon
if (country.attr('class') == 'UK') {
var selected = d3.selectAll('.UK');
// Belgium
} else if (country.attr('class') == 'BEL') {
var selected = d3.selectAll('.BEL');
// Italy
} else if (country.attr('class') == 'IT') {
var selected = d3.selectAll('.IT');
// Spain
} else if (country.attr('class') == 'ES') {
var selected = d3.selectAll('.ES');
// France
} else if (country.attr('class') == 'FRA') {
var selected = d3.selectAll('.FRA');
// all the others
} else {
var selected = country;
}
selected
.style('fill', function(d) {
if (noDataCountry(d) == true) {
return "lightgray";
} else {
return "gray";
}
})
.style("stroke", "white");
// making the tooltip div visible if there's data
var tip = d3.select(".tooltip")
if (noDataCountry(d) == false) {
tip.transition()
.duration(200)
.style("opacity", 0.9)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
};
// checking for fit, and calling populateTooltip()
data0.forEach(function(c) {
if (c.country == d.properties.name ||
/* accounting for some alternative spelling
and organization between the files */
(c.country == "Belgium"
&& (d.properties.name == "Walloon" ||
d.properties.name == "Flemish")) ||
(c.country == "France"
&& d.properties.name == "Corsica") ||
(c.country == "Italy"
&& (d.properties.name == "Sicily" ||
d.properties.name == "Sardinia")) ||
(c.country == "Spain"
&& (d.properties.name == "Balearic Is." ||
d.properties.name == "Canary Is.")) ||
(c.country == "The Netherlands"
&& d.properties.name == "Netherlands") ||
(c.country == "Czech Republic"
&& d.properties.name == "Czech Rep.") ||
(c.country == "United Kingdom"
&& uk.indexOf(d.properties.name) != -1)) {
return populateTooltip(c);
}
// closing data0.forEach()
});
};
function populateTooltip(c) {
/* adds country name and the % of soil sealing
as text to the tooltip div */
var tip = d3.select(".tooltip");
var sum_above_50 = c.cat_50_to_74_percent + c.cat_75_and_above_percent;
tip.html("".concat(c.country)
.concat(":<br><b>")
.concat(sum_above_50)
.concat("</b> of ")
.concat(c.sum_of_cities)
.concat(" cities")
)
.style("color", "black");
};
function mapMouseOut(d) {
/* returns the country to it's original colored state
when the cursor leaves the area */
var country_id = d.properties.brk_a3;
var country = d3.selectAll($("#" + country_id));
// chaining the different scattered contries
if (country.attr('class') == 'UK') {
var selected = d3.selectAll('.UK');
} else if (country.attr('class') == 'BEL') {
var selected = d3.selectAll('.BEL');
} else if (country.attr('class') == 'IT') {
var selected = d3.selectAll('.IT');
} else if (country.attr('class') == 'ES') {
var selected = d3.selectAll('.ES');
} else if (country.attr('class') == 'FRA') {
var selected = d3.selectAll('.FRA');
} else {
var selected = country;
}
selected
.style('fill', function(d) {
if (noDataCountry(d) == true) {
return "lightgray";
} else {
// those with data get the colors
var color
data0.forEach(function(c) {
if (c.country == d.properties.name ||
/* accounting for some alternative spelling
and organization between the files */
(c.country == "Belgium"
&& d.properties.name == "Walloon") ||
(c.country == "The Netherlands"
&& d.properties.name == "Netherlands") ||
(c.country == "Czech Republic"
&& d.properties.name == "Czech Rep.") ||
(c.country == "Italy"
&& italy.indexOf(d.properties.name) != -1) ||
(c.country == "Spain"
&& spain.indexOf(d.properties.name) != -1) ||
(c.country == "France"
&& france.indexOf(d.properties.name) != -1) ||
(c.country == "Belgium"
&& belgium.indexOf(d.properties.name) != -1) ||
(c.country == "United Kingdom"
&& uk.indexOf(d.properties.name) != -1)) {
// coloring the countries according to a traffic light scheme
if (c.percentage_cities_50_and_above_percent < 25) {
color = "#5DC74C"; // green
return color;
}
else if (c.percentage_cities_50_and_above_percent < 50) {
color = "orange";
return color;
}
else if (c.percentage_cities_50_and_above_percent < 75) {
color = "#FF3232"; // lightred
return color;
} else {
color = "#E50000"; // darkred
return color;
}
};
// closing data0.forEach()
}); return color;
}
})
.style("stroke", "white");
// removing the tooltip on mouseout
var tip = d3.select(".tooltip")
tip.transition()
.duration(500)
.style("opacity", 0);
};
////
////
//// SECOND PART: DATA-DRIVEN MODAL VISUALIZATION OF AVERAGE SOIL SEALING
////
////
function showDetails(d) {
// checking for fit, and calling openModal()
data0.forEach(function(c) {
if (c.country == d.properties.name ||
/* accounting for some alternative spelling
and organization between the files */
(c.country == "Belgium"
&& d.properties.name == "Walloon") ||
(c.country == "The Netherlands"
&& d.properties.name == "Netherlands") ||
(c.country == "Czech Republic"
&& d.properties.name == "Czech Rep.") ||
(c.country == "Italy"
&& italy.indexOf(d.properties.name) != -1) ||
(c.country == "Spain"
&& spain.indexOf(d.properties.name) != -1) ||
(c.country == "France"
&& france.indexOf(d.properties.name) != -1) ||
(c.country == "Belgium"
&& belgium.indexOf(d.properties.name) != -1) ||
(c.country == "United Kingdom"
&& uk.indexOf(d.properties.name) != -1)) {
return openModal(c);
}
// closing data0.forEach()
});
function openModal(c) {
/* function that opens the modal that prints the
image-data-representation for the country clicked on */
// percentage value of average grounds sealed
c.num_houses = d3.range(0, c.total_sealed_in_percent, 1);
// percentage value of average grounds non-sealed
c.num_trees = d3.range(0, 100 - c.total_sealed_in_percent, 1);
// setting the stage for the mosaic-style visualization
var country_vis = d3.select('.modal-content')
.select('.mosaic')
/* image size is 40px so this hard-coded
setting allows them to display 10x10 */
.style('width', '400px')
.style('height', '400px');
// refreshing the modal box from the previous call
country_vis.selectAll('img').remove('img');
// adding the country name and amount of cities
var country_info = d3.select('.modal-content').select('p');
var info_text = "<strong>".concat(c.total_sealed_in_percent)
.concat("%</strong> average soil sealing across <strong>")
.concat(c.sum_of_cities)
.concat("</strong> cities in <strong>")
.concat(c.country)
.concat("</strong>");
country_info
.html(info_text);
// insert imgs with class 'house', representing 1% of sealed soil each
var houses = country_vis.selectAll('.house')
.data(c.num_houses)
.enter()
.append('img')
.attr('class', 'house')
.attr('src', 'img/little_house.png')
.attr('alt', 'small house representing sealed soil')
.style('width', '40px')
.style('height', '40px');
// insert imgs with class 'tree', representing 1% of unsealed soil each
var squares = country_vis.selectAll('.tree')
.data(c.num_trees)
.enter()
.append('img')
.attr('class', 'tree')
.attr('src', 'img/tree.svg')
.attr('alt', 'green tree representing unsealed soil')
.style('width', '40px')
.style('height', '40px');
// making the modal box visible
d3.select('#country-info').style('display', 'block');
// closing openModal()
};
// closing showDetails()
};
// THE FINAL PARENTHESES (closing showGraphic())
};
</script>
<!-- HTML part creating the Modal -->
<div id="country-info" class="modal">
<!-- Modal content -->
<div class="modal-content">
<span class="close">x</span>
<p class="modal-description">Here comes the country's name</p>
<div class="visualization">
<div class="mosaic"></div>
<div class="legend">
<!-- this part harcodes the legend for the mosaic viz -->
<h4>LEGEND</h4>
<p>each tile<br>represents 1%</p>
<hr>
<img class="legend-image" src="img/little_house.png">
<p class="legend-desc">sealed soil</p>
<img class="legend-image" src="img/tree.svg">
<p class="legend-desc">open soil</p>
</div>
</div>
</div>
</div>
<footer>
<p>
Data from <a href="http://www.eea.europa.eu/data-and-maps/figures/degree-of-mean-soil-sealing" target="_blank">here</a>
</p>
<p>
(much) <a href="https://github.com/martin-martin/sealed_cities/blob/master/README.md" target="_blank">more info</a>
</p>
</footer>
<!-- loading the external script that contains the logic for the modal box -->
<script type="text/javascript" src="js/modal.js"></script>
<!-- composed by martin-martin in march 2016 -->
</body>
</html>