bpmn-js 阅读指南:
- bpmn.js一个基于Bpmn 2.0的前端工作流展示和绘制工具
- 使用bpmn-js 配置颜色
- Bpmn-js 属性控制
- Bpmn-js自定义Palette
- bpmn-js 事件总线处理
- 聊一聊bpmn-js中的Viewer和Modeler
- 聊一聊bpmn-js中的Palette
- 聊一聊bpmn-js中的elementFactory模块
- bpmn-js通过moddle插件实现自定义元素和自定义属性
bpmn-js
中使用Modeler
进行流程图的建模,而Palette
则是其内部创建的提供左侧工具栏的插件。插件使用didi
实现的依赖注入,其创建使用参考上一篇文章:推荐前端一个轻量级别的依赖注入库:didi。
Palette实现主要依托三个功能模块:Eventbus
(详情参考bpmn-js 事件总线处理)、diagram-js
的Palette
插件(之后简称Palette
)以及bpmn-js
中的PaletteProvider
(之后简称PaletteProvider
)。左侧工具栏的加载原理是:作为Palette
的提供方PalettProvider
则需要在插件注册之前通过Palette
提供的注册器registerProvider
注册监听并通过_rebuild
会发送一个palette.getProviders
事件,将当前提供者添加到Palette
的集合中。Palette
加载后通过eventbus
监听整体页面绘制事件,当页面绘制后Palette将会回调内置_rebuild
方法获取小工具栏组件信息,这时候我们的PaletteProvider
也已经完成了注册,Palette会通过_rebuild
重绘完成整体小工具栏区域的加载。接下来我们了解下bpmn-js
中的左侧小工具栏的加载流程。
PaletteProvider
可以简单的认为它是最终的提供方,小工具栏上面有什么说到底还是由它决定的。在bpmn-js
源码中内置了一个”paletteProvider“
,也就是说我们可以什么都不做会有一套默认的小工具栏供我们使用。我们想对其进行修改bpmn-js
提供给我们两种方式:完全自定义和动态增加。我们先暂时忘掉这两种方式,首先来看下如何去实现一个PaletteProvider
的角色(插件定义细节请查看:推荐前端一个轻量级别的依赖注入库:didi)。
注册
想要成为一个PaletteProvider
的角色,我们就必须要通过diagram-js
的palette
的插件进行注册。
// Palette提供者
function PaletteProvider(palette,...){
....
palette.registerProvider(this);
}
//必须要有diagram-js的palette插件
PaletteProvider.$inject = ['palette']
提供
注册完成后当Palette需要我们绘制的时候我们就需要提供给Palette到底绘制哪些工具?如何绘制?这时候我们需要提供,这里有个核心的方法就是getPaletteEntries
,这个方法是Palette
获取小工具集合的必须包含的方法,该方法需要我们返回一个对象,对象里可以有多个工具,对象格式姑且以PaletteEntry
标识,且所有注册的提供者的集合会被整合。
// 工具对象格式
type PaletteEntry = {
action: (event: Event, autoActivate: boolean) => any || {}; // 事件回调,或者是事件对象如{dragStart:()=>{}}
className?: string; // 类名,这里可用作加载字体图标
group?: string; // 区域划分
html?: string; // 自定义html显示
imageUrl?: string; // 图标链接地址
separator?: boolean;
title?: string; // 悬停显示文字
};
// 改方法必须有
PaletteProvider.prototype.getPaletteEntries = function() {
return {
'hand-tool': {
group: 'tools',
className: 'bpmn-icon-hand-tool',
title: '手型工具',
action: {
click: function(event) {
handTool.activateHand(event);
}
}
},
}
}
上述是手型工具的提供方式,我们常规使用的事件处理也就dragstart、click
两种,以下是bpmn-js
提供的创建action
的方式:
function createAction(type, group, className, title, options) {
function createListener(event) {
var shape = elementFactory.createShape(assign({ type: type }, options));
if (options) {
var di = getDi(shape);
di.isExpanded = options.isExpanded;
}
create.start(event, shape);
}
return {
group: group,
className: className,
title: title,
action: {
dragstart: createListener,
click: createListener
}
};
}
// 上述用到了其他的依赖插件,需要我们在$inject中声明并通过构建函数传入
PaletteProvider.$inject = [
'palette',
'create',
'elementFactory',
'spaceTool',
'lassoTool',
'handTool',
'globalConnect',
'translate'
];
如上createListener
提供的是工具的绘制方法,这里使用的bpmn-js提供的几种svg图形绘制,当然若有需要我们也可以自己绘制,这个后续文章会深入讨论。
PaletteProvider
既然已经了解完成,这里我们来说下开始的时候说的两种小工具的方式:完全自定义和动态增加。
- 完全自定义:将插件名命名为:
‘paletteProvider’
,会自动覆盖已有的paletteProvider
插件。
// 将声明设置为paletteProvider
export default {
__init__: ['paletteProvider'],
paletteProvider: ['type', PaletteProvider],
}
// 修改PaletteProvider.js 的getPaletteEntries
// 改方法必须有
PaletteProvider.prototype.getPaletteEntries = function() {
......
return {
'hand-tool': {
group: 'tools',
className: 'bpmn-icon-hand-tool',
title: '手型工具',
action: {
click: function(event) {
handTool.activateHand(event);
}
}
},
}
}
这样加载后就如上一样只剩一个小小的手型工具了。
- 动态增加:若只是想加一个新的工具进去,完全可以自定义一个名字,设置号
group
分区就可以,我们这里还是以上述为例修改下group
,需要注意的是工具名需要修改, 不然可能会无效,试试效果:
// 自定义名称
export default {
__init__: ['customProvider'],
customProvider: ['type', PaletteProvider],
}
// 修改PaletteProvider.js 的getPaletteEntries
// 改方法必须有
PaletteProvider.prototype.getPaletteEntries = function() {
......
return {
'hand-tool-2': {
group: 'activity',
className: 'bpmn-icon-hand-tool',
title: '手型工具2',
action: {
click: function(event) {
handTool.activateHand(event);
}
}
},
}
}
这样在activity
区域就多了一个手型工具了
Palette
diagram-js
的Palette
插件可以说是整个bpmn-js
的左侧工具的管理模块了,它定义了PaletteProvider的注册方式、提供方法已经工具的类型格式。这里我们来看下几个核心的功能部分。
提供注册
Palette
内部实现了一个registerProvider
方法来让PaletteProvider
进行注册登记,并通知Palette构建组件信息,通过eventbus方式将其加载到内部的event
中
// 注册实现
Palette.prototype.registerProvider = function(priority, provider) {
...
// 添加监听将provider加载到内部的event中
this._eventBus.on('palette.getProviders', priority, function(event) {
event.providers.push(provider);
});
this._rebuild();
};
// 组件构建部分
Palette.prototype._rebuild = function() {
// 这里用于发送信息让注册方法的监听添加provider
var providers = this._getProviders();
...
this._update();
};
// 这里是发送获取组件的消息
Palette.prototype._getProviders = function(id) {
var event = this._eventBus.createEvent({
type: 'palette.getProviders',
providers: []
});
this._eventBus.fire(event);
return event.providers;
};
监听绘制
在Palette
插件开始加载的时候会监听diagram-js
的绘制事件,并在合适的时机重写加载绘制组件:
export default function Palette(eventBus, canvas) {
......
// toolMananger插件用于协助管理palette组件的编辑状态
eventBus.on('tool-manager.update', function(event) {
var tool = event.tool;
self.updateToolHighlight(tool);
});
// 国际化监听
eventBus.on('i18n.changed', function() {
self._update();
});
// diagram初始化监听
eventBus.on('diagram.init', function() {
self._diagramInitialized = true;
self._rebuild();
});
}
如上就是本篇文章的所有的内容了,若是感兴趣或是觉得对你有所帮助,欢迎关注一直在前端路上陪伴你的胖蔡~