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

前言

Q: bpmn.js是什么? 🤔️

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

Q: 我为什么要写该系列的教材? 🤔️

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

由于是系列的文章, 所以更新的可能会比较频繁, 您要是无意间刷到了且不是您所需要的还请谅解😊.

求赞👍, 求Start 🌟, 求Fork 📓, 希望能对你有一点小小的帮助.

所有教材的github地址: 《bpmn-chinese-document》

Properties篇

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

让大家久等的Properties篇🎉.

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

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

最开始接触使用到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

当然你也可以加一些除了meta-model descriptor里的一些自定义属性:

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

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

bpmnModeler6.png

并且这种方式, 也是可以直接修改到bpmn文件中的:

bpmnModeler7.png

后语

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

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

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

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

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

系列全部目录请查看此处: 《全网最详bpmn.js教材目录》

最后, 如果你也对bpmn.js 感兴趣可以进我们的bpmn.js交流群👇👇👇, 共同学习, 共同进步.

关注霖呆呆(LinDaiDai)的公众号:LinDaiDai 选择 其它 菜单中的 bpmn.js群 即可😊

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335