如何连接多条贝塞尔曲线?
How to connect multiple bezier curves?
我想用bezierCurveTo()
画个图。据我所知,1bezierCurveTo()
只能设置3个锚点。如果我使用其中的多个,我会得到一条不平滑的线。我该如何解决?
<canvas id="myCanvas" width="600" height="150" style="border:1px solid #d3d3d3;"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.beginPath();
context.moveTo(0, 150);
context.bezierCurveTo(100, 0, 200, 100, 300, 20);
context.bezierCurveTo(400, 0, 500, 100, 600, 20);
context.strokeStyle = 'blue';
context.stroke();
</script>
我们可以将所有曲线放在一个数组中,然后循环遍历它们,在绘制下一条贝塞尔曲线之前移动到最后一个点。下面是一个示例代码:
<canvas id="myCanvas" width="600" height="150"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
function drawCurve(x, y, curves) {
context.beginPath();
context.moveTo(x, y);
for (i = 0; i < curves.length; i++) {
c = curves[i]
context.bezierCurveTo(c[0], c[1], c[2], c[3], c[4], c[5]);
context.moveTo(c[4], c[5]);
context.stroke();
}
}
context.strokeStyle = 'blue';
drawCurve(0, 150, [
[100, 0, 200, 100, 300, 50],
[400, 0, 500, 100, 600, 20]
]);
context.strokeStyle = 'red';
drawCurve(0, 10, [
[100, 0, 180, 90, 280, 50],
[400, 0, 400, 80, 600, 120]
]);
context.strokeStyle = 'green';
drawCurve(0, 80, [
[100, 0, 90, 45, 140, 25],
[200, 0, 200, 40, 300, 50],
[500, 60, 400, 80, 300, 120],
[300, 120, 200, 160, 100, 80],
]);
</script>
但是“不平滑的线”也取决于你的曲线,如果它们的方向完全相反,我们会看到一个锐边。
请参阅下面的示例,我画的是一颗星星。
<canvas id="myCanvas" width="150" height="150"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
function drawCurve(x, y, curves) {
context.moveTo(x, y);
for (i = 0; i < curves.length; i++) {
c = curves[i]
context.bezierCurveTo(c[0], c[1], c[2], c[3], c[4], c[5]);
context.moveTo(c[4], c[5]);
}
context.stroke();
}
data = []
numPoints = 12
size = 35
angle = 45
for (j = 0; j < numPoints; j++) {
a = angle * Math.PI / 180
points = []
points.push(80 + Math.round(size / 2 * Math.sin(a)))
points.push(80 + Math.round(size / 2 * Math.cos(a)))
points.push(80 + Math.round(size * Math.sin(a)))
points.push(80 + Math.round(size * Math.cos(a)))
points.push(80 + Math.round(size * 2 * Math.sin(a)))
points.push(80 + Math.round(size * 2 * Math.cos(a)))
angle += 360 / numPoints
data.push(points)
}
drawCurve(80, 80, data);
</script>
这是一个不平凡的问题。这取决于您想要实现多少平滑度(只需连接切线,或使连接点处的曲线半径相同)。最简单的方法如图所示([A3-X] / [X-B2] = [A3-A4] / [B1-B2];从A4开始[A3-X]向量,从B1开始[X-B2]到获取 A3x 和 B2x 锚点)。
但您也可以查看 D3 Shape module(例如 Catmul Rom 曲线),它会根据应该经过的点为您生成贝塞尔样条曲线。或者看看某处的算法。
我想用bezierCurveTo()
画个图。据我所知,1bezierCurveTo()
只能设置3个锚点。如果我使用其中的多个,我会得到一条不平滑的线。我该如何解决?
<canvas id="myCanvas" width="600" height="150" style="border:1px solid #d3d3d3;"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.beginPath();
context.moveTo(0, 150);
context.bezierCurveTo(100, 0, 200, 100, 300, 20);
context.bezierCurveTo(400, 0, 500, 100, 600, 20);
context.strokeStyle = 'blue';
context.stroke();
</script>
我们可以将所有曲线放在一个数组中,然后循环遍历它们,在绘制下一条贝塞尔曲线之前移动到最后一个点。下面是一个示例代码:
<canvas id="myCanvas" width="600" height="150"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
function drawCurve(x, y, curves) {
context.beginPath();
context.moveTo(x, y);
for (i = 0; i < curves.length; i++) {
c = curves[i]
context.bezierCurveTo(c[0], c[1], c[2], c[3], c[4], c[5]);
context.moveTo(c[4], c[5]);
context.stroke();
}
}
context.strokeStyle = 'blue';
drawCurve(0, 150, [
[100, 0, 200, 100, 300, 50],
[400, 0, 500, 100, 600, 20]
]);
context.strokeStyle = 'red';
drawCurve(0, 10, [
[100, 0, 180, 90, 280, 50],
[400, 0, 400, 80, 600, 120]
]);
context.strokeStyle = 'green';
drawCurve(0, 80, [
[100, 0, 90, 45, 140, 25],
[200, 0, 200, 40, 300, 50],
[500, 60, 400, 80, 300, 120],
[300, 120, 200, 160, 100, 80],
]);
</script>
但是“不平滑的线”也取决于你的曲线,如果它们的方向完全相反,我们会看到一个锐边。
请参阅下面的示例,我画的是一颗星星。
<canvas id="myCanvas" width="150" height="150"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
function drawCurve(x, y, curves) {
context.moveTo(x, y);
for (i = 0; i < curves.length; i++) {
c = curves[i]
context.bezierCurveTo(c[0], c[1], c[2], c[3], c[4], c[5]);
context.moveTo(c[4], c[5]);
}
context.stroke();
}
data = []
numPoints = 12
size = 35
angle = 45
for (j = 0; j < numPoints; j++) {
a = angle * Math.PI / 180
points = []
points.push(80 + Math.round(size / 2 * Math.sin(a)))
points.push(80 + Math.round(size / 2 * Math.cos(a)))
points.push(80 + Math.round(size * Math.sin(a)))
points.push(80 + Math.round(size * Math.cos(a)))
points.push(80 + Math.round(size * 2 * Math.sin(a)))
points.push(80 + Math.round(size * 2 * Math.cos(a)))
angle += 360 / numPoints
data.push(points)
}
drawCurve(80, 80, data);
</script>
这是一个不平凡的问题。这取决于您想要实现多少平滑度(只需连接切线,或使连接点处的曲线半径相同)。最简单的方法如图所示([A3-X] / [X-B2] = [A3-A4] / [B1-B2];从A4开始[A3-X]向量,从B1开始[X-B2]到获取 A3x 和 B2x 锚点)。
但您也可以查看 D3 Shape module(例如 Catmul Rom 曲线),它会根据应该经过的点为您生成贝塞尔样条曲线。或者看看某处的算法。