Skip to content

Instantly share code, notes, and snippets.

@eetuko

eetuko/.block

Last active Oct 6, 2020
Embed
What would you like to do?
Covid-19 world-wide totals per million population - D3js maps
license: gpl-3.0
height: 540
scrolling: no
border: yes

This map uses D3.js v.5 and includes:

  • Dynamic loading of data from Worldometer
  • The use of topojson to load the shape file
  • The addition of a legend with Susie Lu's legend
  • Some degree of responsiveness
  • Some css work for a smoother experience
// Define size related variables
const dimension = d3.select(".visualisation")
.node()
.parentNode
.getBoundingClientRect();
const margin = 90;
const width = dimension.width;
const height = 500;
const aspect = width / (height - margin);
const rotate = -9.9;
const zoom = d3.zoom()
.scaleExtent([1, 30])
.translateExtent([[0,0],[width, height]])
.on('zoom', function () {
d3.select('g').attr('transform', d3.event.transform)
});
// Add the core svg block
const svg = d3.select(".visualisation")
.append("svg")
.attr("width", width)
.attr("height", height)
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", `0 0 ${width} ${height}`)
.call(zoom);
const globe = svg.append("g");
const tooltip = d3.select('.visualisation').append('div')
.attr('class', 'hidden tooltip');
const projection = d3.geoMercator()
.rotate([rotate,0])
.scale(height / (1.4 * Math.PI))
.translate([width / 2, (height - margin) / 1.2]);
const geoPath = d3.geoPath()
.projection(projection);
const colorScale = d3.scaleSqrt(["#ddd", "#777" ,"#000"]);
const map = {};
Promise.all([
d3.json('./world.topojson'),
d3.json('https://corona.lmao.ninja/v3/covid-19/countries'),
]).then(function([shapes, data]) {
var shapes = topojson.feature(shapes, "world");
// save in a global context and remove antarctic.
map.features = shapes.features.filter((d) => d.properties.ISO_A3 !== "ATA");
map.data = data;
map.metric = d3.select("#metrics").property("value");
selectData();
colorScale.domain([0,
d3.median(map.features, d => d.properties.dataPoint),
d3.max(map.features, d => d.properties.dataPoint)]);
draw();
drawLegend();
d3.select("#metrics").on("change",change);
});
function selectData() {
map.features.forEach((d) => {
var entry1 = map.data.filter(t => t.countryInfo.iso3 == d.properties.ISO_A3)[0];
if(entry1) {
d.properties.dataPoint = entry1[map.metric];
d.properties.country = entry1.country;
} else {
d.properties.dataPoint = 0;
d.properties.country = "Unknown";
}
})
};
function draw() {
globe.selectAll("path.country").remove();
globe.selectAll("path.country")
.data(map.features)
.enter()
.append("path")
.attr("class","country")
.attr('d', geoPath)
.style("fill", d => colorScale(d.properties.dataPoint))
.on('mousemove', function (d) {
tooltip.classed('hidden', false)
.html("<h6>" + d.properties.country + ": " + d.properties.dataPoint + "</h6>")
.attr('style', 'left:' + (d3.event.pageX + 15) + 'px; top:' + (d3.event.pageY + 20) + 'px');
})
.on('mouseout', function () {
tooltip.classed('hidden', true);
});
};
function drawLegend() {
svg.select(".legendLinear").remove();
svg.append("g")
.attr("class", "legendLinear")
.attr("transform", "translate(10," + (height - margin) + ")");
var shapeWidth = 40,
cellCount = 5,
shapePadding = 2,
legendTitle = map.metric.replace("PerOneMillion", "") + " per million population: ";
var legendLinear = d3.legendColor()
.title(legendTitle)
.shape("rect")
.shapeWidth(shapeWidth)
.cells(cellCount)
.labelFormat(d3.format(".3s"))
.orient('horizontal')
.shapePadding(shapePadding)
.scale(colorScale);
svg.select(".legendLinear")
.append("rect")
.attr("class", "legendBackground")
.attr("x", -5)
.attr("y", -22)
.attr("opacity", 0.9)
.attr("rx", 8)
.attr("ry", 8)
.attr("width", legendTitle.length*7.4)
.attr("height", margin);
svg.select(".legendLinear")
.call(legendLinear);
};
function change() {
map.metric = d3.select("#metrics").property("value")
selectData();
colorScale.domain([0,
d3.median(map.features, d => d.properties.dataPoint),
d3.max(map.features, d => d.properties.dataPoint)]);
draw();
drawLegend();
}
d3.select(window)
.on("resize", function() {
var targetWidth = d3.select(".visualisation").node().parentNode.getBoundingClientRect();
svg.attr("width", targetWidth);
svg.attr("height", targetWidth / aspect);
svg.attr("viewBox", `0 0 ${width} ${height}`)
});
<!doctype html>
<html>
<head>
<title>Covid-19 world-wide totals per million population maps</title>
<style>
p, .legendTitle, .label {
font-family: sans-serif;
}
.country {
-webkit-transition: all 0.5s ease-out 0s;
-moz-transition: all 0.5s ease-out 0s;
-ms-transition: all 0.5s ease-out 0s;
-o-transition: all 0.5s ease-out 0s;
transition: all 0.5s ease-out 0s;
}
.country:hover {
fill: #D90429!important;
}
.hidden {
display: none;
}
div.tooltip {
background-color: #fff;
padding: 5px 5px;
text-shadow: #f5f5f5 0 1px 0;
font: 14pt sans-serif;
border: 1px solid;
border-color: grey;
border-radius: 8px;
opacity: 0.95;
position: absolute;
box-shadow: rgba(0, 0, 0, 0.3) 0 2px 5px;
-webkit-transition: all 0.5s ease-out 0s;
-moz-transition: all 0.5s ease-out 0s;
-ms-transition: all 0.5s ease-out 0s;
-o-transition: all 0.5s ease-out 0s;
transition: all 0.5s ease-out 0s;
}
div.tooltip h6 {
margin: 0;
color: #212121;
}
.legendTitle {
font-size: 12pt;
opacity: 0.8;
text-transform: capitalize;
}
.label {
font-size: 10pt;
opacity: 0.8;
}
.legendBackground {
fill: #ffffff!important;
}
</style>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://unpkg.com/topojson@3"></script>
<script src="https://unpkg.com/topojson-client@3"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.25.6/d3-legend.min.js"></script>
</head>
<body>
<p>
Choose your metric from the list:
<select id="metrics">
<option value="casesPerOneMillion" selected="selected">Cases</option>
<option value="deathsPerOneMillion">Deaths</option>
<option value="testsPerOneMillion">Tests</option>
<option value="activePerOneMillion">Active</option>
<option value="recoveredPerOneMillion">Recovered</option>
<option value="criticalPerOneMillion">Critical</option>
</select>
</p>
<div class="visualisation"> </div>
<script src = "./covid_cases.js"></script>
</body>
</html>
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment