function make_map() {
let max_size = 1200;
let break_size = 640;
let map_width = width < max_size ? width : max_size;
let height = 0.575 * map_width;
let div = d3
.create("div")
.style("width", `${map_width}px`)
.style("height", `${height}px`)
.style("overflow", "hidden")
.style("position", "relative");
let svg = div
.append("svg")
.style("overflow", "hidden")
.attr("viewBox", [0, 0, map_width, height]);
let proj = d3
.geoIdentity()
.reflectY(true)
.fitSize([map_width, height], stateTiles);
let path = d3.geoPath().projection(proj);
let map = svg.append("g");
let density_map = new Map();
map
.selectAll("path.tile")
.data(stateTiles.features)
.join("path")
.attr("class", "tile")
.attr("data-fips", (o) => o.properties.fips)
.attr("data-name", (o) => o.properties.name)
.attr("d", path)
.attr("fill", function (d) {
let this_covid_data = covid_data.filter(
(o) => o.fips == d.properties.fips
)[0];
let rolling_mean = d3.mean(
this_covid_data.actualsTimeseries.slice(-14).map((o) => o.newCases)
);
let population = this_covid_data.population;
let density = rolling_mean / population;
density_map.set(d.properties.fips, density);
return d3.interpolateReds((density / max_case_density) ** 1);
})
.attr("data-density", (o) => density_map.get(o.properties.fips))
.attr("stroke-width", "0.8px")
.attr("stroke", function (d) {
return "#000";
})
.attr("stroke-linejoin", "round");
map
.selectAll("text")
.data(stateTiles.features)
.join("text")
.text((o) => o.properties.abbr)
.attr("font-size", `${0.022 * map_width}px`)
.attr("x", function (o) {
return path.centroid(o)[0];
})
.attr("text-anchor", "middle")
.attr("y", function (o) {
return path.centroid(o)[1];
})
.attr("dy", 0.008 * map_width)
.attr("pointer-events", "none");
if (map_width > break_size) {
// Use Tippy, if big enough
map
.selectAll("path.tile")
.nodes()
.forEach(function (t) {
let graph = make_graph(t.getAttribute("data-fips"), {
parameter: "newCases",
roll_by: 14
});
let content = html`<div><span style="font-weight:bold">${t.getAttribute(
"data-name"
)}</span>: Approximately ${Math.round(
100000 * t.getAttribute("data-density")
)} new cases per 100,000</div>${graph}`;
tippy(t, {
content: content,
theme: "light",
maxWidth: 500
});
});
} else {
// Overlay a transparent DIV, if smaller
map
.selectAll("path.tile")
.on("pointerenter", function (evt, d) {
let fips = d.properties.fips;
let graph_width = 0.96 * map_width;
let graph_height = 0.96 * height;
let graph_div = div
.append("div")
.attr("id", `graph${fips}`)
.style("width", `${graph_width}px`)
.style("height", `${graph_height}px`)
.style("position", "absolute")
.style("top", `${0.02 * graph_height}px`)
.style("left", `${0.02 * graph_width}px`)
.style("pointer-events", "none");
div
.append("div")
.attr("class", "close")
.style("width", "20px")
.style("height", "20px")
.style("background-color", "#eee")
.style("border", "solid 1px black")
.style("position", "absolute")
.style("left", "0px")
.style("top", "0px")
.style("text-align", "center")
.text("X")
.on("pointerdown", function (evt) {
evt.stopPropagation();
div.selectAll(".close").remove();
graph_div.remove();
});
graph_div.append(() =>
make_graph(fips, {
graph_width: graph_width,
graph_height: graph_height,
roll_by: 14
})
);
})
.on("mouseout", function (evt, d) {
let fips = d.properties.fips;
div.select(`#graph${fips}`).remove();
});
}
return div.node();
}