Public
Edited
Feb 11, 2024
1 fork
12 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import { canvas } with { image } from "@fil/polyconic-glsl" // "@fil/satellite-glsl";
Insert cell
sdf = {
const edt = spherical ? sphedt1d : edt1d;

const grid = Float64Array.from(originalGrid.ocean);

for (let x = 0; x < width; x++) {
// transform each column
edt(height)(grid, x, width, 1);
}
for (let y = 0; y < height; y++) {
// transform each row, scaled by latitude
const f = Math.sin(((y + 0.5) / height) * Math.PI) ** 2;
edt(width)(grid, y * width, 1, f);
}

// apply sign
for (let i = 0, n = width * height; i < n; i++)
grid[i] = Math.sqrt(grid[i]) * (originalGrid.sign[i] * 2 - 1);

return grid;
}
Insert cell
// spherical version
sphedt1d = (l) => {
const l3 = l * 3;
const v = new Uint16Array(l3);
const f = new Float64Array(l3);
const z = new Float64Array(l3 + 1);
let i;
return (grid, offset, stride, factor) => {
v[0] = 0;
z[0] = -INF;
z[1] = INF;
for (let q = 0; q < l3; q++) {
if (stride === 1) {
// longitudes: repeat 3 times, consider the middle, scaled by the parallel’s length
i = offset + (q % l);
f[q] = grid[i] / factor;
} else {
// latitudes
// repeat with a rotation of (180, 0, 180)
const q0 = q % l;
const panel = Math.floor(q / l);
if (panel === 1) {
i = offset + q0 * stride;
} else {
i = l - 1 - ((offset + (l >> 1)) % l) + (l - 1 - q0) * stride;
}
f[q] = grid[i];
}
}

for (let q = 1, k = 0, s = 0; q < l3; q++) {
do {
const r = v[k];
s = (f[q] - f[r] + q * q - r * r) / (q - r) / 2;
} while (s <= z[k--]);

k += 2;
v[k] = q;
z[k] = s;
z[k + 1] = INF;
}

for (let q = 0, k = 0; q < l3; q++) {
while (z[k + 1] < q) k++;
const r = v[k];
if (q >= l && q < l * 2)
grid[offset + (q - l) * stride] = factor * (f[r] + (q - r) * (q - r));
}
};
}
Insert cell
Insert cell
originalGrid
Insert cell
d3.extent(originalGrid.ocean)
Insert cell
d3.extent(originalGrid.sign)
Insert cell
viewof originalGrid = {
const N = width * height;
const ocean = new Float64Array(N);
const sign = new Uint8Array(N);

const context = DOM.context2d(width, height, 1);
const path = d3.geoPath(projection, context);

context.fillStyle = "rgb(120, 170, 0)";

context.beginPath();
path(land);

context.stroke(); // stroke gives the border
{
const { data } = context.getImageData(0, 0, width, height);
for (let i = 0; i < N; i++) ocean[i] = data[(i << 2) + 3] > 100 ? 0 : INF;
}

context.fill(); // fill gives the sign (interior/exterior)
{
const { data } = context.getImageData(0, 0, width, height);
for (let i = 0; i < N; i++) sign[i] = data[(i << 2) + 1] > 90;
}

const value = { ocean, sign };
return Object.assign(context.canvas, { value, style: "max-width: 100%" });
}
Insert cell
import { schemes } from "@fil/colormaps"
Insert cell
interpolateOleron = d3.scaleSequential((t) => schemes.oleron[(t * 255) | 0])
Insert cell
import { heatmap } from "@fil/heatmap"
Insert cell
INF = 10000000000
Insert cell
width = 1200
Insert cell
height = width / 2
Insert cell
land = d3.json(
`https://unpkg.com/visionscarto-world-atlas@0.0.6/world/${source}_land.geojson`
)
Insert cell
projection = d3.geoEquirectangular().fitExtent(
[
[0, 0],
[width, height]
],
{ type: "Sphere" }
)
Insert cell
d3 = require("d3@7", "d3-geo-projection@4")
Insert cell
// for reference, the original algo
edt1d = (length) => {
const v = new Uint16Array(length);
const z = new Float64Array(length + 1);
const f = new Float64Array(length);
return (grid, offset, stride) => {
v[0] = 0;
z[0] = -INF;
z[1] = INF;
for (let q = 0; q < length; q++) f[q] = grid[offset + q * stride];

for (let q = 1, k = 0, s = 0; q < length; q++) {
do {
const r = v[k];
s = (f[q] - f[r] + q * q - r * r) / (q - r) / 2;
} while (s <= z[k--]);

k += 2;
v[k] = q;
z[k] = s;
z[k + 1] = INF;
}

for (let q = 0, k = 0; q < length; q++) {
while (z[k + 1] < q) k++;
const r = v[k];
grid[offset + q * stride] = f[r] + (q - r) * (q - r);
}
};
}
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