function interpolate(
data,
{
x = (d) => d[0],
y = (d) => d[1],
value = (d) => d[2],
width = data.width || 960,
height = data.height || 500,
border = false,
extrapolate = false
} = {}
) {
const P = d3.map(data, value);
const N = P.length;
const X = d3.map(data, x);
const Y = d3.map(data, y);
const I = d3.range(N).filter((i) => !isNaN(X[i]) && !isNaN(Y[i]));
const V = new Float32Array(width * height).fill(NaN);
const delaunay = d3.Delaunay.from(
I,
(i) => X[i],
(i) => Y[i]
);
const { points, triangles } = delaunay;
for (let i = 0; i < triangles.length; i += 3) {
const T = triangles.subarray(i, i + 3);
let [pa, pb, pc] = Array.from(T, (i) => P[I[i]]);
if (isNaN(pa) || isNaN(pb) || isNaN(pc)) continue;
const [Ax, Bx, Cx] = Array.from(T, (i) => points[2 * i]);
const [Ay, By, Cy] = Array.from(T, (i) => points[2 * i + 1]);
const [x0, x1] = d3.extent([Ax, Bx, Cx]);
const [y0, y1] = d3.extent([Ay, By, Cy]);
const z = (By - Cy) * (Ax - Cx) + (Ay - Cy) * (Cx - Bx);
if (!z) continue;
for (let x = Math.floor(x0); x < x1; x++) {
for (let y = Math.floor(y0); y < y1; y++) {
if (x < 0 || x >= width || y < 0 || y >= height) continue;
const ga = ((By - Cy) * (x - Cx) + (y - Cy) * (Cx - Bx)) / z;
if (ga < 0) continue;
const gb = ((Cy - Ay) * (x - Cx) + (y - Cy) * (Ax - Cx)) / z;
if (gb < 0) continue;
const gc = 1 - ga - gb;
if (gc < 0) continue;
V[x + width * y] = ga * pa + gb * pb + gc * pc;
}
}
}
V.height = height;
V.width = width;
return V;
}