原文链接: 使用delaunator 拥三角形拟合平面圆
https://github.com/mapbox/delaunator
对于圆环, 有些三角形是穿过中间的
计算速度确实快, 卡顿是因为canvas的绘制太慢了, 因为三角形太多了
使用也非常简单, 直接一个nx2的数组就行, 还接收getx和gety用来做坐标转换
<!DOCTYPE html>
<html>
<head>
<title>
Delaunator, the fastest JavaScript library for Delaunay triangulation of
2D points
</title>
<style>
body {
margin: 0;
text-align: center;
font-family: sans-serif;
}
canvas {
border: 1px solid #ccc;
position: relative;
}
a,
a:visited {
color: #09f;
}
</style>
</head>
<body>
<h2><a href="https://github.com/mapbox/delaunator">delaunator</a> demo</h2>
<canvas id="canvas"></canvas>
<script src="https://unpkg.com/delaunator@4.0.1/delaunator.js"></script>
<script>
const points = [];
const width = 100;
const height = 100;
const step = 4;
for (let r = 0; r <= height; r += step) {
for (let x = 0; x <= r; x++) {
const y = (r ** 2 - x ** 2) ** 0.5;
points.push([x, y]);
points.push([x, -y]);
points.push([-x, y]);
points.push([-x, -y]);
}
}
console.log(points.length);
console.time("delaunay");
let delaunay = Delaunator.from(points);
console.log("===",delaunay)
console.timeEnd("delaunay");
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let minX = Infinity;
let minY = Infinity;
let maxX = -Infinity;
let maxY = -Infinity;
for (let i = 0; i < points.length; i++) {
const x = points[i][0];
const y = points[i][1];
if (x < minX) minX = x;
if (y < minY) minY = y;
if (x > maxX) maxX = x;
if (y > maxY) maxY = y;
}
const padding = 5;
const w = 1024;
const h =
((w - 2 * padding) * (maxY - minY)) / (maxX - minX) + 2 * padding;
canvas.style.width = w + "px";
canvas.style.height = h + "px";
canvas.width = w;
canvas.height = h;
if (window.devicePixelRatio >= 2) {
canvas.width = w * 2;
canvas.height = h * 2;
ctx.scale(2, 2);
}
const ratio = (w - 2 * padding) / Math.max(maxX - minX, maxY - minY);
ctx.lineJoin = "round";
ctx.lineCap = "round";
let updated = true;
canvas.onmousemove = function (e) {
points.push([
(e.layerX - padding) / ratio + minX,
(e.layerY - padding) / ratio + minY,
]);
console.time("delaunay111");
delaunay = Delaunator.from(points);
console.timeEnd("delaunay111");
console.log("delaunay222", delaunay);
updated = true;
};
function getX(i) {
return padding + ratio * (points[i][0] - minX);
}
function getY(i) {
return padding + ratio * (points[i][1] - minY);
}
function frame() {
requestAnimationFrame(frame);
draw();
}
frame();
function draw() {
if (!updated) return;
updated = false;
ctx.clearRect(0, 0, w, h);
const triangles = delaunay.triangles;
ctx.beginPath();
for (let i = 0; i < triangles.length; i += 3) {
const p0 = triangles[i];
const p1 = triangles[i + 1];
const p2 = triangles[i + 2];
ctx.moveTo(getX(p0), getY(p0));
ctx.lineTo(getX(p1), getY(p1));
ctx.lineTo(getX(p2), getY(p2));
ctx.closePath();
}
ctx.strokeStyle = "rgba(0,200,0,1)";
ctx.lineWidth = 0.5;
ctx.stroke();
// ctx.fillStyle = 'rgba(255,255,0,0.1)';
// ctx.fill();
ctx.beginPath();
for (const i of delaunay.hull) {
ctx.lineTo(getX(i), getY(i));
}
ctx.closePath();
ctx.lineWidth = 1;
ctx.strokeStyle = "red";
ctx.stroke();
ctx.fillStyle = "black";
ctx.beginPath();
for (let i = 0; i < points.length; i++) {
ctx.rect(getX(i) - 1.5, getY(i) - 1.5, 3, 3);
}
ctx.fill();
}
</script>
</body>
</html>
来源:oschina
链接:https://my.oschina.net/ahaoboy/blog/4952867