canvas提供了兩個繪製貝塞爾曲線api:canvas
- ctx.quadraticCurveTo(cpx, cpy, x, y);
二次貝塞爾曲線,(cpx, cpy)控制點 (x, y)終點api
- ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
三次貝塞爾曲線,(cp1x, cp1y)控制點一, (cp2x, cp2y)控制點二, (x, y)終點spa
題外話:設計
貝塞爾曲線的數學基礎是早在 1912 年就廣爲人知的伯恩斯坦多項式。最先用來輔助汽車車體的工業設計。
CSS3的transition-timing-function屬性,取值就能夠設置爲一個三次貝塞爾曲線方程transition-timing-function: cubic-bezier(0.1, 0.7, 1.0, 0.1)
。
canvas繪圖示例:code
// 二次 ctx.moveTo(200, 100); ctx.quadraticCurveTo(230, 250, 350, 200); // 三次 ctx.moveTo(450, 250); ctx.bezierCurveTo(530, 150, 650, 300, 700, 200);
藍色是控制點ip
問題一:
那canvas是如何經過控制點來繪製出曲線的,或者若是不用這個,本身繪製曲線該如何操做呢:數學
這個是n階貝塞爾曲線的方程:it
咱們重點看二(三)階方程:io
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):function
這個根據曲線斜率,可視化需求可能選取的方式不一致,不過大體原理類似
能夠在起點和終點的垂直平分線
上選一點做爲控制點
, 而後用一個參數來控制曲線的彎曲程度
// 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}