chart = {
const width = 975;
const height = 610;
const minZoom = 1;
const maxZoom = 12;
let selected, abutting = [];
const zoom = d3.zoom()
.scaleExtent([minZoom, maxZoom])
.on("zoom", zoomed);
const svg = d3.create('svg')
.attr('viewBox', [0, 0, width, height]);
svg.on('click', reset);
const g = svg.append('g');
g.append('g')
.attr('class', 'map')
.attr('fill', '#444')
.attr('cursor', 'pointer')
.selectAll('path.county')
.data(counties.features)
.join('path')
.on('click', clicked)
.attr('d', path)
.attr('class', 'county')
.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 zoomed() {
const { transform } = d3.event;
g.attr("transform", transform);
g.attr("stroke-width", 1 / transform.k);
}
function reset() {
svg.transition().duration(750).call(
zoom.transform,
d3.zoomIdentity,
d3.zoomTransform(svg.node()).invert([width / 2, height / 2])
);
}
function clicked(d, i) {
selected = d;
abutting = neighbors[i].map(c => counties.features[c])
const [[x0, y0], [x1, y1]] = path.bounds({ type: 'FeatureCollection', features: abutting });
d3.event.stopPropagation();
svg.transition().duration(750).call(
zoom.transform,
d3.zoomIdentity
.translate(width / 2, height / 2)
.scale(Math.min(maxZoom, 0.9 / Math.max((x1 - x0) / width, (y1 - y0) / height)))
.translate(-(x0 + x1) / 2, -(y0 + y1) / 2),
d3.mouse(svg.node())
);
}
Object.assign(svg.node(), {
reset,
selected() { return selected; },
abutting() { return abutting; },
});
return svg.node()
}