Highcharts - Covid-19 Dashboard
author(s):
Torstein Hønsi
by Torstein Hønsi
HTML
<script src="https://code.highcharts.com/7/highcharts.js"></script>
<script src="https://code.highcharts.com/7/modules/data.js"></script>
<script src="https://code.highcharts.com/7/modules/series-label.js"></script>
<script src="https://code.highcharts.com/maps/7/modules/map.js"></script>
<script src="https://code.highcharts.com/mapdata/custom/world.js"></script>
<!-- Flag sprites service provided by Martijn Lafeber, https://github.com/lafeber/world-flags-sprite/blob/master/LICENSE -->
<link rel="stylesheet" type="text/css" href="//github.com/downloads/lafeber/world-flags-sprite/flags32.css" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<div class="container-fluid">
<div class="btn-group btn-group-toggle" style="margin-bottom: 1rem">
<label class="btn btn-outline-primary active">
<input type="radio" name="source" id="confirmed" autocomplete="off"> Confirmed
</label>
<label class="btn btn-outline-primary">
<input type="radio" name="source" id="deaths" autocomplete="off" checked> Deaths
</label>
</div>
<div class="row">
<div class="col-12 col-md-6">
<div class="card">
<div class="card-header" id="map-header">
</div>
<div class="card-body" id="container"></div>
</div>
</div>
<div class="col-12 col-md-6" id="info">
<div class="card">
<div class="card-header">
<span class="f32"><span id="flag"></span></span>
<span class="header-text"></span>
</div>
<div class="card-header subheader">
Click countries to view history
</div>
<div class="card-body" id="country-chart">
...
CSS
.container-fluid {
margin-top: 10px;
}
#info .f32 .flag {
position: absolute;
top: 8px;
}
.clearfix {
clear: both;
}
.card-header.subheader {
font-size: 0.9rem;
color: rgba(0, 0, 0, 0.75);
background-color: transparent;
border-bottom: none;
}
.card {
height: 80vh;
min-height: 400px;
margin-bottom: 1em;
}
@media screen and (max-width: 780px) {
.card {
max-height: 400px;
}
.col-12 {
padding-left: 2px !important;
padding-right: 2px !important;
}
}
JavaScript
let countries;
let population;
let mapChart;
let countryChart;
const getConfig = type => ({
confirmed: {
day0Value: 200,
header: 'Confirmed Covid-19 Cases',
name: 'Confirmed cases',
valueSuffix: 'confirmed cases'
},
deaths: {
day0Value: 10,
header: 'Deaths caused by Covid-19',
name: 'Deaths',
valueSuffix: 'deaths'
}
}[type]);
const createMap = (type = 'confirmed') => {
const config = getConfig(type);
document.getElementById('map-header').innerHTML = config.header;
// Add lower case codes to the data set for inclusion in the tooltip.pointFormat
const mapData = Highcharts.geojson(Highcharts.maps['custom/world']);
const populationByName = {};
mapData.forEach(function (country) {
country.id = country.properties['hc-key']; // for Chart.get()
country.flag = country.id.replace('UK', 'GB').toLowerCase();
const pop = population.find(
c => country.properties['hc-key'].toUpperCase() === c.code
);
populationByName[country.name] = pop && pop.z || null;
});
// Names used in Highcharts Map Collection
countries['United States of America'] = countries.US;
countries['South Korea'] = countries['Korea, South'];
countries['Czech Republic'] = countries.Czechia;
let maxValue = 0;
const data = Object.keys(countries).map(name => {
const country = countries[name];
const total = country[country.length - 1][type];
if (populationByName[name]) {
const value = total / populationByName[name];
if (populationByName[name] > 1000) {
maxValue = Math.max(value, maxValue);
}
return { name, value, total };
}
return { name, value: null };
});
// Initiate the map chart
if (!mapChart) {
mapChart = Highcharts.mapChart('container', {
chart: {
spacingLeft: 1,
...