bpmn.js Viewer:加载与交互查看流程图

Viewer 是bpmn.js的只读模式,用于加载和展示流程图。本文讲解Viewer的核心功能——加载XML、缩放、导航、高亮与选中,以及常见的交互场景。

Viewer的初始化与基础加载

创建实例

1
2
3
4
5
6
7
8
9
10
11
12
13
const viewer = new BpmnJS({
container: '#canvas'
});

// 加载BPMN XML
viewer.importXML(bpmnXml).then(() => {
console.log('✓ 流程图加载成功');
// 自动适配视窗
const canvas = viewer.get('canvas');
canvas.zoom('fit-viewport');
}).catch(err => {
console.error('✗ 加载失败:', err.message);
});

错误处理

加载可能失败的常见原因:

1
2
3
4
5
6
7
8
9
10
11
viewer.importXML(bpmnXml)
.then(() => {
// 成功
})
.catch(err => {
// err.message 通常是 "意外的XML结构" 或 "缺少关键元素"
console.error('XML格式错误:', err);

// 恢复操作:提示用户或加载默认流程
showErrorDialog(err.message);
});

视图控制:缩放与导航

缩放操作

1
2
3
4
5
6
7
8
9
10
11
12
const canvas = viewer.get('canvas');

// 自动适配视窗(最常用)
canvas.zoom('fit-viewport');

// 指定缩放比例
canvas.zoom(1.0); // 100%
canvas.zoom(1.5); // 150%
canvas.zoom(0.5); // 50%

// 获取当前缩放比例
const currentZoom = canvas.zoom();

视图导航

1
2
3
4
5
6
7
8
const canvas = viewer.get('canvas');

// 滚动到特定元素(居中显示)
const element = viewer.get('elementRegistry').get('TaskId_123');
canvas.viewbox(element);

// 重置视图(回到初始状态)
canvas.zoom('fit-viewport');

元素查询与高亮

获取元素

1
2
3
4
5
6
7
8
9
10
11
const registry = viewer.get('elementRegistry');

// 按ID查询
const element = registry.get('Task_1');

// 获取所有元素
const allElements = registry.getAll();

// 查询特定类型的元素(伪代码)
const tasks = allElements.filter(el => el.type === 'bpmn:UserTask');
const gateways = allElements.filter(el => el.type === 'bpmn:Gateway');

选中与高亮

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const selection = viewer.get('selection');
const canvas = viewer.get('canvas');

// 选中单个元素(自动高亮)
selection.select(element);

// 取消选中
selection.deselect();

// 高亮特定元素(通过CSS类)
canvas.addMarker(element, 'highlight'); // 添加CSS类
canvas.removeMarker(element, 'highlight'); // 移除CSS类

// 常见的marker类型
canvas.addMarker(element, 'selected'); // 选中
canvas.addMarker(element, 'approved'); // 批准(自定义类)
canvas.addMarker(element, 'rejected'); // 拒绝(自定义类)

自定义高亮样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<style>
/* 默认高亮 */
.djs-element.highlight {
background: #f0f0f0 !important;
outline: 2px solid #ffc107;
}

/* 自定义:已批准 */
.djs-element.approved {
background: #e8f5e9 !important;
outline: 2px solid #4caf50;
}

/* 自定义:已拒绝 */
.djs-element.rejected {
background: #ffebee !important;
outline: 2px solid #f44336;
}
</style>

<script>
// 在代码中应用
canvas.addMarker(approveTask, 'approved');
canvas.addMarker(rejectTask, 'rejected');
</script>

流程追踪:高亮执行路径

场景:展示一个订单在流程中的执行位置。

1
2
3
4
5
6
7
8
9
10
11
12
// 假设订单已在"审批任务"处等待
const currentTask = registry.get('ApproveTask_1');
const path = ['StartEvent_1', 'ApproveTask_1'];

// 高亮已执行路径
path.forEach(id => {
const element = registry.get(id);
canvas.addMarker(element, 'executed');
});

// 高亮当前位置
canvas.addMarker(currentTask, 'current-task');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- CSS样式 -->
<style>
/* 已执行步骤 */
.djs-element.executed {
background: #c8e6c9 !important;
}

/* 当前任务 */
.djs-element.current-task {
background: #fff9c4 !important;
outline: 3px solid #fbc02d;
animation: pulse 1.5s infinite;
}

@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
</style>

事件监听

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const eventBus = viewer.get('eventBus');

// 用户点击元素
eventBus.on('element.click', function(event) {
const element = event.element;
console.log('点击了:', element.id, '类型:', element.type);

// 显示元素属性
showProperties(element);
});

// 元素被选中
eventBus.on('selection.changed', function(event) {
const newSelection = event.newSelection;
console.log('选中元素个数:', newSelection.length);
});

// 双击元素
eventBus.on('element.dblclick', function(event) {
console.log('双击了:', event.element.id);
});

常见场景:流程审计

需求:加载流程XML,显示某个订单的执行历史与当前状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
async function loadProcessWithHistory(processXml, executionHistory) {
// 1. 加载流程图
await viewer.importXML(processXml);
viewer.get('canvas').zoom('fit-viewport');

// 2. 根据执行历史高亮路径
const registry = viewer.get('elementRegistry');
const canvas = viewer.get('canvas');

executionHistory.forEach((step, index) => {
const element = registry.get(step.elementId);
if (!element) return;

if (index < executionHistory.length - 1) {
// 已完成步骤
canvas.addMarker(element, 'executed');
} else {
// 当前步骤
canvas.addMarker(element, 'current-task');
}
});

// 3. 绑定点击查看详情
viewer.get('eventBus').on('element.click', (event) => {
const el = event.element;
const history = executionHistory.find(h => h.elementId === el.id);
if (history) {
showExecutionDetails(el, history);
}
});
}

// 使用
const bpmnXml = '...'; // 流程图XML
const history = [
{ elementId: 'StartEvent_1', status: 'completed', time: '2025-12-24 10:00' },
{ elementId: 'ApproveTask_1', status: 'active', time: '2025-12-24 10:05' }
];

loadProcessWithHistory(bpmnXml, history);

Viewer API速查表

方法 用途
importXML(xml) 加载BPMN XML
get('canvas') 获取画布
get('elementRegistry') 获取元素注册表
get('selection') 获取选中管理器
get('eventBus') 获取事件总线
canvas.zoom('fit-viewport') 自动适配视窗
canvas.addMarker(el, class) 添加CSS类高亮
selection.select(el) 选中元素
selection.deselect() 取消选中元素

小结

掌握Viewer:

  • ✓ importXML 加载流程
  • ✓ canvas 操作视图与缩放
  • ✓ elementRegistry 查询元素
  • ✓ 通过 marker 与 CSS 高亮显示
  • ✓ eventBus 监听交互事件

便能构建专业的流程审查与追踪界面

参考资料