Public
Edited
Jul 28, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
async function map({center, zoom = 20, zoomDelta = 0, visibility}) {
const projection = d3.geoMercator()
.center(center)
.scale(Math.pow(2, zoom) / (2 * Math.PI))
.translate([width / 2, height / 2]);

const path = d3.geoPath(projection);

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

const root = svg`<svg viewBox="0 0 ${width} ${height}" style="background: white;">`;

new Promise(resolve => requestIdleCallback(resolve))
.then(visibility)
.then(() => Promise.all(tile().map(async ([x, y, z]) => {
const {roads} = await (await fetch(`https://tile.nextzen.org/tilezen/vector/v1/512/all/${z}/${x}/${y}.json?api_key=${nextzen_key}`)).json();
root.appendChild(svg`<path fill="none" stroke="#000" stroke-width="0.75" d="${path(roads)}">`);
})));

return root;
}
Insert cell
function geocode(query) {
return fetch(`https://api.tiles.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent(query)}.json?access_token=${mapbox_key}`)
.then(response => response.json())
.then(geocoding => geocoding.features[0].center);
}
Insert cell
requestIdleCallback = window.requestIdleCallback || (callback => { Promises.delay(150).then(callback); })
Insert cell
// https://www.nextzen.org
nextzen_key = "jdPwBXkWSB-v5_CPQYDiIQ"
Insert cell
// https://www.mapbox.com/help/how-access-tokens-work/
mapbox_key = "pk.eyJ1IjoibWJvc3RvY2siLCJhIjoiY2s5ZWRqb2w1MDBnYjNmbzcxb2xxaGZjeSJ9.ZOeAUq-8dsbN7zqgG7vkdQ"
Insert cell
width = 954
Insert cell
height = width
Insert cell
d3 = require("d3-geo@1", "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