揭祕 LogicFlow 的拓展機制

前言

自從 LogicFlow 正式開源後,受到的關注比咱們想象的要多。在最開始打算要作 LogicFlow 的時候,咱們花了不少的精力去討論要作一個什麼樣的流程可視化庫。其中一個選擇是基於現有的業務直接實現一個開箱即用,包括了全部的流程編輯庫經常使用功能的庫。可是最終仍是沒有選擇這樣作,由於咱們當時的背景是:不一樣的項目中,在流程圖的外觀、後臺所需數據格式都存在較大的差別。 有些項目用的是 activity, 有些是某些團隊自研的流程引擎。因此咱們須要作一個能支持各系統平滑遷移的流程可視化庫,須要這個庫足夠的靈活,視覺上也要知足個各系統本身的風格,並且最好是流程圖上的各類功能均可以自按需使用。javascript

基於插件化的拓展機制

配置化 or 插件化?

咱們對於如何將 LogicFlow 實現成一個足夠靈活的流程可視化庫存在兩種想法。一種是一切皆可配置,也就是配置化。這個是不少可視化庫的作法,最典型的就是 ECharts,用過 ECharts 的人應該都知道,它的配置功能特別豐富,幾乎能夠作到配置任何圖上的元素的效果,從而達到業務開發者須要的自定義效果。html

可是對於咱們來講,配置化爲了保持其提供足夠的靈活性,咱們須要在內部維護太多的 UI 相關的邏輯。以一個節點爲例:前端

LogicFlow1

若是是採用配置化的方式的話,開發者傳入的配置大體是:java

{
  type: 'rect',
  icon: 'https://example-icon.com/settings.png',
  text: '22\n33333',
}
複製代碼

咱們就須要在內部代碼中判斷傳入的參數是否有 icon,若是有,就在左上角顯示 icon。可是有的流程但願本身在左上角顯示的是文本,咱們可能就要再增長一個字段 nodeText 來控制了。那若是咱們想顯示一個圖標在右邊呢?想裏面顯示 3 列文本呢?node

總的來講,配置化雖然對業務開發者足夠友好,只須要文檔足夠完善,庫內部兼容的效果足夠多,就能夠達到很好的效果。可是對於咱們來講倒是須要付出很大的成本去實現各類效果,並且極可能由於一些其餘狀況,捨棄支持一些不經常使用的效果。從長遠來看,這種配置化方案對咱們來講仍是不夠靈活的。git

另外一種方案就是插件化,就是將不斷變化的非核心功能分散到插件中,避免其與核心代碼耦合,保持其核心部分代碼簡潔和穩定。在插件化方案下,咱們就能夠實現一個支持設置 icon 節點就行了,至於其它特殊需求的節點,就有用戶本身利用自定義機制來實現便可。並且開放到社區後,其它開發者自定義的內容也能夠當作一個插件,貢獻到 LogicFlow 中來。github

插件化會帶來不少好處:json

  1. 讓更多前端社區的人蔘與進來,即便插件部分寫的代碼存在問題,也不會影響核心代碼。
  2. 二次擴展開發,好比咱們計劃以後會在擴展包中實現一個 lf-bpmn 插件,使用此插件能夠兼容 bpmn2.0 規範的流程設計器。也能夠增長一個繪製 venn 圖的 lf-venn 插件,來實如今使用 LogicFlow 繪製 venn 圖。甚至之後能夠每種形態的流程圖編輯,咱們均可以實現一個對應的插件。
  3. 靈活的自定義功能,菜單、工具欄、畫板等都作成插件,開發者以爲不符合他們業務需求,則能夠不用這些插件而是改爲本身開發。

API 健全性&穩定性

什麼是插件?插件是在覈心程序上遵循其提供出來的接口規範再次編寫的出來的程序。插件是不能脫離核心程序單獨存在的,是一種對核心程序功能的擴展。因此我的以爲插件化最重要的一點就是核心程序的 API 健全性和穩定性。若是咱們的 API 不夠完善,社區開發者是沒法開發出符合其需求的插件;若是咱們的 API 變化很大,頗有可能致使以前開發的插件在咱們版本升級後就不能用了,會致使整個 LogicFlow 的社區生態混亂。微信

爲了保證 API 的健全性和穩定性,咱們作了這些事情:markdown

  1. 嚴格遵循開源版本規範。保障 LogicFlow 的發版對周邊生態影響的可控。
  2. API 變化的時候重點考慮向前兼容。
  3. 經過足夠多的內置插件來驗證 API 的健全性和穩定性。

內置插件

