Published
Edited
Jul 1, 2022
1 fork
5 stars
Insert cell
Insert cell
Insert cell
d3.group(packing.descendants(), (d) => d.depth)
Insert cell
Insert cell
Insert cell
padding = 10
Insert cell
function squarePacking(root) {
let config = {
heuristic: "best",
metric: "chessboard",
closeFreq: 1,
closeFactor: 0.3
};

let pack = function (node) {
if (node.children) {
let arrangement = new SquareArrangement([0, 0], config);
node.children.sort((a, b) => b.value - a.value);
node.children.forEach((d) => {
pack(d);
arrangement.addSquare(d.side ** 2);
});
let { min, max } = boundingBox(arrangement.polygon);
let [xside, yside] = [max[0] - min[0], max[1] - min[1]];
let [side, dx, dy] =
xside > yside
? [xside, 0, (xside - yside) / 2]
: [yside, (yside - xside) / 2, 0];
Object.assign(node, { x: padding, y: padding, side: side + padding * 2 });
arrangement.squares.forEach((vlist, i) => {
let childNode = node.children[i];
childNode.x += vlist[0].p[0] - min[0] + dx;
childNode.y += vlist[0].p[1] - min[1] + dy;
});
} else {
Object.assign(node, {
side: Math.sqrt(node.value) + padding * 2,
x: padding,
y: padding
});
}
};

let translate = function (node, dx = 0, dy = 0) {
node.x += dx;
node.y += dy;
if (node.children) {
for (let child of node.children) {
translate(child, node.x, node.y);
}
}
};

pack(root);
translate(root);
return root;
}
Insert cell
data = flare
Insert cell
hierarchy = d3
.hierarchy(data)
.sum((d) => d.size)
.sort((a, b) => b.size - a.size)
Insert cell
packing = squarePacking(hierarchy)
Insert cell
color = d3.scaleOrdinal(d3.range(10), d3.schemePastel2)
Insert cell
Insert cell
import { chart, flare } from "@d3/circle-packing"
Insert cell
import { boundingBox, SquareArrangement } from "@esperanc/square-packing"
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