-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.html
317 lines (288 loc) · 11.4 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
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Oregon Unemployment Rates: 2006 to 2015</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
<link href='https://fonts.googleapis.com/css?family=Lato' rel='stylesheet' type='text/css'>
<style>
body {
margin: 0;
padding: 0;
background: whitesmoke;
font-family: Lato, sans-serif;
color: #0D0000;
}
header {
padding: 6px 10%;
}
h1 {
position: absolute;
z-index: 650;
top: 10px;
left: 15px;
padding: 8px 15px;
margin: 0;
color: whitesmoke;
font-size: 1.5em;
background: rgba(25, 25, 25, 0.8);
border-radius: 5px;
}
h2 {
display: inline-block;
color: #001323;
}
#map {
position: absolute;
width: 100%;
top: 0;
bottom: 0;
}
footer {
padding: 6px 10%;
width: 80%;
}
p {
font-size: 1em;
color: #001323;
}
.legend {
padding: 6px 8px;
font-size: 1em;
background: rgba(75, 75, 75, 0.8);
color: whitesmoke;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
border-radius: 5px;
width: 160px;
}
.legend h3 {
font-size: 1.1em;
font-weight: bold;
line-height: 1em;
color: whitesmoke;
margin: 0;
}
.legend h3 span {
font-size: 1.3em;
margin: 0 20px 0 0;
}
.legend ul {
list-style-type: none;
padding: 0;
margin: 12px 4px 0;
}
.legend li {
height: 22px;
}
.legend span {
width: 30px;
height: 20px;
float: left;
margin-right: 10px;
}
#ui-controls {
width: 176px;
padding: 8px 25px 8px 15px;
background: rgba(75, 75, 75, 0.8);
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
border-radius: 5px;
color: whitesmoke;
}
#ui-controls .min {
float: left;
}
#ui-controls .max {
float: right;
margin-right: -15px;
}
.year-slider {
width: 100%;
}
label {
font-size: 1.1em;
font-weight: bold;
}
</style>
</head>
<body>
<h1>Oregon Unemployment Rates: 2006 – 2015</h1>
<div id="map"></div>
<div id="ui-controls">
<label><span class="min">2006</span><span class="max">2015</span>
<input type="range" min = "2006", max= "2015",
value = "2006", step= "1", class="year-slider">
</label>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/4.1.3/papaparse.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<script src="https://unpkg.com/[email protected]/dist/simple-statistics.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chroma-js/1.2.1/chroma.min.js"></script>
<script>
// map options
var options = {
scrollWheelZoom: true,
zoomSnap: .1,
dragging: true,
zoomControl: false
}
// create the Leaflet map
var map = L.map('map', options);
// request tiles and add to map
var tiles = L.tileLayer('http://stamen-tiles-{s}.a.ssl.fastly.net/toner-background/{z}/{x}/{y}.{ext}', {
attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a> — Map data © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
subdomains: 'abcd',
ext: 'png'
}).addTo(map);
// AJAX requst for GeoJSON data
$.getJSON("data/or-counties.json", function(counties) {
// AJAX request and parsing of CSV data
Papa.parse('data/or-unemployment-rates.csv', {
download: true,
header: true,
complete: function(data) {
//both files are loaded and ready
processData(counties, data);
}
});
});
// function to process and bind CSV attribute data to geometry data
function processData(counties, data) {
// loop through county features
for (var county in counties.features) {
//short-hand reference to county properties
var props = counties.features[county].properties;
//for each of the CSV data rows
for (var d in data.data) {
//if the county fips code and data fips code match
if (props.COUNTYFP == data.data[d].COUNTY_FIP) {
// re-assign the data for that county as the county's prop
counties.features[county].properties = data.data[d];
// no need to keep looping, break from inner loop
break;
}
} // inner loop complete
} // outer loop complete
//empty array to store all the data values
var rates = [];
// iterate through all the counties
counties.features.map(function(county) {
// iterate through all the props of each county
for (var prop in county.properties) {
// if the attribute is a number and not one of the fips codes
if ($.isNumeric(county.properties[prop]) && prop != 'COUNTY_FIP' && prop != 'STATE_FIP') {
// push that attribute value into the array
rates.push(Number(county.properties[prop]));
}
}
});
//determine 5 quantile class breaks
var breaks = chroma.limits(rates, 'q', 5);
// create a function which accepts a number value and returns a color value
//see http://gka.github.io/chorma/.js/#chroma-scale
var colorize = chroma.scale(chroma.brewer.OrRd).classes(breaks).mode('lab');
// call to draw the map
drawMap(counties, colorize);
// call to draw the legend
drawLegend(breaks, colorize);
}
function drawMap(counties, colorize) {
// create Leaflet object with geometry data and add to map
var dataLayer = L.geoJson(counties, {
style: function(feature) {
return {
color: 'black',
weight: 1,
fillOpacity: 1,
fillColor: '#1f78b4'
};
}
}).addTo(map); // add the leaflet GeoJson layer to the map
// first set the zoom/center to the dataLayer's extent
map.fitBounds(dataLayer.getBounds());
// then back the zoom level off a bit (since we're viewing the map full screen)
map.setZoom(map.getZoom() - .2);
// create map slider
createSliderUI(dataLayer, colorize);
// call to initially color the map with first timestamp
updateMap(dataLayer, colorize, 2006);
}
function updateMap(dataLayer, colorize, currentYear) {
// loop through each layer
dataLayer.eachLayer(function(layer) {
// short‐hand reference to properites
var props = layer.feature.properties;
// update the layer color given current timestamp
layer.setStyle({
fillColor: colorize(Number(props[currentYear]))
});
// build the tooltip
var tooltip = '<b>' + props['NAME'] + ' County</b><br />' +
props[currentYear] + '% Unemployment';
// bind the tooltip to the layer
layer.bindTooltip(tooltip, {
sticky: true
});
});
}
function drawLegend(breaks, colorize) {
// create a Leaflet control for the legend
var legendControl = L.control({
position: 'topright'
});
// when the control is added to the map
legendControl.onAdd = function(map) {
// create a new division element with class of 'legend' and return
var legend = L.DomUtil.create('div', 'legend');
return legend;
};
// add the legend control to the map
legendControl.addTo(map);
// select the newly created legend, select and populate the heading,
// creating an unordered list for the class ranges and store as reference
// to variable
var legend = $('.legend').html("<h3><span>2006</span> Unemployment Rates</h3><ul>");
// loop through the break values
for (var i = 0; i < breaks.length - 1; i++) {
// access the color for each class range
var color = colorize(breaks[i], breaks);
// build a list item with color block and values
var classRange = '<li><span style="background:' + color + '"></span> ' +
breaks[i].toLocaleString() + ' — ' +
breaks[i + 1].toLocaleString() + '</li>'
// append the list item to the list
$('.legend ul').append(classRange);
}
// close the unordered list
legend.append("</ul>");
}
function createSliderUI(dataLayer, colorize) {
// create Leaflet control for the slider
var sliderControl = L.control({
position: 'bottomleft'
});
// when added to the map
sliderControl.onAdd = function(map) {
// select an existing DOM element with an id of "ui-controls"
var slider = L.DomUtil.get("ui-controls");
// disable scrolling of map while using controls
L.DomEvent.disableScrollPropagation(slider);
// disable click events while using controls
L.DomEvent.disableClickPropagation(slider);
// return the slider from the onAdd method
return slider;
}
// add the control to the map
sliderControl.addTo(map);
// select the form element
$(".year-slider")
.on("input change", function() { // when user changes
var currentYear = $(this).val(); // update the year
updateMap(dataLayer, colorize, currentYear); // update the map with current timestamp
$('.legend h3 span').html(currentYear); // update timestamp in legend heading
});
} // end createSliderUI()
</script>
</body>
</html>