共计 1351 个字符,预计需要花费 4 分钟才能阅读完成。
3.4 贝塞尔曲线
canvas 提供了两个绘制贝塞尔曲线 api:
ctx.quadraticCurveTo(cpx, cpy, x, y);
二次贝塞尔曲线,(cpx, cpy)控制点 (x, y)终点
ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
三次贝塞尔曲线,(cp1x, cp1y)控制点一, (cp2x, cp2y)控制点二,(x, y)终点
题外话:
贝塞尔曲线的数学基础是早在 1912 年就广为人知的伯恩斯坦多项式。最早用来辅助汽车车体的工业设计。CSS3 的 transition-timing-function 属性,取值就可以设置为一个三次贝塞尔曲线方程 transition-timing-function: cubic-bezier(0.1, 0.7, 1.0, 0.1)。
canvas 绘图示例:
// 二次
ctx.moveTo(200, 100);
ctx.quadraticCurveTo(230, 250, 350, 200);
// 三次
ctx.moveTo(450, 250);
ctx.bezierCurveTo(530, 150, 650, 300, 700, 200);
蓝色是控制点
问题一:那 canvas 是如何通过控制点来绘制出曲线的,或者如果不用这个,自己绘制曲线该如何操作呢:
这个是 n 阶贝塞尔曲线的方程:
我们重点看二 (三) 阶方程:
B(t)是曲线上的点,t 在 0~1 之间取值,P0 起始点,P2 终点,P1 控制点 t 从 0~1 之间取值不断增大,B(t)不断取出曲线上的点,从 P0 移至 P1
const bx = (1-t)*(1-t)*start.x + 2*t*(1-t)*control.x + t*t*end.x;
const by = (1-t)*(1-t)*start.y + 2*t*(1-t)*control.y + t*t*end.y;
问题二:我咋知道控制点该怎么选,特别是起终点动态数据时(也就是说,我们使用时,往往只知道起点 P0 终点 P1):
这个根据曲线斜率,可视化需求可能选取的方式不一致,不过大致原理相似可以在起点和终点的垂直平分线上选一点作为控制点, 然后用一个参数来控制曲线的弯曲程度
// curveness 弯曲程度(0-1)
const cp = {
x: (start.x + end.x) / 2 – (start.y – end.y) * curveness,
y: (start.y + end.y) / 2 – (end.x – start.x) * curveness
};
题外话:
关于 cp 点的求解:线段中点:const mid = [( start.x + end.x) / 2, (start.y + end.y) / 2 ]; 根据起点和终点也可以得到一个向量 v: const v = [end.x – start.x, end.y- start.y]; 将这个向量顺时针旋转 90 度,得到一个垂直于它的向量 v2:const v2 = [v.y, -v.x]; 那么中间控制点的坐标为(向量 v2 乘 curveness 加上中间点坐标)const cp = {x: mid.x + v2.x curveness, y: mid.y + v2.y curveness} = {x:( start.x + end.x) / 2 – (start.y – end.y) * curveness, y:(start.y + end.y) / 2 – (end.x – start.x) * curveness}