Bpmn.js activiti 流程編輯器詳細教程
前言
流程編輯器
什么是流程編輯器:
流程編輯器是一種用于創(chuàng)建、編輯和管理流程圖的工具。它提供了一個可視化的界面,使用戶能夠以圖形化的方式定義和配置流程的各個步驟、條件和流程間的關(guān)系。
流程編輯器通常用于業(yè)務流程管理、工作流程管理和業(yè)務流程自動化等領域。它可以幫助用戶輕松地設計和管理復雜的流程,而無需編寫大量的代碼。通過拖拽和連接不同的圖形元素,用戶可以定義流程的起始點、結(jié)束點、流程分支、條件判斷、任務執(zhí)行等。
流程編輯器還通常提供了一些額外的功能,如版本控制、權(quán)限管理、流程模板的導入和導出等。它可以與其他系統(tǒng)集成,以便將流程定義應用于實際的業(yè)務場景中。
流程編輯器的目的是簡化流程設計和管理的過程,提高工作效率,并確保流程的正確性和一致性。它在許多領域中都有廣泛的應用,包括項目管理、工作流程自動化、電子商務等。
流程編輯器有多種不同的種類,每種都具有不同的特點和用途。以下是一些常見的流程編輯器種類:
- 工作流程編輯器(Workflow Editors):用于創(chuàng)建和管理工作流程,包括定義任務、流程分支、條件和工作流程的執(zhí)行順序等。
- 業(yè)務流程管理(BPM)編輯器(Business Process Management Editors):用于設計和管理業(yè)務流程,支持復雜的流程建模和流程優(yōu)化。
- UML(統(tǒng)一建模語言)編輯器(UML Editors):用于創(chuàng)建和編輯UML圖,包括類圖、時序圖、用例圖等,用于軟件系統(tǒng)的設計和建模。
- 數(shù)據(jù)流程編輯器(Data Flow Editors):用于創(chuàng)建和管理數(shù)據(jù)流程,包括數(shù)據(jù)輸入、處理和輸出的流程圖。
- 網(wǎng)絡拓撲編輯器(Network Topology Editors):用于設計和管理網(wǎng)絡拓撲結(jié)構(gòu),包括節(jié)點、連接和網(wǎng)絡設備的配置。
- 流程圖編輯器(Flowchart Editors):用于創(chuàng)建和編輯流程圖,包括流程的各個步驟、條件和流程控制的圖形表示。
- 規(guī)則引擎編輯器(Rule Engine Editors):用于創(chuàng)建和管理規(guī)則引擎,包括定義規(guī)則、條件和規(guī)則執(zhí)行順序等。
- 這只是一些常見的流程編輯器種類,實際上還有許多其他類型的流程編輯器,每種都有其特定的用途和功能。具體使用哪種編輯器取決于具體的需求和應用場景。
我用的是業(yè)務流程編輯器(bpmn.js)
一、bpmn.js是什么?
1.bpmn.js簡介
bpmn.js是一個用于在Web應用程序中渲染和編輯BPMN(Business Process Model and Notation)流程圖的JavaScript庫。它提供了一套功能強大的API和工具,可以幫助開發(fā)人員在應用程序中集成BPMN流程圖的顯示和編輯功能。
使用bpmn.js,開發(fā)人員可以將BPMN流程圖嵌入到他們的應用程序中,并與其它組件進行交互。它支持創(chuàng)建、修改和刪除BPMN元素,如任務、網(wǎng)關(guān)、事件等,并提供了豐富的事件和回調(diào)函數(shù),以便開發(fā)人員可以根據(jù)用戶的操作進行相應的處理。
bpmn.js還支持將BPMN流程圖導入和導出為XML格式,以便與其他BPMN工具進行交互和共享。它還提供了豐富的樣式和主題選項,使開發(fā)人員可以自定義流程圖的外觀和樣式。
總的來說,bpmn.js是一個強大的工具,可以幫助開發(fā)人員在Web應用程序中實現(xiàn)BPMN流程圖的顯示和編輯功能,并與其它組件進行集成。
官網(wǎng):https://bpmn.io/.
2.為什么要選擇bpmn.js
activiti 官方支持的流程編輯器是ActivitiModeler,現(xiàn)在已經(jīng)停止維護而且如果需要前后端分離使用流程編輯器,并不是很友好。
選擇使用bpmn.js有以下幾個原因:
- 完整的BPMN支持:bpmn.js是一個專門用于處理BPMN流程圖的庫,它提供了完整的BPMN規(guī)范支持,包括各種BPMN元素、事件和流程控制等。這使得它成為構(gòu)建和管理BPMN流程圖的理想選擇。
- 強大的功能和靈活性:bpmn.js提供了豐富的API和工具,使開發(fā)人員可以輕松地創(chuàng)建、修改和刪除BPMN元素。它還支持導入和導出BPMN流程圖,以便與其他BPMN工具進行交互和共享。此外,bpmn.js還提供了自定義樣式和主題的選項,使開發(fā)人員可以根據(jù)需要自定義流程圖的外觀和樣式。
- 跨平臺和易于集成:bpmn.js是基于JavaScript的庫,可以在各種Web應用程序中使用。它與現(xiàn)代Web技術(shù)和框架(如React、Angular和Vue.js)兼容,并且可以與其他組件和工具進行無縫集成。這使得它非常適合在現(xiàn)有的應用程序中添加BPMN流程圖的顯示和編輯功能。
- 社區(qū)支持和活躍度:bpmn.js擁有龐大的開源社區(qū)支持,并且由Camunda等知名公司進行維護和更新。這意味著它有一個活躍的開發(fā)者社區(qū),可以提供幫助、解決問題并分享經(jīng)驗。
- 總而言之,選擇使用bpmn.js可以讓開發(fā)人員輕松地在Web應用程序中實現(xiàn)BPMN流程圖的顯示和編輯功能,并且具有強大的功能、靈活性和跨平臺的特點。
二、在vue中集成Bpmn.js
1.下載依賴
最簡單的一種使用方式:直接使用
CDN
將bpmn.js
引入到代碼中
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>BPMNJS</title> <!--CDN加速--> <script src="https://unpkg.com/bpmn-js@6.0.2/dist/bpmn-viewer.development.js"></script><!--引入一個簡單的xml字符串--> <script src="./xmlStr.js"></script> <style> #canvas { height: 400px; } </style> </head> <body> <div id="canvas"></div> <script> var bpmnJS = new BpmnJS({ container: '#canvas' }); bpmnJS.importXML(xmlStr, err => { if (!err) { // 讓圖能自適應屏幕 var canvas = bpmnJS.get('canvas') canvas.zoom('fit-viewport') } else { console.log('something went wrong:', err); } }); </script> </body> </html>
(上面的xmlStr.js
就是自定義的文件,里面放置了關(guān)于流程的xml,也可以不引用直接在vue文件中定義)
如上面的案例所示, 我們使用CDN
加速直接引入bpmn.js
, 然后本地指定一個容器(也就是id
為canvas
的那個div
), 接著用bpmn.js
提供的方法importXML
就可以解析xml
字符串生成對應的工作流圖了。
運行代碼:
上面提供的使用方式是一種最基本的方式,僅僅是將圖展示出來,不能自己繪畫也不能操作. 所以在工作中使用更多的還是采用npm安裝到項目中使用. 我們可以使用以下命令進行安裝:
使用
npm
下載
npm install --save bpmn-js
注意: 如果在已有項目引入,可能會因為版本問題導致啟動失敗,最好是看看相對于的版本
我這里使用的版本是:
"dependencies": { "bpmn-js": "^6.2.1", "bpmn-js-properties-panel": "^0.33.1", "camunda-bpmn-moddle": "^4.3.0", "core-js": "^3.4.4", "houtaroy-bpmn-js-properties-panel-activiti": "0.0.1", "svg-sprite-loader": "3.7.3", },
2.引入樣式
安裝好依賴后,在main.js
文件中引入樣式:
// bpmn 相關(guān)依賴 import 'bpmn-js/dist/assets/diagram-js.css' import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css' import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css' import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css' // 左邊工具欄以及編輯節(jié)點的樣式 import 'bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css'
新建一個bpmn.vue
頁面,編寫html
代碼
<template> <div id="app"> <div class="container"> <!-- 創(chuàng)建一個canvas畫布 npmn-js是通過canvas實現(xiàn)繪圖的,并設置ref讓vue獲取到element --> <div class="bpmn-container"> <div class="bpmn-canvas" ref="canvas"></div> <!-- 工具欄顯示的地方 --> <div class="bpmn-js-properties-panel" id="js-properties-panel"></div> </div> <!-- 把操作按鈕寫在這里面 --> <div class="action"> <el-button icon="el-icon-download" @click="downloadBpmn" title="下載流程文件"></el-button> <el-button icon="el-icon-picture" @click="downloadSvg" title="下載流程圖"></el-button> <el-button type="success" icon="el-icon-check" circle title="保存修改" @click="editModel"></el-button> <a hidden ref="downloadLink"></a> </div> </div> </div> </template>
編寫js
代碼
<script> import BpmnModeler from 'bpmn-js/lib/Modeler' // 工具欄相關(guān) // import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda' import propertiesPanelModule from 'bpmn-js-properties-panel' // import camundaModdleDescriptor from 'camunda-bpmn-moddle/resources/camunda' import activitiModdleDescriptor from './activiti.json' // 引入 import propertiesProviderModule from 'houtaroy-bpmn-js-properties-panel-activiti/lib/provider/activiti' // 漢化 import customTranslate from './customTranslate.js' export default { data () { return { modelId: '', bpmnModeler: null, canvas: null, bpmnTemplate: `` } }, methods: { newDiagram () { this.createNewDiagram(this.bpmnTemplate) }, // 下載bpmn xml文件 downloadBpmn () { const that = this that.bpmnModeler.saveXML({ format: true }, (err, xml) => { if (!err) { // 獲取文件名 const name = `${that.getFilename(xml)}.bpmn20.xml` // 將文件名以及數(shù)據(jù)交給下載方法 that.download({ name: name, data: xml }) } }) }, // 下載bpmn.svg流程圖片 downloadSvg () { const that = this that.bpmnModeler.saveXML({ format: true }, (err, date) => { if (!err) { // 獲取文件名 const name = `${that.getFilename(date)}.svg` // 從建模器畫布中提取svg圖形標簽 let context = '' const djsGroupAll = that.$refs.canvas.querySelectorAll('.djs-group') for (let item of djsGroupAll) { context += item.innerHTML } // 獲取svg的基本數(shù)據(jù),長寬高 const viewport = that.$refs.canvas .querySelector('.viewport') .getBBox() // 將標簽和數(shù)據(jù)拼接成一個完整正常的svg圖形 const svg = ` <svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='${viewport.width}' height='${viewport.height}' viewBox='${viewport.x} ${viewport.y} ${viewport.width} ${viewport.height}' version='1.1' > ${context} </svg> ` // 將文件名以及數(shù)據(jù)交給下載方法 that.download({ name: name, data: svg }) } }) }, // 獲取文件名 getFilename (xml) { const regex = /<process.*?id="(.*?)"/ const match = xml.match(regex) if (match) { return match[1] } return null }, // 編輯模型 editModel () { const that = this that.bpmnModeler.saveXML({ format: true }, (err, xml) => { if (!err) { // 獲取文件名 const name = `${that.getFilename(xml)}` // // 從建模器畫布中提取svg圖形標簽 // let context = '' // const djsGroupAll = this.$refs.canvas.querySelectorAll('.djs-group') // for (let item of djsGroupAll) { // context += item.innerHTML // } // // 獲取svg的基本數(shù)據(jù),長寬高 // const viewport = this.$refs.canvas // .querySelector('.viewport') // .getBBox() // // 將標簽和數(shù)據(jù)拼接成一個完整正常的svg圖形 // const svg = ` // <svg // xmlns='http://www.w3.org/2000/svg' // xmlns:xlink='http://www.w3.org/1999/xlink' // width='${viewport.width}' // height='${viewport.height}' // viewBox='${viewport.x} ${viewport.y} ${viewport.width} ${viewport.height}' // version='1.1' // > // ${context} // </svg> // ` that.$http({ url: '', method: 'post', data: that.$http.adornData({ modelId: that.modelId, name: name, bpmnXml: xml, svg: '', descritpion: '' }) }).then(({ data }) => { that.$message({ message: that.$i18n.t('publics.operation'), type: 'success', duration: 1500, onClose: () => {} }) }) } }) }, // 獲取流程圖數(shù)據(jù) getModel () { const that = this this.$http({ url: '', method: 'get', params: this.$http.adornParams({ modelId: that.modelId }) }).then(({ data }) => { that.bpmnTemplate = '`' + data + '`' this.$message({ message: this.$i18n.t('publics.operation'), type: 'success', duration: 1500, onClose: () => { that.init() } }) }) }, download ({ name = 'diagram.bpmn', data }) { // 這里就獲取到了之前設置的隱藏鏈接 const downloadLink = this.$refs.downloadLink // 把數(shù)據(jù)轉(zhuǎn)換為URI,下載要用到的 const encodedData = encodeURIComponent(data) if (data) { // 將數(shù)據(jù)給到鏈接 downloadLink.href = 'data:application/bpmn20-xml;charset=UTF-8,' + encodedData // 設置文件名 downloadLink.download = name // 觸發(fā)點擊事件開始下載 downloadLink.click() } }, async init () { // 獲取畫布 element const that = this that.canvas = that.$refs.canvas // 將漢化包裝成一個模塊 const customTranslateModule = { translate: ['value', customTranslate] } // 創(chuàng)建Bpmn對象 that.bpmnModeler = new BpmnModeler({ // 設置bpmn的繪圖容器為上門獲取的畫布 element container: that.canvas, // 加入工具欄支持 propertiesPanel: { parent: '#js-properties-panel' }, additionalModules: [ // 工具欄模塊 propertiesProviderModule, propertiesPanelModule, // 漢化模塊 customTranslateModule ], moddleExtensions: { activiti: activitiModdleDescriptor } }) await that.createNewDiagram(that.bpmnTemplate) }, clearBpmn () { this.bpmnModeler.clear() }, async createNewDiagram (bpmnTemplate) { const that = this // 將字符串轉(zhuǎn)換成圖顯示出來; this.bpmnModeler.importXML(bpmnTemplate, err => { if (err) { that.$Message.error('打開模型出錯,請確認該模型符合Bpmn2.0規(guī)范') } else { // 讓圖能自適應屏幕 var canvas = that.bpmnModeler.get('canvas') canvas.zoom('fit-viewport') } }) } }, created () { this.getModel() // // 刪除 bpmn logo bpmn.io官方要求不給刪或者隱藏,否則侵權(quán) 內(nèi)部使用 // const bjsIoLogo = document.querySelector('.bjs-powered-by') // while (bjsIoLogo.firstChild) { // bjsIoLogo.removeChild(bjsIoLogo.firstChild) // } }, beforeDestroy () { this.clearBpmn() } } </script>
編寫styly
樣式
<style> .bpmn-container { width: 100%; height: 100vh; display: flex; } .bpmn-canvas { width: calc(100% - 300px); height: 100vh; } .bpmn-js-properties-panel { width: 320px; height: inherit; overflow-y: auto; } .action { position: fixed; bottom: 40px; left: 800px; display: flex; } </style>
在這里需要注意我的代碼中,在
import
導入camunda
時我注釋了,是因為Bpmn.js默認支持的是camunda
,而我的后端使用的是activiti
,兩者是不兼容的。所以需要丟棄camunda
,換成activiti
下載activiti
插件
"houtaroy-bpmn-js-properties-panel-activiti": "0.0.1",
更換對應引入的camunda
漢化包:customTranslate.js
+translationsGerman
import translations from './translationsGerman' export default function customTranslate (template, replacements) { replacements = replacements || {} // Translate template = translations[template] || template // Replace return template.replace(/{([^}]+)}/g, function (_, key) { var str = replacements[key] if ( translations[replacements[key]] !== null && translations[replacements[key]] !== 'undefined' ) { str = translations[replacements[key]] } return str || '{' + key + '}' }) }
export default { // Labels 'Activate the global connect tool': '激活全局連接工具', 'Append {type}': '追加 {type}', 'Append EndEvent': '追加 結(jié)束事件 ', 'Append Task': '追加 任務', 'Append Gateway': '追加 網(wǎng)關(guān)', 'Append Intermediate/Boundary Event': '追加 中間/邊界 事件', 'Add Lane above': '在上面添加道', 'Divide into two Lanes': '分割成兩個道', 'Divide into three Lanes': '分割成三個道', 'Add Lane below': '在下面添加道', 'Append compensation activity': '追加補償活動', 'Change type': '修改類型', 'Connect using Association': '使用關(guān)聯(lián)連接', 'Connect using Sequence/MessageFlow or Association': '使用順序/消息流或者關(guān)聯(lián)連接', 'Connect using DataInputAssociation': '使用數(shù)據(jù)輸入關(guān)聯(lián)連接', 'Remove': '移除', 'Activate the hand tool': '激活抓手工具', 'Activate the lasso tool': '激活套索工具', 'Activate the create/remove space tool': '激活創(chuàng)建/刪除空間工具', 'Create expanded SubProcess': '創(chuàng)建擴展子過程', 'Create IntermediateThrowEvent/BoundaryEvent': '創(chuàng)建中間拋出事件/邊界事件', 'Create Pool/Participant': '創(chuàng)建池/參與者', 'Parallel Multi Instance': '并行多重事件', 'Sequential Multi Instance': '時序多重事件', 'DataObjectReference': '數(shù)據(jù)對象參考', 'DataStoreReference': '數(shù)據(jù)存儲參考', 'Loop': '循環(huán)', } // 這里只是部分的漢化,多的就不寫出來了,如果有需要的可以去網(wǎng)上找找有很多
然后還有activiti.json
這個是更換activiti
必不可少的,可以看看元示例
{ "name": "Activiti", "uri": "http://activiti.org/bpmn", "prefix": "activiti", "xml": { "tagAlias": "lowerCase" }, "associations": [], "types": [ { "name": "Process", "isAbstract": true, "extends": [ "bpmn:Process" ], "properties": [ { "name": "diagramRelationId", "isAttr": true, "type": "String" } ] }, { "name": "InOutBinding", "superClass": [ "Element" ], // 就是將camunda用activiti替換掉,還有挺多的無法全部展示
引入完成后就可以看看流程編輯器的樣子。
到這里一個完整的bpmn.js
就引入完成了,下面再講講bpmn.js的事件以及監(jiān)聽器吧
三,bpmn.js事件
這里主要是說明關(guān)于bpmn.js
的一些事件, 通過此章節(jié)你可以了解到:
- 監(jiān)聽
modeler
并綁定事件 - 監(jiān)聽
element
并綁定事件 - 通過監(jiān)聽事件判斷操作方式
1,監(jiān)聽modeler并綁定事件
有些時候我們期望的是在用戶在進行不同操作的時候能夠監(jiān)聽到他操作的是什么, 從而做想要做的事情.
是進行了shape
的新增還是進行了線的新增.
比如如下的一些監(jiān)聽事件:
shape.added
新增一個shape
之后觸發(fā);shape.move.end
移動完一個shape
之后觸發(fā);shape.removed
刪除一個shape
之后觸發(fā);
繼續(xù)在項目案例bpmn.vue
的基礎上創(chuàng)建一個event.vue
文件:
// event.vue <script> ... success () { this.addModelerListener() }, // 監(jiān)聽 modeler addModelerListener() { const bpmnjs = this.bpmnModeler const that = this // 這里我是用了一個forEach給modeler上添加要綁定的事件 const events = ['shape.added', 'shape.move.end', 'shape.removed', 'connect.end', 'connect.move'] events.forEach(function(event) { that.bpmnModeler.on(event, e => { console.log(event, e) var elementRegistry = bpmnjs.get('elementRegistry') var shape = e.element ? elementRegistry.get(e.element.id) : e.shape console.log(shape) }) }) },
然后就可以獲取到相關(guān)節(jié)點的信息
其實具體有哪些事件我在官網(wǎng)上都沒有找到說明, 以上只是我在查找到bpmn.io/diagram.js/…文件之后, 取的一些我項目里有用到的事件.
2,監(jiān)聽element并綁定事件
上面介紹的是監(jiān)聽modeler并綁定事件, 可能你也需要監(jiān)聽用戶點擊圖形上的element或者監(jiān)聽某個element改變:
- element.click 點擊元素;
- element.changed 當元素發(fā)生改變的時候(包括新增、移動、刪除元素)
繼續(xù)在success()
上添加監(jiān)聽事件:
// event.vue <script> ... success () { ... this.addEventBusListener() }, addEventBusListener () { let that = this const eventBus = this.bpmnModeler.get('eventBus') // 需要使用eventBus const eventTypes = ['element.click', 'element.changed'] // 需要監(jiān)聽的事件集合 eventTypes.forEach(function(eventType) { eventBus.on(eventType, function(e) { console.log(e) }) }) } </script>
配置好addEventBusListener()
函數(shù)后, 在進行元素的點擊、新增、移動、刪除的時候都能監(jiān)聽到了.
但是有一點很不好, 你在點擊“畫布”的時候, 也就是根元素也可能會觸發(fā)此事件, 我們一般都不希望此時會觸發(fā), 因此我們可以在on
回調(diào)中添加一些判斷, 來避免掉不需要的情況:
eventBus.on(eventType, function(e) { if (!e || e.element.type == 'bpmn:Process') return // 這里我的根元素是bpmn:Process console.log(e) })
此時我們可以把監(jiān)聽到返回的節(jié)點信息打印出來看看:
如上圖, 它會打印出該節(jié)點的Shape
信息和DOM
信息等, 但我們可能只關(guān)注于Shape
信息(也就是該節(jié)點的id
、type
等等信息), 此時我們可以使用elementRegistry
來獲取Shape
信息:
eventBus.on(eventType, function(e) { if (!e || e.element.type == 'bpmn:Process') return // 這里我的根元素是bpmn:Process console.log(e) var elementRegistry = this.bpmnModeler.get('elementRegistry') var shape = elementRegistry.get(e.element.id) // 傳遞id進去 console.log(shape) // {Shape} console.log(e.element) // {Shape} console.log(JSON.stringify(shape)===JSON.stringify(e.element)) // true })
或者你也可以直接就用e.element
獲取到Shape
的信息, 我比較了一下它們兩是一樣的. 但是官方是推薦使用elementRegistry
的方式.
3.通過監(jiān)聽事件判斷操作方式
上面我們已經(jīng)介紹了modeler
和element
的監(jiān)聽綁定方式, 在事件應用中, 你更多的需要知道用戶要進行什么操作, 好寫對應的業(yè)務邏輯.
這里就以工作中要用到的場景為案例進行講解.
- 新增了shape
- 新增了線(connection)
- 刪除了shape和connection
- 移動了shape和線
// event.vue ... success () { this.addModelerListener() this.addEventBusListener() }, // 添加綁定事件 addBpmnListener () { const that = this // 獲取a標簽dom節(jié)點 const downloadLink = this.$refs.saveDiagram const downloadSvgLink = this.$refs.saveSvg // 給圖綁定事件,當圖有發(fā)生改變就會觸發(fā)這個事件 this.bpmnModeler.on('commandStack.changed', function () { that.saveSVG(function(err, svg) { that.setEncoded(downloadSvgLink, 'diagram.svg', err ? null : svg) }) that.saveDiagram(function(err, xml) { that.setEncoded(downloadLink, 'diagram.bpmn', err ? null : xml) }) }) }, addModelerListener() { // 監(jiān)聽 modeler const bpmnjs = this.bpmnModeler const that = this // 'shape.removed', 'connect.end', 'connect.move' const events = ['shape.added', 'shape.move.end', 'shape.removed'] events.forEach(function(event) { that.bpmnModeler.on(event, e => { var elementRegistry = bpmnjs.get('elementRegistry') var shape = e.element ? elementRegistry.get(e.element.id) : e.shape // console.log(shape) if (event === 'shape.added') { console.log('新增了shape') } else if (event === 'shape.move.end') { console.log('移動了shape') } else if (event === 'shape.removed') { console.log('刪除了shape') } }) }) }, addEventBusListener() { // 監(jiān)聽 element let that = this const eventBus = this.bpmnModeler.get('eventBus') const eventTypes = ['element.click', 'element.changed'] eventTypes.forEach(function(eventType) { eventBus.on(eventType, function(e) { if (!e || e.element.type == 'bpmn:Process') return if (eventType === 'element.changed') { that.elementChanged(eventType, e) } else if (eventType === 'element.click') { console.log('點擊了element') } }) }) }, elementChanged(eventType, e) { var shape = this.getShape(e.element.id) if (!shape) { // 若是shape為null則表示刪除, 無論是shape還是connect刪除都調(diào)用此處 console.log('無效的shape') // 由于上面已經(jīng)用 shape.removed 檢測了shape的刪除, 因此這里只判斷是否是線 if (this.isSequenceFlow(shape.type)) { console.log('刪除了線') } } if (!this.isInvalid(shape.type)) { if (this.isSequenceFlow(shape.type)) { console.log('改變了線') } } }, getShape(id) { var elementRegistry = this.bpmnModeler.get('elementRegistry') return elementRegistry.get(id) }, isInvalid (param) { // 判斷是否是無效的值 return param === null || param === undefined || param === '' }, isSequenceFlow (type) { // 判斷是否是線 return type === 'bpmn:SequenceFlow' }
到此這篇關(guān)于Bpmn.js activiti 流程編輯器詳細教程的文章就介紹到這了,更多相關(guān)activiti 流程編輯器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于JavaScript中forEach和each用法淺析
這篇文章主要給大家介紹了關(guān)于JavaScript中forEach和each使用方法的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面跟著小編一起來學習學習吧。2017-07-07JS定時器使用,定時定點,固定時刻,循環(huán)執(zhí)行詳解
下面小編就為大家?guī)硪黄狫S定時器使用,定時定點,固定時刻,循環(huán)執(zhí)行詳解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-05-05深入理解JavaScript系列(3) 全面解析Module模式
Module模式是JavaScript編程中一個非常通用的模式,一般情況下,大家都知道基本用法,本文嘗試著給大家更多該模式的高級使用方式2012-01-01js實現(xiàn)日期天數(shù)、時分秒的倒計時完整代碼
這篇文章主要給大家介紹了關(guān)于js實現(xiàn)日期天數(shù)、時分秒的倒計時的相關(guān)資料,實現(xiàn)倒計時功能首先是得到目標時間,然后用當前時間減去目標時間,最后將時間差傳化為天數(shù)、時、分、秒,需要的朋友可以參考下2023-11-11js字符串轉(zhuǎn)換成數(shù)字與數(shù)字轉(zhuǎn)換成字符串的實現(xiàn)方法
本篇文章主要是對js字符串轉(zhuǎn)換成數(shù)字與數(shù)字轉(zhuǎn)換成字符串的實現(xiàn)方法進行了詳細的介紹,需要的朋友可以過來參考下,希望對大家有所幫助2014-01-01Javascript:為input設置readOnly屬性(示例講解)
本篇文章主要是對Javascript中為input設置readOnly屬性的示例代碼進行了介紹。需要的朋友可以過來參考下,希望對大家有所幫助2013-12-12從setTimeout看js函數(shù)執(zhí)行過程
這篇文章主要介紹了從setTimeout看js函數(shù)執(zhí)行過程,需要的朋友可以參考下2017-12-12