JSFiddle - React, Tailwind, and code Playground
HTML
<script src="//d3js.org/d3.v4.min.js"></script>
<script src="//d3js.org/d3-tile.v0.0.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<!DOCTYPE html>
<meta charset="utf-8">
<svg></svg>
CSS
body {
margin: 0;
}
path {
fill: none;
stroke: red;
stroke-linejoin: round;
}
JavaScript
var pi = Math.PI,
tau = 2 * pi;
var width = Math.max(960, window.innerWidth),
height = Math.max(500, window.innerHeight),
active = d3.select(null);
// Initialize the projection to fit the world in a 1Ă—1 square centered at the origin.
var projection = d3.geoMercator()
.scale(1 / tau)
.translate([0, 0]);
var path = d3.geoPath()
.projection(projection);
var tile = d3.tile()
.size([width, height]);
var zoom = d3.zoom()
.scaleExtent([1 << 11, 1 << 14])
.on("zoom", zoomed);
var svg = d3.select("svg")
.attr("width", width)
.attr("height", height);
var raster = svg.append("g");
var vector = svg.append("g").attr("id", "vector");
d3.json("https://mbostock.github.io/d3/talk/20111018/world-countries.json", function(collection) {
vector.selectAll("path")
.data(collection.features)
.enter().append("path")
.style("fill", "white")
.style("fill-opacity", 0.5)
.attr("d", path).on("click", clicked);
// Compute the projected initial center.
var center = projection([-98.5, 39.5]);
// Apply a zoom transform equivalent to projection.{scale,translate,center}.
svg
.call(zoom)
.call(zoom.transform, d3.zoomIdentity
.translate(width / 2, height / 2)
.scale(1 << 12)
.translate(-center[0], -center[1]));
function clicked(d) {
console.log("triggered");
if (active.node() === this) return reset();
active.classed("active", false);
active = d3.select(this).classed("active", true);
var bounds = path.bounds(d),
dx = bounds[1][0] - bounds[0][0],
dy = bounds[1][1] - bounds[0][1],
x = (bounds[0][0] + bounds[1][0]) / 2,
y = (bounds[0][1] + bounds[1][1]) / 2,
scale = 0.9 / Math.max(dx / width, dy / height);
scale = Math.min(1 << 14, scale);
var translate = [width / 2 - scale * x, height / 2 - scale * y];
console.log(bounds);
svg.transition()
.duration(2000)
//...