Published
Edited
Apr 6, 2021
1 fork
Insert cell
Insert cell
Insert cell
function frag(x, y, t) {
const r = 0; step.resistanceField[y][x];
const f = step.floodField[y][x];
const fScale = 1e300;
const f1 = Math.log(Math.abs(f * fScale)) / Math.log(fScale);
// const f1 = Math.log(Math.max(0, f * fScale)) / Math.log(fScale);
// const f2 = Math.log(-Math.min(0, f * fScale)) / Math.log(fScale);
// const f1 = Math.log(f * 1e20) / Math.log(1e20);
return [r * 255, f1 * 255, f1 * 255, 255];
const s = paths.sumMap[y][x];
const tr = travelMap[y][x];
return [r * 255, s < Infinity ? (s * 1) : 0, Math.min(255, (1 - (1 - tr) * (1 - tr)) * 500), 255];
}
Insert cell
fps(step);
Insert cell
Insert cell
step = {
const w = canvasWidth;
const h = canvasHeight;

let t = 0;
let floodField = createCellField(w, h, (x, y) => 0);
while (true) {
t++;
const resistanceField = createCellField(w, h, (x, y) => noise(x, y, t));
const lastFloodField = floodField;
floodField = createCellField(w, h, (x, y) => 0);
for (let y = 1; y < h - 1; y++) {
for (let x = 1; x < w - 1; x++) {
const q = lastFloodField[y][x];
const r = resistanceField[y][x];
const dt = 0.01;
let dq = 0;
for (const n of neightbours) {
const nx = x + n.dx;
const ny = y + n.dy;
const nq = lastFloodField[ny][nx];
const nr = resistanceField[ny][nx];

const resistance = (nr + r) / 2 * n.d;
dq += (nq - q) / resistance * dt;
}
floodField[y][x] += dq;
}
}
floodField[start.y][start.x] = resistanceResource;
yield {
t,
resistanceField,
floodField,
}
}
}
Insert cell
Insert cell
Insert cell
function createCellField(w, h, fCell) {
return Array.from({length: h}, (_, y) => Array.from({length: w}, (_, x) => fCell(x, y)));
}
Insert cell
function fillCellField(field, fCell) {
for (let y = 0; y < field.length; y++) {
for (let x = 0; x < field[y].length; x++) {
field[y][x] = fCell(x, y);
}
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
paths = {
return 0;
const sumMap = Array.from(
{length: canvasHeight},
(_, y) => Array.from(
{length: canvasWidth},
(_, x) => Number.POSITIVE_INFINITY));
const lastSumMap = Array.from(
{length: canvasHeight},
(_, y) => Array.from(
{length: canvasWidth},
(_, x) => Number.POSITIVE_INFINITY));
const precessorMap = Array.from(
{length: canvasHeight},
(_, y) => Array.from(
{length: canvasWidth},
(_, x) => undefined));

sumMap[start.y][start.x] = 0;
let qe = 0;
const queue = [];
queue[qe++] = start;
for (let qi = 0; qi < qe; qi++) {
const {x: ex, y: ey} = queue[qi];
const esum = sumMap[ey][ex];
if (esum >= lastSumMap[ey][ex]) {
continue;
}
lastSumMap[ey][ex] = esum;
for (const n of neightbours) {
const nx = ex + n.dx;
const ny = ey + n.dy;
if (nx < 0 || nx >= canvasWidth) {
continue;
}
if (ny < 0 || ny >= canvasHeight) {
continue;
}
const sum = esum + n.d * resistanceField[ny][nx];
if (sum >= sumMap[ny][nx]) {
// better path to this neightbour is already found
continue;
}
sumMap[ny][nx] = sum;
precessorMap[ny][nx] = {x: ex, y: ey};
if (sum > resistanceResource) {
// this neightbour is already unreachable, no need to go further
continue;
}
queue[qe++] = {x: nx, y: ny};
}
}
return {
sumMap,
precessorMap,
};
}
Insert cell
travelMap = {
return 0;
// const startV = voltageMap[startI];

const travelMap = Array.from(
{length: canvasHeight},
(_, y) => Array.from(
{length: canvasWidth},
(_, x) => 0));

let xMin = Number.POSITIVE_INFINITY;
let xMax = Number.NEGATIVE_INFINITY;
let yMin = Number.POSITIVE_INFINITY;
let yMax = Number.NEGATIVE_INFINITY;

for (let y = 0; y < canvasHeight; y++) {
for (let x = 0; x < canvasWidth; x++) {
const pmsi = paths.sumMap[y][x];
if (pmsi === Infinity || pmsi <= resistanceResource) {
continue;
}

if (xMin > x) { xMin = x; }
if (xMax < x) { xMax = x; }
if (yMin > y) { yMin = y; }
if (yMax < y) { yMax = y; }

// const u = voltageMap[i] - startV;
const u = 1;
const a = u / pmsi;

let p = paths.precessorMap[y][x];

while (p) {
travelMap[p.y][p.x] += a;
p = paths.precessorMap[p.y][p.x];
}
}
}

let min = Number.POSITIVE_INFINITY;
let max = Number.NEGATIVE_INFINITY;

for (let y = yMin; y <= yMax; y++) {
for (let x = xMin; x <= xMax; x++) {
let v = travelMap[y][x];
if (v < 0) { v = 0; }
travelMap[y][x] = v;

if (v > max) { max = v; }
if (v < min) { min = v; }
}
}

const range = max - min;

for (let y = yMin; y <= yMax; y++) {
for (let x = xMin; x <= xMax; x++) {
travelMap[y][x] = (travelMap[y][x] - min) / range;
}
}

return travelMap;
}
Insert cell
{
const w = canvasWidth;
const h = canvasHeight;
const imageData = new ImageDataUint32(context.getImageData(0, 0, w, h));

for (let y = 0; y < h; y++) {
for (let x = 0; x < w; x++) {
imageData.setPixelArr(x, y, frag(x, y, t));
}
}
context.putImageData(imageData, 0, 0);
}
Insert cell
context = {
const w = canvasWidth;
const h = canvasHeight;
const context = DOM.context2d(w, h, 1);
context.canvas.style.imageRendering = "pixelated";
context.canvas.style.background = "black";
return context;
}
Insert cell
import {fps} from '@zzzev/fps-counter'
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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