滴滴開源 LogicFlow:專注流程可視化的前端框架

桔妹導讀:LogicFlow 脫胎於滴滴技術團隊在客服業務下的實踐,是由滴滴智能中臺體驗平臺研發的一款流程可視化的前端框架,提供了一系列流程圖交互、編輯所必需的功能和靈活的節點自定義、插件等拓展能力,方便我們快速在業務系統內滿足類流程圖編輯器的需求。目前,LogicFlow 已經在公司內外不同用戶的流程配置需求中得到了驗證。



1. 
背景

首先,滴滴智能中臺體驗平臺技術團隊幾乎支持了滴滴所有業務板塊客服系統的訴求,面對多樣性、邏輯變更快的業務場景,傳統的面向場景編程成本高且週期長。因此我們建設了線上配置化的運營系統,讓運營、產品同學能夠通過畫流程圖的方式變更線上的業務邏輯,比如用戶電話進線時的互動式語音應答、人工客服在處理用戶進線時的標準作業流程、用戶自助解決問題的 H5 頁面配置系統等千人千面的應用場景。


其次,各業務系統雖然都需要應用流程可視化技術,但需求各不相同。有的對流程圖的要求比較簡單,圖的數據格式也簡單,而有的需要按照 BPMN 的規範來繪製流程圖,對於定製化的要求較高。我們調研了市面上相關的框架 (BPMN.js、X6、Jsplumb、G6-editor),均存在不滿足的場景,技術棧統一的成本很高。具體表現在:


  • BMPN.js、Jsplumb 的拓展能力不足,自定義節點支持成本很高;只能全量引入,各系統無法按需引入;

  • 與後端配套的流程引擎適配,成本較高。均不支持數據轉換、不支持流程的校驗等業務定製需求;

  • 文檔、示例不健全。X6 和 BPMN 的文檔不健全,示例少(2020 初調研結論)。


因此,我們在 2020 上半年開啓了 LogicFlow 的項目,支持各系統的流程可視化需求。

 


2. 
LogicFlow 的能力和特性
LogicFlow 當前已具備了哪些能力呢,我會分兩部分來介紹:

1.  快速搭建流程圖編輯器

提供了一個流程圖編輯所必需的各項能力,這也是 LogicFlow 的基礎能力:


  • 圖的繪製能力。基於 SVG 來繪製形狀各異的節點和線,並提供了基礎的節點(矩形、圓形、多邊形等)和線(直線、折線、曲線);

  • 圖的交互。根據節點、線、圖的各類鼠標事件(hover、點擊、拖拽等)做出反應。比如節點拖拽、拖拽創建連線、線的調整、雙擊節點編輯文本等;

  • 提升編輯效率的能力。提供網格、對齊線,上一步、下一步,鍵盤快捷鍵,圖放大縮小等配套能力,幫助用戶提升編輯效率;

  • 提供了豐富的 API 。宿主研發通過 API 傳參調用和監聽事件的方式,與 LogicFlow 完成交互。


通過以上能力,前端研發可以低成本、快速的搭建起流程可視化的應用,提供流暢的產品交互。下面是通過 LogicFlow 內置的節點和配套能力,做的流程圖示例:



2. 基於業務場景拓展

當基礎能力無法滿足業務需求的時候,便需要基於業務場景拓展。這也是 LogicFlow 能支持客服側多個系統的核心能力。


  • 設置圖上所有元素的樣式。比如各種節點、線、錨點、箭頭、對齊線的大小顏色等,滿足對前端樣式調整的需求;

  • API 拓展。支持在 LogicFlow 上註冊自定義的方法,比如通過 API 拓展提供圖片下載的方法;

  • 自定義節點、線。內置的矩形、圓形等圖形類節點往往無法滿足實際的業務需求,需要定義具有業務意義的節點。LogicFlow 提供了 的方式讓用戶定製具有自定義圖形、業務數據的節點,比如流程審批場景中的 “審批” 節點;

  • 拓展組件。LogicFlow 在 SVG 圖層上提供了 HTML 層和一系列座標轉換邏輯,並支持在 HTML 層註冊組件。宿主研發可以通過 LogicFlow 的 API,基於任何 View 框架開發組件,比如節點的右鍵菜單、控制面板等;

  • 數據轉換 adapter。LogicFlow 默認導出的圖數據不一定適合所有業務,此時可以通過 adapter API,在圖數據從 LogicFlow 輸入、輸出的時候做自定義轉換,比如轉換成 BPMN 規範的圖數據;

  • 內置部分拓展能力。基於上述拓展能力,我們還單獨提供了 extension 包,用來存放客服業務下沉澱出的具有通用性的節點、組件等,比如面向 BPMN 規範的節點和數據 adapter,默認菜單。注意 extension 可以單獨安裝,並支持按需引入 。


