背景
bpmn-js是个流程图绘制的工具,但是现在我希望实现的是,绘制的不是节点而是一个vue组件。
保留线的拖拽和连接。
方案
那就说明不是依赖于节点的样式,找到了他有个属性,就是类似覆盖节点的操作。
思路就是用vue组件做遮罩,盖住原本的节点样式。
/**
* 批量操作节点
*/
handleAddOverlay() {
const bpmnModeling = this.bpmnModeler.get('modeling')
const contextPad = this.bpmnModeler.get('contextPad')
this.bpmnModeler.on('import.done', () => {
// 加载完成后每个元素遍历
const elementRegistry = this.bpmnModeler.get('elementRegistry')
elementRegistry.forEach(element => {
if (['bpmn:Task'].includes(element.type)) {
const parent = elementRegistry.getGraphics(element)
bpmnModeling.resizeShape(element, {
width: element.width || this.config.width || 60,
height: element.height || this.config.height || 60,
x: getDi(element).bounds.x,
y: getDi(element).bounds.y
})
// 遍历任务节点,为每个节点添加 overlays
if (this.isShowComponent) {
bpmnModeling.setColor(element, { stroke: this.config.borderColor || '#eee' }) // 修改边框颜色
bpmnModeling.setColor(element, { fill: this.config.fillColor || '#fff' }) // 修改边框颜色
this.addOverlay(element, parent)
}
}
})
})
},
接下来是挂载覆盖物的重点,如何让覆盖物跟随节点的移动而移动
/**
*
* @param {*} element
* 增加覆盖物节点操作
*/
addOverlay(element, parent) {
const __this = this
const overlays = this.bpmnModeler.get('overlays')
const bpmnModeling = this.bpmnModeler.get('modeling')
const elementRegistry = this.bpmnModeler.get('elementRegistry')
const index = this.data.nodeLists.findIndex(item => item.config.id === element.id)
// 添加覆盖物 ------------------------------------- begin
overlays.add(element, 'my-overlay', {
position: __this.overlayPosition,
show: {
minZoom: 0.1
},
html: '<div id="my-component"></div>'
})
const Profile = Vue.extend(this.config.components)
overlays.get({ element: element, type: 'my-overlay' })[0].htmlContainer.id = element.id
new Profile({
router,
propsData: {
element: element,
node: index > -1 ? this.data.nodeLists[index] : {},
func: this.func,
...this.props
},
mounted() {
const component = this
// 绑定鼠标按下事件
component.$el.addEventListener('mousedown', event => {
__this.isDrag = false
event.preventDefault()
if (!__this.disable) {
dragMouseDown(event)
}
})
// 自定义组件点击事件
component.$el.addEventListener('click', () => {
if (!__this.isDrag) {
__this.showContextPad(element)
const bpmnElement = elementRegistry.get(element.id)
__this.currentElement = bpmnElement
__this.$emit('click', bpmnElement) // 点击事件
}
})
}
}).$mount('#my-component')
// 添加覆盖物 -------------------------------------end
// 必须作为公共变量进行值更改
let pos1 = 0
let pos2 = 0
let pos3 = 0
let pos4 = 0
/**
*
* @param {*} e
* @param {*} overlayPosition
* 鼠标按下开始
*/
function dragMouseDown(e) {
e = e || window.event
e.preventDefault()
pos3 = e.clientX
pos4 = e.clientY
document.onmousemove = event => {
__this.isDrag = true
elementDrag(event, __this.overlayPosition)
}
document.onmouseup = () => {
__this.currentElement = null
document.onmouseup = null
document.onmousemove = null
}
}
/**
*
* @param {*} e
* @param {*} overlayPosition
* 节点的拖拽
*/
function elementDrag(e, overlayPosition) {
e = e || window.event
e.preventDefault()
// 计算新的元素位置
pos1 = pos3 - e.clientX
pos2 = pos4 - e.clientY
pos3 = e.clientX
pos4 = e.clientY
const bpmnElement = elementRegistry.get(element.id)
const deltaX = overlayPosition.x + pos1
const deltaY = overlayPosition.y + pos2
// 移动父节点及其连接线
moveParentNode(bpmnElement, deltaX, deltaY)
}
/**
*
* @param {*} element
* @param {*} dx
* @param {*} dy
* 更改父节点操作
*/
function moveParentNode(element, dx, dy) {
const parent = element.parent
if (!parent) {
return
}
// // 更新父节点的位置信息
bpmnModeling.moveElements([element], { x: -dx, y: -dy }, null)
// 更新覆盖物的位置
const overlay = overlays.get({ element: parent, type: 'my-overlay' })
overlay.position = {
top: overlay.top - dy,
left: overlay.left - dx
}
}
},