doMap = (features, options = {}) => {
const w = options.width || width;
const h = options.height || 600;
const p = options.padding || 20;
const projection = d3
.geoAlbersUsa()
.fitExtent([[p, p], [w - p, h - p]], countiesGeo);
const path = d3.geoPath(projection);
const zoom = d3
.zoom()
.scaleExtent([1, 8])
.on("zoom", zoomed);
const container = html`<div class="container">
<div class="legend"></legend>
</div>`;
const styles = html`<style>
.container {
position: relative;
}
.container .legend {
position: absolute;
right: 6px;
top: 6px;
background: rgba(255, 255, 255, 0.8);
padding: 6px 6px 2px;
}
</style>`;
container.append(styles);
container.querySelector(".legend").append(
legend({
color: colorScale,
title: "Ratio of deaths from COVID-19",
height: 45
})
);
const svg = d3
.select(container)
.append("svg")
.attr("viewBox", [0, 0, w, h]);
const g = svg
.append("g")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round");
g.append("g")
.attr("id", "nation-boundary")
.attr("stroke-width", 0.8)
.append("path")
.attr("d", path(topojson.mesh(us, us.objects.nation)))
.attr("fill", "#eee")
.attr("stroke", "#888");
if (features) {
g.append("g")
.attr("id", "counties-data")
.selectAll("path")
.data(features)
.join("path")
.attr("d", d => path(d))
.attr("fill", d => colorScale(d.properties.rate))
.on("click", (event, d) => {
container.value = `${d.properties.data[0].county_name}, ${d.properties.data[0].state}`;
container.dispatchEvent(new CustomEvent("input"));
})
.on("mouseover", ({ currentTarget }) => {
d3.select(currentTarget)
.attr("stroke", "yellow")
.attr("stroke-width", 2);
})
.on("mouseout", ({ currentTarget }) => {
d3.select(currentTarget)
.attr("stroke", "none")
.attr("stroke-width", 0);
});
}
g.append("g")
.attr("id", "county-boundaries")
.attr("stroke-width", 0.5)
.append("path")
.attr(
"d",
path(
topojson.mesh(
us,
us.objects.counties,
(a, b) => a !== b && ((a.id / 1000) | 0) === ((b.id / 1000) | 0)
)
)
)
.attr("fill", "none")
.attr("stroke", "#e2e2e2");
g.append("g")
.attr("id", "state-boundaries")
.attr("stroke-width", 0.7)
.append("path")
.attr("d", path(topojson.mesh(us, us.objects.states)))
.attr("fill", "none")
.attr("stroke", "#888");
svg
.append("rect")
.attr("width", w)
.attr("height", h)
.attr("fill", "none")
.attr("stroke", "#222")
.attr("stroke-width", 2);
function zoomed({ transform }) {
g.attr("transform", transform);
g.selectAll("g").attr("stroke-width", 1 / transform.k);
}
svg.call(zoom);
container.value = null;
return container;
}