基於上述拓展的能力,前端研發能夠根據實際業務場景的需求,靈活的開發出所需的節點、組件等。下面有兩個基於 LogicFlow 拓展能力做出的流程圖:


BPMN

審批流程


3. 定位對比


上圖是通過橫縱兩個維度來對比目前大家耳熟能詳的幾個開源框架,以瞭解 LogicFlow 的定位。橫軸是該框架在圖可視化能力的豐富程度,縱軸越靠上則代表這個框架在業務流程應用上的成熟度越高,初次部署的開發成本越低。讓我們分別來介紹一下這幾個框架:


  • activiti 作爲工作流引擎提供了前後端的解決方案,簡單二次開發就可以部署一套業務流程的管理平臺;

  • Bpmn.js:基於 BPMN2.0 規範,設計的流程圖編輯器;

  • G6:antv 旗下專注圖形可視化,各類分析類圖表。比如生態樹、腦圖、輻射圖、縮進圖等等;

  • X6:圖編輯引擎,核心能力是節點、連線和畫布。不僅支持了流程圖,還有 Dag 圖、ER 圖。


LogicFlow 的定位在上圖的 Bpmn.js 和 X6 之間,填補中間的空白。核心提供了流程圖的編輯器,並且通過拓展能力來支持 BPMN 等規範所需的流程節點和數據格式,以滿足當前業務下的現狀。



3. 
實現原理和架構
1.  整體架構圖


核心包 @logicflow/core 提供了流程圖編輯器基礎的能力,右邊的 @logicflow/extension 是基於 @logicflow/core 的拓展性開發的插件。

2.  流程圖編輯器的設計方案

主要介紹一下實現流程圖編輯器重要的選型和方案設計:

2.1 圖渲染方案

前端繪製圖形無非就是 HTML + CSS、Canvas、Svg 三種方式,我們綜合做了一下對比,列出了相應的優劣勢:


在流程圖的場景下,不需要渲染大量的節點(最多幾千個元素),對於動畫的訴求也不高。Svg 基於 DOM 的特性會更適合我們,一個是學習成本和開發成本更低,另一個是基於 DOM 可以做的拓展也更多。不過 Svg 標籤內部並不支持插入其他比如 div 這種標籤,所以在實現某些功能的時候,都需要結合其他 HTML 標籤。


所以最終我們選擇使用 HTML + Svg 來完成圖的渲染,Svg 負責圖形、線的部分,HTML 來實現文本、菜單、背景等圖層。


2.2 模塊抽象


基於上述方案,下一步我們要做的是對實現一張流程圖做分類和抽象。



通過上圖:


  • 我們構建了多個圖層來承擔不同的職責,以方便實現功能和能力拓展。最上層的是 Svg 圖層,所有圖形(節點、線、對齊線、outLine 等)均在 Svg 上渲染,也負責監聽圖上的各種事件。Svg 下層的分別是組件層,負責拓展 UI 組件;Grid 層,負責渲染網格;背景層,添加自定義的背景;

  • Shape 的職責主要是基於 Svg 對圖形渲染的封裝,提供默認樣式、把用戶傳入的屬性做轉換等,主要包含 Rect、Circle、Ellipse、Polygon、Path、PolyLine、Text 等,方便 LogicFlow 內部複用,比如圓形節點和錨點都需要 Circle;

  • 基於 Shape,還實現了很多小元素,比如節點和線需要的錨點,比如線上的箭頭等等;

  • 而 BaseNode、BaseEdge 則是節點和線通用能力的封裝,聚合 shape、錨點、文本,還封裝了對事件和樣式的處理等。通過繼承 BaseNode,傳入 shape 我們可以得到 RectNode、CircleNode 等可渲染的節點。


因爲流程圖是富交互或者說是重編輯的,有了這幾個基礎的模塊,接下來要做的就是富交互的方案設計,即用戶在圖上做的任何操作都要給出響應。比如我觸發一個節點的拖拽,那關聯的線可能需要跟着動,還能識別出在某個水平線上有沒有其他節點(對齊線)。


2.3 MVVM + Virtual DOM


首先我們考慮到整個圖編輯器具備很多狀態存儲,並且要實現編輯圖上各模塊的響應就必須要有狀態的通信能力。第二如果要實現類似 redo/undo 這類功能,那整個圖就一定需要根據數據得出渲染,即 fn(state) => View ,比較好的方式就是通過 Model 來驅動 View。


