Public
Edited
Mar 10
Insert cell
Insert cell
Insert cell
{
const n = n0;
const N = d3.range(n);
const size = (width / n) | 0;
return html`<div style="display:flex;flex-wrap: wrap;">${[
...N.map((d) => multibrotSet(d + 2, size, 2.2)),
...N.map((d) => label(size, d + 2)),
...N.map((d) => multibrotSet(-d - 2, size, 2.4)),
...N.map((d) => label(size, -d - 2))
]}</div>`;
}
Insert cell
Insert cell
multibrotSet(n, 480)
Insert cell
function multibrotSet(n, size, range = 2, max = 80) {
return cm.raster2D({
width: size,
height: size,
fill: (x, y) => {
x = cm.map(x, 0, 1, -range, range);
y = cm.map(y, 0, 1, -range, range);
const x0 = n < 0 ? x : 0;
const y0 = n < 0 ? y : 0;
for (var a = x0, b = y0, i = 0, max = 80; i < max; i++) {
const r = Math.sqrt(a * a + b * b);
const theta = Math.atan2(b, a);
const rn = Math.pow(r, n);
a = rn * Math.cos(n * theta) + x;
b = rn * Math.sin(n * theta) + y;
if (a * a + b * b > 4) break;
}
return colors[i];
}
});
}
Insert cell
function label(size, d) {
return html`<div style="width: ${size}px; background:#21171B; color:white; text-align:center; padding-bottom:10px">z ↦ z<sup>${d}</sup> + c</div>`;
}
Insert cell
colors = Array.from({ length: 80 }, (_, i) => {
const d = d3.interpolateTurbo(i / 80);
const { r, g, b, opacity } = d3.color(d).rgb();
return [r, g, b, opacity * 255];
})
Insert cell
function map(x, a, b, c, d) {
if (a == b) return (c + d) / 2;
return ((x - a) / (b - a)) * (d - c) + c;
}
Insert cell
function raster2D({ width, height, fill, dpr = window.devicePixelRatio || 1 }) {
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
const scaledW = width * dpr;
const scaledH = height * dpr;
canvas.width = scaledW;
canvas.height = scaledH;
canvas.style.width = width + "px";
canvas.style.height = height + "px";
context.scale(dpr, dpr);
const imageData = context.getImageData(0, 0, scaledW, scaledH);
const data = imageData.data;
for (let i = 0; i < scaledW; i++) {
for (let j = 0; j < scaledH; j++) {
const x = map(i, 0, scaledW, 0, 1);
const y = map(j, 0, scaledH, 0, 1);
const color = fill(x, y, scaledW, scaledH);
if (color) {
const index = (j * scaledW + i) * 4;
const [r, g, b, a] = color;
data[index] = r;
data[index + 1] = g;
data[index + 2] = b;
data[index + 3] = a;
}
}
}
context.putImageData(imageData, 0, 0);
return canvas;
}
Insert cell
cm = ({ raster2D, map })
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