自定义bpmn.jspalette样式
前期准备
我在之前的 vue-bpmn
项目的 git
仓库下新创建了一个分支 custom
,用来存放自定义样式的相关内容,项目快速预览地址
bpmn.js
的面板布局了解一下
如果我们想自定义工具栏的样式的话,可以选择在默认的Palette基础上进行修改(或者添加新的备选项),也可以完全自定义工具栏 palette
在默认的Palette基础上修改
在默认的左侧工具栏里新增一个自定义的项
- 元素类型:
bpmn:Task
- 元素名称:
init-task
- 样式:沿用
bpmn:Task
原有的样式,仅仅将边框改为红色 - 作用:创建一个类型为
init-task
的任务节点
先看看效果怎么样:
另一种自定义样式效果:
前期准备
我们直接在新创建的分支 custom
上写代码,顺便删除创建分支后复制过来的不必要的文件,相关案例代码dulily/vue-bpmn
bpmn.js
的修改样式源码参考
新建文件:在 views
文件夹下新建一个名为 custom-palette.vue
的文件(配置路由),然后将之前的基础案例中的内容复制进去;然后在 components
文件夹下新建一个文件夹 custom
用来放置后面需要的自定义的东西,然后在 custom
文件夹下新建 CustomPalette.js
文件和 index.js
文件
编写 CustomPalette.js
文件
我们可以在CustomPalette.js
文件里边写上我们要自定义的项,这个 js
文件是导出一个类(类的名称可以随意去,但是在引用的时候不能随意取)
// CustomPalette.js
export default class CustomPalette {
constructor(bpmnFactory, create, elementFactory, palette, translate) {
this.bpmnFactory = bpmnFactory;
this.create = create;
this.elementFactory = elementFactory;
this.translate = translate;
palette.registerProvider(this);
}
// 这个函数就是绘制palette的核心
getPaletteEntries(element) {}
}
CustomPalette.$inject = [
'bpmnFactory',
'create',
'elementFactory',
'palette',
'translate'
]
上面代码解析:
- 定义一个类
- 使用
$inject
注入一些需要的变量 - 在类中使用
palette.registerProvider(this)
指定这是一个palette
定义完 CustomPalette.js
之后,我们需要在其同级的 index.js
中将它导出
// custom/index.js
import CustomPalette from './CustomPalette'
export default {
__init__: ['customPalette'],
customPalette: ['type', CustomPalette]
}
注意:__init__
中的名字必须是 customPalette
,它下面的属性名也必须是 customPalette
,否则会报错哦
在页面中使用
在页面中如何使用
<!--custom-palette.vue-->
<script>
...
import customModule from './custom'
...
this.bpmnModeler = new BpmnModeler({
...
additionalModules: [
// 左边工具栏以及节点
propertiesProviderModule,
// 自定义的节点
customModule
]
})
</script>
编写核心函数 getPaletteEntries
代码
函数的名称不能变,否则会报错,首先它返回的是一个对象,对象中指定的就是你要自定义的项
// CustomPalette.js
getPaletteEntries(element) {
return {
'create.init-task': {
group: 'model', // 分组名
className: 'bpmn-icon-task red', // 样式类名
title: translate('创建一个类型为init-task的任务节点'),
action: { // 操作
dragstart: createTask(), // 开始拖拽时调用的事件
click: createTask() // 点击时调用的事件
}
}
}
}
自己定义的项名称为:create.init-task
,它有几个固定的属性:
group
:属于哪个分组,比如tools
、event
、gateway
、activity
等等,用于分类className
:样式类名,我们可以通过设置样式给元素修改样式title
:鼠标移动到元素上面给出的提示信息action
:用户操作时会触发的事件
下一步我们要做的就是 :通过 className
来设置样式;通过 action
来定义要触发的事情
编写 className
代码
在 src
目录下的assets
文件夹下新建了一个 css
文件夹,并在 css
文件夹中新建了 一个全局样式文件 custom.css
,然后在 main.js
中引用这个全局样式文件
// main.js 中引入全局css文件
import '../src/assets/css/custom.css'
然后我们在 css
文件中添加样式
/* custom.css */
.bpmn-icon-task.red {
color: #cc0000 !important;
}
解析:上面的 className
之所以用 bpmn-icon-task,是因为这个图标类是
bpmn.js中自带的
iconfont类,可以使图标显示为
task` 图标的效果
字体图标改变颜色只需要设置 color
就可以了
如果我们想换一只图片的话也可以使用 className
来实现
/* custom.css */
.icon-custom { /* 定义一个公共的类名 */
border-radius: 50%;
background-size: 65%;
background-repeat: no-repeat;
background-position: center;
}
.icon-custom.init-task { /* 加上背景图 */
background-image: url('https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/rules.png');
}
然后修改 create.init-task
中的 className
// CustomPalette.js
'create.init-task': {
className: 'icon-custom init-task'
}
这样我们就可以看到自定义的图标了
编写 action
代码
此时,页面工具栏上已经能渲染出我们自定义的元素了,但是点击或者拖拽是没有效果的。
我们希望实现点击或者拖拽元素能在画布中画出一个 init-task
,因此,得给这个元素加上事件,也就是编写一个函数用来创建 bpmn:Task
这个元素
// CustomPalette.js
function createTask() {
return function(event) {
const businessObject = bpmnFactory.create('bpmn:Task');
const shape = elementFactory.createShape({
type: 'bpmn:Task',
businessObject
});
console.log(shape) // 只在拖动或者点击时触发
create.start(event, shape);
}
}
这里演示的就是利用 bpmn.js
提供的一些方法创建 shape
然后将其添加到画布上
这里创建的是一个类型为 bpmn:Task
的元素,还可以用来创建 bpmn:StartEvent、bpmn:ServiceTask、bpmn:ExclusiveGateway
等
现在我们拖动或点击 init-task
图标就可以在页面上创建一个 Task
元素了
此时,画布中的元素还是原始状态,后面学习如何自定义渲染
完整的 CustomPalette.js
代码
整合代码
// CustomPalette.js
export default class CustomPalette {
constructor (bpmnFactory, create, elementFactory, palette, translate) {
this.bpmnFactory = bpmnFactory
this.create = create
this.elementFactory = elementFactory
this.translate = translate
palette.registerProvider(this)
}
// 这个函数就是绘制palette的核心
getPaletteEntries(element) {
const {
bpmnFactory,
create,
elementFactory,
// translate
} = this
function createTask () {
return function (event) {
const businessObject = bpmnFactory.create('bpmn:Task') // 这个也可以不要
const shape = elementFactory.createShape({
type: 'bpmn:Task',
businessObject
})
console.log(shape, element) // 只在拖动或者点击时触发
create.start(event, shape)
}
}
return {
'create.init-task': {
group: 'model', // 分组名
className: 'bpmn-icon-task red', // 样式类名
title: this.translate('创建一个类型为init-task的任务节点'),
action: { // 操作
dragstart: createTask(), // 开始拖拽时调用的事件
click: createTask() // 点击时调用的事件
}
}
}
}
}
CustomPalette.$inject = [
'bpmnFactory',
'create',
'elementFactory',
'palette',
'translate'
]
在默认的 Palette
基础上修改的方式,实际上就是定义了一个 CustomPalette
,然后在 new BpmnModeler
生成的对象中引用进去
完全自定义Palette
如果我们不想使用它提供的默认选项,完全自定义的话就不能使用上面的方法了。需要重写 BpmnModeler
这个类,自己实现 modeler
前期准备
继续在上面的项目基础上在 components
下创建一个 customModeler
文件夹,在 customModeler
文件夹下新建 custom
文件夹和 index.js
文件,然后在 views
文件夹下新建 custom-modeler.vue
文件(记得配置路由)
customModeler
文件夹下的文件用来放置自定义的 modeler
项目结构:
编写 CustomPalette.js
的代码
export default function PaletteProvider (bpmnFactory, palette, create, elementFactory, globalConnect) {
this.bpmnFactory = bpmnFactory
this.create = create
this.elementFactory = elementFactory
this.globalConnect = globalConnect
palette.registerProvider(this)
}
// 这个函数就是绘制palette的核心
PaletteProvider.prototype.getPaletteEntries = function (element) {
const {
bpmnFactory,
create,
elementFactory
} = this
function createTask () {
return function (event) {
const businessObject = bpmnFactory.create('bpmn:Task') // 这个也可以不要
const shape = elementFactory.createShape({
type: 'bpmn:Task',
businessObject
})
console.log(shape, element) // 只在拖动或者点击时触发
create.start(event, shape)
}
}
return {
'create.init-task': {
group: 'model', // 分组名
className: 'icon-custom init-task', // 样式类名
title: '创建一个类型为init-task的任务节点',
action: { // 操作
dragstart: createTask(), // 开始拖拽时调用的事件
click: createTask() // 点击时调用的事件
}
}
}
}
PaletteProvider.$inject = [
'bpmnFactory',
'palette',
'create',
'elementFactory',
'globalConnect'
]
重写 PaletteProvider
类,同时覆盖了其原型上的 getPaletteEntries
方法,从而达到覆盖原有的工具栏的效果
编写 custom/index.js
代码
import CustomPalette from './CustomPalette'
export default {
__init__: ['paletteProvider'],
paletteProvider: ['type', CustomPalette]
}
导出我们自定义的 Palette
编写 customModeler/index.js
代码
import Modeler from 'bpmn-js/lib/Modeler'
import inherits from 'inherits'
import CustomModule from './custom'
export default function CustomModeler (options) {
Modeler.call(this, options)
this._customElements = []
}
inherits(CustomModeler, Modeler)
CustomModeler.prototype._modules = [].concat(
CustomModeler.prototype._modules, [
CustomModule
]
)
导出的类继承了 Modeler
核心的类,保证其他功能的实现
在页面上引用
需要将我们原本通过 BpmnModeler
创建的对象改为通过我们自定义的 CustomModeler
来创建,编写 custom-modeler.vue
<!--custom-modeler.vue-->
<script>
...
import CustomModeler from './customModeler'
...
this.bpmnModeler = new CustomModeler({ // 原本是用BpmnModeler
...
additionalModules: [] // 可以不用引用任何东西
})
</script>
效果如图
后续学习如何渲染在画布中的问题