getVisibleTiles = function(projection, zoom) {
function getVisibleChildren(x, y, z) {
console.log(x, y, z);
let visible = false;
let stream = projection.stream({
point: () => { visible = true; },
lineStart: () => {},
lineEnd: () => {},
polygonStart: () => {},
polygonEnd: () => {}
});
const extent = mercator.clipExtent();
const size = (extent[1][0] - extent[0][0]) / (2 ** z);
const epsilon = 0.001;
const x0 = x * size + epsilon,
y0 = y * size + epsilon,
x1 = (x + 1) * size - epsilon,
y1 = (y + 1) * size - epsilon;
const step = Math.min(size, 1);
const tile = {
type: "Polygon",
coordinates: [
[]
// Interpolate along each of the four edges of the Mercator polygon. This is a rather
// crude way to do interpolation (with a constant step size) but it's easier than the
// adaptive resampling that d3 does natively, which is not available to us here since
// we're not using a projection.
.concat(d3.range(x0, x1 + step / 2, +step).map(x => [x, y0]))
.concat(d3.range(y0, y1 + step / 2, +step).map(y => [x1, y]))
.concat(d3.range(x1, x0 - step / 2, -step).map(x => [x, y1]))
.concat(d3.range(y1, y0 - step / 2, -step).map(y => [x0, y]))
// convert this mercator polygon to a spherical polygon on the Earth
.map(point => mercator.invert(point))
],
};
// Project the spherical polygon representing the tile by feeding it through the stream.
d3.geoStream(tile, stream);
// If any point in the tile was visible in the output projection, then our stream will have
// received that point via its `point` method and set `visible = true`.
if (visible) {
if (z < zoom) {
// if we're not yet at the desired zoom level, recurse on each of the four sub-tiles
let visibleChildren = []
.concat(getVisibleChildren(2 * x, 2 * y, z + 1)) // upper left
.concat(getVisibleChildren(2 * x + 1, 2 * y, z + 1)) // upper right
.concat(getVisibleChildren(2 * x, 2 * y + 1, z + 1)) // lower left
.concat(getVisibleChildren(2 * x + 1, 2 * y + 1, z + 1)) // lower right
return visibleChildren;
} else {
return [tile]; // this tile is visible and is of the desired zoom level
}
} else {
return []; // this tile is not visible
}
}
return getVisibleChildren(0, 0, 0);
}