最終我們選擇基於 MVVM,這個廣泛被應用於當前前端工程中的設計模式來構建 LogicFlow 的圖編輯器,定義圖的 View 和 Model 層,使工程代碼具備一定的解耦。與此同時,引入 Mobx 來實現我們的狀態管理、數據響應的能力,一張圖基於一份 Model 做狀態的通信。此外,考慮 Mobx 的另一個原因是:只要我想,那就可以做到最細顆粒度的數據綁定(觀測),可以減少沒必要的渲染。


以下是 LogicFlow 圖編輯器的 MVVM 示意圖:



通過上圖可以看到,View 層(圖、節點等)通過數據綁定,會在 Model 發生變化之後做出響應/更新。前面我們提到了關於圖的渲染我們是基於 Svg + HTML 實現的,那要做 View 層的更新無非就是命令式和聲明式兩個選擇:


  • 命令式。比如 jQuery 的 api,$('.rectNode').attrs({x: 1, y: 2}),像這種方式操作 DOM 代碼其實比較繁瑣,在重交互的場景下寫的代碼會比較冗餘。雖然我們最終找到了有一個庫能夠很方便的支持通過命令式的方式來繪圖 —— antv/g。

  • 聲明式。比如 React/Vue 這類 View 框架,其中一個比較核心的能力就是做到了 state => UI ,通過聲明式的方式來構建 DOM,只要狀態發生變化,那 UI 就更新。


除了考慮到命令式在操作 DOM 的場景下寫代碼會比較繁瑣之外,還有一個原因就是操作 DOM 的成本問題,在基於 State 更新 UI 的設計下,我們自然而然想到了引入 Virtual DOM 來解決某些場景下的更新效率,這也可以一定程度上彌補「基於 Svg 渲染圖形」可能造成的渲染性能問題。


總之,選擇 MVVM 的設計模式並引入 Virtual DOM,最根本的兩個原因是:


  • 提升我們圖編輯器場景下的開發效率。

  • 以及在 HTML + Svg 的圖渲染方案下,可以追求更好的性能表現。


我們與 X6 做了一次渲染時的性能比較,在相同的運行環境下,分別測出 LogicFlow 和 X6 在不同量級的節點/線下,渲染出流程圖的時間,理論上渲染時間越短,性能表現約好。




通過上述表格,我們測算出 LogicFlow 在初始渲染速度上是優於 X6 的,並且這還沒有開啓LogicFlow  的按需加載功能,也驗證了我們的技術選型。你也可以在示例頁進行測試:

https://yhlchao.github.io/LF-VS-Other/


2.4 事件系統


介紹了在 “狀態” 和 “響應” 我們做的設計,那要收集到用戶的各類 “操作” 並及時上報和冒泡,就需要一套事件系統。最主要的就是複用和統一上報。



複用即怎麼保證所有節點和線都能具備默認的事件回調,以及針對複雜事件(拖拽)的處理邏輯如何共用。


  • Behavior。針對複雜事件的處理,我們做了 function 和 class 形式的封裝,比如 Drag 是通過 mousemove、down、up 來模擬 h5 的 dragEnter、dragOver、dragEnd 和 drop 事件,DnD 則是通過抽象 dragsource 和 droptarget 兩個實體來實現 drag 和 drop 的交互,比如拖拽創建節點;

  • 在前文模塊抽象章節提到了內部有 BaseNode 和 BaseEdge 這樣的抽象,內置節點和自定義的節點都通過繼承基類來獲得通用的能力,所以 LogicFlow 內部默認的事件回調實際是通過繼承來複用的;

  • EventCenter。通過事件總線做統一上報,把內部捕獲到的所有用戶行爲事件,按照一定的規範和格式 emit(ev, args) 都上報到 EventCenter,最終冒泡到 LogicFlow 類,由 LogicFlow 類統一跟宿主交互。此外,圖編輯器內任何地方也都可以通過 EventCenter 做事件的觸發和監聽。


2.5 工具中心

工具中心的定位是解決某類特定問題的 utils,比如上面提到的 Behavior(複雜事件的封裝) 和 EventCenter。此外,在圖編輯的過程中,如果要實現比較好的交互效果,實際有很多複雜的計算邏輯要處理。


  • 座標系。瀏覽器的 clientX、clientY 座標系,以及 Svg 圖本身的座標系,當出現圖的縮放和平移的時候,兩個座標系是不同的,在事件處理的時候就需要做兩個座標系的轉換。

  • Algorithm。是專門通過幾何、算法來處理可視化的一些問題。比如:當一個節點在同一方向有多條折線連出的時候,如何做路徑的合併以展示起來更美觀,如下:



