Published
Edited
Oct 4, 2019
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
url = (z, x, y, t) =>
endpoint
.replace(/{Time}/, t)
.replace(/{TileMatrixSet}/, "GoogleMapsCompatible_Level9")
.replace(/{TileMatrix}/, z)
.replace(/{TileRow}/, y)
.replace(/{TileCol}/, x)
Insert cell
cache = tileRack.initRasterCache(tileSize, url) // Use tileRack's default raster tile factory
Insert cell
Insert cell
Insert cell
function dayDifference(dashString) {
let test = new Date(dashString);
let base = new Date(dashFormat(selectedDate.date));
return base < test
? d3.timeDay.count(base, test)
: d3.timeDay.count(test, base);
}
Insert cell
Insert cell
hdist = getTileMetric(tileset)
Insert cell
function metric(tile) {
let deltas = hdist(tile);
let dzFac = -1.0 + 1.0 / 2 ** deltas.dz;
return Math.max(deltas.dx, deltas.dy) + dzFac + dayDifference(tile.t);
}
Insert cell
numCachedTiles = cache.trim(metric, 1.5)
Insert cell
Insert cell
function drawTiles(ctx) {
ctx.clearRect(0, 0, width, mapHeight);

// Get the current and neighboring times
let current = dashFormat(selectedDate.date);
let prev = dashFormat(d3.timeDay.offset(selectedDate.date, -1));
let next = dashFormat(d3.timeDay.offset(selectedDate.date, 1));

for (const [x, y, z] of tileset) {
const [xw, yw, zw] = d3.tileWrap([x, y, z]);

// Get tile for selected date, and draw it if available
let tileBox = cache.retrieve([zw, xw, yw, current]);
let tx = tileset.translate[0];
let ty = tileset.translate[1];
if (tileBox) drawTileBox(ctx, tileBox, x + tx, y + ty, tileset.scale);

// Pre-load tiles for adjacent dates
cache.retrieve([zw, xw, yw, prev]);
cache.retrieve([zw, xw, yw, next]);
}
}
Insert cell
animate = {
while (true) yield drawTiles(mapContext);
}
Insert cell
Insert cell
Insert cell
tiler = d3
.tile()
.tileSize(tileSize)
.size([width, mapHeight])
.clampX(false) // Allow panning across longitude 180 degrees
Insert cell
tileset = tiler(transform)
Insert cell
projection = d3
.geoMercator()
.center([-77, 26.5])
.scale(Math.pow(2, 13) / (2 * Math.PI))
.translate([width / 2, mapHeight / 2])
Insert cell
mutable transform = d3.zoomIdentity
.translate(projection([0, 0])[0], projection([0, 0])[1])
.scale(projection.scale() * 2 * Math.PI)
Insert cell
zoom = d3
.zoom()
.scaleExtent([1 << 10, 1 << 17])
.extent([[0, 0], [width, mapHeight]])
.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
Insert cell
Insert cell
Insert cell
Insert cell
dashFormat = d3.timeFormat("%Y-%m-%d")
Insert cell
axisStyle // Importing it doesn't activate it?
Insert cell
Insert cell
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