有个需求要实现两点间多条连线,效果以下:git
这里的曲线能够直接经过二阶贝塞尔曲线来实现,曲线的控制点在两点连线的垂直线上,从直觉上我第一个想到的解法是要用到三角函数,因而就开始了如下推理过程github
弧度 = 角度 * Math.PI / 180
角度 = 弧度 * 180 / Math.PI
Math.atan2(y, x): 返回从 点 (x,y) 到 x轴 的弧度
Math.cos(弧度): 直角三角形中,相邻直角边/斜边 的值
Math.sin(弧度): 直角三角形中,相对直角边/斜边 的值
二阶贝塞尔曲线:由两个数据点(A 和 B),一个控制点(C)来描述曲线状态
复制代码
目标:假定控制点 C
到 A
B
连线中点的距离是固定的 10
, 计算出红色直角三角形的两个直角边的长度算法
Math.atan2(y, x)
计算 A(x0, y0)
点到 B(x1, y1)
点的连线与 X
轴的弧度,这里须要用 y1-y0
获得 y
值,x1-x0
获得 x
值,它的做用如图上的蓝色线,能够理解为把 x
y
轴平移到 A
点,经过计算获得了 角1
的弧度 h
角1
=== 角2
角2
的相对直角边长度:L1 = Math.sin(h) * 10
角2
的相邻直角边长度:L2 = Math.cos(h) * 10
A
B
连线中点坐标的计算方式 mx = (x0+x1)/2
my = (y0+y1)/2
C
的坐标最终为 cx = mx + L1
cy = mx - L2
function getXY(a, b, distance) {
const y = b.y - a.y;
const x = b.x - a.x;
const radian = Math.atan2(y, x);
const L1 = Math.sin(radian) * distance;
const L2 = Math.cos(radian) * distance;
const mx = (a.x + b.x)/2;
const my = (a.y + b.y)/2;
const cx = mx + L1;
const cy = mx - L2;
return { x: cx, y: cy };
}
const A = { x: 10, y: 30 };
const B = { x: 300, y: 200 };
const C = getXY(A, B, 10);
复制代码
按本身的想法写完以后,我在 Echarts
的源码中中看到了这种曲线的另一种超简单的算法apache
var x2 = (x0 + x1) / 2 - (y0 - y1) * 系数;
var y2 = (y0 + y1) / 2 - (x1 - x0) * 系数;
复制代码
简单的分析了一下,仍是经过三角形的方法,能够判断 C
的坐标能够和 A
B
点坐标差值产生关联,在不一样的系数下能够获得全部中垂线上的点坐标bash
以上是从结果推算出来的结论,但它背后对应的公式原理,还不是很明白,但愿能有掘友提供一些思路echarts
I'm Gafish 原创文章,首发于 个人博客,内容若有错误,还望指正,谢谢您的阅读。svg