Public
Edited
Feb 18, 2023
Insert cell
Insert cell
Insert cell
coastlines = {
const context = DOM.context2d(width, height);
context.clearRect(0, 0, width, height);
let colors = d3.schemeSpectral[11];
let scale = d3.scaleQuantize()
.domain([0, 1])
.range(palette)

let { corners, triangles } = geometry.voronoi.delaunay;
let n_tri = geometry.n_tri;

let center_x = width / 2;
let center_y = height / 2;

let dist_factor = 0.5 * Math.sqrt( (width * width) + (height * height));

let peaks = [];
let seen = [];
for (let i = 0; i < geometry.n_cells; i++) {
let polygon = geometry.voronoi.cellPolygon(i);
let x = polygon[0][0];
let y = polygon[0][1];

let comb_value = geometry.cell_noise_values[i];
if (comb_value <= params.waterline) {
context.fillStyle = scale(0.2);
} else if (comb_value <= geometry.cell_noise_max * 0.99) {
context.fillStyle = scale(comb_value);
} else {
peaks.push(i);
seen.push(i);
context.fillStyle = scale(0.8);
}
context.beginPath();
geometry.voronoi.renderCell(i,context);
context.fill()
}

var to_visit = [peaks[0]];
while (true) {
if (to_visit.length <= 0) {
break;
}
var next_gen = []
for (let i of to_visit) {
let edges = Array.from(pairwise(geometry.voronoi.cellPolygon(i)));
for (let j of geometry.voronoi.neighbors(i)) {
if (geometry.cell_noise_values[j] <= params.waterline) {

let neighbor_edges = Array.from(pairwise(geometry.voronoi.cellPolygon(j)));
for (const my_edge of edges) {
for (const neighbor_edge of neighbor_edges) {
if (_.isEqual(my_edge, neighbor_edge) ||
_.isEqual(my_edge, neighbor_edge.slice().reverse())) {

// console.log("found edge!",my_edge);
context.beginPath();
context.strokeStyle = "black";
context.lineWidth = 2;
context.moveTo(my_edge[0][0],my_edge[0][1]);
context.lineTo(my_edge[1][0],my_edge[1][1]);
context.stroke();
}
}
}
} else {
if (!seen.includes(j) && !next_gen.includes(j)) {
next_gen.push(j);
}
}
seen.push(j);
}
for (const edge of edges) {
if ( (edge[0][0] === 0.0 && edge[1][0] === 0.0)
||(edge[0][1] === 0.0 && edge[1][1] === 0.0)
||(edge[0][0] === width && edge[1][0] === width)
||(edge[0][1] === height && edge[1][1] == height)
) {
console.log("found boundary!",edge);
context.beginPath();
context.strokeStyle = "black";
context.lineWidth = 6;
context.moveTo(edge[0][0],edge[0][1]);
context.lineTo(edge[1][0],edge[1][1]);
context.stroke();
}
}

if (peaks.includes(i)) {
context.fillStyle = scale(0.8);
}
}
// console.log("queued up:", next_gen);
to_visit = next_gen;
}

return context.canvas;
}

