最好用的流程编辑器bpmn-js系列文章
上一篇文章『最好用的流程编辑器bpmn-js系列之本地文件』介绍了如何将本地的bpmn文件渲染到流程编辑器以及将编辑器内的流程作为图片或bpmn文件保存到本地,这篇文章将会介绍流程编辑界面的一些优化
以下演示代码基于上一节搭建好的vue环境,使用bpmn版本为当前最新版7.3.0
文章开头先说一下我在写本系列教程中除了阅读部分源码和论坛外,还参考了很多网上的优秀文章,在此感谢这些无私的贡献者,目前网上大多数教程都是基于7.3.0之前的版本写的,在使用importXML
等方法时用了如下callback的方式
modeler.importXML(xml, (err, warnings) => {
// ...
});
但当将bpmn-js我升级到了7.3.0之后,再使用上边的方式就会出现报错
Error: Passing callbacks to importXML is deprecated and will be removed in a future major release.
提示这种回调方式不建议使用,并且会在后续版本中移除,推荐如下这样的写法来代替
try {
const result = await modeler.importXML(xml);
const { warnings } = result;
console.log(warnings);
} catch (err) {
console.log(err.message, err.warnings);
}
除了importXML
方法外,其他需要使用上边这种写法的还有importDefinitions
、open
、saveXML
、saveSVG
、createDiagram
在流程编辑的过程中,会出现操作撤销和恢复撤销的需求,bpmn-js提供了redo
和undo
方法来实现,使用比较简单
先添加两个按钮
<li>
<a href="javascript:" class="active" @click="handlerUndo" title="撤销操作">撤销</a>
</li>
<li>
<a href="javascript:" class="active" @click="handlerRedo" title="恢复操作">恢复</a>
</li>
然后编写对应的方法
handlerRedo() {
this.bpmnModeler.get("commandStack").redo();
},
handlerUndo() {
this.bpmnModeler.get("commandStack").undo();
}
当流程比较复杂,元素较多的时候,我们需要放大流程,关注于流程的某一块编辑,这时候就需要用到bpmn-js提供的zoom
方法来实现流程图的放大缩小
添加三个按钮,分别为放大、缩小、还原
<li>
<a href="javascript:" class="active" @click="handlerZoom(0.1)" title="放大">放大</a>
</li>
<li>
<a href="javascript:" class="active" @click="handlerZoom(-0.1)" title="缩小">缩小</a>
</li>
<li>
<a href="javascript:" class="active" @click="handlerZoom(0)" title="还原">还原</a>
</li>
然后编写对应的方法handlerZoom
来控制放大和缩小,放大缩小实际上是通过zoom
方法来实现的,zoom
方法接收一个num参数,这个参数为显示的比例,默认为1,放大就是增加这个值,缩小就是减小这个值,还原就是将这个值重置为1
handlerZoom(radio) {
const newScale = !radio ? 1.0 : this.scale + radio;
this.bpmnModeler.get("canvas").zoom(newScale);
this.scale = newScale;
}
需要注意的是这里的this.scale
就是默认值1,需要在data中定义这个变量
bpmn-js除了提供如上一些方法能方便操作画布元素外,还提供键盘快捷键的操作支持,可通过在创建BpmnModeler时添加keybord
配置来实现
this.bpmnModeler = new BpmnModeler({
container: canvas,
keyboard: {
bindTo: window
}
});
目前bpmn-js支持如下一些快捷键操作
除了键盘快捷键外,bpmn-js也支持ctrl+鼠标滚轮来控制放大缩小
许多流程图软件的背景都是网格状,bpmn-js如何添加网格背景呢?修改相应class的css即可
.containers {
background: white;
overflow: auto;
background-image: linear-gradient(
90deg,
rgba(220, 220, 220, 0.5) 6%,
transparent 0
),
linear-gradient(rgba(192, 192, 192, 0.5) 6%, transparent 0);
background-size: 12px 12px;
width: 100%;
height: calc(100vh - 82px);
-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
}
如果你想修改或禁用bpmn-js的某些默认功能,例如你不想要左侧的工具栏Palette,则可以通过additionalModules
选项来实现,additionalModules
允许你使用自定义模块来修改或替换现有功能
this.bpmnModeler = new CustomModeler({
container: canvas,
additionalModules: [
{
// 禁用滚轮滚动
zoomScroll: ["value", ""],
// 禁止拖动线
bendpoints: ["value", ""],
// 禁用左侧面板
paletteProvider: ["value", ""],
// 禁止点击节点出现contextPad
contextPadProvider: ["value", ""],
// 禁止双击节点出现label编辑框
labelEditingProvider: ["value", ""]
}
]
});
bpmn-js基本使用文章中我们讲到了bpmn-js有两个模式Modeler编辑模式和Vierer预览模式,实际上有很多小伙伴并不使用bpmn-js提供的Viewer模式,而是通过禁用以上这些组件来达到类似Viewer展示的模式
很多时候我们需要监听用户的操作并给予相应的反馈,例如在bpmn-js本地文件文章中关于监听变化下载文件的介绍中,我们需要监听到流程的变化,并实时将数据补充到a标签中,用到了如下代码
this.bpmnModeler.on("commandStack.changed", opscoffee)
这里的bpmnModeler.on
就是个监听方法,能监听到流程的变化,除此之外bpmn-js还提供了eventBus
来帮助我们做事件监听,用法如下
export default {
...
methods: {
init() {
const canvas = this.$refs.canvas;
this.bpmnModeler = new BpmnModeler({
container: canvas
});
this.createNewDiagram();
},
async createNewDiagram() {
try {
const result = await this.bpmnModeler.importXML(this.xmlStr);
const { warnings } = result;
console.log(warnings);
this.success();
} catch (err) {
console.log(err.message, err.warnings);
}
},
success() {
this.addEventBusListener();
},
addEventBusListener() {
const that = this;
const eventBus = this.bpmnModeler.get("eventBus");
eventBus.on("element.click", function(e) {
console.log("eventBusListener", e);
});
}
}
};
</script>
在createNewDiagram
渲染完成后调用success
方法,success
中添加了addEventBusListener
监听方法,然后通过eventBus.on
来实现对事件的监听,例如这里监听了element.click
点击事件
监听到事件后就很方便的进行后续的操作了,例如我想判断如果用户点击了UserTask任务
,那么就打印任务id、type、name,则可以这样实现
addEventBusListener() {
const that = this;
const eventBus = this.bpmnModeler.get("eventBus");
eventBus.on("element.click", function(e) {
that.elementClick(e);
});
},
elementClick(e) {
if (e.element.businessObject.$type === "bpmn:UserTask") {
console.log(
"这是一个用户节点",
e.element.businessObject.id,
e.element.businessObject.$type,
e.element.businessObject.name
);
}
}
那么究竟有哪些事件类型呢?我们可以通过bpmnModeler.get("eventBus")
方法来获取,常用的有如下这些
当我们需要获取流程中的节点时,可以使用如下方法来获取全部节点或检索指定类型的节点
bpmnModeler.get("elementRegistry").getAll()
bpmnModeler.get("elementRegistry").get(ID)
通过modeling的updateProperties
方法可以修改节点属性,例如这里修改节点name
为ops-coffee.cn
const modeling = this.bpmnModeler.get("modeling");
const element = this.bpmnModeler
.get("elementRegistry")
.get("Activity_1w1vj9r");
modeling.updateProperties(element, {
name: "ops-coffee.cn"
});
接触bpmn-js不久,且第一次用VUE,边学边写,文章难免出错,各位多多包含。想要打造一个好用的适合自己的流程编辑器,需要了解的内容比较多,bpmn-js会分多篇文章来介绍,下一篇介绍bpmn-js的Viewer模式下的节点颜色修改、鼠标拖动等内容,欢迎关注
部分小伙伴对流程编辑器不了解,或是对BPMN不了解,我搭建了个在线的Demo: https://bpmn.ops-coffee.cn,点击链接即可轻松体验,建议PC端打开效果更好