前言
上一章节我们介绍了关于bpmn.js
如何与后端交互,实现特定的线用特定的颜色, 要是不了解的小伙请移步
bpmn.js + vue + vuex的业务实现-与后端交互
这一章节主要讲解的是关于bpmn.js
如何根据状态而呈现节点不同的颜色或图片
开源链接
gitee:gitee.com/zh-howe/bpm…
根据状态而呈现不同的颜色或图片
在上一章节中已经与后端交互,实现了赋予不同节点不同的class,我们可以用同样的方法添加不同的图片和颜色
设置颜色
//.customRenderer.less
.djs-visual.running {
path {
display: none !important;
}
rect {
fill: #1890ff !important;
stroke: #1890ff !important;
}
.djs-label {
font-weight: bold !important;
fill: #fff !important;
}
}
//.customRenderer.less
// 给节点添加class以更改样式
let className = this.runningActivitiesIds.includes(element.id)
? 'djs-visual running'
: this.highLightedActivitiesIds.includes(element.id)
? 'djs-visual Activities'
: 'djs-visual unActivities';
svgAttr(parentNode, 'class', className);
设置图片
//customRenderer.js
// 计数器,当匹配到就加1,匹配不到为0就默认图片
let count = 0;
customConfig.map(item => {
if (element.businessObject.name.includes(item.labelKey)) {
count++;
const customIcon = svgCreate('image', {
...attr,
href: isFinish ? item.url : item.unUrl,
});
svgAppend(parentNode, customIcon);
return customIcon;
}
if (!count) {
const customIcon = svgCreate('image', {
...attr,
href: isFinish
? require('@/images/workflow/approve.png')
: require('@/images/workflow/unapprove.png'),
});
svgAppend(parentNode, customIcon);
return customIcon;
}
});
完整的customRenderer.js
import BaseRenderer from 'diagram-js/lib/draw/BaseRenderer';
import {
append as svgAppend,
attr as svgAttr,
create as svgCreate,
select as svgSelect,
selectAll as svgSelectAll,
clone as svgClone,
clear as svgClear,
remove as svgRemove,
} from 'tiny-svg';
import store from '@/store';
import { customConfig, createArr } from '../utils/util';
import { is } from 'bpmn-js/lib/util/ModelUtil';
const HIGH_PRIORITY = 1500;
export default class CustomRenderer extends BaseRenderer {
constructor(eventBus, bpmnRenderer, modeling) {
super(eventBus, HIGH_PRIORITY);
this.bpmnRenderer = bpmnRenderer;
this.modeling = modeling;
// 已完成的id数组
this.highLightedActivitiesIds = store.getters.highLightedActivitiesIds;
// 正在进行的id数组
this.runningActivitiesIds = store.getters.runningActivitiesIds;
}
canRender(element) {
// ignore labels
return !element.labelTarget;
}
/**
* 自定义连接线的样式
* @param {*} parentNode 当前元素的svgNode
* @param {*} element
* @returns
*/
drawConnection(parentNode, element) {
const line = this.bpmnRenderer.drawConnection(parentNode, element);
// 给节点添加class以更改样式
let className = this.highLightedActivitiesIds.includes(element.id)
? 'djs-visual Activities'
: this.runningActivitiesIds.includes(element.id)
? 'djs-visual running'
: 'djs-visual unActivities';
console.log(className);
svgAttr(parentNode, 'class', className);
return line;
}
/**
* 自定义节点图形
* @param {*} parentNode 当前元素的svgNode
* @param {*} element
* @returns
*/
drawShape(parentNode, element) {
const shape = this.bpmnRenderer.drawShape(parentNode, element);
const { type, width, height, x, y } = element;
if (type === 'bpmn:ExclusiveGateway') {
svgAttr(parentNode, 'class', 'djs-visual gateway-grey');
// 计数器,当匹配到就加1,匹配不到为0就默认图片
// 判断当前的id是否在已完成或正在进行的id数组里,以添加不同的图片
const isFinish =
this.highLightedActivitiesIds.includes(element.id) ||
this.runningActivitiesIds.includes(element.id);
const attr = { x: -7, y: 5, width: 65, height: 42 };
const customIcon = svgCreate('image', {
...attr,
href: isFinish
? require('@/images/workflow/gateway.png')
: require('@/images/workflow/ungateway.png'),
});
svgAppend(parentNode, customIcon);
return customIcon;
}
// 根据不同节点添加相应图片
if (type == 'bpmn:UserTask' && !!element.businessObject.name) {
// 获取label
const text = svgSelect(parentNode, 'text');
const tspan = svgSelectAll(text, 'tspan');
// 偏移label
const tspanText = element.businessObject.name;
let len = tspanText.length;
// 每五个字符换行
if (len > 5) {
let textArr = createArr(tspanText, 0, 5, 5);
textArr.map((item, index) => {
if (tspan.length >= textArr.length) {
tspan[index].innerHTML = textArr[index];
} else {
const num = textArr.length - tspan.length;
let y = svgAttr(tspan[tspan.length - 1], 'y');
let ts = svgCreate('tspan', {
x: 30,
y: parseFloat(y) + 14.4,
});
svgAppend(text, ts);
const newTspan = svgSelectAll(text, 'tspan');
newTspan[index].innerHTML = textArr[index];
}
});
const newTspan = svgSelectAll(text, 'tspan');
newTspan.map(item => {
svgAttr(item, 'x', 35);
});
} else {
svgAttr(tspan[0], 'x', 35);
}
// if (tspan?.length > 1) {
// svgAttr(tspan[0], 'x', 40);
// svgAttr(tspan[1], 'x', 25);
// // 重写label,换行
// if (tspanText.includes('(')) {
// console.log(tspanText);
// tspan[0].innerHTML = tspanText.split('(')[0];
// tspan[1].innerHTML = '(' + tspanText.split('(')[1];
// } else if (tspanText.includes('(')) {
// console.log(tspanText);
// tspan[0].innerHTML = tspanText.split('(')[0];
// tspan[1].innerHTML = '(' + tspanText.split('(')[1];
// }
// if (tspanText.split('(')[1]?.length < 5 || tspanText.split('(')[1]?.length < 5) {
// svgAttr(tspan[1], 'x', 35);
// }
// } else {
// svgAttr(tspan[0], 'x', 35);
// }
// 判断当前的id是否在已完成或正在进行的id数组里,以添加不同的图片
const isFinish =
this.highLightedActivitiesIds.includes(element.id) ||
this.runningActivitiesIds.includes(element.id);
const attr = { x: width / 20, y: height / 3, width: 25, height: 25 };
// 给节点添加class以更改样式
let className = this.runningActivitiesIds.includes(element.id)
? 'djs-visual running'
: this.highLightedActivitiesIds.includes(element.id)
? 'djs-visual Activities'
: 'djs-visual unActivities';
svgAttr(parentNode, 'class', className);
// 计数器,当匹配到就加1,匹配不到为0就默认图片
let count = 0;
customConfig.map(item => {
if (element.businessObject.name.includes(item.labelKey)) {
count++;
const customIcon = svgCreate('image', {
...attr,
href: isFinish ? item.url : item.unUrl,
});
svgAppend(parentNode, customIcon);
return customIcon;
}
if (!count) {
const customIcon = svgCreate('image', {
...attr,
href: isFinish
? require('@/images/workflow/approve.png')
: require('@/images/workflow/unapprove.png'),
});
svgAppend(parentNode, customIcon);
return customIcon;
}
});
}
return shape;
}
getShapePath(shape) {
return this.bpmnRenderer.getShapePath(shape);
}
}
CustomRenderer.$inject = ['eventBus', 'bpmnRenderer', 'modeling'];
完整文件目录展示
- custom 文件用于编写自定义renderer
- utils用于存储图片及文字数据
- customRenderer.vue是用于渲染流程图