Public
Edited
Oct 11, 2023
1 fork
8 stars
Insert cell
Insert cell
Insert cell
{
let width = 1000;
let height = 600;
let projection = d3.geoMercator();
let svg = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height]);

// Tiles
let url = (x, y, z) => `https://tile.openstreetmap.org/${z}/${x}/${y}.png`;
let tile = d3
.tile()
.size([width, height])
.scale(projection.scale() * 2 * Math.PI)
.translate(projection([0, 0]))
.tileSize(512)
.zoomDelta(2);

let layer = svg.append("g").attr("class", "mercatortiles");

layer
.selectAll("image")
.data(tile(), (d) => d)
.join("image")
.attr("xlink:href", (d) => url(...d))
.attr("x", ([x]) => (x + tile().translate[0]) * tile().scale)
.attr("y", ([, y]) => (y + tile().translate[1]) * tile().scale)
.attr("width", tile().scale)
.attr("height", tile().scale);

// Path
svg
.append("path")
.datum(world)
.attr("d", d3.geoPath(projection))
.attr("fill", "none")
.attr("stroke", "black");

const baseScale = projection.scale();
const baseTranslate = projection.translate();

function zoom({ transform }) {
// Adapt projection
projection
.scale(transform.k * baseScale)
.translate([
baseTranslate[0] * transform.k + transform.x,
baseTranslate[1] * transform.k + transform.y
]);

const path = d3.geoPath(projection);
svg.selectAll("path").attr("d", path);

tile = d3
.tile()
.size([width, height])
.scale(projection.scale() * 2 * Math.PI)
.translate(projection([0, 0]))
.tileSize(512)
.zoomDelta(2);

svg
.select(".mercatortiles")
.selectAll("image")
.data(tile(), (d) => d)
.join("image")
.attr("xlink:href", (d) => url(...d))
.attr("x", ([x]) => (x + tile().translate[0]) * tile().scale)
.attr("y", ([, y]) => (y + tile().translate[1]) * tile().scale)
.attr("width", tile().scale)
.attr("height", tile().scale);
}

svg.call(
d3
.zoom()
.extent([
[0, 0],
[width, height]
])
.scaleExtent([1, 20])
.on("zoom", zoom)
);

return svg.node();
}
Insert cell
world = FileAttachment("world.json").json()
Insert cell
d3 = require("d3@7", "d3-tile@1")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more