Archived
1
0
Fork 0
This repository has been archived on 2024-06-28. You can view files and clone it, but cannot push or open issues or pull requests.
covidmap/public/index.html
2020-03-22 22:39:12 +01:00

225 lines
7.3 KiB
HTML

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>COVID19 Fälle Österreich pro Bezirk</title>
<style>
html {
font-family: sans-serif;
}
html, body {
margin: 0;
width: 100%;
height: 100%;
}
path {
/*fill: #ccc;*/
stroke: lightblue;
stroke-width: 1px;
}
path:hover {
fill: red;
}
div.tooltip {
position: absolute;
text-align: center;
width: 150px;
/*height: 28px;*/
padding: 2px;
/*font: 12px sans-serif;*/
background: lightsteelblue;
border: 0;
border-radius: 3px;
pointer-events: none;
}
#selector {
position: absolute;
top: 0;
right: 0;
padding: 5px;
}
#selector form {
align-items: center;
display: flex;
}
#selector span {
height: 100%;
border: solid 2px lightsteelblue;
}
#sources {
position: absolute;
bottom: 0;
right: 0;
padding: 5px;
}
#updated {
position: absolute;
bottom: 0;
left: 0;
padding: 5px;
}
@media (max-width: 800px) {
#selector, #updated, #sources {
position: initial;
}
}
</style>
</head>
<body>
<div id="selector">
<form id="form">
<input type="radio" name="absolute" value="relative" id="relative" checked>
<label for="relative">Relativ</label>
<input type="radio" name="absolute" value="absolute" id="absolute">
<label for="absolute">Absolut</label>
<input type="radio" name="useLog" value="linear" id="linear" checked>
<label for="linear">Linear</label>
<input type="radio" name="useLog" value="log" id="log">
<label for="log">Logarithmisch</label>
</form>
</div>
<div id="sources">
Daten von <a href="https://info.gesundheitsministerium.at/">Gesundheitsministerium</a>,
<a href="https://www.data.gv.at/katalog/dataset/stat_gliederung-osterreichs-in-politische-bezirke131e2">Karte</a>,
<a href="https://www.statistik.at/wcm/idc/idcplg?IdcService=GET_NATIVE_FILE&RevisionSelectionMethod=LatestReleased&dDocName=059037">Bevölkerungszahlen</a>
<a href="https://lw1.at/i">Impressum</a>
</div>
<div id="updated"></div>
<script src="libs/d3.js"></script>
<script src="libs/d3-legend.js"></script>
<script src="libs/topojson-client.js"></script>
<script>
document.getElementById("form").reset();
const width = window.innerWidth - 20,
height = window.innerHeight - 20;
let useLog = false;
let absolute = false;
const svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var projection = d3.geoMercator().scale(4000);
const path = d3.geoPath().projection(projection);
var tooltipDiv = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
function initMap() {
Promise.all([
fetch("map.json").then(value => value.json()),
fetch("data.json").then(value => value.json()),
])
.then(([topology, data]) => {
svg.selectAll("*").remove();
const geojson = topojson.feature(topology, topology.objects.STATISTIK_AUSTRIA_POLBEZ_20200101Polygon);
const counts = data.data;
const bbox = topology.bbox;
document.getElementById("updated").innerText = data.lastUpdate;
projection.center([(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2]);
projection.fitSize([width, height], geojson);
const color = d3.scaleQuantize([data.min, data.max], d3.schemeBlues[7]);
const colorScale = useLog ? d3.scaleSequentialSymlog() : d3.scaleSequential();
const min = absolute ? data.absmin : data.relmin * 1000;
const max = absolute ? data.absmax : data.relmax * 1000;
colorScale.domain([min, max])
.interpolator(d3.interpolateBlues);
svg.append("g")
.attr("class", "legendLinear")
.attr("transform", "translate(20,20)");
const legendLinear = d3.legendColor()
.shapeWidth(30)
.cells(10)
// .orient('horizontal')
.scale(colorScale)
.title(absolute ? "Fälle" : "Fälle pro 1000 Einwohner");
svg.select(".legendLinear")
.call(legendLinear);
svg.selectAll("path")
.data(geojson.features)
.enter().append("path")
.attr("d", path)
.attr("fill", d => {
const name = d.properties.name;
if (counts[name]) {
const pop = counts[name].pop;
const cases = counts[name].cases;
const colorNum = absolute ? cases : (cases / pop * 1000);
return colorScale(colorNum);
}
return "white";
})
.on("mouseover", function (d) {
const name = d.properties.name;
let text;
if (!counts[name]) {
text = `<b>${name}</b>`
} else {
const pop = counts[name].pop;
const cases = counts[name].cases;
const fract = cases / pop * 1000;
text = `<b>${name}</b><br>${cases.toLocaleString()} Fälle bei ${pop.toLocaleString()} Einwohnern<br>(${fract.toFixed(2)} pro 1000 Einwohner)`;
}
tooltipDiv.transition()
.duration(200)
.style("opacity", .9);
tooltipDiv.html(text)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function (d) {
tooltipDiv.transition()
.duration(500)
.style("opacity", 0);
})
})
.catch((err) => {
console.error(err);
});
}
initMap();
const things = document.querySelectorAll("[type='radio']");
things.forEach(function (button) {
button.addEventListener("click", function (e) {
if (e.currentTarget.name === "absolute") {
absolute = e.currentTarget.value === "absolute"
} else if (e.currentTarget.name === "useLog") {
useLog = e.currentTarget.value === "log"
}
initMap();
})
});
</script>