Published
Edited
Apr 22, 2019
Insert cell
Insert cell
Insert cell
animation = {
const fills = new Array(cellWidth * cellHeight);
const width = cellWidth * (cellSize + cellSpacing) + cellSpacing;
const height = cellHeight * (cellSize + cellSpacing) + cellSpacing;
const context = DOM.context2d(width, height);
// context.canvas.style.imageRendering = "pixelated";
context.fillStyle = "#fff";
context.fillRect(0, 0, width, height);
context.fillStyle = "#fff";
fillCells(context);
for (let n, l = 0, frontier = [0]; n = frontier.length; ++l) {
let frontier1 = [];
context.fillStyle = sinebow(l / 2000);
for (let i = 0, i0, i1; i < n; ++i) {
fillCell(context, i0 = frontier[i]);
if (cells[i0] & E && !fills[i1 = i0 + 1]) fillEast(context, i0), fills[i1] = frontier1.push(i1);
if (cells[i0] & W && !fills[i1 = i0 - 1]) fillEast(context, i1), fills[i1] = frontier1.push(i1);
if (cells[i0] & S && !fills[i1 = i0 + cellWidth]) fillSouth(context, i0), fills[i1] = frontier1.push(i1);
if (cells[i0] & N && !fills[i1 = i0 - cellWidth]) fillSouth(context, i1), fills[i1] = frontier1.push(i1);
}
frontier = frontier1;
yield context.canvas;
}
}
Insert cell
function generate(cellWidth, cellHeight) {
const heap = new Queue();
const cells = new Uint8Array(cellWidth * cellHeight);
let edge;
heap.push({index: 0, direction: N}, Math.random());
heap.push({index: 0, direction: E}, Math.random());
while (edge = heap.pop()) {
let i0 = edge.index, i1;
let d0 = edge.direction, d1;
let x0 = i0 % cellWidth, x1;
let y0 = i0 / cellWidth | 0, y1;
if (d0 === N) i1 = i0 - cellWidth, x1 = x0, y1 = y0 - 1, d1 = S;
else if (d0 === S) i1 = i0 + cellWidth, x1 = x0, y1 = y0 + 1, d1 = N;
else if (d0 === W) i1 = i0 - 1, x1 = x0 - 1, y1 = y0, d1 = E;
else i1 = i0 + 1, x1 = x0 + 1, y1 = y0, d1 = W;
if (cells[i1] === 0) {
cells[i0] |= d0, cells[i1] |= d1;
if (y1 > 0 && cells[i1 - cellWidth] === 0) {
heap.push({index: i1, direction: N}, Math.random());
}
if (y1 < cellHeight - 1 && cells[i1 + cellWidth] === 0) {
heap.push({index: i1, direction: S}, Math.random());
}
if (x1 > 0 && cells[i1 - 1] === 0) {
heap.push({index: i1, direction: W}, Math.random());
}
if (x1 < cellWidth - 1 && cells[i1 + 1] === 0) {
heap.push({index: i1, direction: E}, Math.random());
}
}
}
return cells;
}
Insert cell
function fillCells(context) {
for (let y = 0, i = 0; y < cellHeight; ++y) {
for (let x = 0; x < cellWidth; ++x, ++i) {
fillCell(context, i);
if (cells[i] & S) fillSouth(context, i);
if (cells[i] & E) fillEast(context, i);
}
}
}
Insert cell
function fillCell(context, i) {
const x = i % cellWidth;
const y = i / cellWidth | 0;
context.fillRect(
x * cellSize + (x + 1) * cellSpacing,
y * cellSize + (y + 1) * cellSpacing,
cellSize, cellSize
);
}
Insert cell
function fillEast(context, i) {
const x = i % cellWidth;
const y = i / cellWidth | 0;
context.fillRect(
(x + 1) * (cellSize + cellSpacing),
y * cellSize + (y + 1) * cellSpacing,
cellSpacing, cellSize
);
}
Insert cell
function fillSouth(context, i) {
const x = i % cellWidth;
const y = i / cellWidth | 0;
context.fillRect(
x * cellSize + (x + 1) * cellSpacing,
(y + 1) * (cellSize + cellSpacing),
cellSize, cellSpacing
);
}
Insert cell
cells = replay, generate(cellWidth, cellHeight)
Insert cell
cellSize = 2
Insert cell
cellSpacing = 0.01
Insert cell
cellWidth = Math.floor((width - cellSpacing) / (cellSize + cellSpacing))
Insert cell
cellHeight = Math.floor((600 - cellSpacing) / (cellSize + cellSpacing))
Insert cell
N = 1 << 0
Insert cell
S = 1 << 1
Insert cell
W = 1 << 2
Insert cell
E = 1 << 3
Insert cell
function sinebow(t) {
return "#" + [0, 1, 2].map(i => {
const v = 255 * Math.sin(Math.PI * (t + i / 3)) ** 2;
return Math.round(v).toString(16).padStart(2, "0");
}).join("");
}
Insert cell
Queue = require("flatqueue@1")
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