bpmn-js自定义之Modeler以及相关引用

项目环境:

  • 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 ],
};

结构目录参考图:

bpmn-js自定义之Modeler以及相关引用_第1张图片 

经过以上两步,自定义的CustomModeler对象就出来了,然后将上面的代码整理好放在不同的目录等待引用,下面是CustomModeler的参数设置与使用方法:

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的自定义以及相关的引用就已经完成了,能看到这里的同学很不错了,可能一开始可能是比较难理解的,只能多看几遍慢慢吸收,接下来的篇章就是分解自定义左侧工具栏、自定义右侧属性栏等等相关的内容,感谢你的耐心阅读。

 

 

你可能感兴趣的:(经验分享)