如何計算出一根線到一個圖形的切點,以達到線可以連接圖形非錨點的位置,如下圖:



  • History。主要提供 redo 和 undo 的能力。通過兩個棧來存儲 undos 和 redos,並限制最大長度,得益於 MVVM 的設計模式,能方便的做數據變化的觀測和 Model 驅動 View。


3. 可擴展性


介紹完流程圖編輯器的設計方案,現在來介紹 LogicFlow 的另一個重要特性,關於拓展性方面的設計。對於 LogicFlow,是解決某個領域問題的開發框架,首先 API 要具備可擴展性;此外 LogicFlow 還提供了視圖層,在 View 部分應該能夠讓用戶做二次開發。這兩個擴展的方向確定之後,最主要的還是結合業務需求,要能滿足當前和未來一段時間內預見的業務場景,但也不能過度設計。


3.1 API 上的設計


首先,LogicFlow 在面向用戶使用這一層,完全是基於面向對象的設計模式封裝的,最大的好處是幾乎每個程序員都熟悉它的使用,使用成本低。通過下面初始化方式便可以瞭解。



通過 class LogicFlow,用戶實例化一次便得到一個流程圖的實例,狀態也是私有的,各種使用方法通過 lf 的實例調用即可。


關於 API 拓展的設計總結來看:


  • 面向對象的設計模式, LogicFlow 內部做好封裝,用戶可以做繼承、重寫接口/方法;

  • 方法的設計。首先是要有固定類型的輸入和輸出。此外,LogicFlow 也提供了類似於 extends 的方法,通過  LogicFlow.use(fn) 在原型上拓展方法;

  • 通過觀察者的模式做通信,即提供 on 方法供宿主訂閱各類內部事件;

  • 圖的數據可定製。無論是一個節點、線有哪些自定義的業務屬性,還是流程圖要導出什麼樣的數據,都應該能夠定製。


3.2 插件化


View 層的拓展性,除了用戶能夠定製展現方式之外,最重要的是插件化,因爲在流程可視化這條路上,不同的業務場景下需要的能力不盡相同,LogicFlow 很難做到支持所有的場景,所以提供好的插拔能力,讓用戶二次開發是比較好的選擇。前,在 UI 界面上,我們開放了兩個能力:


  • 節點和線支持二次開發,即自定義節點、線。

  • 可開發 UI 組件註冊到 LogicFlow 的組件畫布內。


基於插件化的思路,我們已經支持了不同的業務系統,並在這個過程中把一些稍微通用的能力沉澱出來,並封裝到 lf-extension 包,比如用來支持 BPMN 規範的節點。目前 extension 內的拓展主要分了四類:UI 組件、自定義節點、API、adapter。



4. 
未來規劃

首先是API 的易用性和豐富程度。具體的功能 scope 除了我們當前的迭代計劃(詳見 github 倉庫的 project),還會根據用戶的需求排出優先級後加入進來,也希望大家多多提意見和需求。這個方向的基調是保持 LogicFlow 流程可視化的定位,把 core 的 API 豐富,extension 的能力增強。


其次是更完善的文檔和示例。主要是文檔易讀、完善,能夠有完整的示例和代碼,供開發者 copy paste 代碼,目前示例只有 react 版,2021.4 之前會增加 vue 版的示例。


最後,不僅是流程可視化庫,更期望提供整套解決方案。LogicFlow 只解決了前端流程圖編輯的技術問題,但關於圖數據的定義,流程最終如何被執行,還需要一個配套的流程引擎。


目前,關於「流程引擎」我們團隊也有相應的解決方案 —— turbo(Java 版已開源:https://github.com/didi/turbo),我們會把 LogicFlow 和 turbo 做成端到端的解決方案,並提供完整的應用示例。此外,Nodejs 版的引擎也在規劃中,大家拭目以待。



5. 
寫在最後

通過本文相信你對 LogicFlow 已經有一個大概的認識了,如果在你負責的業務中也有流程可視化的訴求,並且有較高的拓展性需求,那 LogicFlow 會是一個好的選擇。對於 LogicFlow 技術本身的實現細節、對於相似業務的探討也都歡迎大家來交流。們後續會有更多的文章介紹 LogicFlow 在技術設計細節以及我們對於可視化、業務流程、邏輯編排等領域的一些思考,盡情期待。


LogicFlow 官方網站:http://logic-flow.org/

github 倉庫地址:https://github.com/didi/LogicFlow


開源團隊

 

延伸閱讀


   
   
   

內容編輯 | Mango
聯繫我們 | [email protected]

本文分享自微信公衆號 - 滴滴技術(didi_tech)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章