Public
Edited
Jul 6, 2023
Insert cell
Insert cell
// https://tiles.mapgenie.io/games/diablo-4/sanctuary/default-v3/14/[8150-8169]/[8150-8169].jpg
Insert cell
tileParams14 = ({
zoom: 14,
tileCount: 20,
offset: 8150
})
Insert cell
tileParams15 = ({
zoom: 15,
tileCount: 20,
offset: 16300
})
Insert cell
tileParams = tileParams15;
Insert cell
tiles = {
const { zoom, tileCount, offset } = tileParams;
const tileIndexes = d3.cross(d3.range(0, tileCount), d3.range(0, tileCount));
const urls = tileIndexes.map(([x,y]) => `https://tiles.mapgenie.io/games/diablo-4/sanctuary/default-v3/${zoom}/${x+offset}/${y+offset}.jpg`);
const coords = tileIndexes.map(([x,y]) => [x, y, 1, 1].map(c => c * 256));
return d3.zip(urls, coords).map(([url, coords]) => ({ url, coords }))
}
Insert cell
{
const ctx = canvas.getContext("2d");
for (let tile of tiles) {
const img = await loadImage(tile.url);
ctx.drawImage(img, ...tile.coords);
}
}
Insert cell
{
const start = performance.now();
await Promises.delay(100 + Math.random() * 100);
return performance.now() - start;
}
Insert cell
async function loadImage(url) {
const img = document.createElement("img");
const promise = new Promise((resolve, reject) => {
img.onload = () => resolve(img);
img.onerror = (e) => reject(e);
});
img.src = url;
await Promise.all([promise, Promises.delay(100 + Math.random() * 100)]);
return img;
}
Insert cell
canvas = {
const canvas = DOM.canvas(256 * tileParams.tileCount, 256 * tileParams.tileCount);
canvas.style.maxWidth = "100%";
canvas.style.backgroundColor = "#ff00ff11";
return canvas;
}
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