225 lines
7.3 KiB
HTML
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>
|