Q: bpmn.js是什麼? 🤔️javascript
」
bpmn.js是一個BPMN2.0渲染工具包和web建模器, 使得畫流程圖的功能在前端來完成.css
Q: 我爲何要寫該系列的教材? 🤔️html
」
由於公司業務的須要於是要在項目中使用到bpmn.js
,可是因爲bpmn.js
的開發者是國外友人, 所以國內對這方面的教材不多, 也沒有詳細的文檔. 因此不少使用方式不少坑都得本身去找.在將其琢磨完以後, 決定寫一系列關於它的教材來幫助更多bpmn.js
的使用者或者是期於找到一種好的繪製流程圖的開發者. 同時也是本身對其的一種鞏固.前端
因爲是系列的文章, 因此更新的可能會比較頻繁, 您要是無心間刷到了且不是您所須要的還請諒解😊.vue
不求贊👍不求心❤️. 只但願能對你有一點小小的幫助.java
你們在瞭解了前一篇properties
的內容後, 應該對屬性有了一個大概的認識吧.git
這一章節讓咱們來講說properties-panel
😄...github
其實在前面的《全網最詳bpmn.js教材-基礎篇》中已經提到了怎樣使用properties-panel
, 不過那裏只是簡單的教了你們如何引用而沒有細說, 如今就讓我來詳細爲你們講解一下它具體的使用方法。web
經過這一章節的閱讀你能夠學習到:npm
Properties-panel
的基本使用
Properties-panel
properties-panel
本質上是bpmn.js
的一個擴展, 它實現了BPMN 2.0建模器,使你能夠經過屬性面板編輯與執行相關的屬性。
官方的一個截圖:
properties-panel
在以前的文章中有不少內容沒有介紹清楚, 在這一章中我會仔細的介紹.
首先是安裝上.
若是你想要使用它的話, 得本身安裝一下:
$ npm install --save bpmn-js-properties-panel
複製代碼
一樣的記得在項目中引入樣式:
import 'bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css' // 右邊工具欄樣式
複製代碼
使用上, 得在html
代碼中提供一個標籤做爲盛放它的容器:
<div id="js-properties-panel" class="panel"></div>
複製代碼
以後, 在構建BpmnModeler
的時候添加上它:
// 這裏引入的是右側屬性欄這個框
import propertiesPanelModule from 'bpmn-js-properties-panel'
// 而這個引入的是右側屬性欄裏的內容
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda'
const bpmnModeler = new BpmnModeler({
//添加控制板
propertiesPanel: {
parent: '#js-properties-panel'
},
additionalModules: [
propertiesPanelModule,
propertiesProviderModule
]
})
複製代碼
在以前的文章中我沒有弄清楚propertiesPanelModule
和propertiesProviderModule
的做用, 致使將左側工具欄和右側屬性的引用方式寫錯了, 如今已經在<全網最詳bpmn.js教材-基礎篇>中更正了...抱歉...
camunda-bpmn-moddle
還有一點, 若是你想使用Camunda BPM來執行相關屬性的話, 也得安裝一個叫camunda-bpmn-moddle
的擴展:
$ npm install --save camunda-bpmn-moddle
複製代碼
將其添加到項目中:
// 右側屬性欄
import propertiesPanelModule from 'bpmn-js-properties-panel'
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda'
// 一個描述的json
import camundaModdleDescriptor from 'camunda-bpmn-moddle/resources/camunda'
const bpmnModeler = new BpmnModeler({
//添加控制板
propertiesPanel: {
parent: '#js-properties-panel'
},
additionalModules: [
propertiesPanelModule,
propertiesProviderModule
],
moddleExtensions: {
//若是要在屬性面板中維護camunda:XXX屬性,則須要此
camunda: camundaModdleDescriptor
}
})
複製代碼
(Camunda BPM
是一個用於工做流執行引擎和工做流自動化的解決方案, 在這裏就不展開說了)
而camunda-bpmn-moddle
的做用就是告訴使用者camunda:XXX
擴展屬性。
說了這個咱也聽不懂啊, 來講點具體的吧, 好比你已經安裝並已經在項目上使用了properties-panel
以後, 打開頁面, 隨便選擇一個節點(就拿開始節點來講吧), 會出現四個選項卡(tab)能讓你修改屬性, 若是你沒有安裝camunda
並引用camundaModdleDescriptor
的話, 使用後面三個功能, 控制檯就會報錯了:
它會告訴你unknown type <camunda:FormData>
...
由於其實你查看camunda-bpmn-moddle/resources/camunda
的源碼就會發現, 這其實就是一個json
文件, 裏面存放的就是對各個屬性的描述. 咱們在後面自定義properties-panel
的時候也會須要編寫這樣的一個json
文件, 待會你就知道了.
OK...讓咱們來實際使用看看它們有什麼效果.
爲了方便查看, 我給bpmnModeler
綁定一個commandStack.changed
事件, 在圖形每次改變的時候將最新的xml
打印出來.
(關於事件綁定的部分能夠看<全網最詳bpmn.js教材-事件篇>)
以後仍是點擊開始節點, 並修改一些屬性. 結果發現你修改的屬性居然同步更新到了xml
上面:
Good Body! 你是否是想到了什麼?!
沒錯! 和上一篇文章的updateProperties
方法是否是很像呢, 都是可以更新屬性到xml
上.
Properties-panel
與palette
, contextPad
等自定義方式同樣, Properties-panel
也能夠在默認的基礎上進行修改, 它容許你加上一些自定義的屬性.
不過官方把它叫作Properties Panel Extension
, 好像更專業一些...不過無所謂了, 你知道是那個意思就好了.
官方這裏也提供了一個例子: properties-panel-extension
我其實也是跟着官方的這個例子來探索它是怎麼使用的.
首先讓咱們來明確一點, 還記得咱們在使用原版properties-panel
的時候, 引入了兩個東西嗎?
// 這裏引入的是右側屬性欄這個框
import propertiesPanelModule from 'bpmn-js-properties-panel'
// 而這個引入的是右側屬性欄裏的內容
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda'
additionalModules: [
propertiesPanelModule,
propertiesProviderModule
]
複製代碼
我研究了一下, 若是你不引入第一個只引入第二個的話, 屬性欄就出不來了.
而若是你只引入第一個不引入第二個的話, 就會報錯...
我理解一下大概是這樣意思:
propertiesPanelModule
表示的是屬性欄這個框, 就是告訴別人這裏要有個屬性欄;
propertiesProviderModule
表示的是屬性欄裏的內容, 也就是點擊不一樣的
element
該顯示什麼內容.
看到這, 你是否是有了點思路呢? 嘻嘻😁...
既然這樣的話, 咱們只須要重寫propertiesProviderModule
就能夠了, 不要引入官方提供的(也就是從bpmn-js-properties-panel/lib/provider/camunda
引入的), 而是自定義一個propertiesProviderModule
來顯示本身想要的內容.
properties-panel
的內容可能有點多, 我就另外建立了一個項目來作案例分析.
項目仍是用vue
來編寫, 不過其實你只要有點基礎都能看得懂.
先讓咱們來看看要實現的效果:
General
和權限兩個選項卡(tab);
xml
中
讓咱們在components
文件夾下建立一個properties-panel-extension
文件夾, 這裏用來放咱們要自定義的屬性內容.
而後在properties-panel-extension
下再新建一個descriptors
和provider
文件夾.
json
文件
因爲General
是它本來就有的一個選項卡, 因此咱們能夠不用管它, 如今咱們想要自定義的是一個名叫「權限」
的選項卡, 因此我在provider
文件夾下又建立了一個authority
文件夾, 裏面用來放咱們選項卡的內容...
以後一頓操做, 讓目錄變成了這樣:
AuthorityPropertiesProvider.js
這個文件就是來編寫權限
這個選項卡的, 它是咱們須要編寫的主要文件.
parts
這個文件夾就是來放各個組下的子元素, 好比這裏的「標題」
, 我給它取名爲TitleProps
.
若是你看到上面那麼多的文件感受眼花繚亂的話, 請沒必要慌張😂, 這是正常的反應...
因此爲了後面更好的講解, 我決定先來介紹一下provider
的返回值與頁面的結構是如何對應上的.
經過上面👆的圖, 咱們能夠看出來:
provider
下都會有一個
tabs
數組(一個
tab
就是一個選項卡)
tab
下都會有一個
groups
數組(一個
group
就是一個組)
group
下都會有一堆
props
, 它們多是輸入框, 也多是下拉框
OK...如今是否是好理解多了😄...
因此咱們只須要在AuthorityPropertiesProvider.js
中返回一個這樣的結構就能夠了:
/*-選項卡 | -組 | -屬性*/
return [
{ // 選項卡
id: 'general',
groups: [] // 組
},
{ // 選項卡
id: 'authority',
groups: [
{ // 組
id: 'edit-authority', // 組id
entries: [
{ // 單個props
id: 'title',
description : '權限的標題',
label : '標題',
modelProperty : 'title'
}
]
}
]
}
]
複製代碼
AuthorityPropertiesProvider.js
代碼編寫的順序我打算從上往下一層一層的講.
因此先來看看AuthorityPropertiesProvider.js
整體是要返回什麼.
// AuthorityPropertiesProvider.js
import inherits from 'inherits';
// 引入自帶的PropertiesActivator, 由於咱們要用到它來處理eventBus
import PropertiesActivator from 'bpmn-js-properties-panel/lib/PropertiesActivator';
export default function AuthorityPropertiesProvider( eventBus, bpmnFactory, canvas, // 這裏是要用到什麼就引入什麼 elementRegistry, translate ) {
PropertiesActivator.call(this, eventBus);
this.getTabs = function (element) {
var generalTab = {};
var authorityTab = {};
return [
generalTab,
authorityTab
];
}
}
inherits(AuthorityPropertiesProvider, PropertiesActivator);
複製代碼
這樣看, 結構是否是也很清晰呢? 😊
咱們其實就是要重寫裏面的getTabs
方法, 返回咱們須要的tab
.
每一個tab
都有固定的屬性:
var authorityTab = {
id: 'authority',
label: '權限',
groups: createAuthorityTabGroups(element)
};
複製代碼
你必須得準守以上命名規則來寫哈😣...
createAuthorityTabGroups
函數代碼在肯定了tab
以後, 咱們須要告訴它裏面有哪些組, 這時候就能夠建立一個createAuthorityTabGroups
函數來返回想要的組.
// AuthorityPropertiesProvider.js
import TitleProps from './parts/TitleProps';
function createAuthorityTabGroups(element) {
var editAuthorityGroup = {
id: 'edit-authority',
label: '編輯權限',
entries: [] // 屬性集合
}
// 每一個屬性都有本身的props方法
TitleProps(editAuthorityGroup, element);
// OtherProps1(editAuthorityGroup, element);
// OtherProps2(editAuthorityGroup, element);
return [
editAuthorityGroup
];
}
複製代碼
好比上面👆我就返回了一個編輯權限
的組.
而各個屬性是放到組的entries
字段下的...
咿呀, 這裏怎麼沒看到給entries
數組添加屬性呢?
可是下面好像有一個TitleProps
呀, 這個是幹嗎的🤔?
看着有點像用來添加屬性的...
TitleProps.js
代碼是的, 因爲屬性可能會被多處用到, 因此我將它單獨提了出來, 放到了parts
這個文件夾下, 後面就能夠往裏面不停的加屬性了.
這個屬性的方法有點特別, 它接收兩個參數:
element
由於同一個屬性可能存在於不一樣的組裏, 因此能夠傳入一個組.
另外可能要經過元素的類型來作各類判斷, 因此能夠傳入當前元素.
// /parts/TitleProps.js
import entryFactory from 'bpmn-js-properties-panel/lib/factory/EntryFactory';
import { is } from 'bpmn-js/lib/util/ModelUtil';
export default function(group, element) {
if (is(element, 'bpmn:StartEvent')) { // 能夠在這裏作類型判斷
group.entries.push(entryFactory.textField({
id : 'title',
description : '權限的標題',
label : '標題',
modelProperty : 'title'
}));
}
}
複製代碼
啊😺, 原來entries
是在每個Props
裏添加屬性的啊🙈...
在push
方法裏, 你得告訴它是要添加一個什麼類型的Props
.
主要就是經過entryFactory
, 例如這裏就是返回一個text
類型的輸入框.
有時候你想要的不只僅是輸入框怎麼辦🙈?
不要緊, entryFactory
自己爲你提供了不少類型.
Ctrl + 左鍵
查看entryFactory
的源碼, 你能夠發現有不少類型:
OK...
至此, 咱們的自定義authorityTab
權限選項卡就寫完了 😊!
你若是想添加其它的選項卡用上面👆的方式就能夠了...
generalTab
代碼上面👆的權限
選項卡是咱們自定義的一些內容, 若是你想要使用官方提供的一些tab
和屬性怎麼辦呢?
generalTab
就爲你演示了該如何作...
首先一樣的, generalTab
須要長成這樣:
var generalTab = {
id: 'general',
label: 'General',
groups: createGeneralTabGroups(element, bpmnFactory, canvas, elementRegistry, translate)
};
複製代碼
咱們看到createGeneralTabGroups
好像傳遞了不少參數進去, 那是由於咱們要在裏面用到它們, 而這些參數在構造AuthorityPropertiesProvider
函數的時候就引入進來的...
來看看createGeneralTabGroups
是如何編寫的:
// AuthorityPropertiesProvider.js
import idProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/IdProps';
import nameProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/NameProps';
import processProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/ProcessProps';
import linkProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/LinkProps';
import eventProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/EventProps';
import documentationProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/DocumentationProps';
function createGeneralTabGroups(element, bpmnFactory, canvas, elementRegistry, translate) {
var generalGroup = {
id: 'general',
label: 'General',
entries: []
};
idProps(generalGroup, element, translate);
nameProps(generalGroup, element, bpmnFactory, canvas, translate);
processProps(generalGroup, element, translate);
var detailsGroup = {
id: 'details',
label: 'Details',
entries: []
};
linkProps(detailsGroup, element, translate);
eventProps(detailsGroup, element, bpmnFactory, elementRegistry, translate);
var documentationGroup = {
id: 'documentation',
label: 'Documentation',
entries: []
};
documentationProps(documentationGroup, element, bpmnFactory, translate);
return [
generalGroup,
detailsGroup,
documentationGroup
];
}
複製代碼
在general
中, 導出了三個組, 而每一個組中的Props
都是bpmn-js-properties-panel/lib/provider/bpmn/parts
這個文件夾中拿的...
一樣的, 你查找它的源碼, 也能發現不少其它的Props
, 你須要什麼, 直接取來用就能夠了[狗頭].
AuthorityPropertiesProvider.js
完整代碼額, 要不仍是貼下完整的代碼?
其實也很少, 91
行:
import inherits from 'inherits';
import PropertiesActivator from 'bpmn-js-properties-panel/lib/PropertiesActivator';
import idProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/IdProps';
import nameProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/NameProps';
import processProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/ProcessProps';
import linkProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/LinkProps';
import eventProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/EventProps';
import documentationProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/DocumentationProps';
import TitleProps from './parts/TitleProps';
function createGeneralTabGroups(element, bpmnFactory, canvas, elementRegistry, translate) {
var generalGroup = {
id: 'general',
label: 'General',
entries: []
};
idProps(generalGroup, element, translate);
nameProps(generalGroup, element, bpmnFactory, canvas, translate);
processProps(generalGroup, element, translate);
var detailsGroup = {
id: 'details',
label: 'Details',
entries: []
};
linkProps(detailsGroup, element, translate);
eventProps(detailsGroup, element, bpmnFactory, elementRegistry, translate);
var documentationGroup = {
id: 'documentation',
label: 'Documentation',
entries: []
};
documentationProps(documentationGroup, element, bpmnFactory, translate);
return [
generalGroup,
detailsGroup,
documentationGroup
];
}
function createAuthorityTabGroups(element) {
var editAuthorityGroup = {
id: 'edit-authority',
label: '編輯權限',
entries: []
}
// 每一個屬性都有本身的props方法
TitleProps(editAuthorityGroup, element);
// OtherProps1(editAuthorityGroup, element);
// OtherProps2(editAuthorityGroup, element);
return [
editAuthorityGroup
];
}
export default function AuthorityPropertiesProvider( eventBus, bpmnFactory, canvas, // 這裏是要用到什麼就引入什麼 elementRegistry, translate ) {
PropertiesActivator.call(this, eventBus);
this.getTabs = function(element) {
var generalTab = {
id: 'general',
label: 'General',
groups: createGeneralTabGroups(element, bpmnFactory, canvas, elementRegistry, translate)
};
var authorityTab = {
id: 'authority',
label: '權限',
groups: createAuthorityTabGroups(element)
};
return [
generalTab,
authorityTab
];
}
}
inherits(AuthorityPropertiesProvider, PropertiesActivator);
複製代碼
通過咱們的拆分, 感受異常簡單有木有 😊 !
(沒錯, 霖呆呆就是這麼一個簡單善良如白紙通常的男子😳...)
authority.json
代碼OK...其實到了這裏就接近尾聲了, 可是其實還有很是關鍵的一步要作...
剛剛咱們自定義了一個叫作權限
的選項卡, 還有一個叫title
的屬性, 而且還指定了只有StartEvent
中出現, 那麼此時咱們還得在一個叫authority.json
的文件中作一些說明.
(之因此取名爲authority.json
, 是由於我添加的選項卡叫權限
, 這個命名隨便你本身)
它長成這樣:
{
"name": "Authority",
"prefix": "authority",
"uri": "http://authority",
"xml": {
"tagAlias": "lowerCase"
},
"associations": [],
"types": [
{
"name": "LinDaiDaiStartEvent",
"extends": [
"bpmn:StartEvent"
],
"properties": [
{
"name": "title",
"isAttr": true,
"type": "String"
}
]
}
]
}
複製代碼
在這個描述文件中, 咱們定義了一個新類型LinDaiDaiStartEvent
, 該類型擴展了該類型bpmn:StartEvent
並向其添加「title」
屬性做爲屬性。
注️: 有必要在描述符中定義要擴展的元素。若是但願該屬性對全部bpm
n元素均有效,則能夠擴展bpmn:BaseElement
️
例如🌰這樣:
...
{
"name": "LinDaiDaiStartEvent",
"extends": [
"bpmn:BaseElement"
],
...
}
複製代碼
AuthorityPropertiesProvider
通過一輪翻雲覆雨(C + V)的操做, 終於將大頭給寫完了...
下面讓咱們來看看怎麼用它...
在/provider/authority
文件夾下建立一個index.js
用於導出:
import AuthorityPropertiesProvider from './AuthorityPropertiesProvider';
export default {
__init__: [ 'propertiesProvider' ],
propertiesProvider: [ 'type', AuthorityPropertiesProvider ]
};
複製代碼
看着很眼熟啊, 哈哈😄... 和contextPad
什麼的好像...
用於演示, 我在項目中建立了一個properties-panel-extension.vue
, 並在其中引用上bpmn.js
和咱們的剛剛編寫好的authority
.
<template>
<div class="containers" ref="content">
<div class="canvas" ref="canvas"></div>
<div id="js-properties-panel" class="panel"></div>
</div>
</template>
<script> // 原有的 properties-panel 這個框 import propertiesPanelModule from 'bpmn-js-properties-panel' // 自定義的 properties-panel內容 import propertiesProviderModule from './properties-panel-extension/provider/authority'; // 引入描述文件 import authorityModdleDescriptor from './properties-panel-extension/descriptors/authority' ... additionalModules: [ // 右邊的工具欄(固定引入) propertiesPanelModule, // 自定義右邊工做欄的內容 propertiesProviderModule ], moddleExtensions: { // camunda: camundaModdleDescriptor, authority: authorityModdleDescriptor } ... </script>
複製代碼
看到這裏, 相信你對properties-panel
又有了一個新的認識...
恭喜你🎉🎉🎉
霖呆呆非常欣慰...
上面👆教材案例的代碼地址: LinDaiDai/bpmn-vue-properties-panel
關於properties-panel
要講的內容有點多, 因此我將其分爲了兩篇來寫.
還有幾天過年了🧨...霖呆呆有個小小的願望, 就是在年前能破200
的粉絲...
卑微博主在線懇求關注...哈哈哈😂
(看着好心酸)
最後, 若是你也對bpmn.js
感興趣能夠進咱們的bpmn.js交流羣👇👇👇, 共同窗習, 共同進步.
關注霖呆呆的公衆號, 選擇「其它」菜單中的「bpmn.js羣」便可😁
系列所有目錄請查看此處: 《全網最詳bpmn.js教材》
系列相關推薦: