Published
Edited
Oct 3, 2019
Importers
3 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function getTileMetric(tiles) {
// Store coordinates of the corners of the map
let [x1, y1, zoom] = d3.tileWrap(tiles[0]);
let [x2, y2] = d3.tileWrap(tiles[tiles.length - 1]);
// If straddling the antimeridian, force positive width
let nTiles = 2 ** zoom;
if (x2 < x1) x2 += nTiles;

return function(tile) {
let dz = zoom - tile.z;
// Convert tile x, y to the equivalent values at the MAP zoom level
let zoomFac = 2 ** dz;
let tb = Object({
x1: tile.x * zoomFac,
x2: (tile.x + 1) * zoomFac,
y1: tile.y * zoomFac,
y2: (tile.y + 1) * zoomFac
});

// Compute horizontal distances. Be careful with the antimeridian
let dx = Math.min(
// Test for non-intersection with tile in raw position
Math.max(x1 - tb.x2, tb.x1 - x2),
// Re-test with tile shifted across antimeridian
Math.max(x1 - (tb.x2 + nTiles), tb.x1 + nTiles - x2)
);
let dy = Math.max(y1 - tb.y2, tb.y1 - y2);

return Object({ dx, dy, dz });
};
}
Insert cell
hdist = getTileMetric(tileset)
Insert cell
Insert cell
function metric(tile) {
let dist = hdist(tile);
return Math.max(dist.dx, dist.dy) - 1.0 + 1.0 / 2 ** dist.dz;
}
Insert cell
Insert cell
numCachedTiles = cache.trim(metric, 2)
Insert cell
Insert cell
cache = tileRack.initRasterCache(cacheTileSize, (z, x, y) =>
tileSource.url(x, y, z)
)
Insert cell
mutable cacheTileSize = tileSource.realTileSize();
Insert cell
resolutionString = {
let mqString = `(resolution: ${devicePixelRatio}dppx)`;
matchMedia(mqString).addEventListener("change", () => {
mutable cacheTileSize = tileSource.realTileSize();
});
return mqString;
}
Insert cell
Insert cell
Insert cell
tiler = d3
.tile()
.tileSize(tileSource.cssTileSize())
.size([width, height])
.clampX(false) // Allow panning across longitude 180 degrees
Insert cell
tileset = tiler(transform)
Insert cell
projection = d3
.geoMercator()
.center([-122.4183, 37.7750])
.scale(Math.pow(2, 21) / (2 * Math.PI))
.translate([width / 2, height / 2])
Insert cell
mutable transform = d3.zoomIdentity
.translate(projection([0, 0])[0], projection([0, 0])[1])
.scale(projection.scale() * 2 * Math.PI)
Insert cell
Insert cell
zoom = d3
.zoom()
.scaleExtent([1 << 10, 1 << 26])
.extent([[0, 0], [width, height]])
.translateExtent([[-Infinity, -0.5], [Infinity, 0.5]])
.on("zoom", () => {
mutable transform = d3.event.transform;
})
Insert cell
d3
.select(mapContext.canvas)
.call(zoom)
.call(zoom.transform, mutable transform)
Insert cell
Insert cell
animate = {
while (true) yield drawTiles(mapContext);
}
Insert cell
//upate = {
// drawTiles(mapContext, tileset);
//}
Insert cell
//factory.element.addEventListener(
// "tileLoaded",
// () => drawTiles(mapContext, tileset),
// false
//)
Insert cell
Insert cell
Insert cell
import { drawTileBox } from "@jjhembd/zoomable-map-with-tile-cache"
Insert cell
Insert cell
function rescalePixels(cssTileSize) {
return devicePixelRatio > 1 ? 2 * cssTileSize : cssTileSize;
}
Insert cell
Insert cell
tileRack = import("tile-rack@0.2.0")
Insert cell
d3 = require("d3@5", "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