天天看點

【bpmn.js 使用總結】三、自定義工具欄 Palette自定義 Palette

自定義 Palette

[了解 BPMN 内部】後,對一些子產品以及它們之間的配合應該有了一定的概念,下面開始動手嘗試修改一下

palette

工具欄

案例代碼在這裡取:

customPalette

開始

你可以實作

  • 通過配置生成工具欄
  • 自定義工具欄樣式、布局
  • 可指定工具欄容器

為了了解更簡單

  • 自定義工具欄樣式、布局 (非必須,後續實作)
  • 可指定工具欄容器(非必須,後續實作)

注意:标記 🎯 的地方為重點

1. 建立相關檔案

建立自定義工具欄的相關檔案,結構如下

| -- palette
    |-- CustomPaletteProvider.js
    |-- CustomPalette.js
    |-- index.js
           

PaletteProvider 顧名思義

”調色闆提供程式“

,也就是将工具欄的資料告訴

Palette

,由

Palette

構造工具欄。

是以我們需要先将代碼準備好,然後去修改它:

  • 前往 bpmn-js 将源碼 PaletteProvider.js 拷貝至 CustomPaletteProvider.js
  • 前往 diagram-js 将源碼 Palette.js 拷貝至 CustomPalette.js
  • 參考

    PaletteProvider.js

    Palette.js

    對應的

    index.js

    ,将剛剛建立的

    index.js

    ,修改成如下
import customPalette from './CustomPalette'
import PaletteProvider from './CustomPaletteProvider'
// 除了引進的子產品的名字可以修改,其他的不建議修改,會報錯
export default {
  __depends__: [
    {
      __init__: ['customPalette'],
      customPalette: ['type', customPalette]
    }
  ], // 依賴于 customPalette 這個子產品
  __init__: ['customPaletteProvider'], // 調用 customPaletteProvider 來初始化
  customPaletteProvider: ['type', PaletteProvider]
}
           

到此三個檔案已經準備就緒了,下面我們來引用它。

2. 引用

引入剛剛建立的檔案

export default {
  // ...
  init() {
    this.bpmnModeler = new BpmnModeler({
      additionalModules: [customPalette]
    })
    // ...
  }
}
           

到此,目前頁面應該是正常顯示的,因為我們隻是将檔案拷貝出來,修改引用,友善後續的修改。

3. 修改工具欄構造者 CustomPalette

修改

CustomPalette.js

檔案

首先老規則,修改注入需要用的資料

Palette.$inject = [
  'eventBus',
  'canvas',
  // ---------- 自定義區域 ------------
  'elementFactory',
  'create',
  'config.paletteContainer',
  'config.paletteEntries'
  // ---------- 自定義區域 ------------
]
           

預設隻注入了兩個,其餘根據需要來增加。

下面将注入的資料指派

function Palette(
  eventBus,
  canvas,

  elementFactory,
  create,
  paletteContainer,
  paletteEntries
) {
  this._eventBus = eventBus
  this._canvas = canvas
  // 新增指派
  this._entries = paletteEntries // 傳入的工具欄資料
  this._paletteContainer = paletteContainer // 傳入的工具欄容器
  this._elementFactory = elementFactory
  this._create = create
  // ...
}
           

然後就可以在這個函數中資料注入的資料了,

注意注入順序和函數參數的順序要一緻哦~

到此,一個資料以及布局已經準備完畢,接下來該實作它的

拖動或者點選生成元素

的功能了

Palette.prototype.trigger = function(action, event, autoActivate) {
  var entries = this._entries,
    entry,
    handler,
    originalEvent,
    button = event.delegateTarget || event.target

  // ---------- 自定義區域 ------------
  // 建立元素的方法需要這兩個構造器
  var elementFactory = this._elementFactory,
    create = this._create
  // ---------- 自定義區域 ------------

  handler = entry.action

  originalEvent = event.originalEvent || event

  // simple action (via callback function)
  if (isFunction(handler)) {
    if (action === 'click') {
      handler(originalEvent, autoActivate, elementFactory, create)
    }
  } else {
    // ---------- 自定義區域 ------------
    if (handler[action]) {
      // 在原來 2 個參數的基礎上,新增 2 個參數 elementFactory, create
      handler[action](originalEvent, autoActivate, elementFactory, create) // 🎯 這裡便是回調 action.dragstart 或者click 或者 其他事件
    }
    // ---------- 自定義區域 ------------
  }

  event.preventDefault()
}
           

init

的時候綁定了兩個事件,當我們點選或在拖動工具欄的時候觸發,進而可以生成元素。

CustomPalette.js

至此基本修改完成了。

4. 修改資料的提供者 PaletteProvider

現在開始修改

PaletteProvider.js

檔案

修改前,可以先看一下

PaletteProvider.prototype.getPaletteEntries

這個方法

源碼是在這個方法中将預設工具欄資料傳入給

palette.js

可以學習一下他是如何構造工具欄資料的,後面會用到。

如下代碼實作了一條分割線和三個事件

// l
'global-connect-tool': {
  group: 'tools',
  className: 'bpmn-icon-connection-multi',
  title: translate('Activate the global connect tool'),
  action: {
    click: function (event) {
      globalConnect.toggle(event)
    }
  }
},
// 2
'tool-separator': {
  group: 'tools',
  separator: true
},
// 3
'create.start-event': createAction(
  'bpmn:StartEvent', 'event', 'bpmn-icon-start-event-none',
  translate('Create StartEvent')
),
// 4
'create.intermediate-event': createAction(
  'bpmn:IntermediateThrowEvent', 'event', 'bpmn-icon-intermediate-event-none',
  translate('Create Intermediate/Boundary Event')
)
           
【bpmn.js 使用總結】三、自定義工具欄 Palette自定義 Palette

因為我們的目的是希望有一個獨立的檔案來配置工具欄,而不是在源碼中,是以我們開始簡化這個 getPaletteEntries 如下:

// 注意: 可以通過 config這個對象拿到 執行個體化 Modeler 的時候的參數
// 是以這裡通過注入 congif.paletteEntries 拿到 paletteEntries 的值
// 後續會介紹如何傳入
PaletteProvider.$inject = ['config.paletteEntries', 'customPalette']

export default function PaletteProvider(paletteEntries, customPalette) {
  this._entries = paletteEntries

  customPalette.registerProvider(this)
}

PaletteProvider.prototype.getPaletteEntries = function(element) {
  return this._entries // 🎯 傳回工具欄資料
}
           

5. 配置工具欄 paletteEntries

同級目錄下建立

config/paletteEntries.js

,

paletteEntries.js

的目的是傳回一個包含工具資料的集合(對象或數組)

這裡簡單建立兩個工具元素,

開始和結束

export default {
  'create.start-event': createAction(
    'bpmn:StartEvent',
    'event',
    'bpmn-icon-start-event-none',
    'Create StartEvent'
  ),
  'create.task': createAction(
    'bpmn:Task',
    'activity',
    'bpmn-icon-task',
    'Create Task'
  )
}

function createAction(type, group, className, title, options) {
  // 還記得 CustomPalette.js 嗎?便是這裡回調 createListener 函數
  // if (action === 'click') {
  // 		handler(originalEvent, autoActivate, elementFactory, create)
  // 	}
  function createListener(event, autoActivate, elementFactory, create) {
    var shape = elementFactory.createShape({ type })

    create.start(event, shape)
  }

  return {
    group: group,
    className: className,
    title: title,
    action: {
      dragstart: createListener,
      click: createListener
    }
  }
}
           

然後再做兩件事,

引入工具欄配置

去除預設工具欄

export default {
  // ...
  init() {
    // // 去除預設工具欄
    const modules = Modeler.prototype._modules
    const index = modules.findIndex(it => it.paletteProvider)
    modules.splice(index, 1)

    this.bpmnModeler = new BpmnModeler({
      paletteEntries,
      additionalModules: [customPalette]
    })
    // ...
  }
}
           

效果如下:

【bpmn.js 使用總結】三、自定義工具欄 Palette自定義 Palette

6. 修改樣式

bpmn:Task

使用了字型圖示

bpmn-icon-task

下面我們修改它,換成 img。

修改

paletteEntries.js

export default {
  'create.task': createAction(
    'bpmn:Task',
    'activity',
    'bpmn-icon-task-custom', // 🙋‍♂️ 使用圖檔後,記得修改成自己的類名
    'Create Task',
    require('./img/task.png') // 📌
  )
}

function createAction(type, group, className, title, imageUrl) {
  // ...

  return {
    group: group,
    className: className,
    title: title,
    imageUrl, // 📌
    action: {
      dragstart: createListener,
      click: createListener
    }
  }
}
           
【bpmn.js 使用總結】三、自定義工具欄 Palette自定義 Palette

最後

一切大功告成,你将擁有一個全新的工具欄。

突然,你發現通過工具欄生成的元素還保持着

最初

的樣子。

無需擔心,因為我們還沒告訴

bpmn

該怎麼渲染它

點選了解如何自定義渲染 customRenderer

相關

可能對你有幫助的官方資源:

  • bpmn-js-example-custom-elements

目錄:

  • 基礎使用
  • 了解 BPMN 内部
  • 自定義 Palette
  • 自定義 Palette => 指定 Palette 容器
  • 自定義 Renderer
  • 自定義 contextPad
  • 自定義連線和箭頭的顔色
  • 自定義規則
  • 自定義 properties-panel
  • 右上角小地圖
  • 總結常用 API 🚩
  • 為 Viewer 添加一些功能
  • bpmn-camunda DEMO