chart = {
const width = 975;
const height = 610;
const zoom = d3
.zoom()
.scaleExtent([1, 8])
.on("zoom", zoomed);
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.on("click", reset);
const g = svg.append("g");
const states = g
.append("g")
.attr("cursor", "pointer")
.selectAll("path")
.data(topojson.feature(us, us.objects.states).features)
.join("path")
.attr("fill", "#444")
.on("click", clicked)
.attr("d", path)
.call(states => states.append("title").text(d => d.properties.name));
g.append("path")
.attr("fill", "none")
.attr("stroke", "white")
.attr("stroke-linejoin", "round")
.attr("d", path(topojson.mesh(us, us.objects.states, (a, b) => a !== b)));
svg.call(zoom);
function reset() {
svg
.transition()
.duration(750)
.call(
zoom.transform,
d3.zoomIdentity,
d3.zoomTransform(svg.node()).invert([width / 2, height / 2])
);
clearPrev();
}
function clicked(d) {
const [[x0, y0], [x1, y1]] = path.bounds(d);
d3.event.stopPropagation();
clearPrev();
mutable selected = this;
d3.select(this)
.transition()
.duration(500)
.attr("fill", "#74917D");
svg
.transition()
.duration(750)
.call(
zoom.transform,
d3.zoomIdentity
.translate(width / 2, height / 2)
.scale(
Math.min(8, 0.9 / Math.max((x1 - x0) / width, (y1 - y0) / height))
)
.translate(-(x0 + x1) / 2, -(y0 + y1) / 2),
d3.mouse(svg.node())
);
}
function zoomed() {
const { transform } = d3.event;
g.attr("transform", transform);
g.attr("stroke-width", 1 / transform.k);
}
function clearPrev() {
if (mutable selected !== null) {
d3.select(mutable selected)
.transition()
.duration(500)
.attr("fill", "#444");
}
mutable selected = null;
}
return svg.node();
}