编辑bpmn_最好用的流程编辑器bpmnjs系列之ContextPad
最好用的流程编辑器bpmn-js系列文章
上一篇文章『最好用的流程编辑器bpmn-js系列之Palette』介绍了modeler模式下如何自定义左侧工具栏Palette,这篇文章将会介绍如果自定义ContextPad
以下演示代码基于上一节搭建好的vue环境,使用bpmn版本为当前最新版7.3.0
自定义ContextPad
自定义ContextPad与自定义Palette一样,有两种方式可以选择,第一种就是基于默认的ContextPad来修改,第二种就是完全写个新的ContextPad来替代默认的ContextPad,同样的这里就下完全自定义ContextPad,因为与自定义Palette高度相似,这里以具体代码为主
1.在custom目录下新建CustomContextPadProvider.js
文件,内容如下
import { assign } from "min-dash";
export default function ContextPadProvider( config, injector, contextPad, modeling, elementFactory, connect, create, translate) { this.modeling = modeling; this.elementFactory = elementFactory; this.connect = connect; this.create = create; this.translate = translate; config = config || {};
if (config.autoPlace !== false) { this.autoPlace = injector.get("autoPlace", false); }
contextPad.registerProvider(this);}
ContextPadProvider.$inject = [ "config.contextPad", "injector", "contextPad", "modeling", "elementFactory", "connect", "create", "translate"];
ContextPadProvider.prototype.getContextPadEntries = function (element) { const { autoPlace, create, elementFactory, translate, modeling, connect } = this;
function appendAction(type, className, title, options) { function appendStart(event, element) { var shape = elementFactory.createShape(assign({ type: type }, options)); create.start(event, shape, { source: element }); }
var append = autoPlace ? function (event, element) { var shape = elementFactory.createShape( assign({ type: type }, options) ); autoPlace.append(element, shape); } : appendStart;
return { group: "model", className: className, title: title, action: { dragstart: appendStart, click: append } }; }
function removeElement(e) { modeling.removeElements([element]); }
var actions = {};
if ( element.type === "bpmn:UserTask" || element.type === "bpmn:SequenceFlow" ) { assign(actions, { edit: { group: "edit", className: "bpmn-icon-business-rule", title: translate("属性"), action: {} } }); }
assign(actions, { delete: { group: "edit", className: "bpmn-icon-trash", title: translate("Remove"), action: { click: removeElement } } });
return actions;};
主要思路依然是构建最终输出的字段数据,可以根据不同类型的shape添加不同的ContextPad,以上代码就是默认所有shape都有删除按钮,然后给UserTask
类型的shape和连线都添加了一个名为“属性”的按钮
同样的这里所需要的shape数据也可以参考上篇文章最后给出的那两个Github源码链接
2.在custom/index.js
文件中添加如下内容将自定义的ContextPad导出
import CustomContextPadProvider from "./CustomContextPadProvider";
export default { __init__: ["contextPadProvider"], contextPadProvider: ["type", CustomContextPadProvider]};
这里只有自定义ContextPad
的配置,如果你是想在自定义Palette
的基础上再自定义ContextPad
的话,将以上代码与原本的内容整合即可
3.在customModeler/index.js
文件中编写自定义的CustomModeler
类
import inherits from "inherits";
import Viewer from "bpmn-js/lib/Viewer";
import ZoomScrollModule from "diagram-js/lib/navigation/zoomscroll";import MoveCanvasModule from "diagram-js/lib/navigation/movecanvas";
function CustomViewer(options) { Viewer.call(this, options);}
inherits(CustomViewer, Viewer);
CustomViewer.prototype._modules = [].concat(Viewer.prototype._modules, [ ZoomScrollModule, MoveCanvasModule]);
export { CustomViewer };
同样的如果你想在自定义Palette
的基础上再自定义ContextPad
,则在之前的代码基础上与以上代码整合
4.在页面上引用自定义的CustomModeler
以替代原本引用的BpmnModeler
类,这样就能用到我们自定义的Palette啦
import { xmlStr } from "../mock/xmlStrPreview";import { CustomModeler } from "../components/customBpmn";
export default { ... methods: { init() { const canvas = this.$refs.canvas; this.bpmnModeler = new CustomModeler({ container: canvas }); this.createNewDiagram(); }, async createNewDiagram() { try { const result = await this.bpmnModeler.importXML(xmlStr); const { warnings } = result; console.log(warnings); } catch (err) { console.log(err.message, err.warnings); } } }};
最终效果如下:
点击处理
bpmn.js给节点关联属性是通过右侧面板Properties-panel
来实现的,其核心是对xml文件的修改,但我们并没有这样用,而是直接给每个节点关联一个表单,这个节点的所有数据都保存在这个表单里,后台单独存于数据库,这里所说的节点包含图形shape和连线SequenceFlow等流程图里的元素,节点ID与表单数据一一对应
节点要关联表单数据,就需要用到我们上边添加的名为“属性”的按钮,当点击“属性”按钮时出现表单,因为不同类型的节点需要弹出不同的表单,所以在点击按钮之后主程序也需要知道点击的节点类型等数据,这就涉及到了组件间的数据传递,试了很多方法都不行,最终只能借助于借助于store
来实现了,具体代码如下
1.在store目录下新建modules目录,modules目录下创建模块化文件bpmn.js
,目录结构如下
2.在bpmn.js
中编写如下代码
const bpmn = { state: { nodeVisible: false, nodeInfo: {} }, mutations: { TOGGLENODEVISIBLE: (state, visible) => { state.nodeVisible = visible; }, SETNODEINFO: (state, info) => { state.nodeInfo = info; } }, actions: {}};
export default bpmn;
想要了解以上代码的意思,我们需要先了解下Vuex的基本思想:当我们在页面上点击了一个按钮,它会触发一个action
,action
随后会执行一个mutation
,mutation
会去改变state
,当state
改变后页面就能根据state
来进行相应的处理了
然后再来看上边的代码,用到了Vuex基本思想里边的state
和mutations
,其中state
为单一状态树,简单理解为我们定义的变量,全局变量,其他组件可以获取的到的变量,而想要修改state
里定义的变量就必须通过mutations
来实现,mutations
就定义了两个事件来对应修改state里的两个变量
state
里定义的两个变量分别为用来记录表单展示状态的nodeVisible
以及点击节点信息的nodeInfo
,默认情况下nodeVisible
为false,表示表单为隐藏状态,当点击ContextPad的的“属性”按钮时修改为true,展示表单,同时会把点击的节点信息赋予nodeInfo
,这个后边代码会有实现
想要定义的store生效还需要以下两步进行store挂载及引用
3.store/index.js
中编写如下代码挂载store
import Vue from "vue";import Vuex from "vuex";
import bpmn from "./modules/bpmn";
Vue.use(Vuex);
export default new Vuex.Store({ state: {}, mutations: {}, actions: {}, modules: { bpmn }});
4.在main.js
中引入store
import store from "./store";
new Vue({ store}).$mount("#app");
以上就定义好了store,接下来就是使用store了,首先需要处理的是,当点击ContextPad里的“属性”按钮时,修改store里nodeVisible
和nodeInfo
值
5.修改CustomContextPadProvider.js
文件,给action添加click
方法,click
方法修改store里定义的state
function clickElement(e) { store.commit("SETNODEINFO", element); store.commit("TOGGLENODEVISIBLE", true);}
if ( element.type === "bpmn:UserTask" || element.type === "bpmn:SequenceFlow") { assign(actions, { edit: { group: "edit", className: "bpmn-icon-business-rule", title: translate("属性"), action: { click: clickElement } } });}
对store的修改只能通过store.commit
来实现
6.最后在页面中就可以借助computed
和watch
来实现对store里数据的获取以及对页面的处理
export default { ... data() { return { userTask: false, scriptTask: false, sequenceFlow: "", formData: { name: "", type: "" } }; }, computed: { task: { get: function() { const that = this; const element = this.$store.state.bpmn.nodeInfo;
if (element.businessObject) { if (element.businessObject.$type === "bpmn:UserTask") { that.formData.type = "用户任务"; that.formData.name = element.businessObject.name; that.userTask = this.$store.state.bpmn.nodeVisible; }
if (element.businessObject.$type === "bpmn:SequenceFlow") { that.sequenceFlow = element.businessObject.name; that.scriptTask = this.$store.state.bpmn.nodeVisible; } }
return false; }, set: function(val) { this.$store.state.bpmn.nodeVisible = val; } } }, watch: { task(val) {} }};
最终实现的效果如下
但这里有一个问题,就是当我在表单里修改了节点名称,也就是节点的name属性时不会同步到左侧的流程图节点上,那该如何实现同步呢?也很简单,修改下watch即可
watch: { task(val) {}, userTask(val) { this.$store.state.bpmn.nodeVisible = val; }, sequenceFlow(val) { const element = this.$store.state.bpmn.nodeInfo; const modeling = this.bpmnModeler.get("modeling"); modeling.updateLabel(element, val); }, "formData.name": { handler(val, old) { const element = this.$store.state.bpmn.nodeInfo; const modeling = this.bpmnModeler.get("modeling"); modeling.updateLabel(element, val); }, deep: true }}
获取store里的值然后通过modeling.updateLabel
方法来更新节点的名称,至此问题完美解决
写在最后
接触bpmn-js不久,且第一次用VUE,边学边写,文章难免出错,各位多多包含。bmpn系列的文章已经写了六篇,至此我们的使用已经基本到此,感谢各位小伙伴的支持。除了这几篇文章外,我还创建了BPMN的主页:https://blog.ops-coffee.cn/bpmn内容更为丰富,包含了一些这系列文章中没有的内容,例如API列表、ICON列表等,欢迎查看
部分小伙伴对流程编辑器不了解,或是对BPMN不了解,我搭建了个在线的demo,点击文末阅读原文轻松体验,建议PC端打开效果更好
编辑bpmn_最好用的流程编辑器bpmnjs系列之ContextPad相关推荐
- BPMN开源工作流编辑器bpmn-js落地实践中文文档
BPMN是一套标准的业务流程建模符号规范,bpmn-js是基于此规范实现的一套渲染工具包和web建模器,可以实现拖拽生成工作流程图,效果大概如下 最近刚好用到,研究之后写了系列文章,分享给有需要的小伙 ...
- 工作流流程编辑器的几种解决方案
前言 近阶段参与的项目需要集成工作流功能,在对比了市面上比较流行的极大框架后,最后不出意外应该是三个框架中的一个:Activiti.Flowable.Camunda. 这里先不讨论工作流驱动引擎部分, ...
- 纯ActionScript3.0打造的工作流程编辑器(WorkFlowEdit V1.0Bata1.0)
首先,在此要特别感谢Y.Boy,我这个是根据它的UMLer改造过来的. 这是一个纯AS3打造的流程编辑器,目前刚开发测试,还存在很多bug. 想看看效果: 猛击这里 效果图片: 下面是效果图片: ...
- 富文本编辑器开发系列5——浏览器`Selection API`探究
系列文章快速阅读: 富文本编辑器开发系列-1-基础概念 富文本编辑器开发系列2-document.execCommand 的API 富文本编辑器开发系列3-selection 富文本编辑器开发系列4- ...
- vscode beautify sass 格式化_最强编辑器 VSCode 系列之插件推荐【不定期更新】
[TOC] 前言 emsp;如果你还不知道这款最强编辑器的话,查看本站热门文章,最强编辑器 VSCode 系列之入门简介. 通用 无论你用什么语言,都会用得到的插件. Project Manager ...
- vscode html注释快捷键_最强编辑器 VSCode 系列之插件推荐【不定期更新】
[TOC] 前言 emsp;如果你还不知道这款最强编辑器的话,查看本站热门文章,最强编辑器 VSCode 系列之入门简介. 通用 无论你用什么语言,都会用得到的插件. Project Manager ...
- AQL及抽样流程和计划系列标准
AQL及抽样流程和计划系列标准 AQL是Acceptance Quality Limit(允收质量限值), 是QC人员必须掌握的表格及方法, 并用它来确保产品质量, 其中, 不同的抽样流程及计划也 ...
- WordPress文章内容编辑,wp文章在线批量编辑,wp文章内容可视化编辑器
WordPress文章内容更新是SEO中比较让大家焦虑的事情.每天WordPress文章内容的高质量的发布更新是一个烦杂的工作. 我们知道搜索引擎通过蜘蛛抓取我们每天更新的URL.搜索引擎会根据蜘蛛抓 ...
- 编辑数学公式_LaTeXiT for mac(数学公式编辑器)
LaTeXiT for mac免费版是一款mac版数学公式编辑器,LaTeXiT for Mac可快速方便地编辑复杂的数学公式,然后将其直接拖入到需要输入的文本中,非常方便.喜欢的小伙伴可以私信小编哦 ...
最新文章
- 带有Oracle Digital Assistant和Fn Project的会话式UI。 第二部分
- Grace Ex助力区块链数字资产迈向全新未来
- 12.使用default-Action配置统一访问
- android图标成功,Android多启动图标实现
- java 基础--类与对象的创建,引用,static静态方法的创建与使用,static变量
- 弘辽科技:拼多多店铺星级多久更新一次?如何提升?
- 20大风控文本分类算法-基于字符级的tfidf+逻辑回归
- Application.DoEvents();
- 初学DSP(2)-TMS320F280049C代码探究
- 深圳活动会议媒体邀约,电视台,网媒媒体资源
- 独立同分布(I.I.D.)是什么?(转载)
- 入侵检测系统 IDS 简析
- c语言写plc程序正反转,西门子PLC控制电机正反转编程实例!
- 中兴OLT C300 enable密码
- 聚类算法(五)——层次聚类 linkage (含代码)
- linux aux是什么命令,Linux查看所有进程ps -aux命令介绍
- 自考计算机原理,自考计算机原理考点.doc
- FOC开环驱动电机(开源小项目==FOC控制BLDC电机)
- 毛衣大战,殃及池鱼,亡羊补牢,尚可一试。
- 2022金九银十 —— 招聘有感,给各位测试同学的一些建议
热门文章
- 教你如何将二进制文件导入到数据库
- 补习系列(19)-springboot JPA + PostGreSQL
- 大型情感剧集Selenium:2_options设置 #华为云·寻找黑马程序员#
- DevOps on DevCloud|如何构建Kotlin开发的Android Apps
- HTML多选框滚动条,08:HTMLayout 自定义滚动条样式
- java 无开发环境时在记事本中编写的方法与命令行运行java代码
- 被word格式折磨疯掉的我
- Python 绘制散点图
- CSS-标准盒模型和怪异盒模型box-sizing
- js文件复制_note