Published
Edited
Aug 10, 2019
1 fork
5 stars
Insert cell
Insert cell
options = ({
intervals: 3,
speed: -.05,
colorBands: 10,
colorFunc: d3.interpolateSpectral,
})
Insert cell
canvas = {
const context = DOM.context2d(width, height, 1);
const image = context.createImageData(width, height);
const pixels = new Uint32Array(image.data.buffer);
const len = colors.length;
const dmax = distance.reduce((max, v) => v > max ? v : max, 0);
const ds = len * options.intervals / dmax;
const mod = (v, n) => ((v % n) + n) % n;
while (true) {
const o = options.speed * ds * Date.now();
for (let i = 0; i < n; ++i) pixels[i] = colors[mod(Math.round(distance[i] * ds + o), len)];
context.putImageData(image, 0, 0);
yield context.canvas;
}
}
Insert cell
colors = new Uint32Array(new Uint8ClampedArray(
Array(options.colorBands).fill()
.map((_, i, a) => d3.color(options.colorFunc(i/a.length)))
.flatMap(c => [c.r, c.g, c.b, 255])
).buffer)
Insert cell
distance = {
const distance = new Array(n);
let frontier = [(height - 1) * width];
distance[frontier[0]] = 0;
for (let d = 0; frontier.length; ++d) {
let frontier1 = [];
for (let i = 0, n0 = frontier.length; i < n0; ++i) {
let i0 = frontier[i], i1;
if (cells[i0] & E && distance[i1 = i0 + 1] === undefined) distance[i1] = d, frontier1.push(i1);
if (cells[i0] & W && distance[i1 = i0 - 1] === undefined) distance[i1] = d, frontier1.push(i1);
if (cells[i0] & S && distance[i1 = i0 + width] === undefined) distance[i1] = d, frontier1.push(i1);
if (cells[i0] & N && distance[i1 = i0 - width] === undefined) distance[i1] = d, frontier1.push(i1);
}
frontier = frontier1;
}
return distance;
}
Insert cell
cells = {
const cellWidth = width;
const cellHeight = height;
const heap = new FlatQueue();
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
N = 1 << 0
Insert cell
S = 1 << 1
Insert cell
W = 1 << 2
Insert cell
E = 1 << 3
Insert cell
n = width * height
Insert cell
height = 600
Insert cell
FlatQueue = require("flatqueue@1")
Insert cell
d3 = require("d3-color@1", "d3-scale-chromatic@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