Published
Edited
May 27, 2021
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
const svg = d3.select(DOM.svg(width, height))
.style("fill","white")
const delaunay = d3.Delaunay.from(trees, d => d.x, d => d.y )
const voronoi = delaunay.voronoi([0.5, 0.5, width - 0.5, height - 0.5])
// um what is this part?
const renderCell = (d) => {
return d == null ? null : "M" + d.join("L") + "Z";
}
var circle = svg.selectAll("g")
.data(trees)
.enter().append("g")
var cell = circle.append("path")
.data(trees.map((d,i) => voronoi.renderCell(i)) )
.style("stroke", "#006a4e")
.style("stroke-width", "10")
.attr("d", d => d)
.attr("id", function(d, i) { return "cell-" + i; })
.attr("fill", "#b8d5cd")
const emoji = "🌲";
svg.selectAll(".emoji")
.data(trees)
.join("text")
.attr("x", d => d.x)
.attr("y", d => d.y)
.classed("emoji", true)
.text(emoji);
return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
centeredForest = {
const svg = d3.select(DOM.svg(width, height)).style("fill", "white");

// um what is this part?
const renderCell = d => {
return d == null ? null : "M" + d.join("L") + "Z";
};

var circle = svg
.selectAll("g")
.data(trees)
.join("g");

// we need to use JSON parse and stringify because there is some copy on modify shenanigans
// that happens in JS that I don't even want to go into right now
// but rather than use voronoi directly, we'll use our algorithm to create
// evenly spaced trees in the forest!

// console.log(lloydTrees)
const voronoi = d3.Delaunay.from(lloydTrees, d => d.x, d => d.y).voronoi([
0.5,
0.5,
width - 0.5,
height - 0.5
]);

var cell = circle
.append("path")
.data(lloydTrees.map((d, i) => voronoi.renderCell(i)))
.style("stroke", "#006a4e")
.style("stroke-width", "10")
.attr("d", d => d)
.attr("id", function(d, i) {
return "cell-" + i;
})
.attr("fill", "#b8d5cd");

const emoji = "🌲";

svg
.selectAll(".emoji")
.data(lloydTrees)
.join("text")
.attr("x", d => d.x)
.attr("y", d => d.y)
.classed("emoji", true)
.text(emoji);

return svg.node();
}
Insert cell
Insert cell
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
lloydTrees = lloydAlgo(JSON.parse(JSON.stringify(trees)), NumIters)
Insert cell
Insert cell
mutable debug = {}
Insert cell
lloydAlgo = (points, NumIterations = 20) => {
// 0️⃣ have N points

// create the voronoi structure
const voronoi = d3.Delaunay.from(points, d => d.x, d => d.y).voronoi([
0.5,
0.5,
width - 0.5,
height - 0.5
]);

// here's our previous set of points - lets get read to update them
// d3.Delaunay represents them as a flat array of coordinates [x0, y0, x1, y1, x2, y2…]
// mutable debug = v.delaunay.points;


for (let i = 0; i < NumIterations; ++i) {

for (let j = 0; j < points.length; ++j) {

// 1️⃣ computeeach cell of each voronoi polygon

const cell = voronoi.cellPolygon(j);

// 2️⃣ compute centroid of each voronoi polygon

const [x_centroid, y_centroid] = d3.polygonCentroid(cell);

/* 3️⃣ move each point towards centroid of its polygon

Here .03 is a dampending ratio
Since each point has two entries in the array (an x and a y) we need to multiply j by 2 (j * 2)
+1 sets the y
*/
voronoi.delaunay.points[j * 2] +=
(x_centroid - voronoi.delaunay.points[j * 2]) * 0.03;
voronoi.delaunay.points[j * 2 + 1] +=
(y_centroid - voronoi.delaunay.points[j * 2 + 1]) * 0.03;
}

//update to make x & y changes
voronoi.update()

} // 4️⃣ go back to step 1️⃣

return Array.from(points, (_, j) => ({
x: voronoi.delaunay.points[2 * j],
y: voronoi.delaunay.points[2 * j + 1]
}));
}
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