若是咱們只提供表示這圖編輯部分的@logicflow/core,那麼意味 LogicFlow 就是一個半成品,既不利於推廣,也不利於上手使用。因此咱們將 LogicFlow 將非核心功能例如菜單、工具欄等組件; 各種特點形態節點; 一些常見的流程實際應用場景等都採用插件的方式實現放到了@logicflow/extension包中。其中就有 bpmn-js 插件,這裏我大體介紹一下 LogicFlow 是如何如何利用插件機制,去實現兼容 bpmn-js 的插件。

  1. 首先是 bpmn-js 中的各類節點和連線,好比用戶節點(userTask)、判斷節點(gateWay)、順序流(sequenceFlow)等,咱們利用 LogicFlow 自定義節點和自定義連線機制, 將全部的 bpmn-js 須要的基礎圖形封裝成 BpmnElement 插件。
  2. LogicFlow 默認生成的數據格式是節點和邊組成的 json, 而 bpmn-js 須要生成的數據格式是知足 bpmn 2.0 標準的xml。因此咱們提供了一個 BpmnAdapter,在數據輸入到 LogicFlow 的時候將 bpmn xml 轉換爲 LogicFlow Data, 在輸出的時候又將 LogicFlow Data 轉換爲 bpmn xml.
  3. 最後咱們再把流程圖繪製過程當中須要用到的菜單、畫板、快捷工具等利用 LogicFlow 的自定義組件功能,封裝成 Bpmn Component 組件。
  4. 將上面的三個插件,一塊兒封裝爲 Bpmn 插件。

LogicFlow2

LogicFlow 自己只是一個單純的流程圖編輯器,不帶有業務屬性。爲了更好的易用性,咱們提供了 Bpmn-js 插件,讓使用 bpmn-js 的項目可以快速替換。有了 Bpmn 插件後,直接經過 LogicFlow 裝載 bpmn 插件,這個頁面就表現成爲 bpmn-js 了。

import LogicFlow from '@logicflow/core';
import { Bpmn } from '@logicflow/extension';

LogicFlow.use(Bpmn);
複製代碼

LogicFlow 的拓展能力

前面提到過,插件的擴展性是否強大,是看核心程序提供的 API 是否有足夠的擴展性。LogicFlow 在絕大多數 API 上的設計,其目標就是支持的拓展能力。咱們在@logicflow/extension中開發的插件,也是一種驗證咱們 API 的方式。從下圖能夠看到LogicFlow 在支持拓展能力上的總體思路。

LogicFlow3

自定義節點

爲了提升易用性,在節點方面,LogicFlow 內置了基礎節點,而後在@logicflow/extension中也實現了一些特殊節點。開發者在實際使用中,能夠基於這些基礎節點和特殊節點進行自定義知足其業務需求的節點。

  1. 基礎節點: 在@logicflow/core內部有一個 BaseNode 抽象類,這個類中實現了流程圖中節點所需的絕大部分邏輯,例如節點拖動、點擊等事件處理和連線處理等。同時也有獲取節點外觀屬性、獲取節點基礎屬性、獲取節點配置自定義屬性等能夠被子類重寫的方法。
  2. 內置節點:BaseNode 是抽象類,爲了易用性,咱們在 LogicFlow 中還內置了一些基礎圖形的節點。好比矩形(RectNode)、圓形(CircleNode)、菱形(DiamondNode)和多邊形(PolygonNode)。
  3. 擴展節點:爲了讓開發者在使用的減小接入成本,LogicFlow 除了在覈心包中提供了內置節點給與開發繼承自定義外,還在擴展包@logicflow/extension中提供了更多的節點。例如圓柱體(CylinderNode)、帶有圖標的矩形(RectIconNode)等。
  4. 自定義節點:開發者能夠在本身的項目中基於 LogicFlow 中的任何一種節點(包括@logicflow/extension中的節點),採用繼承重寫對應的方法,實現本身業務需求的節點。一樣,開發者本身自定義的節點也能夠成爲插件,開源到社區中。後續咱們會增長 LogicFlow 的插件市場,到時你們能夠自由選擇本身項目所需的節點。

LogicFlow4

自定義節點規則

在某些時候,咱們可能須要控制連線的鏈接方式,好比 A 節點不能做爲連線的起點、B 節點不能做爲連線的終點、C 節點後面必須是 A 節點等等。LogicFlow 提供了自定義節點規則功能來實現這個需求。

LogicFlow 內部有getConnectedSourceRulesgetConnectedTargetRules兩個公共方法,分別返回當前節點做爲連線開始點和做爲鏈接目標點時的校驗規則。當在面板上進行連線操做的時候,會判斷全部的規則是否經過,只有經過了才能鏈接。

