-
Notifications
You must be signed in to change notification settings - Fork 16
/
index.html
394 lines (364 loc) · 20.6 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
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Coronavirus country comparator</title>
<link rel="shortcut icon" href="favicon.ico">
<link href="css/roboto.css" rel="stylesheet">
<link href="css/vuetify.min.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<meta property="og:title" content="Coronavirus country comparator" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://boogheta.github.io/coronavirus-countries/" />
<meta property="og:image" content="https://boogheta.github.io/coronavirus-countries/img/screenshotv2.png"/>
<meta property="og:description" content="Compare the spread of the COVID-19 coronavirus in all countries by numbers of confirmed and deceased ones as reported by JHU CSSE and different countries"/>
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@boogheta">
<meta name="twitter:creator" content="@boogheta">
<meta name="twitter:title" content="Coronavirus country comparator">
<meta name="twitter:description" content="Compare the spread of the COVID-19 coronavirus in all countries by numbers of confirmed and deceased ones as reported by JHU CSSE and different countries">
<meta name="twitter:image" content="https://boogheta.github.io/coronavirus-countries/img/screenshotv2.png">
</head>
<body>
<noscript><strong>Coronavirus country comparator requires JavaScript. Please enable it to continue.</strong></noscript>
<div id="corona"><v-app dark toolbar>
<aside class="navigation-drawer navigation-drawer--absolute navigation-drawer--clipped navigation-drawer--is-booted navigation-drawer--is-mobile navigation-drawer--open navigation-drawer--permanent" id="menu">
<v-list dense id="controls">
<v-subheader class="">
<v-icon>grain</v-icon>
<span>Cases
<small v-if="perCapita">(per million inhabitants)</small>
</span>
</v-subheader>
<v-list-tile
v-for="item in cases"
v-if="!item.disabled"
:key="item.id"
:class="{'unchecked': !item.selected}"
@click="selectCase(item.id)"
@mouseover="hoverCase(item, true)"
@mouseleave="hoverCase(item, false)"
>
<v-list-tile-action v-if="vizChoice === 'multiples'" class="caseIcon">
<v-icon :style="{'color': item.color}">fiber_manual_record</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>
<span :class="{'country': true, 'caseIcon': vizChoice === 'multiples'}">{{ item.id.replace(/_/, ' ') }}</span>
<span class="value amount">{{ item.value != null ? item.value : item[typVal][scope] }}</span>
</v-list-tile-title>
</v-list-tile-content>
<v-list-tile-action>
<v-radio-group v-model="caseChoice" v-if="vizChoice !== 'multiples'">
<v-radio hide-details color="white" :value="item.id"></v-radio>
</v-radio-group>
<v-switch light color="white"
v-if="vizChoice === 'multiples'"
v-model="item.selected"
@click.native.stop=""
></v-switch>
</v-list-tile-action>
</v-list-tile>
<v-subheader class="bordered">
<v-icon>timeline</v-icon>
<span>Scale</span>
</v-subheader>
<v-list-tile id="scale" class="radiooption">
<v-radio-group row hide-details v-model="scaleChoice">
<v-radio small
color="white"
v-for="c in ['linear', 'logarithmic', 'daily']"
:class="c"
:label="c"
:value="c"
:disabled="c === 'logarithmic' && vizChoice === 'stacked'"
></v-radio>
</v-radio-group>
<v-list-tile-action class="extraaction">
<v-icon color="white"
:style="'margin-top: 30px; opacity: ' + (!(perDay && vizChoice === 'series') ? 0 : (hideNegative ? 1 : 0.25))"
:title="hideNegative ? 'display negative values' : 'hide negative values'"
@click="hideNegative = !hideNegative"
>remove_circle_outline</v-icon>
<v-icon color="white"
:style="'margin-top: -30px; opacity: ' + (!(perDay && vizChoice === 'series') ? 0 : (smoothen ? 1 : 0.25))"
:title="smoothen ? 'unsmooth' : 'smooth curve using a 7-days moving average'"
@click="smoothen = !smoothen"
>vertical_align_center</v-icon>
</v-list-tile-action>
</v-list-tile>
<v-list-tile class="switchoption"
:title="vizChoice === 'stacked' ? 'population ratios makes no sense for stacked area charts' : ''"
>
<v-list-tile-content>
<v-list-tile-title
:class="{'switcher': vizChoice !== 'stacked', 'value': true, 'unchecked': perCapita}"
@click="if (vizChoice !== 'stacked') perCapita = !perCapita"
>absolute values</v-list-title>
</v-list-tile-content>
<v-list-tile-action>
<v-switch :disabled="vizChoice === 'stacked'" light v-model="perCapita" color="white"></v-switch>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title
:class="{'switcher': vizChoice !== 'stacked', 'unchecked': !perCapita || vizChoice === 'stacked'}"
@click="if (vizChoice !== 'stacked') perCapita = !perCapita"
>population ratio</v-list-title>
</v-list-tile-content>
</v-list-tile>
<v-subheader class="bordered">
<v-icon>view_comfy</v-icon>
<span>Visualize as</span>
</v-subheader>
<v-list-tile class="radiooption">
<v-radio-group row hide-details v-model="vizChoice">
<v-radio small
color="white"
v-for="c in ['series', 'stacked', 'multiples']"
:label="c"
:value="c"
></v-radio>
</v-radio-group>
</v-list-tile>
<v-subheader class="bordered">
<v-icon>explore</v-icon>
<v-select auto single-line hide-details
v-model="scope"
:items="scopeChoices"
item-text="label"
item-value="name"
class="select scopefocus"
@change="scope = $event"
>
</v-select>
</v-subheader>
<v-list-tile>
<v-list-tile-content class="sort">
<v-list-tile-title>
<small
:class="{'country': true, 'unchecked': countriesOrder !== 'names'}"
@click="countriesOrder = 'names'"
>sort by name</small>
<small
:class="{'value': true, 'unchecked': countriesOrder !== 'cases'}"
@click="countriesOrder = 'cases'"
>sort by {{ caseLabel }}</small>
</v-list-tile-title>
</v-list-tile-content>
<span class="selectAll"
@click="selectAllPlaces"
:title="(allSelected ? 'Uns' : 'S') + 'elect all ' + levelsLabel(level)"
>
<v-icon>{{ allSelected ? "cancel_presentation" : "done_all" }}</v-icon>
</span>
</v-list-tile>
</v-list>
<v-list dense id="countries">
<v-list-tile
v-for="item in countries"
v-if="!perCapita || item.population"
:key="item.id"
:class="{'unchecked': !item.selected}"
>
<v-list-tile-content>
<v-list-tile-title>
<span class="country" :title="item.name.length > 20 ? item.name : ''">{{ item.name }}</span>
<span class="value amount">{{ item.lastStr }}</span>
</v-list-tile-title>
</v-list-tile-content>
<v-list-tile-action>
<v-switch light v-model="item.selected" color="white"></v-switch>
<span class="keep"
v-if="item.selected && legend.length > 1"
@click="keepOnlyPlace(item.name)"
:title="'Keep only ' + item.name"
>
<v-icon>input</v-icon>
</span>
</v-list-tile-action>
</v-list-tile>
</v-list>
<v-list dense id="lowermenu">
<v-subheader class="selectAlign" v-if="vizChoice === 'series'">
<v-icon>compare_arrows</v-icon>
Align to <v-select auto single-line hide-details
v-model="refCase"
:items="refCases"
item-text="id"
item-value="id"
:append-icon="false"
class="select"
@change="refCase = $event"
>
</v-select> from
<v-chip small outline close class="grey--text"
v-model="refCountrySelected"
@input="refCountry = null"
@click="refCountry = null"
><small>unset</small></v-chip>
</v-subheader>
<v-list-tile v-if="vizChoice === 'series'">
<v-list-tile-content><v-select auto single-line hide-details
v-model="refCountry"
:items="refCountriesSelection"
item-text="name"
item-value="name"
class="select"
@change="refCountry = $event"
:placeholder="'select a startdate or ' + level"
>
</v-select></v-list-tile-content>
</v-list-tile>
<v-subheader
id="opendata"
:class="{'bordered': vizChoice === 'series'}"
title="Download the json data behind this application"
@click="exportData"
>
<v-icon>file_download</v-icon>
<span>Open Data</span>
</v-subheader>
</v-list>
<div class="navigation-drawer__border"></div>
</aside>
<v-toolbar class="dark" fixed>
<v-toolbar-title>
<a href="https://boogheta.github.io/coronavirus-countries/"><img src="img/covid19.png" alt="COVID19" width=50 /></a>
<v-title>
Coronavirus Country Comparator<br/>
<span class="source" title="Switch data source by choosing a different group of places to compare (World countries, Italy regions, France departments, USA states, etc.)">Data source: <a :href="source.url" target=_blank">{{ source.name }}</a><br/>
<span class="update"> (last update: {{ lastUpdateStr }} GMT)</span></span>
</v-title>
</v-toolbar-title>
<span class="disclaimer" v-if="source.disclaimer" v-html="source.disclaimer"></span>
<v-spacer></v-spacer>
<v-btn fab small class="ml-3" @click.native.stop="help = true">
<v-icon>help</v-icon>
</v-btn>
<a href="https://medialab.sciencespo.fr/" target="_blank">
<img src="img/medialab.png" alt="médialab Sciences Po" height=35 />
</a>
</v-toolbar>
<main>
<center id="loader" v-if="init">
<img src="img/loader.gif" alt="loader" /><br/>
<span>{{ initMessage }}...</span>
</center>
<div class="svg" style="height: 6000px">
<div v-if="vizChoice === 'multiples'" class="legend multiples">
<div
v-for="item in (legend.length ? legend : no_country_selected)"
:class="{'btn': true, 'btn--raised': true, 'theme--light': true, 'inactive': item.inactive}"
:style="item.style"
>{{ item.name }}
<div class="remove"
v-if="!item.inactive"
title="click to remove"
@click="item.selected = false"
:style="'top: '+(legendFontSize < 12 ? 1 : 3)+'px'"
>
<v-icon :style="'font-size: '+(legendFontSize + 4)+'px'">highlight_off</v-icon>
</div>
</div>
</div>
</div>
<div class="zoomslider"></div>
<center><div id="legend" class="legend facets">
<div
v-for="item in (legend.length ? legend : no_country_selected)"
:key="item.id"
v-if="item.selected && vizChoice !== 'multiples'"
:class="{'btn': true, 'btn--raised': true, 'btn--disabled': item.inactive}"
:style="item.style"
@mouseenter="hoverCountry(item, true)"
@mouseleave="hoverCountry(item, false)"
>
<div class="remove"
v-if="!item.inactive"
title="click to remove"
@click="item.selected = false"
>
<v-icon>highlight_off</v-icon>
</div>
<div class="btn__content">
<span>{{ item.name }}<small v-if="refCountrySelected && item.shift"> ({{ item.shiftStr }})</small></span>
<span class="lowercase amount">{{ item.value !== null ? item.value : item.lastStr }}
<small v-if="perCapita && !item.inactive">per million</small>
</span>
</div>
<div class="colorpicker"
v-if="!item.inactive && item.id !== 'total'"
title="click to change color"
@click="document.getElementById('colorpicker-' + item.id).click()"
>
<v-icon>colorize</v-icon>
<input type="color"
:id="'colorpicker-' + item.id"
v-model="item.color"
@change="setColor(item)"
style="width: 0px; height: 0px; opacity: 0"
/>
</div>
</div>
</div></center>
</main>
<div class="tooltipBox"><center><b>{{ hoverDate }}</b></center></div>
<v-dialog v-model="help" width="75%">
<v-card>
<v-card-title class="headline">Coronavirus Country Comparator</v-card-title>
<v-card-text>
This <i>datascape</i> application was initially built on top of the <a href="https://github.com/CSSEGISandData/COVID-19/tree/master/csse_covid_19_data/csse_covid_19_time_series" target="_blank">data openly released daily</a> by the <a href="https://systems.jhu.edu/" target="_blank">Center for Systems Science and Engineering (CSSE)</a> at Johns Hopkins University (JHU) for the <a href="https://gisanddata.maps.arcgis.com/apps/opsdashboard/index.html#/bda7594740fd40299423467b48e9ecf6" target="_blank">great dashboard</a> they built.<br/>
It now also features data from a variety of national sources (France, Germant, Italy, Spain and UK), as well as <a href="https://github.com/owid/covid-19-data/tree/master/public/data/vaccinations" target="_blank">international vaccination data</a> as published by <a href="https://ourworldindata.org/covid-vaccinations">Our World in Data</a>.
</v-card-text>
<v-card-text><b>WARNING:</b> Data is based on figures officially reported by countries and international organisations with various counting methods. It should therefore be considered with caution: they shall not reflect exact figures and can only be considered as minimum values.<br/><b>Confirmed</b> cases depend on the number of tests performed which can vary widely from one country to another; researchers estimate that it might only reflect between 10 and 50 % of the number of actually infected people.<br/><b>Deceased</b> cases should also only be considered as minimum values, as a variety of casualties consecutive to the virus might not be accounted accurately. For instance France's dataset only includes deceased cases reported by hospitals.<br/><b>Recovered</b> and <b>active cases</b> are not proposed anymore since they were never very reliable and were consequently <a href="https://github.com/CSSEGISandData/COVID-19/issues/4465" target="_blank">dropped by JHU on Aug 12th, 2021</a>.<br/>Some datasets for specific countries like Canada, Germany, or the USA only include confirmed and deceased cases. Others such as France, Italy or Spain can include other counts among <b>tested</b>, <b>hospitalized</b>, <b>intensive care</b> or even <b>vaccinated (fully or once)</b>.</v-card-text>
<v-card-text><b>Features:</b><ul>
<li>Hover the legend to focus a specific curve.</li>
<li>Hover the plot to read each curve's values at specific dates inside the legend.</li>
<li>Use the mouse wheel or the slider between the graph and the legend to zoom or unzoom on specific time periods.</li>
<li>Adjust the scale to <b>linear</b>, <b>logarithmic</b> or <b>daily</b> to visualize cumulative values since the beginning of the epidemy, tendencies or everyday evolution.</li>
<li>Switch between total <b>absolute values</b> or <b>population ratio</b> by million inhabitants to compare the penetration rate of the disease in the population.</li>
<li>Select <b>series</b> to compare tendencies for each selected place. Switch to <b>stacked</b> to measure how each place contribute to the bigger picture. Or switch to <b>multiples</b> to see all curves separated.</li>
<li>In series mode with a daily scale, use the <v-icon>vertical_align_center</v-icon> button to smooth the curves by using a 7 days moving average (and attenuate week-ends' lower reporting effects). This mode also allows to force the vertical axis to start at 0 and hide negative values by clicking the <v-icon>remove_circle_outline</v-icon> button.</li>
<li>Choose to compare all the World's countries or all regions/provinces/states of some main countries. Use the <v-icon>done_all</v-icon> icon to select all places at once.</li>
<li>Use <b>Align to</b> in series mode to select a place and see how others fit with a few days delay. Regression is calculated as the mean delay between the number of confirmed or deceased cases in the considered country compared to the reference one during the 30 days following the reach of 10 deceased cases (or 20 days and 50 cases when aligning on confirmed).</li>
<li>You can also select <b>after 10<sup>th</sup> deceased case</b> (or 50<sup>th</sup> confirmed) in the <b>Align to</b> menu to align all curves to a same "zero day".</li>
</ul></v-card-text>
<v-card-text>
This web application is a free libre open source software released under AGPL V3 license and its source code is <a href="https://github.com/boogheta/coronavirus-countries" target="_blank">available on GitHub</a>.<br/>
The interface is based on <a href="https://vuejs.org" target="_blank">Vue.js</a>, <a href="https://vuetifyjs.com/" target="_blank">Vuetify.js</a>, <a href="https://d3js.org" target="_blank">d3.js</a> and <a href="https://github.com/johnwalley/d3-simple-slider" target="_blank">d3-simple-slider</a>.<br/>
The logo is a <a href="https://pixabay.com/fr/illustrations/virus-coronavirus-sars-cov-2-flash-4915867/" target="_blank">creation from Alexei Hulsov</a> openly released under the <a href="https://pixabay.com/fr/service/license/" target="_blank">Pixabay license</a>.<br/>
<a href="https://github.com/boogheta/coronavirus-countries/issues" target="_blank">Bug reports, suggestions and pull requests</a> are very welcome! Adding new datasets is quite easy when there is a proper updated source. If you know of good datasets for specific countries regions and think it should be proposed, please <a href="https://github.com/boogheta/coronavirus-countries/issues" target="_blank">point it out</a>!</v-card-text>
<v-card-text>You can contact me on Twitter at: <a href="http://twitter.com/boogheta" target="_blank">@boogheta</a></v-card-text>
<v-card-text>Benjamin Ooghe-Tabanou — <a href="https://medialab.sciencespo.fr/" target="_blank">médialab Sciences Po</a></v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn class="white--text darken-1" flat @click.native="help = false">Close</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-app></div>
<!-- Matomo -->
<script type="text/javascript">
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(['setDoNotTrack', true]);
_paq.push(['disableCookies']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u='https://ws.sciences-po.fr/';
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '17']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<noscript><p><img src="https://ws.sciences-po.fr/matomo.php?idsite=17&rec=1" style="border:0;" alt="" /></p></noscript>
<!-- End Matomo Code -->
<script type="text/javascript" src="js/d3.v4.min.js"></script>
<script type="text/javascript" src="js/d3-simple-slider.min.js"></script>
<script type="text/javascript" src="js/vue.min.js"></script>
<script type="text/javascript" src="js/vuetify.min.js"></script>
<script type="text/javascript" src="js/corona.js"></script>
</body>
</html>