Insert cell
Insert cell
Insert cell
Insert cell
peaks = {
const context = DOM.context2d(width, height);
context.clearRect(0, 0, width, height);
let colors = d3.schemeSpectral[11];
let scale = d3.scaleQuantize()
.domain([0, 1])
.range(palette)

let { corners, triangles } = geometry.voronoi.delaunay;
let n_tri = triangles.length / 3;

let center_x = width / 2;
let center_y = height / 2;

let dist_factor = 0.5 * Math.sqrt( (width * width) + (height * height));

for (let i = 0; i < n_tri; i++) {
let polygon = geometry.voronoi.delaunay.trianglePolygon(i);
let x = polygon[0][0];
let y = polygon[0][1];
let comb_value = geometry.noise_values[i];

if (comb_value <= params.waterline) {
context.fillStyle = scale(0.2);
} else if (comb_value < geometry.noise_max * 0.85) {
context.fillStyle = "orange";
} else {
context.fillStyle = "red";
}
context.beginPath();
geometry.voronoi.delaunay.renderTriangle(i,context);
context.fill()
}
return context.canvas;
}
Insert cell
geometry = {
let points = new FastPoissonDiskSampling({
shape: [width, height],
radius: 10,
tries: 1
});
let voronoi = new d3.Delaunay(points.fill().flat()).voronoi([0, 0, width, height]);

let { corners, triangles } = voronoi.delaunay;
let n_tri = triangles.length / 3;

let center_x = width / 2;
let center_y = height / 2;

let dist_factor = 0.5 * Math.sqrt( (width * width) + (height * height));

//
let noise_values = [];

var max = 0.0;
for (let i = 0; i < n_tri; i++) {
let polygon = voronoi.delaunay.trianglePolygon(i);
let x = polygon[0][0];
let y = polygon[0][1];
let noise_value = (perlin3(x / (1.5 * params.noise_scale), y / params.noise_scale, params.t / params.speed));
let noise_value_2 = (perlin3(x / (0.3 * params.noise_scale), y / (0.2 * params.noise_scale), params.t / params.speed));

let dist = Math.sqrt( (x - center_x) * (x - center_x) + (y - center_y) * (y - center_y) );
let dist_value = 1 - (dist / dist_factor);

let cos_dist = Math.cos(dist * Math.PI * params.cos_scale / dist_factor);

let n_cos_dist = cos_dist > 0 ? cos_dist : 0.0;

let n_val = noise_value > 0 ? noise_value : 0.0;
let n_val_2 = noise_value_2 > 0 ? noise_value_2 : 0.0;

let comb_value = n_cos_dist * params.cos_gain + (n_val * 0.7 + n_val_2 * 0.4) * params.noise_gain * n_cos_dist;

if (comb_value > max) { max = comb_value; }

noise_values[i] = comb_value;
}

var cell_max = 0;
var cell_noise_values = [];

let cell_arr = Array.from(voronoi.cellPolygons());

let n_cells = cell_arr.length;
for (let i = 0; i < n_cells; i++) {
let polygon = voronoi.cellPolygon(i);
let x = polygon[0][0];
let y = polygon[0][1];

let noise_value = (perlin3(x / (1.5 * params.noise_scale), y / params.noise_scale, params.t / params.speed));
let noise_value_2 = (perlin3(x / (0.3 * params.noise_scale), y / (0.2 * params.noise_scale), params.t / params.speed));

let dist = Math.sqrt( (x - center_x) * (x - center_x) + (y - center_y) * (y - center_y) );
let dist_value = 1 - (dist / dist_factor);

let cos_dist = Math.cos(dist * Math.PI * params.cos_scale / dist_factor);

let n_cos_dist = cos_dist > 0 ? cos_dist : 0.0;

let n_val = noise_value > 0 ? noise_value : 0.0;
let n_val_2 = noise_value_2 > 0 ? noise_value_2 : 0.0;

let comb_value = n_cos_dist * params.cos_gain + (n_val * 0.7 + n_val_2 * 0.4) * params.noise_gain * n_cos_dist;

if (comb_value > cell_max) { cell_max = comb_value; }

cell_noise_values[i] = comb_value;
}

return {
n_tri: n_tri,
n_cells: n_cells,
points: points,
voronoi: voronoi,
noise_values: noise_values,
noise_max: max,
cell_noise_values: cell_noise_values,
cell_noise_max: cell_max
}
}
Insert cell
noise_canvas = {
const context = DOM.context2d(width, height, 1);
context.clearRect(0, 0, width, height);

const image = context.createImageData(width, height);

let center_x = width / 2;
let center_y = height / 2;

for (let z = 0, y = 0, i = 0; y < height; ++y) {
for (let x = 0; x < width; ++x, i += 4) {
let noise_value = (perlin2(x / 64, y / 64) + 1);
let dist_value = Math.sqrt( (x - center_x) * (x - center_x) + (y - center_y) * (y - center_y) );
let cos_value = Math.cos(x * Math.PI / width, y * Math.PI / height ) * 64;
image.data[i + 3] = dist_value * 0.5 + noise_value * 64;
}
}

context.putImageData(image, 0, 0);
return context.canvas;
}
Insert cell
{
const height = 600;
const context = DOM.context2d(width, height, 1);
const image = context.createImageData(width, height);
const noise = octave(perlin2, 3);
for (let z = 0, y = 0, i = 0; y < height; ++y) {
for (let x = 0; x < width; ++x, i += 4) {
image.data[i + 3] = (noise(x / 64, y / 64) + 1) * 128;
}
}
context.putImageData(image, 0, 0);
return context.canvas;
}
Insert cell
function * pairwise (iterable) {
const iterator = iterable[Symbol.iterator]()
let current = iterator.next()
let next = iterator.next()
while (!next.done) {
yield [current.value, next.value]
current = next
next = iterator.next()
}
}

