bpmn.js
bpmn-js 是一个 BPMN 2.0 渲染工具包和 Web 建模器。它使用 JavaScript 编写,可以在现代浏览器中嵌入 BPMN 2.0 图表,并且不依赖任何服务端后台。这使得它能够轻松嵌入到任意 Web 应用中。
该库的设计既可以作为查看器(viewer),也可以作为 Web 建模器(modeler)。你可以使用 viewer 将 BPMN 2.0 图表嵌入到应用中,并结合你的数据进行扩展。你也可以使用 modeler 在应用内部创建 BPMN 2.0 图表。
bpmn-js 功能布局

生产的画布可见功能主要包含以下部分
Palette:左侧元素工具栏,可以通过点击或者拖拽触发添加新元素Shapes:所有 Bpmn.js 可见节点,Moddle 描述文件内可发现均继承自ElementConnections:所有节点之间的连线,Bpmn.js 中连线的类型均为SequenceFlowContextPad:用鼠标选中一个元素时会出现,主要是操作该元素的上下文以及节点自身的类型等PopupMenu:默认在鼠标点击ContextPad中的扳手图表时出现,主要用于控制选中元素类型的调整等properties-panel:需要额外添加模块面板,用鼠标选中一个元素时会出现,主要是查看或者操作该元素的对应属性。可以通过自定义扩展该节点对应xml的属性
bpmn.js内部原理
官方文档:https://bpmn.io/toolkit/bpmn-js/walkthrough/
bpmn-js 建立在两个重要的库之上:diagram-js 和 bpmn-moddle:

bpmn-js使用 diagram-js 绘制图形和连线。它提供了与这些图形元素进行交互的方法,以及诸如叠加层之类的其他工具,可以帮助用户构建功能强大的 BPMN 查看器。对于诸如建模之类的高级用例,它提供了上下文内容面板,调色板和重做/撤消之类的功能。
bpmn-moddle 知道 BPMN 2.0 标准中定义的 BPMN 2.0 元模型。它使我们能够读写 BPMN 2.0 架构兼容的 XML 文档,并访问在图上绘制的图形和连线背后的 BPMN 相关信息。
在这两个库的基础上,bpmn-js 定义了 BPMN 细节,例如外观,建模规则和工具(即调色板)。
图表交互 / 建模(diagram-js)
github: https://github.com/bpmn-io/diagram-js
diagram-js 是一个用于在 Web 上展示和修改图表的工具箱。它允许我们渲染可视化元素,并在其之上构建交互式体验。
它提供了一个非常简单的模块系统,用于构建功能,并通过依赖注入(dependency injection)来实现服务发现。这个系统同时还提供了一些核心服务,用于实现图表的基本功能。
此外,diagram-js 还定义了图形元素及其关系的数据模型。
模块系统
在底层,diagram-js 使用依赖注入(DI)来连接和发现图表组件。这个机制基于 didi 构建。
在 diagram-js 的语境下,模块指的是提供具名服务及其实现的单元。所谓服务,可以是一个函数或一个实例,它可能会消费其他服务,在图表上下文中完成某些功能。
下面展示了一个通过事件总线(eventBus,另一个常用服务)注册事件,从而挂载到生命周期事件的服务:
const MyLoggingPlugin = (eventBus) => {
eventBus.on('element.changed', (event) => {
console.log('element ', event.element, ' changed');
});
}
// 静态 $inject 注入eventBus
MyLoggingPlugin.$inject = [ 'eventBus' ];我们必须通过模块定义,将服务以唯一名称的方式发布:
import CoreModule from 'diagram-js/lib/core';
// 作为模块导出
export default {
__depends__: [ CoreModule ], // {2}
__init__: [ 'myLoggingPlugin' ], // {3}
myLoggingPlugin: [ 'type', MyLoggingPlugin ] // {1}
};这个定义告诉 DI 基础设施:该服务名为 myLoggingPlugin {1},它依赖于 diagram-js 的核心模块 {2},并且需要在图表创建时初始化 {3}。更多细节可以参考 didi 文档。
接下来我们可以启动 diagram-js,并传入自定义模块:
import MyLoggingModule from 'path-to-my-logging-module';
const diagram = new Diagram({
modules: [
MyLoggingModule
]
});要将该模块接入 bpmn-js,可以使用 additionalModules 选项,就像我们之前展示的加入properties-panel那样。
import BpmnModeler from "bpmn-js/lib/Modeler"
const modeler = new BpmnModeler({
// ...
additionalModules: [MyLoggingModule]
})核心服务
diagram-js 核心是围绕许多基本服务构建的:
Canvas- 提供了 api 用于添加和删除图形元素;处理生命周期的元素,并提供 api 来缩放和滚动。EventBus- 这个库使用 fire 和 forget 策略的全局通信。相关模块可以订阅的各种事件,并在它们触发后立即采取行动。EventBus可以帮助我们解耦问题,并且模块化功能。ElementFactory- 用于根据 diagram-js 的内部数据模型创建图形和连线的工厂。ElementRegistry- 知道添加到图表中的所有元素,并提供 API 来检索元素(通过 id)及其图形化表示。GraphicsFactory- 负责创建图形和连线的图形表示。实际的外观由渲染器定义,即 draw module 模块内的 DefaultRenderer
数据模型
在内部,diagramjs 实现了一个由图形和连线组成的简单数据模型。

