bpmn-js自定义元素开发:扩展BPMN 2.0规范,添加业务特定节点类型
在业务流程建模中,标准BPMN 2.0元素往往无法满足特定业务场景需求。bpmn-js提供了灵活的扩展机制,允许开发者添加自定义元素类型。本文将通过实际案例,详细介绍如何开发自定义BPMN元素,包括元素定义、渲染和交互逻辑的实现。
自定义元素开发基础
bpmn-js的自定义元素开发涉及三个核心模块:元素工厂(Element Factory)、渲染器(Renderer)和规则(Rules)。元素工厂负责创建自定义元素的业务对象和图形属性,渲染器定义元素的视觉呈现,规则控制元素间的交互行为。官方提供的集成测试示例展示了完整的自定义元素实现,可参考test/integration/custom-elements/目录下的代码。
自定义元素工厂实现
元素工厂是创建自定义元素的起点,负责定义元素的尺寸、类型等基础属性。以下是一个创建三角形和圆形元素的工厂实现:
// [CustomElementFactory.js](https://link.gitcode.com/i/455842efea1cc581fee2fde5bf53aaee)
export default function CustomElementFactory(injector) {
injector.invoke(ElementFactory, this);
this.create = function(elementType, attrs) {
var type = attrs.type;
if (/^custom:/.test(type)) {
type = attrs.type.replace(/^custom:/, '');
var size = this._getCustomElementSize(type);
return this._baseCreate(elementType, assign({
type: elementType,
businessObject: {}
}, attrs, size));
}
return this.createElement(elementType, attrs);
};
this._getCustomElementSize = function(type) {
var shapes = {
triangle: { width: 40, height: 40 },
circle: { width: 140, height: 140 }
};
return shapes[type] || { width: 100, height: 80 };
};
}
该工厂通过_getCustomElementSize方法为不同类型的自定义元素设置尺寸,并通过create方法注册以custom:为前缀的元素类型。这种命名约定可以避免与标准BPMN元素冲突。
自定义渲染器开发
渲染器决定了自定义元素在画布上的视觉表现。bpmn-js使用SVG绘制所有元素,自定义渲染器需要实现特定元素的绘制逻辑。
三角形和圆形元素渲染实现
以下渲染器实现了三角形和圆形元素的SVG绘制:
// [CustomRenderer.js](https://link.gitcode.com/i/94f1f35d8e9be84ded7b56b76741fc14)
export default function CustomRenderer(eventBus, styles) {
BaseRenderer.call(this, eventBus, 2000);
this.handlers = {
'custom:triangle': function(parentGfx, element) {
return self.drawTriangle(parentGfx, element.width);
},
'custom:circle': function(parentGfx, element, attrs) {
return self.drawCircle(parentGfx, element.width, element.height, attrs);
}
};
this.drawTriangle = function(parentGfx, side) {
var points = [
{ x: side/2, y: 0 },
{ x: side, y: side },
{ x: 0, y: side }
];
var polygon = svgCreate('polygon');
svgAttr(polygon, { points: points.map(p => `${p.x},${p.y}`).join(' ') });
svgAttr(polygon, { stroke: '#3CAA82', fill: '#3CAA82' });
svgAppend(parentGfx, polygon);
return polygon;
};
this.drawCircle = function(parentGfx, width, height) {
var circle = svgCreate('circle');
svgAttr(circle, {
cx: width/2, cy: height/2,
r: Math.round((width + height)/4),
stroke: '#4488aa', fill: 'white'
});
svgAppend(parentGfx, circle);
return circle;
};
}
渲染器通过handlers对象注册元素类型与绘制函数的映射,使用tiny-svg库创建SVG元素并设置样式属性。三角形使用<polygon>元素绘制,圆形使用<circle>元素,分别设置了不同的颜色和尺寸计算方式。
自定义规则实现
自定义规则控制元素间的交互行为,如连接限制、元素放置规则等。通过扩展BpmnRules,可以为自定义元素添加特定的业务规则。
自定义连接规则示例
以下规则限制了只有圆形元素可以连接到三角形元素:
// [CustomRules.js](https://link.gitcode.com/i/cdbfb48fe935ed27fa6f653858f965ba)
export default function CustomRules(eventBus, bpmnRules) {
this.canConnect = function(context) {
var source = context.source,
target = context.target;
// 允许从圆形连接到三角形
if (source.type === 'custom:circle' && target.type === 'custom:triangle') {
return true;
}
// 应用默认BPMN规则
return bpmnRules.canConnect(context);
};
}
规则实现通过重写canConnect方法,添加自定义连接逻辑,并在不匹配自定义规则时回退到默认BPMN规则。这种方式既保留了标准BPMN行为,又添加了自定义元素的特殊规则。
自定义元素集成与使用
完成上述组件后,需要将自定义模块集成到bpmn-js实例中。通过配置additionalModules选项,可以将自定义工厂、渲染器和规则注册到模型器中。
模型器集成示例
import Modeler from 'lib/Modeler';
import CustomElementFactory from './CustomElementFactory';
import CustomRenderer from './CustomRenderer';
import CustomRules from './CustomRules';
var modeler = new Modeler({
container: '#canvas',
additionalModules: [
{
__init__: [ 'customElementFactory', 'customRenderer', 'customRules' ],
customElementFactory: [ 'type', CustomElementFactory ],
customRenderer: [ 'type', CustomRenderer ],
customRules: [ 'type', CustomRules ]
}
]
});
// 创建自定义元素
modeler.get('elementFactory').create('shape', {
type: 'custom:triangle',
x: 100, y: 100
});
集成过程需要将自定义模块注册到bpmn-js的依赖注入系统中,使用__init__数组指定模块初始化顺序。创建自定义元素时,只需指定以custom:为前缀的类型名称即可。
高级自定义:业务属性扩展
除了视觉和交互扩展,还可以为自定义元素添加业务属性。通过扩展BPMN模型(Moddle)的元数据,可以定义自定义元素的XML序列化方式,使自定义元素能够与BPMN 2.0标准格式兼容。
自定义元素元数据定义
创建custom.json文件定义自定义元素的元数据:
{
"name": "custom",
"uri": "http://custom/bpmn",
"prefix": "custom",
"types": [
{
"name": "Triangle",
"superClass": [ "bpmn:Shape" ],
"properties": [
{ "name": "priority", "type": "Integer", "isAttr": true }
]
},
{
"name": "Circle",
"superClass": [ "bpmn:Shape" ],
"properties": [
{ "name": "riskLevel", "type": "String", "isAttr": true }
]
}
]
}
在模型器初始化时加载自定义元数据:
var modeler = new Modeler({
container: '#canvas',
moddleExtensions: {
custom: customMeta
}
});
通过这种方式,自定义元素可以拥有业务特定的属性(如priority和riskLevel),并能正确序列化为XML格式,实现与其他BPMN工具的互操作性。
总结与最佳实践
自定义元素开发是bpmn-js的高级特性,需要理解元素生命周期、渲染流程和规则系统。以下是开发自定义元素的最佳实践:
- 使用命名空间:始终使用
custom:前缀或自定义命名空间,避免与标准元素冲突 - 保持兼容性:通过元数据定义确保自定义元素可序列化,支持导入导出
- 模块化设计:将元素工厂、渲染器和规则分离实现,便于维护
- 复用现有机制:尽可能继承现有类(如
ElementFactory、BaseRenderer),减少重复代码
通过本文介绍的方法,开发者可以为bpmn-js添加各种业务特定的元素类型,扩展BPMN 2.0规范以满足实际业务需求。完整的实现示例可参考项目中的集成测试代码,包含了从元素创建到渲染的全流程实现。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



