Published
Edited
Sep 6, 2020
Fork of Hulls
5 stars
Insert cell
Insert cell
Insert cell
Insert cell
line = d3.line()
.x(d => d[0])
.y(d => d[1])
.curve(d3.curveCatmullRomClosed);
Insert cell
hullResult = hull(points)
Insert cell
hullPath = line(hullResult)
Insert cell
function hull(points) {
// No sense in rendering a hull for fewer than two points
// Comment by David - Makes sense actually, if your client has such requirements for you
if (points.length < 2) return d3.polygonHull([points[0],points[0], ...points]);

// polygonHull seems to require a minimum of three points, but works
// just fine if two of the points are identical, so we can patch over
// the problem of a two point cluster by duplicating the first point.
if (points.length < 3) return d3.polygonHull([points[0], ...points]);

return d3.polygonHull(points);
}
Insert cell
{
function dragged(d) {
d3.select(this)
.attr("cx", d[0] = d3.event.x)
.attr("cy", d[1] = d3.event.y);
path.attr("d", line(hull(svg.selectAll("circle").data())));
}
const svg = d3.select(DOM.svg(width, height));
const path = svg.append("path")
.attr("fill", "steelblue")
.attr("stroke", "steelblue")
.attr("stroke-width", 16)
.attr("opacity", 0.2)
.attr("d", hullPath);
svg.selectAll("circle").data(points)
.enter().append("circle")
.style("cursor", "grab")
.attr("fill", "steelblue")
.attr("cx", d => d[0])
.attr("cy", d => d[1])
.attr("r", 4)
.call(d3.drag()
.on("start", function () { d3.select(this).style("cursor", "grabbing"); })
.on("end", function () { d3.select(this).style("cursor", "grab"); })
.on("drag", dragged));
return svg.node();
}
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