Public
Edited
Sep 16, 2023
7 forks
10 stars
Insert cell
Insert cell
chart = {
const width = 960;
const height = width;
const tree = d3.quadtree([], (i) => points[i][0], (i) => points[i][1]);
tree.cover(d3.min(points, ([x]) => x), d3.min(points, ([, y]) => y));
tree.cover(d3.max(points, ([x]) => x), d3.max(points, ([, y]) => y));
const x = d3.scaleLinear([tree._x0, tree._x1], [0.5, width - 0.5]);
const y = d3.scaleLinear([tree._y0, tree._y1], [height - 0.5, 0.5]);

const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("style", "max-width: 100%; height: auto;");

const g = svg.append("g")
.attr("stroke", "currentColor")
.attr("fill", "none");

g.append("rect")
.attr("x", x(tree._x0))
.attr("y", y(tree._y1))
.attr("width", x(tree._x1) - x(tree._x0))
.attr("height", y(tree._y0) - y(tree._y1));

yield svg.node();

const nodes = new Set();
for (let i = 0; i < points.length; ++i) {
tree.add(i);
let t = svg.transition();

svg.append("circle")
.attr("fill", "currentColor")
.attr("stroke", "white")
.attr("cx", x(points[i][0]))
.attr("cy", y(points[i][1]))
.attr("r", 0)
.transition(t)
.attr("r", 2.5);

quadtree_visitParent.call(tree, (x0, y0, x1, y1) => {
const key = [x0, y0, x1, y1].join();
if (nodes.has(key)) return;
nodes.add(key);
t = t.transition();
const xm = (x0 + x1) / 2;
const ym = (y0 + y1) / 2;
g.append("line").attr("x1", x(xm)).attr("y1", y(ym)).attr("x2", x(xm)).attr("y2", y(ym)).transition(t).attr("x1", x(x0));
g.append("line").attr("x1", x(xm)).attr("y1", y(ym)).attr("x2", x(xm)).attr("y2", y(ym)).transition(t).attr("x2", x(x1));
g.append("line").attr("x1", x(xm)).attr("y1", y(ym)).attr("x2", x(xm)).attr("y2", y(ym)).transition(t).attr("y1", y(y0));
g.append("line").attr("x1", x(xm)).attr("y1", y(ym)).attr("x2", x(xm)).attr("y2", y(ym)).transition(t).attr("y2", y(y1));
});

await t.end();
}
}
Insert cell
function quadtree_visitParent(callback) {
let quads = [], q, node = this._root, parent, child, x0, y0, x1, y1, xm, ym;
if (node) quads.push({node, x0: this._x0, y0: this._y0, x1: this._x1, y1: this._y1});
while ((q = quads.pop())) {
node = q.node, parent = q.parent;
if (parent) callback(parent.x0, parent.y0, parent.x1, parent.y1);
if (!node.length) continue;
x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
if ((child = node[3])) quads.push({parent: q, node: child, x0: xm, y0: ym, x1: x1, y1: y1});
if ((child = node[2])) quads.push({parent: q, node: child, x0: x0, y0: ym, x1: xm, y1: y1});
if ((child = node[1])) quads.push({parent: q, node: child, x0: xm, y0: y0, x1: x1, y1: ym});
if ((child = node[0])) quads.push({parent: q, node: child, x0: x0, y0: y0, x1: xm, y1: ym});
}
return this;
}
Insert cell
points = ((random) => Array.from({length: 10}, () => [random(), random()]))(d3.randomNormal.source(d3.randomLcg(42))())
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