我在 html 画布上使用context.quadraticCurveTo(controlX, controlY, endX, endY);
.
我有控制点和起点和终点,它们不一定在水平方向上相互水平。
如何使用这些参数找到曲线上的中心点?
其实我想在这个中心点上放一个 div 标签。在这个过程中是否涉及任何方程求解?
我在 html 画布上使用context.quadraticCurveTo(controlX, controlY, endX, endY);
.
我有控制点和起点和终点,它们不一定在水平方向上相互水平。
如何使用这些参数找到曲线上的中心点?
其实我想在这个中心点上放一个 div 标签。在这个过程中是否涉及任何方程求解?
quadraticCurveTo
绘制二次贝塞尔曲线.
计算曲线上任意给定位置(从 0 到 1)的点坐标的公式是
x(t) = (1-t)^2 * x1 + 2 * (1-t) * t * x2 + t^2 * x3
y(t) = (1-t)^2 * y1 + 2 * (1-t) * t * y2 + t^2 * y3
其中 (x1, y1) 是起点, (x2, y2) 是控制点, (x3, y3) 是终点。
所以,把它变成 JavaScript,我们最终会得到类似的东西
function _getQBezierValue(t, p1, p2, p3) {
var iT = 1 - t;
return iT * iT * p1 + 2 * iT * t * p2 + t * t * p3;
}
function getQuadraticCurvePoint(startX, startY, cpX, cpY, endX, endY, position) {
return {
x: _getQBezierValue(position, startX, cpX, endX),
y: _getQBezierValue(position, startY, cpY, endY)
};
}
如果将开始点、结束点和控制点以及中间位置传递到getQuadraticCurvePoint
那里,您应该得到一个具有 X 和 Y 坐标的对象。0.5
function _getQBezierValue(t, p1, p2, p3) {
var iT = 1 - t;
return iT * iT * p1 + 2 * iT * t * p2 + t * t * p3;
}
function getQuadraticCurvePoint(startX, startY, cpX, cpY, endX, endY, position) {
return {
x: _getQBezierValue(position, startX, cpX, endX),
y: _getQBezierValue(position, startY, cpY, endY),
};
}
var position = 0.0;
var startPt = { x: 120, y: 10 };
var controlPt = { x: 410, y: 250 };
var endPt = { x: 10, y: 450 };
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
function drawNextPoint() {
var pt = getQuadraticCurvePoint(
startPt.x,
startPt.y,
controlPt.x,
controlPt.y,
endPt.x,
endPt.y,
position,
);
position = (position + 0.006) % 1.0;
ctx.fillStyle = "rgba(255,0,0,0.5)";
ctx.fillRect(pt.x - 2, pt.y - 2, 5, 5);
}
ctx.strokeStyle = "black";
ctx.moveTo(startPt.x, startPt.y);
ctx.quadraticCurveTo(controlPt.x, controlPt.y, endPt.x, endPt.y);
ctx.stroke();
setInterval(drawNextPoint, 40);
<canvas id="c" width="500" height="500">
一种可能的方式:
// compute coordinates of the middle point of a quadratic Bezier curve
// need two functions: quadraticBezierCurvePoint and quadraticBezierCurvesMiddle
function quadraticBezierCurvePoint(t, c) {
// compute relative coordinates of a point on the curve using t and c
// t is a number between 0 and 1
// c is an array of 3 points:
// the initial point of the curve (always (0,0))
// the "handle" point of the curve
// the final point of the curve
var t1, t1_2a, t1_2b, t1_2c;
t1 = 1 - t;
t1_2a = t1 * t1;
t1_2b = (2 * t) * t1;
t1_2c = t * t;
return {
x: (c[0].x * t1_2a) + (t1_2b * c[1].x) + (t1_2c * c[2].x),
y: (c[0].y * t1_2a) + (t1_2b * c[1].y) + (t1_2c * c[2].y)
};
}
function quadraticBezierCurvesMiddle(m, c) {
var k, km = 1000,
km2 = (km >> 1),
len = 0,
len2, x, y, a = new Array(km + 1);
// compute curve lengths from start point to any point
// store relative point coordinates and corresponding length in array a
for (k = 0; k <= km; k++) {
a[k] = {
pt: quadraticBezierCurvePoint(k / km, c),
len: 0
};
if (k > 0) {
x = a[k].pt.x - a[k - 1].pt.x;
y = a[k].pt.y - a[k - 1].pt.y;
a[k].len = a[k - 1].len + Math.sqrt(x * x + y * y);
}
}
// retrieve the point which is at a distance of half the whole curve length from start point
// most of the time, this point is not the one at indice km2 in array a, but it is near it
len2 = a[km].len / 2;
if (a[km2].len > len2)
for (k = km2; k >= 0; k--) {
if (len2 >= a[k].len) break;
} else
for (k = km2; k <= km; k++) {
if (len2 <= a[k].len) break;
}
// return absolute coordinates of the point
return {
x: Math.round((a[k].pt.x + m.x) * 100) / 100,
y: Math.round((a[k].pt.y + m.y) * 100) / 100
};
}
以及对应的jsfiddle:jsfiddle.net/pTccL/