项目环境:
- bpmn.js: 7.5.x
- vue: 2.x
项目中使用到bpmnjs的时候,大多数情况都是需要自定义定制才能满足需求,因此bpmnjs的自定义基本不可避免,今天我们来进行vue中的bpmnjs的Modeler自定义过程;
由于bpmnjs自定义过程稍微复杂,刚开始理解起来有些难度,不懂的地方大家耐心多看几遍;
首先自定义要先继承原Modeler,再将需要自定义的模块(CustomModule)与原有模块(modules)合并(或者说覆盖)
import inherits from "inherits";
import Modeler from "bpmn-js/lib/Modeler";
import CustomModule from "../custom/index.js";
function CustomModeler(options) {
Modeler.call(this, options);
this._customElements = [];
}
inherits(CustomModeler, Modeler);
CustomModeler.prototype._modules = [].concat(CustomModeler.prototype._modules, [CustomModule]);
export { CustomModeler };
被引用的自定义模块CustomModule的custom/index.js文件(这个文件很重要,以后几乎所有需要自定义引入的模块都在这里import)内容参考如下,假设自定义了左侧工具栏模块:
import paletteProvider from "../customPalette/paletteprovider";
import customPalette from "../customPalette/palette";
export default {
__init__: [
"paletteProvider",
'palette'
],
paletteProvider: ["type", paletteProvider],
palette: [ 'type', customPalette ],
};
结构目录参考图:
经过以上两步,自定义的CustomModeler对象就出来了,然后将上面的代码整理好放在不同的目录等待引用,下面是CustomModeler的参数设置与使用方法:
<div ref="bpmnbox" class="canvas-box"></div>
import customTranslate from '@/components/bpmnProcess/customTranslate/customTranslate';
import flowableDescriptor from '@/components/bpmnProcess/properties-panel/descriptor/flowable.json';
import flowableMoudle from '@/components/bpmnProcess/properties-panel/extension-moddle/flowable';
export default{
data(){
return{
}
},
methods:{
async getModeler(){
const { CustomModeler } = await require('@/components/bpmnProcess/customModeler')
return new CustomModeler({
container: this.$refs.bpmnbox,
keyboard: {
bindTo: window
},
height: '100%',
moddleExtensions: {
flowable: flowableDescriptor
},
additionalModules: [
flowableMoudle,
{ //汉化
translate: ['value', customTranslate]
},
{
// 禁用滚轮滚动
zoomScroll: ["value", ""]
}
]
})
}
}
}
以上的三个自定义模块customTranslate、flowableDescriptor、flowableMoudle的js文件分别参考如下:
- customTranslate:汉化模块
import translations from './translations';
export default function customTranslate(template, replacements) {
replacements = replacements || {};
// Translate
template = translations[template] || template;
// Replace
return template.replace(/{([^}]+)}/g, function(_, key) {
return translations[replacements[key]] || replacements[key] || '{' + key + '}';
});
}
上面的translations参考内容如下(汉化键值对):
export default {
'Task': '任务',
'Process': '流程',
'UserTask': '用户任务',
'GateWay': '网关',
'StartEvent': '开始事件',
'EndEvent': '结束事件'
}
- flowableDescriptor:扩展属性相关描述文件
{
"name": "Flowable",
"uri": "http://flowable.org/bpmn",
"prefix": "flowable",
"xml": {
"tagAlias": "lowerCase"
},
"associations": [],
"types": [
{
"name": "UserTask",
"isAbstract": true,
"extends": [
"bpmn:UserTask",
"bpmn:MultiInstanceLoopCharacteristics"
],
"properties": [
{
"name": "timerEventDefinition",
"type": "Expression"
},{
"name": "multiInstanceLoopCharacteristics",
"type": "MultiInstanceLoopCharacteristics"
}
]
},
{
"name": "StartEvent",
"isAbstract": true,
"extends": [
"bpmn:StartEvent"
],
"properties": [
{
"name": "timerEventDefinition",
"type": "Expression"
}
]
},
{
"name":"Properties",
"isAbstract": true,
"extends":[],
"superClass":["Element"],
"meta":{
"allowedIn":["*"]
},
"properties":[
{
"name":"values",
"isMany":true,
"isbody":true,
"type":"Formright"
}
]
},
{
"name":"Formright",
"isAbstract": true,
"extends":[
"flowable:Exec_before",
"flowable:Exec_after"
],
"superClass":["Element"],
"meta":{
"allowedIn":["*"]
},
"properties":[
{
"name":"value",
"isAttr":true,
"type":"String"
},
{
"name": "body",
"isBody": true,
"type": "String"
}
]
},
{
"name": "Property",
"superClass": [
"Element"
],
"properties": [
{
"name": "id",
"type": "String",
"isAttr": true
},
{
"name": "name",
"type": "String",
"isAttr": true
},
{
"name": "value",
"type": "String",
"isAttr": true
}
]
}
]
}
//参考官方仓库:https://github.com/bpmn-io/moddle/blob/master/docs/descriptor.md
- flowableMoudle:扩展属性模块
module.exports = {
__init__:["FlowableModdleExtension"],
FlowableModdleExtension:["type",require("./flowableExtension")]
}
flowableExtension文件内容参考如下(其实这些文件全都可以在依赖目录找到,只是需要替换成'flowable'):
"use strict";
var some = require("min-dash").some;
var ALLOWED_TYPES = {
FailedJobRetryTimeCycle: ["bpmn:StartEvent", "bpmn:BoundaryEvent", "bpmn:IntermediateCatchEvent", "bpmn:Activity"],
Connector: ["bpmn:EndEvent", "bpmn:IntermediateThrowEvent"],
Field: ["bpmn:EndEvent", "bpmn:IntermediateThrowEvent"]
};
function is(element, type) {
return element && typeof element.$instanceOf === "function" && element.$instanceOf(type);
}
function exists(element) {
return element && element.length;
}
function includesType(collection, type) {
return (
exists(collection) && some(collection, function(element) {
return is(element, type);
})
);
}
function anyType(element, types) {
return some(types, function(type) {
return is(element, type);
});
}
function isAllowed(propName, propDescriptor, newElement) {
var name = propDescriptor.name,
types = ALLOWED_TYPES[name.replace(/flowable:/, "")];
return name === propName && anyType(newElement, types);
}
function FlowableModdleExtension(eventBus) {
eventBus.on(
"property.clone",
function(context) {
var newElement = context.newElement,
propDescriptor = context.propertyDescriptor;
this.canCloneProperty(newElement, propDescriptor);
},
this
);
}
FlowableModdleExtension.$inject = ["eventBus"];
FlowableModdleExtension.prototype.canCloneProperty = function(newElement, propDescriptor) {
if (isAllowed("flowable:FailedJobRetryTimeCycle", propDescriptor, newElement)) {
return (
includesType(newElement.eventDefinitions, "bpmn:TimerEventDefinition") ||
includesType(newElement.eventDefinitions, "bpmn:SignalEventDefinition") ||
is(newElement.loopCharacteristics, "bpmn:MultiInstanceLoopCharacteristics")
);
}
if (isAllowed("flowable:Connector", propDescriptor, newElement)) {
return includesType(newElement.eventDefinitions, "bpmn:MessageEventDefinition");
}
if (isAllowed("flowable:Field", propDescriptor, newElement)) {
return includesType(newElement.eventDefinitions, "bpmn:MessageEventDefinition");
}
};
module.exports = FlowableModdleExtension;
使用例子(vue2):
this.modeler = await this.getModeler()
获取Modeler各模块:
this.eventBus = this.modeler.get("eventBus")
this.modeling = this.modeler.get("modeling")
this.moddle = this.modeler.get("moddle")
this.bpmnFactory = this.modeler.get("bpmnFactory")
this.elementRegistry = this.modeler.get("elementRegistry")
this.canvas = this.modeler.get("canvas")
this.selection = this.modeler.get("selection")
到这里,Modeler的自定义以及相关的引用就已经完成了,能看到这里的同学很不错了,可能一开始可能是比较难理解的,只能多看几遍慢慢吸收,接下来的篇章就是分解自定义左侧工具栏、自定义右侧属性栏等等相关的内容,感谢你的耐心阅读。