Insert cell
function octave(noise, octaves) {
return function(x, y, z) {
let total = 0;
let frequency = 1;
let amplitude = 1;
let value = 0;
for (let i = 0; i < octaves; ++i) {
value += noise(x * frequency, y * frequency, z * frequency) * amplitude;
total += amplitude;
amplitude *= 0.5;
frequency *= 2;
}
return value / total;
};
}
Insert cell
function perlin3(x, y, z) {
const xi = Math.floor(x), yi = Math.floor(y), zi = Math.floor(z);
const X = xi & 255, Y = yi & 255, Z = zi & 255;
const u = fade(x -= xi), v = fade(y -= yi), w = fade(z -= zi);
const A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z;
const B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z;
return lerp(
w,
lerp(
v,
lerp(u, grad3(p[AA], x, y, z), grad3(p[BA], x - 1, y, z)),
lerp(u, grad3(p[AB], x, y - 1, z), grad3(p[BB], x - 1, y - 1, z))
),
lerp(
v,
lerp(u, grad3(p[AA + 1], x, y, z - 1), grad3(p[BA + 1], x - 1, y, z - 1)),
lerp(u, grad3(p[AB + 1], x, y - 1, z - 1), grad3(p[BB + 1], x - 1, y - 1, z - 1))
)
);
}
Insert cell
function perlin2(x, y) {
const xi = Math.floor(x), yi = Math.floor(y);
const X = xi & 255, Y = yi & 255;
const u = fade(x -= xi), v = fade(y -= yi);
const A = p[X] + Y, B = p[X + 1] + Y;
return lerp(
v,
lerp(u, grad2(p[A], x, y), grad2(p[B], x - 1, y)),
lerp(u, grad2(p[A + 1], x, y - 1), grad2(p[B + 1], x - 1, y - 1))
);
}
Insert cell
function grad3(i, x, y, z) {
const h = i & 15;
const u = h < 8 ? x : y;
const v = h < 4 ? y : h === 12 || h === 14 ? x : z;
return (h & 1 ? -u : u) + (h & 2 ? -v : v);
}
Insert cell
function grad2(i, x, y) {
const v = i & 1 ? y : x;
return i & 2 ? -v : v;
}
Insert cell
function fade(t) {
return t * t * t * (t * (t * 6 - 15) + 10);
}
Insert cell
function lerp(t, a, b) {
return a + t * (b - a);
}
Insert cell
// const P = new Uint8Array(256);
// for (let i = 0; i < 256; ++i) P[i] = i;
// d3.shuffle(P);
P = Uint8Array.of(151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180)
Insert cell
p = {
const p = new Uint8Array(512);
for (let i = 0; i < 256; ++i) p[i] = p[i + 256] = P[i];
return p;
}
Insert cell
height = 1000
Insert cell
Insert cell
Insert cell
_ = require("lodash")
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