Vue+bpmn.js自定义流程图之render(三)

自定义bpmn.js画板元素render

  • 一、回顾
  • 二、代码
    • 1.目录
    • 2.代码实现
      • 1.render.js文件
      • 2.util.js文件
      • 3.index.js文件
  • 三、效果

一、回顾

经过前面 palette 模块的自定义,左侧工具栏的样式已经出来了,但是 rendercontextPad 这两个部分还是原来的样式。同样的,这两部分也需要重写对应的方法来实现自定义。
Vue+bpmn.js自定义流程图之render(三)_第1张图片

二、代码

1.目录

同样在plugins文件目录下新建render文件夹。创建一个index.js入口文件和render.js自定义render文件(用来覆盖默认render),再创建一个util.js文件,用来存放render的自定义配置(元素大小和自定义元素图片路径)。

2.代码实现

1.render.js文件

render.js

import inherits from 'inherits'
import BaseRenderer from 'diagram-js/lib/draw/BaseRenderer'
import {
    isObject,
    assign,
    forEach
} from 'min-dash';
import {
    append as svgAppend,
    create as svgCreate,
    classes as svgClasses
} from 'tiny-svg'

import {
    customElements,
    customConfig,
    hasLabelElements
} from './util'


export default function CustomRenderer(eventBus, styles, textRenderer) {

    //删除双击事件
    delete eventBus._listeners['element.dblclick']
    BaseRenderer.call(this, eventBus, 2000)
    var computeStyle = styles.computeStyle
    function renderLabel(parentGfx, label, options) {
        options = assign({
            size: {
                x: 0,
                y: 20,
                width: 40,
            }
        }, options);

        var text = textRenderer.createText(label || '', options);
        svgClasses(text).add('djs-label');
        svgAppend(parentGfx, text);

        return text;
    }
    //计算文字宽度
    String.prototype.pxWidth = function (font) {
        // re-use canvas object for better performance
        var canvas = String.prototype.pxWidth.canvas || (String.prototype.pxWidth.canvas = document.createElement("canvas")),
            context = canvas.getContext("2d");

        font && (context.font = font);
        var metrics = context.measureText(this);

        return metrics.width;
    }
  //绘制自定义元素
    this.drawCustomElements = function (parentNode, element) {
        const {
            type,

        } = element // 获取到类型

        if (type !== 'label') {
            if (customElements.includes(type)) { // or customConfig[type]
                const {
                    url,
                    attr,
                    defaultName
                } = customConfig[type]
                //可以设置节点默认值
                // if (!element.businessObject.name && defaultName) {
                //     element.businessObject.name = defaultName
                // }

                const customIcon = svgCreate('image', {
                    ...attr,
                    href: url
                })
                element['width'] = attr.width //  直接修改了元素的宽高
                element['height'] = attr.height
                svgAppend(parentNode, customIcon)
                // 判断是否有name属性来决定是否要渲染出label
                // if (!hasLabelElements.includes(type) && element.businessObject.name) {
                //当类型为UserTask时,自定义绘制label标签(标签会在shape里面)
                if (type === 'bpmn:UserTask' && element.businessObject.name) {
                    const textWidth = element.businessObject.name.pxWidth('normal 13px')
                    const text = svgCreate('text', {
                        x: attr.x + (attr.width / 2 - textWidth / 1.6),
                        y: attr.y + attr.height + 15,
                        fontSize: "13px",
                        fill: "#000"
                    })
                    text.innerHTML = element.businessObject.name
                    svgAppend(parentNode, text)
                }
                // renderLabel(parentNode, element.label)

                return customIcon
            }
            const shape = this.bpmnRenderer.drawShape(parentNode, element)
            return shape
        }
    }
}

inherits(CustomRenderer, BaseRenderer)

CustomRenderer.$inject = ['eventBus', 'styles', 'textRenderer']

CustomRenderer.prototype.canRender = function (element) {
    // ignore labels
    return true
    // return !element.labelTarget;
}

CustomRenderer.prototype.drawShape = function (p, element) {
    const {
        type,
    } = element

    if (customElements.includes(type)) {
        return this.drawCustomElements(p, element)
    }
}

CustomRenderer.prototype.getShapePath = function (shape) {

}

上面代码做的事情:
重写 renderer类,同时覆盖了其原型上的 drawShape方法

通过drawShape来绘制各种类型的元素,先判断哪些元素类型需要自定义绘制,然后通过drawCustomElements方法绘制自定义元素。

2.util.js文件

util.js

//  数组的作用就是用来放哪些类型是需要我们自定义的, 从而在渲染的时候就可以与不需要自定义的元素作区分.
const startNode = require('/public/bpmn_imgs/startNode.png')
const endNode = require('/public/bpmn_imgs/endNode.png')
const taskNode = require('/public/bpmn_imgs/taskNode.png')
const gatewayNode = require('/public/bpmn_imgs/gatewayNode.png')
const customElements = ['bpmn:StartEvent', 'bpmn:ExclusiveGateway', 'bpmn:UserTask', 'bpmn:EndEvent'] //需要自定义的元素类型
const hasLabelElements = ['bpmn:StartEvent', 'bpmn:ExclusiveGateway', 'bpmn:UserTask', 'bpmn:EndEvent'] // 一开始就有label标签的元素类型
const customConfig = { // 自定义元素的配置
    'bpmn:StartEvent': {
        url: startNode,
        defaultName: '开始',
        attr: {
            x: 0,
            y: 0,
            width: 40,
            height: 40
        }
    },
    'bpmn:EndEvent': {
        url: endNode,
        defaultName: '结束',
        attr: {
            x: 0,
            y: 0,
            width: 40,
            height: 40
        }
    },
    'bpmn:UserTask': {
        url: taskNode,
        attr: {
            x: 0,
            y: 0,
            width: 40,
            height: 40
        }
    },
    'bpmn:ExclusiveGateway': {
        url: gatewayNode,
        attr: {
            x: 0,
            y: 0,
            width: 40,
            height: 40
        }
    },

}

export {
    customElements,
    hasLabelElements,
    customConfig
}

util.js 导出了一些自定义元素的配置 customConfig 中配置了需要自定义的元素的图片url和宽、高、坐标。

3.index.js文件

index.js

import CustomRenderer from './render'

export default {
    __init__: ["CustomRenderer"],
    CustomRenderer: ["type", CustomRenderer]
};

三、效果

render这个模块的类重写完过后,应该看到绘制在画板上的元素变成自定义的了

Vue+bpmn.js自定义流程图之render(三)_第2张图片

但是contextPad这个部分还是原生的样式,这个模块同样也需要重写。到这里我们应该清楚了我们就是通过重写bpmn的几个方法来达到自定义的效果,所以搞懂方法里的参数和作用也很重要,有兴趣的自己打印出来里面的参数研究一下,会更加清晰代码到底做了什么。

你可能感兴趣的:(vue相关,vue.js,javascript,前端,bpmn)