Public
Edited
Nov 24, 2024
Insert cell
Insert cell
chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("stroke-width", 2);

const points = d3.range(50).map(i => ({
x: Math.random() * (width - 32 * 2) + 32,
y: Math.random() * (height - 32 * 2) + 32,
}));

let voronoi = d3.Delaunay
.from(points, d => d.x, d => d.y)
.voronoi([0, 0, width, height]);
console.log([...voronoi.cellPolygons()][0])

// считаем координаты центра и радиус вписоной окружности
const circles = [...voronoi.cellPolygons()].map((polygon) => {
const [x, y] = d3.polygonCentroid(polygon);
const [cx,cy] = findIncenter(polygon);
const radius = 0.7 * Math.sqrt(Math.abs(d3.polygonArea(polygon)) / Math.PI);

return {
x: Number(x.toFixed(2)),
y: Number(y.toFixed(2)),
r: Number(radius.toFixed(2)),
cx,
cy
};
});
const circle = svg.append("g")
.selectAll("circle")
.data(circles)
.join("circle")
.attr("cx", d => d.cx)
.attr("cy", d => d.cy)
.attr("r", d=>d.r)
.attr("fill", (d, i) => d3.schemeCategory10[i % 10]).call(
d3.drag()
.on("start", (event, d) => {
circle.filter(p => p === d).raise().attr("stroke", "black");
})
.on("drag", (event, d) => {
d.x = event.x;
d.y = event.y;
update(d);
})
.on("end", (event, d) => {
circle.filter(p => p === d).attr("stroke", null);
})
);

const mesh = svg.append("path")
.attr("fill", "none")
.attr("stroke", "#ccc")
.attr("stroke-width", 1)
.attr("d", voronoi.render());

function update(dragalbeCircle) {
voronoi = d3.Delaunay.from(circles, d => d.x, d => d.y).voronoi([0, 0, width, height]);

circle.each((d, i, nodes) => {
const polygon = voronoi.cellPolygon(i);
const [x, y] = d3.polygonCentroid(polygon);
const [cx,cy] = findIncenter(polygon);
const radius = 0.7 * Math.sqrt(Math.abs(d3.polygonArea(polygon)) / Math.PI);

d.r = Number(radius.toFixed(2));
d.cx=cx;
d.cy=cy;
if (dragalbeCircle === d){
d.x = x;
d.y = y;
}
})
.attr("r", d => d.r)
.attr("cx", d => d.cx)
.attr("cy", d => d.cy);

mesh.attr("d", voronoi.render());
}

return svg.node();
}
Insert cell
function findIncenter(polygon) {
// Check if the polygon has at least three vertices
if (polygon.length < 3) {
throw new Error('A polygon must have at least three vertices.');
}

// Calculate the centroid of the polygon
let centroid = [0, 0];
for (let i = 0; i < polygon.length; i++) {
centroid[0] += polygon[i][0];
centroid[1] += polygon[i][1];
}
centroid[0] /= polygon.length;
centroid[1] /= polygon.length;

// Calculate the incenter using the centroid and vertex midpoints
let incenter = [0, 0];
let totalWeight = 0;

for (let i = 0; i < polygon.length; i++) {
let currentVertex = polygon[i];
let nextVertex = polygon[(i + 1) % polygon.length];

// Calculate the midpoint of the current edge
let midpoint = [(currentVertex[0] + nextVertex[0]) / 2, (currentVertex[1] + nextVertex[1]) / 2];

// Calculate the weight of the current edge
let weight = Math.sqrt(Math.pow(midpoint[0] - centroid[0], 2) + Math.pow(midpoint[1] - centroid[1], 2));

// Update the incenter coordinates
incenter[0] += midpoint[0] * weight;
incenter[1] += midpoint[1] * weight;

// Update the total weight
totalWeight += weight;
}

// Normalize the incenter coordinates
incenter[0] /= totalWeight;
incenter[1] /= totalWeight;

return centroid;
}
Insert cell
function findMinimumInscribedCircleRadius(polygon) {
// Get the incenter of the polygon
const incenter = findIncenter(polygon);

// Initialize with the distance to the first vertex
let minRadius = distance(incenter, polygon[0]);

// Loop through the rest of the vertices to find the minimum distance
for (let i = 1; i < polygon.length; i++) {
const currentRadius = distance(incenter, polygon[i]);
minRadius = Math.min(minRadius, currentRadius);
}

return minRadius;
}


Insert cell
// Function to calculate the distance between two points
function distance(point1, point2) {
return Math.sqrt(Math.pow(point1[0] - point2[0], 2) + Math.pow(point1[1] - point2[1], 2));
}
Insert cell
height = 600
Insert cell
d3 = require("d3@6")
Insert cell
polylabel = require("polylabel@1.1.0")
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