全网最详bpmn.js教材-properties篇

前言

Q: bpmn.js是什么? 🤔️javascript

bpmn.js是一个BPMN2.0渲染工具包和web建模器, 使得画流程图的功能在前端来完成.html

Q: 我为何要写该系列的教材? 🤔️前端

由于公司业务的须要于是要在项目中使用到bpmn.js,可是因为bpmn.js的开发者是国外友人, 所以国内对这方面的教材不多, 也没有详细的文档. 因此不少使用方式不少坑都得本身去找.在将其琢磨完以后, 决定写一系列关于它的教材来帮助更多bpmn.js的使用者或者是期于找到一种好的绘制流程图的开发者. 同时也是本身对其的一种巩固.java

因为是系列的文章, 因此更新的可能会比较频繁, 您要是无心间刷到了且不是您所须要的还请谅解😊.git

不求赞👍不求心❤️. 只但愿能对你有一点小小的帮助.github

Properties篇

哈哈 来了 来了 它终于来了😂.web

让你们久等的Properties篇🎉.npm

其实霖呆呆工做上用到的bpmn.js的内容也就只局限于以前写的文章了, 算是将实际用到的知识全盘脱出了... 那么就有人会好奇的问了...为何连Properties-panel这样重要的功能都没有用到呢🤔️?json

这其实和咱们团队的用法有关:canvas

最开始接触使用到bpmn.js是由于须要用它来绘制工做流实现决策引擎的这么一个功能. 而咱们的作法是前端经过bpmn.js来绘制流程图, 图中的StartUserTaskBusinessRuleTask等等我在这里都称之为节点. 每一个节点都对应着xml文件中的标签, 传统的作法多是将各个节点的属性都保存到标签上, 例如我这里有一个开始节点的xml标签:

<startEvent id="StartEvent_1y45yut" name="开始" roles="admin"></startEvent>
复制代码

而后给这个节点增长上一个名为“权限(roles)”的自定义属性, 这个属性会保存在xml中, 而且导出这个文件的时候也会留在上面.

咱们虽然每一个节点也都会关联不少信息, 可是这些信息并非直接保存在xml 标签里的. 而是每一个节点都会有一个 id , 后台有一个表专门用于存放每一个节点的附加信息, 因此每次点击节点的时候, 都经过这个id来调取后台存储的数据, 从而拿到节点对应的属性, 右边出现一个抽屉将这些属性信息显示在里面能够进行修改. 修改保存以后, 也是调用后台的接口来修改表里的信息. 因此主要的逻辑仍是集中在后台上. 所以对于xml的操做还真不是太多, 天然的也就没用上Properties-panel了.

可是个人这种作法, 你也能够理解为右边出现的“抽屉” 就是我自定义的Properties-panel, 由于它确实也起到了与节点关联属性的做用.

OK, 言归正传啦, 虽然我工做中并无用到它, 可是通过读者给出的意见以及本身对它的一些研究, 仍是能用它作一些业务实现的, 但愿在你认真看完以后能有所收获😁.

经过这一章节的阅读你能够学习到:

  • 什么是 bpmn properties🤔️?
  • 如何读取 bpmn properties🤔️?
  • 如何修改 bpmn properties🤔️?
  • 使用 updateProperties方法🤔️?

bpmn properties属性介绍以及基本用法

1. 什么是bpmn properties🤔️?

让咱们先来搞懂一下什么是bpmn properties🤔️?

咱们在用bpmn.js画的每个节点其实都被称之为diagram element(图表元素, 是否是很好理解😁)

而在bpmn文件中的每一个xml标签称之为BPMN element.

diagram elementBPMN element的一些属性关联起来靠的是一个叫作businessObject的属性. 从名称上理解你也能够知道它是一个对象(Object), 你能够在这个对象中添加上一些特殊的属性, 而且这些属性是能够直接插到BPMN element上的.

举个例子🌰:

我绘制了一个StartEvent节点, 它对应的:

  • diagram element:

    {
    	id: "StartEvent_1y45yut",
    	type: "bpmn:StartEvent",
    	businessObject: {
    		$type: "bpmn:StartEvent",
    		name: "开始"
    	}
    }
    复制代码
  • BPMN element:

    <startEvent id="StartEvent_1y45yut" name="开始"></startEvent>
    复制代码

像这类属性就是bpmn properties, 你能够用它来实现你的业务须要.

2. 如何读取bpmn properties🤔️?

不知道你们是否还记得我在《事件篇》中用到的一段代码:

addModelerListener () {
       // 监听 modeler
      const bpmnjs = this.bpmnModeler
      const that = this
      const events = ['shape.added', 'shape.move.end', 'shape.removed']
      events.forEach(function(event) {
        that.bpmnModeler.on(event, e => {
          var elementRegistry = bpmnjs.get('elementRegistry')
          var shape = e.element ? elementRegistry.get(e.element.id) : e.shape
          if (event === 'shape.added') {
            console.log('新增了shape')
          } else if (event === 'shape.move.end') {
            console.log('移动了shape')
          } else if (event === 'shape.removed') {
            console.log('删除了shape')
          }
        })
      })
    }
复制代码

这个方法是放在 将字符串转换成图显示出来 以后, 用于给元素绑定事件.

其中就有用到elementRegistry.

因此若是是在html中, 你就能够用这种方式来获取bpmn properties:

<body>
  <div id="canvas"></div>
