最好用的流程编辑器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的基本思想:当我们在页面上点击了一个按钮,它会触发一个actionaction随后会执行一个mutationmutation会去改变state,当state改变后页面就能根据state来进行相应的处理了

然后再来看上边的代码,用到了Vuex基本思想里边的statemutations,其中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里nodeVisiblenodeInfo

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.最后在页面中就可以借助computedwatch来实现对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相关推荐

  1. BPMN开源工作流编辑器bpmn-js落地实践中文文档

    BPMN是一套标准的业务流程建模符号规范,bpmn-js是基于此规范实现的一套渲染工具包和web建模器,可以实现拖拽生成工作流程图,效果大概如下 最近刚好用到,研究之后写了系列文章,分享给有需要的小伙 ...

  2. 工作流流程编辑器的几种解决方案

    前言 近阶段参与的项目需要集成工作流功能,在对比了市面上比较流行的极大框架后,最后不出意外应该是三个框架中的一个:Activiti.Flowable.Camunda. 这里先不讨论工作流驱动引擎部分, ...

  3. 纯ActionScript3.0打造的工作流程编辑器(WorkFlowEdit V1.0Bata1.0)

    首先,在此要特别感谢Y.Boy,我这个是根据它的UMLer改造过来的. 这是一个纯AS3打造的流程编辑器,目前刚开发测试,还存在很多bug. 想看看效果:   猛击这里 效果图片: 下面是效果图片: ...

  4. 富文本编辑器开发系列5——浏览器`Selection API`探究

    系列文章快速阅读: 富文本编辑器开发系列-1-基础概念 富文本编辑器开发系列2-document.execCommand 的API 富文本编辑器开发系列3-selection 富文本编辑器开发系列4- ...

  5. vscode beautify sass 格式化_最强编辑器 VSCode 系列之插件推荐【不定期更新】

    [TOC] 前言 emsp;如果你还不知道这款最强编辑器的话,查看本站热门文章,最强编辑器 VSCode 系列之入门简介. 通用 无论你用什么语言,都会用得到的插件. Project Manager ...

  6. vscode html注释快捷键_最强编辑器 VSCode 系列之插件推荐【不定期更新】

    [TOC] 前言 emsp;如果你还不知道这款最强编辑器的话,查看本站热门文章,最强编辑器 VSCode 系列之入门简介. 通用 无论你用什么语言,都会用得到的插件. Project Manager ...

  7. AQL及抽样流程和计划系列标准

    AQL及抽样流程和计划系列标准   AQL是Acceptance Quality Limit(允收质量限值), 是QC人员必须掌握的表格及方法, 并用它来确保产品质量, 其中, 不同的抽样流程及计划也 ...

  8. WordPress文章内容编辑,wp文章在线批量编辑,wp文章内容可视化编辑器

    WordPress文章内容更新是SEO中比较让大家焦虑的事情.每天WordPress文章内容的高质量的发布更新是一个烦杂的工作. 我们知道搜索引擎通过蜘蛛抓取我们每天更新的URL.搜索引擎会根据蜘蛛抓 ...

  9. 编辑数学公式_LaTeXiT for mac(数学公式编辑器)

    LaTeXiT for mac免费版是一款mac版数学公式编辑器,LaTeXiT for Mac可快速方便地编辑复杂的数学公式,然后将其直接拖入到需要输入的文本中,非常方便.喜欢的小伙伴可以私信小编哦 ...

最新文章

  1. 带有Oracle Digital Assistant和Fn Project的会话式UI。 第二部分
  2. Grace Ex助力区块链数字资产迈向全新未来
  3. 12.使用default-Action配置统一访问
  4. android图标成功,Android多启动图标实现
  5. java 基础--类与对象的创建,引用,static静态方法的创建与使用,static变量
  6. 弘辽科技:拼多多店铺星级多久更新一次?如何提升?
  7. 20大风控文本分类算法-基于字符级的tfidf+逻辑回归
  8. Application.DoEvents();
  9. 初学DSP(2)-TMS320F280049C代码探究
  10. 深圳活动会议媒体邀约,电视台,网媒媒体资源
  11. 独立同分布(I.I.D.)是什么?(转载)
  12. 入侵检测系统 IDS 简析
  13. c语言写plc程序正反转,西门子PLC控制电机正反转编程实例!
  14. 中兴OLT C300 enable密码
  15. 聚类算法(五)——层次聚类 linkage (含代码)
  16. linux aux是什么命令,Linux查看所有进程ps -aux命令介绍
  17. 自考计算机原理,自考计算机原理考点.doc
  18. FOC开环驱动电机(开源小项目==FOC控制BLDC电机)
  19. 毛衣大战,殃及池鱼,亡羊补牢,尚可一试。
  20. 2022金九银十 —— 招聘有感,给各位测试同学的一些建议

热门文章

  1. 教你如何将二进制文件导入到数据库
  2. 补习系列(19)-springboot JPA + PostGreSQL
  3. 大型情感剧集Selenium:2_options设置 #华为云·寻找黑马程序员#
  4. DevOps on DevCloud|如何构建Kotlin开发的Android Apps
  5. HTML多选框滚动条,08:HTMLayout 自定义滚动条样式
  6. java 无开发环境时在记事本中编写的方法与命令行运行java代码
  7. 被word格式折磨疯掉的我
  8. Python 绘制散点图
  9. CSS-标准盒模型和怪异盒模型box-sizing
  10. js文件复制_note