function* mapfillContours(
valuePoint,
projection,
{
debug = false,
land = {},
graticule = {},
N = 5000,
thresholds = 40,
color: fill = color
} = {}
) {
const time = performance.now();
const height = width / 2.3;
const context = DOM.context2d(width, height);
const path = d3
.geoPath(
projection.fitExtent(
[
[2, 2],
[width - 2, height - 2]
],
{
type: "Sphere"
}
)
)
.context(context);
const phi = (1 + Math.sqrt(5)) / 2,
fibonacci = (i, N) => [i / phi, (i + 0.5) / N],
points = Array.from({ length: N }, (_, i) => {
const [x, y] = fibonacci(i, N);
return [(x * 360) % 360, (Math.acos(2 * y - 1) / Math.PI) * 180 - 90];
});
context.beginPath();
path({ type: "Sphere" });
context.fill();
context.stroke();
context.clip();
yield context.canvas;
const v = d3.geoVoronoi(points);
const contours = d3
.tricontour()
.thresholds(thresholds)
.triangulate(() => v.delaunay.delaunay)
.pointInterpolate((i, j, a) => d3.geoInterpolate(points[i], points[j])(a))
.value(valuePoint)
.ringsort((rings) => [rings]);
let first = true;
for (const c of contours.isobands(points)) {
if (first) {
first = false;
context.beginPath();
path({ type: "Sphere" });
context.fillStyle = fill(c.value);
context.fill();
}
rearrange(c.coordinates);
context.beginPath();
path(c);
context.strokeStyle = context.fillStyle = fill((c.value + c.valueMax) / 2);
context.fill();
context.stroke();
}
draw();
function draw() {
context.beginPath();
path(land);
path(graticule);
context.strokeStyle = "#333";
context.stroke();
context.beginPath();
path({ type: "Sphere" });
context.strokeStyle = "#333";
context.lineWidth = 1;
context.stroke();
context.fillStyle = "white";
if (debug) context.fillText((performance.now() - time) | 0, 10, 10);
}
}