map = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
const projection = d3
.geoMercator()
.scale(1 / (2 * Math.PI))
.translate([0, 0]);
const render = d3.geoPath(projection);
const tile = d3
.tile()
.extent([[0, 0], [width, height]])
.tileSize(512);
const zoom = d3
.zoom()
.scaleExtent([1 << 10, 1 << 150])
.extent([[0, 0], [width, height]])
.on("zoom", ({ transform }) => zoomed(transform));
let image = svg
.append("g")
.attr("pointer-events", "none")
.selectAll("image");
const geoGenerator = d3.geoPath().projection(projection);
const path = svg
.append("g")
.selectAll("path")
.data(data)
.join("path")
.style("fill", d => "none")
.style("stroke", "red");
svg.call(zoom).call(
zoom.transform,
d3.zoomIdentity
.translate(width / 2, height / 2)
.scale(-initialScale)
.translate(...projection(initialCenter))
.scale(-1)
);
function zoomed(transform) {
const tiles = tile(transform);
image = image
.data(tiles, d => d)
.join("image")
.attr("xlink:href", d => url(...d))
.attr("x", ([x]) => (x + tiles.translate[0]) * tiles.scale)
.attr("y", ([, y]) => (y + tiles.translate[1]) * tiles.scale)
.attr("width", tiles.scale)
.attr("height", tiles.scale);
projection
.scale(transform.k / (2 * Math.PI))
.translate([transform.x, transform.y]);
path.attr("d", d =>
geoGenerator({
type: "Feature",
geometry: {
type: "LineString",
coordinates: [
[d.source_lon, d.source_lat],
[d.target_lon, d.target_lat]
]
}
})
);
}
return svg.node();
}