class CnodeModel extends RectModel {
  /* ignore other code*/
  // 判斷這個節點的下一個節點是否符合自定義要求
  getConnectedSourceRules(): ConnectRule[] {
    const rules = super.getConnectedSourceRules();
    const gateWayOnlyAsTarget = {
      message: 'C節點下一個節點只能是A節點',
      validate: (source: BaseNode, target: BaseNode) => {
        let isValid = true;
        if (target.type !== 'a-node ') {
          isValid = false;
        }
        return isValid;
      },
    };
    rules.push(gateWayOnlyAsTarget);
    return rules;
  }
  // 判斷這個節點的上一個節點是否符合自定義要求
  getConnectedTargetRules() {}
}
複製代碼

自定義連線

自定義連線方案和自定義節點基本一致,由基礎連線實現線的絕大部分邏輯,而後在內置連線中實現連線的特殊交互處理,最後再由開發者基於內置連線進行自定義開發。固然,因爲絕大多數圖編輯上線的表現形式都只有直線、折線和曲線三種形式,因此通常開發者自定義連線都是改變一下樣式(顏色、虛線)和名字(如Bpmn中連線叫作bpmn:sequenceFlow)。

LogicFlow4

自定義屬性

通常來講,對於一個節點,咱們只須要typexytext就能夠完整的圖中的一個節點的全部可見信息了。type控制這個節點的類型,xy控制着節點所處的位置,text控制着節點上的文本。 可是在實際使用中,咱們可能須要將更多的帶有業務性質的屬性放到節點上,而後在基於這些業務屬性,在節點顯示的作出對應處理。例如在流程中,咱們須要將某些節點高亮,表示這些節點正處於異常狀態。

LogicFlow 中提供了一個properties字段用於開發者存放本身業務相關的屬性,而後能夠在自定義節點的時候,基於這些properties本身進行處理。

lf.register('custom-process', ({TriangleNode,TriangleModel }) => {
  class CustomProcessNode extends TriangleNode {
    static extendKey = 'CustomProcessNode';
    getShapeStyle() {
      const attributes = super.getShapeStyle();
      const properties = super.getProperties();
      // 判斷自定義屬性customStatus是否爲error,
      // 若是是,則將這個節點的填充顏色設置爲紅色。
      if (properties.customStatus === 'error') {
        attributes.fill = 'red'
      }
      return attributes;
    }
  }
  return {
    view: CustomProcessNode,
    model: PolygonNodeModel,
  };
});
複製代碼

上面的代碼自定義了一個 custom-process 節點,當傳入的數據中節點 type 爲 custom-process,節點屬性中 customStatus 爲 error 的時候,流程圖上顯示的就是一個紅色的三角形。

自定義組件

在 LogicFlow 中,除了節點和連線這種由 svg 渲染的圖形外,還存在着一些用於圖編輯過程當中進行控制的組件,這些組件 LogicFlow 是經過 html 來實現的(好比菜單、控制面板等)。LogicFlow 開放了在圖上插入 DOM 的能力,開發者就能夠基於這個能力來實現自定義組件。

有了在圖上自由插件 DOM 的能力,咱們就能夠作不少事情了,好比能夠實現一個自由調整節點顏色、字體大小的工具。這個工具的開發就只須要按照咱們正常前端開發便可。而後在監聽到用戶選中節點後,將這個 DOM 插入到節點對應的位置旁邊。

主題

上面咱們提到過能夠用自定義節點來定製任何節點的外觀,可是對每一個節點都單獨自定義一次太多麻煩。LogicFlow 提供了主題功能,來統一設置因此節點的外觀基礎屬性。好比咱們想讓全部的矩形都不帶邊框。

lf.setTheme({
  rect: {
    strokeWidth: 0
  },
})
複製代碼

主題除了能夠設置節點和連線的外觀之外,還能夠設置內部功能的樣式,好比文本、對齊線等。

最後

經過上面的介紹,你們對 LogicFlow 的拓展機制應該有了必定的瞭解。LogicFlow 自己不是一個專門處理某個場景的流程設計工具,而是一個流程圖編輯庫。大多數狀況下,拓展性強就意味着沒法開箱即用,爲了讓 LogicFlow 成爲一個開箱即用的庫,LogicFlow 採用了插件化的機制,經過插件,將場景限定到實際業務場景中來。

LogicFlow 仍是一個很新的開源項目,提供的插件還不夠豐富,也存在業務場景考慮不周的狀況,歡迎你們在 github 上提 issue,咱們必定會認真對待每個 issue!LogicFlow 也在尋找 contributor ,若是你感興趣的話,歡迎一塊兒來共建!

更多閱讀資料:

相關文章
相關標籤/搜索