一个图形有父对象、子对象集合以及传入和传出连线的集合。
一个连线有一个父对象以及来源和目的,指向一个图形。
ElementRegistry 负责根据该模型创建图形和连线。在建模过程中,Modeling 服务将根据用户操作更新元素关系。
辅助服务(即工具箱)
除了数据模型及其核心服务之外,diagram-js 还提供了一个丰富的工具箱,其中包含其他帮助程序。
CommandStack- 负责建模过程中的重做和撤消。ContextPad- 围绕提供元素的上下文操作。Overlays- 提供了用于图表元素的附加信息 api 。Modeling- 提供用于更新画布上元素的 API(移动、删除)- 🙋♂️ 这个常用Palette- 左侧工具栏
总结一下:diagram-js 提供了一个通用、可扩展、可插拔的图形编辑框架,它不关心 BPMN 语义,只专注于图形 + 交互 + 模块化扩展
BPMN 元模型(bpmn-moddle)
bpmn-moddle 是专门用于处理 BPMN 2.0 语义 / 元模型 / XML 的库。它与 diagram-js 是分离的、语义角度独立的那部分。
它的职责 /功能包括:
- 元模型定义 (Meta-model) bpmn-moddle 基于
moddle(一个定义元模型的通用库)来定义 BPMN 的类型、属性、关系等。 - XML ↔ 对象模型 映射
fromXML(xmlString):把 BPMN 2.0 的 XML 文档解析为 JavaScript 对象(按照元模型结构组织)toXML(objectModel):把 JavaScript 对象模型(经过编辑后的)序列化回合规的 BPMN 2.0 XML。
- 验证 / 结构约束 因为 bpmn-moddle 知道 BPMN 2.0 的规范(哪些元素合法、哪些属性可有可无、关系约束等),它可以在导入 / 编辑 / 导出时进行基础验证。比如,不允许把某些类型连线到不合适的节点。
- 业务对象 (businessObject) 在 bpmn-js 渲染 / 编辑时,每个图形元素(shape / connection)背后都会关联一个
businessObject,这个对象就是 bpmn-moddle 的那套对象模型(类型 / 属性 / 关系)。通过它就可以访问 BPMN 语义层面的信息(比如这个节点是 “bpmn:UserTask” / “bpmn:StartEvent” / 这个 sequenceFlow 的条件表达式等)。
总结:bpmn-moddle 是负责 “理解 BPMN” 的那部分 —— 它不关心图形如何画、如何交互,只负责语义模型和与 XML 的转换。
bpmn-js 将事物整合在一起
这层是 bpmn-js 本身,这部分把 diagram-js(图形交互)和 bpmn-moddle(BPMN 语义)组合在一起,加上 BPMN 专属的渲染、规则、工具、Palette、行为逻辑等。
其主要职责与流程:
- 导入 / 解析阶段
- 用户给一个 BPMN XML 文档(字符串),bpmn-js 通过 bpmn-moddle 的
fromXML将其解析成对象模型树(语义模型)。 - 然后 bpmn-js 遍历语义模型,决定哪些节点 / 关系要渲染出来(即是可视元素)。为每个需要显示的节点 / 边创建对应的 diagram-js 图形元素(shape / connection)。这时它会把语义对象(businessObject)挂到图形元素上,使两者关联。
- 用户给一个 BPMN XML 文档(字符串),bpmn-js 通过 bpmn-moddle 的
- 渲染阶段
- 渲染器 (例如
BpmnRenderer) 知道每一种 BPMN 元素要如何画(图形、样式、图标等),并把图形元素画在画布(Canvas)上。 - 如果有需要,也可以定制某些 BPMN 元素的渲染(覆写默认 renderer)以显示自己风格的图形。
- 渲染器 (例如
- 编辑 / 模型阶段
- 用户可以在编辑器(Modeler 模式)中做各种建模操作:创建节点 / 删除 / 连线 / 修改属性 / 拖拽 / 重连 / 拆分 / 合并 等等。bpmn-js 提供 Modeling 模块来响应这些操作。
- 在具体执行操作时,会检查 “规则”(
BpmnRules)来决定某些操作是否合法(比如不能把一个结束事件当成起始事件的目标,不能把某种连接连到不允许的节点等) - 若操作合法,则 Modeling 模块会更新图形层(diagram-js 的数据模型 /图形)和语义层(bpmn-moddle 对象模型)—— 也就是说,要同时保持图形结构和语义模型的一致性。这个同步更新由 bpmn-js 的更新器(
BpmnUpdater等)负责。
- 导出 / 保存阶段
- 用户完成编辑后,可以把当前的语义模型通过 bpmn-moddle 的
toXML导出为 BPMN 2.0 合规的 XML。 - 在这个过程中,可以做一定校验、保证导出的 XML 满足规范。
- 用户完成编辑后,可以把当前的语义模型通过 bpmn-moddle 的
- 扩展 / 插件机制
- bpmn-js 提供
additionalModules选项,在创建 Modeler / Viewer 的时候可以注入自定义模块 / 服务,从而替换 / 增强某些行为(渲染、规则、工具、Palette、contextPad 等) - 例如添加自定义元素、重写某些 modeling 规则、定制 context pad(元素旁边的操作菜单)、定制 shape 渲染等。
- 你甚至可以基于 bpmn-js 打包一个自定义发行版(bundle)来提供给你的用户或产品。
- bpmn-js 提供
- 不同变体 / 模式 bpmn-js 提供几种不同用途 / 功能集的模式 / 版本:
Viewer:只做显示 / 导入 / 查看,不提供编辑能力。NavigatedViewer:在 Viewer 基础上加一些导航功能(平移、缩放、定位)Modeler:完整的编辑 / 构建 BPMN 图功能,包含 Palette、context pad、Modeling、规则、更新、undo/redo 等。
简化的 “数据流 + 交互流” 视图
下面是一个简化的步骤流程,帮助你把抽象原理对照到实际操作上:
- 加载 / 初始化
- 创建一个 Modeler / Viewer 实例
- 注册内置模块 + 任何
additionalModules - 初始化 diagram-js 的图形画布、事件总线、核心服务等
- 导入 BPMN XML
- 用 bpmn-moddle 的
fromXML→ 得到 BPMN 对象树 - 遍历对象树,为每个应可视化的元素创建对应的图形元素(shape / connection),并把语义对象 (businessObject) 关联进去
- 调用渲染器把它们画到 Canvas 上
- 用 bpmn-moddle 的
- 用户交互 / 编辑
- 用户发起某个操作(拖拽、连线、删除、重绘等)
- 事件触发 → 通过 EventBus 分发
- Modeling 模块 / 自定义扩展响应操作,请求进行某种修改
- 在执行修改之前,使用规则模块 (BpmnRules) 判断是否允许
- 若合法:Modeling 模块调用内部更新器 (BpmnUpdater 等) 同步更新语义层 + 图形层
- 操作加入 CommandStack,以支持撤销 / 重做
- 导出 / 保存
- 最终语义模型 + 属性修改后,调用 bpmn-moddle 的
toXML将其序列化为 BPMN 2.0 XML - 导出的 XML 可以交互给其他 BPMN 工具或服务使用
- 最终语义模型 + 属性修改后,调用 bpmn-moddle 的
- 扩展 / 插件
- 在创建 Modeler / Viewer 时注入额外模块,修改 / 拓展默认行为
- 插件可以监听事件、替代渲染、定义新规则、增加新的工具按钮 / 操作等