效果图
原理
joinjs中通过svg来绘制流程图,然后我们可以使用localToClientRect
这个方法对节点(element)复制,它会在原来的element在svg位置上生成一个html元素,但是这样会造成原来的element节点监听的点击事件无法触发,我们可以使用原生来操作对这个元素(比如样式的设置和事件的监听)
代码
<template><div class="app"><div ref="myholder" id="paper"></div></div>
</template><script>
import * as joint from '@joint/core'
import $ from 'jquery'
export default {data() {return {graph: null,}},mounted() {const namespace = joint.shapesvar graph = new joint.dia.Graph({}, { cellNamespace: namespace })this.graph = graphvar paper = new joint.dia.Paper({el: this.$refs.myholder,model: this.graph,width: 800,height: 300,cellViewNamespace: namespace,drawGrid: true,gridSize: 10,background: {color: 'rgba(0, 255, 0, 0.3)',},// 禁止交互interactive: false, // disable default interaction (e.g. dragging)// 当mousemove事件的数量超过clickThreshold时,在mouseup之后不会触发pointerclick事件clickThreshold: 10,})this.paper = paper// const element = new joint.shapes.standard.Rectangle()// element.position(100, 50)// element.resize(100, 40)// element.addTo(this.graph)// Draw an HTML rectangle above the element.// var bbox = element.getBBox()// var clientRect1 = paper.localToClientRect(bbox)// var div = document.createElement('div')// div.style.position = 'fixed'// div.style.background = 'red'// div.style.left = clientRect1.x + 'px'// div.style.top = clientRect1.y + 'px'// div.style.width = clientRect1.width + 'px'// div.style.height = clientRect1.height + 'px'// div.innerHTML = `<span class='yellow'>哈哈哈</span>`// $(div).click(() => {// console.log('发生了点击')// })// paper.el.appendChild(div)// 整合const node1 = this.drawRect({ x: 50, y: 30 }, '流程-1')const node2 = this.drawRect({ x: 200, y: 30 }, '流程-2')const node3 = this.drawRect({ x: 350, y: 30 }, '流程-3')const node4 = this.drawRect({ x: 500, y: 30 }, '流程-4')const node5 = this.drawRect({ x: 50, y: 100 }, '流程-1.1')const node6 = this.drawRect({ x: 350, y: 100 }, '流程-2.1')const node7 = this.drawRect({ x: 350, y: 150 }, '流程-2.2')const node2_to_node6_vetices = [new joint.g.Point(250, 100)]const node2_to_node7_vetices = [new joint.g.Point(250, 150)]this.drawLine(node1, node2)this.drawLine(node2, node3)this.drawLine(node3, node4)this.drawLine(node1, node5)this.drawLine(node2, node6, node2_to_node6_vetices)this.drawLine(node2, node7, node2_to_node7_vetices)},methods: {drawRect({ x, y }, text) {var rect = new joint.shapes.standard.Rectangle()rect.position(x, y)rect.resize(100, 40)rect.attr({body: {fill: '#2c3e50',},label: {text,fill: '#3498DB',fontSize: 18,fontWeight: 'bold',fontVariant: 'Microsoft YaHei',},})rect.addTo(this.graph)this.transformHtml(rect, text)return rect},drawLine(node1, node2, vertices) {var link = new joint.shapes.standard.Link()link.source(node1)link.target(node2)link.addTo(this.graph)if (vertices) {link.vertices(vertices)link.router('orthogonal')// link.connector('rounded')}// link.vertices([// new joint.g.Point(250, 100),// new joint.g.Point(280, 100),// new joint.g.Point(300, 120),// ])//link.attr({line: {stroke: 'gray',},})},transformHtml(element, text) {var bbox = element.getBBox()// NOTE:重点方法 绘制一个html元素在element元素之上// Draw an HTML rectangle above the element.var clientRect1 = this.paper.localToClientRect(bbox)var div = document.createElement('div')div.style.position = 'fixed'div.style.background = 'red'div.style.left = clientRect1.x + 'px'div.style.top = clientRect1.y + 'px'div.style.width = clientRect1.width + 'px'div.style.height = clientRect1.height + 'px'div.innerHTML = `<span class='yellow'>${text}</span>`$(div).click(function () {console.log(this)})this.paper.el.appendChild(div)},},
}
</script><style lang="less" scoped>
#paper {border: 1px solid;
}/deep/.yellow {color: yellow;
}
</style>