<script> var bpmnJS = new BpmnJS({ container: '#canvas' }); bpmnJS.importXML(xmlStr, function(err) { if (!err) { var elementRegistry = bpmnJs.get('elementRegistry') var startEventElement = elementRegistry.get('StartEvent_1y45yut'), startEvent = startEventElement.businessObject; console.log(startEvent.name) // 开始 } } </script>
复制代码

而在一些class里, 好比CustomRenderer.js里, 你能够直接用.的方式就获取到了:

export default class CustomRenderer extends BaseRenderer {
	drawShape (parentNode, element) {
		// element.businessObject
		// or 解构
		// const { businessObject } = element
	}
}
复制代码

3. 如何修改bpmn properties🤔️?

你在bpmn文件中, 可能会看到这样一段代码:

<bpmn:sequenceFlow id="SequenceFlow_1" sourceRef="StartEvent_1" targetRef="Task_1" name="FOO &gt; BAR?">
      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression"><![CDATA[${foo > bar}]]></bpmn:conditionExpression>
    </bpmn:sequenceFlow>
复制代码

里面的xsi:typesourceRef这些属性是啥啊🤔️? 我怎么知道哪类标签有哪些属性🤔️?

你其实能够在官方给的这个bpmn.json中查找到:

《meta-model descriptor》

设置的话能够根据如下方法:

var moddle = bpmnJS.get('moddle');

// 建立一个BPMN element , 而且载入到导出的xml里 var newCondition = moddle.create('bpmn:FormalExpression', { body: '${ value > 100 }' });

复制代码// 写入属性, 可是不支持撤销 sequenceFlow.conditionExpression = newCondition; 复制代码

上面👆的这种方式是不支持撤销的, 若是你想要可以 撤销/从新 的话, 你能够经过如下这种方式:

var modeling = bpmnJS.get('modeling'); 复制代码modeling.updateProperties(sequenceFlowElement, { conditionExpression: newCondition }); 复制代码

也就是经过modeling.updateProperties()这个方法.

这个modeling好像是须要引入的, 反正若是我是使用DNS 远程的引入下面的这个js好像就会报错Uncaught Error: No provider for "modeling"!.

<script src="https://unpkg.com/bpmn-js@6.0.2/dist/bpmn-viewer.development.js"></script>
复制代码

固然若是你是使用npm 下载的话就没有这个问题了.

这个方法的第一个参数是一个 diagram element, 也就是前面咱们提到的用elementRegistry获取到的对象.

第二个参数是要修改的属性, 它是一个Map结构.

4. 使用updateProperties方法

例如🌰, 我想在点击某个类型为bpmn:Task的节点的时候, 修改它的name属性, 我能够这么作:

  • 给节点添加点击事件
  • 判断节点类型为 bpmn:Task , 只对这种类型的节点作后续处理
  • 使用 updateProperties更新 name
createNewDiagram () {
        // 将字符串转换成图显示出来
        this.bpmnModeler.importXML(xmlStr, (err) => {
            if (err) {
                // console.error(err)
            } else {
                // 这里是成功以后的回调, 能够在这里作一系列事情
                this.success()
            }
        })
    },
    success () {
        this.addModelerListener() // 添加监听事件
    },
    addModelerListener () {
    		const eventBus = this.bpmnModeler.get('eventBus')
      	const modeling = this.bpmnModeler.get('modeling')
      	const elementRegistry = this.bpmnModeler.get('elementRegistry');
      	const eventTypes = ['element.click', 'element.changed'];
      	eventTypes.forEach(function(eventType) {
          	eventBus.on(eventType, function (e) {
              	if (!e || !e.element) {
                  console.log('无效的e', e)
                  return
                }
              	if (eventType === 'element.click') {
                  console.log('点击了element', e)
                  var shape = e.element ? elementRegistry.get(e.element.id) : e.shape
                  if (shape.type === 'bpmn:Task') {
                    modeling.updateProperties(shape, {
                    	name: '我是修改后的Task名称'
                  	})
                  }
                }
            })
        })
    }
复制代码

固然你也能够一次性修改多个属性:

modeling.updateProperties(startEventElement, {
	name: '我是修改后的虚线节点',
	isInterrupting: false
})
复制代码

我经过查找前面的 meta-model descriptor 知道StartEvent还有一个isInterrupting属性, 因而试着修改它, 结果居然成功了, 将开始节点变为了虚线为边框的节点:

bpmnModeler5.png
bpmnModeler5.png

固然你也能够加一些除了meta-model descriptor里的一些自定义属性:

modeling.updateProperties(shape, {
	name: '我是修改后的虚线节点',
	isInterrupting: false,
	customText: '我是自定义的text属性'
})
复制代码

只不过, 它们会被放到$attrs中:

bpmnModeler6.png
bpmnModeler6.png

而且这种方式, 也是能够直接修改到bpmn文件中的:

bpmnModeler7.png
bpmnModeler7.png

后语

这一章节主要是向你们介绍了一下bpmn properties的概念以及操做方式...其实在这以前, 我甚至不知道怎么给xml标签上添加属性, 也甚至不知道updateProperties怎么使用😂...

还好皮厚的我不耻下问, 在群里问了一些小伙伴...

哈哈哈, 手动艾特感谢 @网易-付超老哥 还有@李岱老哥 , 在研究bpmn.js属性上面给个人帮助, 固然我也知道不少小伙伴但愿我能快点更上一篇关于properties-panel的内容...

但今天真的有点累了... 容我先缓一缓, 咱明天再更行不😁.

(嗯...不行也得行, 我说了算...)

最后, 若是你也对bpmn.js 感兴趣能够扫码进咱们的交流群👇👇👇, 共同窗习, 共同进步.

最最后, 喜欢霖呆呆的小伙伴能够关注个人公众号呀, 我会不按期的更新一些前端方面的知识, 另外单身的小哥哥小姐姐也有福利呀嘻嘻嘻嘻😁

LinDaiDai公众号二维码.jpg
LinDaiDai公众号二维码.jpg
相关文章
相关标签/搜索