chart = {
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, 960, 600])
.style("background-color", "#efeeed");
const dateLabel = svg
.append("text")
.attr("x", 960 / 2)
.attr("y", 30)
.attr("text-anchor", "middle")
.attr("font-size", 32)
.attr("font-weight", "bold")
.attr("font-family", "Inter");
svg
.append("path")
.datum(topojson.merge(us, us.objects.states.geometries))
.attr("fill", "#ddd")
.attr("d", d3.geoPath());
svg
.append("path")
.datum(topojson.mesh(us, us.objects.states, (a, b) => a !== b))
.attr("fill", "none")
.attr("stroke", "white")
.attr("stroke-linejoin", "round")
.attr("d", d3.geoPath());
const rivers = svg
.selectAll("path.river")
.data(us_rivers.features)
.join("path")
.classed("river", true)
.attr("d", d3.geoPath(projection))
.attr("fill", "none")
.attr("stroke", "#ccc")
.attr("stroke-width", 0.5);
const g = svg.append("g").attr("fill", "#c60101").attr("stroke", "none");
const dot = g
.selectAll("circle")
.data(data, (d, i) => {
return i;
})
.join("circle")
.attr("transform", (d) => `translate(${d})`)
.attr("r", 2.5)
.attr("opacity", 0)
.attr("stroke", "white")
.attr("stroke-width", 0.25);
let previousDate = -Infinity;
return Object.assign(svg.node(), {
update(date) {
dot
.filter((d) => d.date > previousDate && d.date <= date)
.transition()
.duration(3000)
.attr("r", (d) => circleSizeScale(d.properties[circleSizeKey]))
.attr("opacity", 0.82);
dot
.filter((d) => d.date <= previousDate && d.date > date)
.transition()
.attr("r", 2.5)
.attr("opacity", 0);
previousDate = date;
dateLabel.text(d3.utcFormat("%Y")(date));
}
});
}