Published
Edited
Oct 27, 2018
12 stars
Insert cell
Insert cell
{
const edges = [...generate(cellWidth, cellHeight)];
const width = cellWidth * (cellSize + cellSpacing) + cellSpacing;
const height = cellHeight * (cellSize + cellSpacing) + cellSpacing;
const context = DOM.context2d(width, height);
context.canvas.style.background = "#000";
context.canvas.style.imageRendering = "pixelated";
context.fillStyle = "#fff";
yield context.canvas;
for (let m = 240, k = 4, i = -m, n = edges.length; i < n; i += k) {
for (let j = Math.max(0, i - k), i1 = Math.min(n, i + m); j < i1; ++j) {
const {index, direction} = edges[j];
context.fillStyle = `hsl(0,100%,${(1 - Math.max(0, j - i) / m) * 100}%)`;
switch (direction) {
case E: {
fillCell(context, index + 1);
fillEast(context, index);
break;
}
case W: {
fillCell(context, index - 1);
fillEast(context, index - 1);
break;
}
case S: {
fillCell(context, index + cellWidth);
fillSouth(context, index);
break;
}
case N: {
fillCell(context, index - cellWidth);
fillSouth(context, index - cellWidth);
break;
}
default: {
fillCell(context, index);
break;
}
}
}
yield context.canvas;
}
}
Insert cell
function* generate(cellWidth, cellHeight) {
const heap = new Queue();
const cells = new Uint8Array(cellWidth * cellHeight);
const index = (cellWidth >> 1) + (cellHeight >> 1) * cellWidth;
let edge;
heap.push({index, direction: N}, Math.random());
heap.push({index, direction: E}, Math.random());
yield {index};
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;
yield edge;
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());
}
}
}
}
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
cellSize = 3
Insert cell
cellSpacing = 1
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
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