{
function mandelbrot(transform = {}, dpr = window.devicePixelRatio ?? 1) {
const { x: tx = 0, y: ty = 0, k = 1 } = transform;
return (x, y, width, height) => {
x = (x - tx * dpr) / width / k;
y = (y - ty * dpr) / height / k;
x = -2 + 3 * x;
y = -1.164 + 1.164 * 2 * y;
for (var i = 0, a = 0, b = 0, n = 500; i < n; i++) {
const a2 = a ** 2;
const b2 = b ** 2;
[a, b] = [a2 - b2 + x, 2 * a * b + y];
if (a2 + b2 > 4) break;
}
return colors[i % colors.length];
};
}
function add(t1, t2) {
const k = t1.k * t2.k;
const x = t1.x * t2.k + t2.x;
const y = t1.y * t2.k + t2.y;
return d3.zoomIdentity.translate(x, y).scale(k);
}
const width = 800;
const height = (width / 580) * 460;
const dpr = 1;
const cellSize = 10;
const rows = Math.ceil(height / cellSize);
const cols = Math.ceil(width / cellSize);
const cells = d3.cross(d3.range(cols), d3.range(rows));
const state = cm.state({
transform: d3.zoomIdentity,
prevTranform: d3.zoomIdentity,
fill: mandelbrot()
});
const app = cm.app({
width,
height,
use: { zoom: cm.zoom },
draw: () => [
cm.html("span", {
styleDisplay: "block",
textContent: `scale = ${state.prevTranform.k}`
}),
cm.html("span", {
styleDisplay: "block",
textContent: `translate = ${state.prevTranform.x}, ${state.prevTranform.y} `
}),
cm.svg("svg", {
width,
height,
children: [
cm.svg("rect", cells, {
x: (d) => d[0] * cellSize,
y: (d) => d[1] * cellSize,
width: cellSize,
height: cellSize,
fill: (d) => ((d[0] + d[1]) % 2 === 0 ? "white" : "#eee")
}),
cm.image2D({
fill: state.fill,
transform: state.transform,
dpr,
zoom: {
onZoom: ({ transform }) => (state.transform = transform),
onEnd: ({ transform, reset }) => {
state.prevTranform = add(state.prevTranform, transform);
state.fill = mandelbrot(state.prevTranform, dpr);
state.transform = d3.zoomIdentity;
reset();
}
}
})
]
})
]
});
invalidation.then(() => app.dispose());
return app.render();
}