Public
Edited
Mar 30
Insert cell
Insert cell
{
const size = 640;
const shapes = [];
const random = d3.randomUniform(-25, 25);
let [dx0, dy0, dx1, dy1, i0, i1, j0, j1] = [0, 0, 0, 0, 0, 0, 0, 0];

drawShape(size / 2, size / 2, 150);

const input = d3.extent(shapes.map((d) => d.r)).reverse();
const scale = (i) => d3.scaleSequential(input, d3[`interpolate${colors[i]}`]);

function drawShape(x, y, r) {
if (r < 4) return;
shapes.push({ x, y, r });
drawShape(x, y, r - 15);
}

function draw({ frameCount }) {
if (frameCount !== 0) {
[dx0, dy0] = [dx1, dy1];
[dx1, dy1] = [random(), random()];
[i0, i1] = [i1, frameCount === 1 ? 0 : d3.randomInt(colors.length)()];
[j0, j1] = [j1, frameCount === 1 ? 0 : d3.randomInt(symbols.length)()];
}

const [c0, c1] = [scale(i0), scale(i1)];
const [s0, s1] = [symbols[j0], symbols[j1]];

return cm.svg("g", shapes, {
transform: (_, i) => `translate(${i * dx0},${i * dy0})`,
transition: (d, i) => [
{
transform: `translate(${i * dx1},${i * dy1})`,
duration: 1000,
delay: i * 20,
ease: d3.easeElastic
}
],
children: (d, i) => {
const p = [d.x - d.r, d.y - d.r, d.r * 2];
const path = () => flubber.interpolate(s0(...p), s1(...p));
return [
cm.svg("path", {
stroke: "#000",
d: s0(...p),
fill: c0(d.r),
strokeWidth: 0.5,
transition: [
{ fill: c1(d.r), duration: 500, delay: i * 25 },
{ d: path, duration: 500, delay: 500 + i * 25 }
]
})
];
}
});
}

const app = cm.app({
draw,
loop: true,
frameRate: 0.5,
width: size,
height: size,
use: { transition: cm.transition }
});

invalidation.then(() => app.dispose());

return app.render();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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