Public
Edited
Feb 21
1 fork
Insert cell
Insert cell
Insert cell
{
const width = 800;
const vector = d3.range(count);
const cells = d3.cross(vector, vector);
const scale = d3.scaleBand().domain(vector).range([0, width]).padding(0.1);
const r = scale.bandwidth() / 2;
const size = scale.step();
const pos = (x) => scale(x) + r;
const center = [width / 2, width / 2, width];
const to = (end) => move(current, end);

let view;
let current = center;
let zooming = false;

function move(start, end) {
if (zooming) return;
zooming = true;
const interpolator = d3.interpolateZoom(start, end);
const duration = interpolator.duration * 1.2;
const selection = d3.select(view);
const transform = (t) => {
const view = interpolator(t);
const k = width / view[2]; // scale
const translate = [width / 2 - view[0] * k, width / 2 - view[1] * k]; // translate
return `translate(${translate}) scale(${k})`;
};
// TODO: Use cm.transition
selection
.transition()
.duration(duration)
.attrTween("transform", () => transform)
.end()
.then(() => ((zooming = false), (current = end)));
}

return cm.render({
width,
height: width,
stroke: "black",
draw: [
(view = SVG.g({
transform: "translate(0, 0) scale(1)",
children: [
SVG.g(cells, {
"stroke-width": 1.2,
style: "cursor:pointer",
transform: ([x, y]) => `translate(${pos(x)}, ${pos(y)})`,
children: [([x, y]) => rose(r, x + 1, y + 1)],
// prettier-ignore
onclick: ([x, y]) => () => to(current === center ? [pos(x), pos(y), size]: center)
})
]
}))
]
});
}
Insert cell
function rose(r, n, d) {
const k = n / d;
const m = reduceDenominator(n, d);
const points = [];
for (let a = 0; a < Math.PI * 2 * m + 0.02; a += 0.02) {
const r1 = r * Math.cos(k * a);
const x = r1 * Math.cos(a);
const y = r1 * Math.sin(a);
points.push([x, y]);
}
return SVG.path({
d: d3.line().curve(d3.curveCatmullRom)(points),
stroke: "black",
fill: "transparent"
});
}
Insert cell
function reduceDenominator(numerator, denominator) {
const rec = (a, b) => (b ? rec(b, a % b) : a);
return denominator / rec(numerator, denominator);
}
Insert cell
SVG = cm.SVG
Insert cell
cm = require(await FileAttachment("charming@1.umd.min.js").url())
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