流程圖——正交連線的算法的一種簡單實現

起源

要用svg作一個流程圖相似visio的連線,以下圖的git

其實有不少庫已經實現了流程圖,好比 jointjs,gojs,jsplumb 等等。惋惜都不是免費的。github

分析

若是要作的簡單呢,就用貝塞爾曲線就行了,只須要提供起點終點兩個點的座標,就能用簡單的算法生成一個svg 的path了。這樣算法網上應該找獲得。算法

可是若是要用正交連線來實現,這個複雜度就上升了幾個檔次。咱們來看看正交連線的多個狀況:jsp

假設起點往下,目標節點在起始節點的右下方,那麼可能存在的狀況一共有四種。考慮到目標節點相對起始節點的方位有四種可能,那麼全部連線的可能有4*4=16 種,再考慮到起點出發方向也有四種,那麼全部的可能性有16 *4 = 64種。也就是說,若是你要用if else 來寫,須要寫64個分支。svg

怎麼辦

固然沒必要寫64個if else ,寫程序不就是要抽象出規律嘛! 將這個連線分紅這麼幾個部分:性能

那麼這個連線規律在哪裏?有的狀況它轉了一個彎,有的狀況它又轉了兩個彎,這個規律太難找了。下圖舉了兩個例子,一樣是終點相對於起點在左上角,第一種狀況是轉了兩個彎,第二種狀況是轉了一個彎。

可是,我用了十八牛二虎之力找到了它的規律。spa

真相

這個連線的最終走向與這幾個條件有關:3d

  1. 起點的出發方向
  2. 終點的進入方向
  3. 終點相對於起點的方向
  4. 起點開始的最小延伸線
  5. 終點進入前的最小延伸線 (看下圖)

6. 正交線的轉折時機(我實際在作的時候,是用了中點轉折)

實現思路

  1. 由於使用svg 的path 來畫正交線。核心點是要找到轉折點的座標(其實用什麼都同樣)。
  2. 先獲取起點到終點的向量(下文稱爲直接向量),以及兩個正交向量(下文稱爲 直接向量的水平向量和豎直向量)
    3.開始計算正交線了,先要獲取到正交線的起始方向。能夠看到:起點方向和直接方向的豎直向量 方向相反,正交線沒有必要往下走,所以正交線的起始必定是水平的。事實上咱們並不知道豎直和水平的具體狀況,在實際操做中是這樣的:先從直接向量的水平向量和豎直向量中找到與起點方向平行的向量,再判斷是否同向,若是是同向,則正交線的起始方向與起點方向同向,若是不是則取另外一個垂直方向。
判斷平行: x0 * y1-x1 * y0 === 0;
判斷是否同公式,向量夾角爲0度,則向量點積爲1:x0 * y0 + x1 * y1 === 1
複製代碼
  1. 而後要獲取正交線的最終方向。也是同樣的思路,若是終點的進入方向與直接方向相反則取垂直方向,若是相同則取同向
  2. 獲得了正交線起始方向和最終方向,如今須要獲取正交線中間轉彎的狀況。判斷這正交線起始方向和最終方向是否同向,若是同向,則須要轉兩個彎,若是不是同向,則只需轉一個彎。

若是 正交線起始方向 == 正交線最終方向
那麼 轉彎數 = 2
不然 轉彎數 = 1
複製代碼
  1. 若是轉一個彎,那麼獲取轉彎的座標點

轉彎的座標點 = 正交線的第一個點 + 正交線起始方向向量
複製代碼

若是轉兩個彎,先獲取第一個轉彎點,既正交線始末方向的中點code

第一個轉彎點= 正交線的第一個點 + 正交線起始方向向量 * 0.5
複製代碼

再獲取第二個轉彎點 ,cdn

非起始方向向量 = 從直接向量的水平向量和豎直向量 中取出與起始方向向量垂直的那個向量
第二個轉彎點 = 第一個轉彎點 + 非起始方向向量
複製代碼
  1. 最終生成全部點的座標集合

全部點的座標集合 = [起點,正交線的起點,...正交線的轉彎點,正交線的終點,終點]
複製代碼

總結

這個算法的計算量不是很大,性能ok,適合邊拖曳邊重繪。但不是尋路算法,意味着沒有避讓節點的功能。

下一步要用曼哈頓算法來作一個。

這個demo拿去玩

desdesdesgo.github.io/flow-connec…

生成點的算法 github.com/Desdesdesgo…

相關文章
相關標籤/搜索