2025-06-03 08:08:49 +00:00
|
|
|
|
import { BezierEdge, BezierEdgeModel, h } from '@logicflow/core'
|
|
|
|
|
|
import { createApp, h as vh } from 'vue'
|
|
|
|
|
|
import { isActive, connect, disconnect } from './teleport'
|
|
|
|
|
|
import CustomLine from './CustomLine.vue'
|
|
|
|
|
|
function isMouseInElement(element: any, e: any) {
|
|
|
|
|
|
const rect = element.getBoundingClientRect()
|
|
|
|
|
|
return (
|
|
|
|
|
|
e.clientX >= rect.left &&
|
|
|
|
|
|
e.clientX <= rect.right &&
|
|
|
|
|
|
e.clientY >= rect.top &&
|
|
|
|
|
|
e.clientY <= rect.bottom
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
const DEFAULT_WIDTH = 32
|
|
|
|
|
|
const DEFAULT_HEIGHT = 32
|
|
|
|
|
|
class CustomEdge2 extends BezierEdge {
|
|
|
|
|
|
isMounted
|
|
|
|
|
|
customLineApp?: any
|
|
|
|
|
|
root?: any
|
|
|
|
|
|
constructor() {
|
|
|
|
|
|
super()
|
|
|
|
|
|
this.isMounted = false
|
|
|
|
|
|
this.handleMouseUp = (e: any) => {
|
|
|
|
|
|
this.props.graphModel.clearSelectElements()
|
|
|
|
|
|
this.props.model.isSelected = true
|
|
|
|
|
|
const element = e.target.parentNode.parentNode.querySelector('.lf-custom-edge-wrapper')
|
|
|
|
|
|
if (isMouseInElement(element, e)) {
|
|
|
|
|
|
this.props.model.graphModel.deleteEdgeById(this.props.model.id)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 渲染vue组件
|
|
|
|
|
|
* @param root
|
|
|
|
|
|
*/
|
|
|
|
|
|
protected renderVueComponent(root: any) {
|
|
|
|
|
|
this.unmountVueComponent()
|
|
|
|
|
|
this.root = root
|
|
|
|
|
|
const { graphModel } = this.props
|
|
|
|
|
|
if (root) {
|
|
|
|
|
|
if (isActive()) {
|
|
|
|
|
|
connect(
|
|
|
|
|
|
this.targetId(),
|
|
|
|
|
|
CustomLine,
|
|
|
|
|
|
root,
|
|
|
|
|
|
this.props.model,
|
|
|
|
|
|
graphModel,
|
|
|
|
|
|
(node: any, graph: any) => {
|
|
|
|
|
|
return { model: node, graph }
|
2025-06-25 13:58:01 +00:00
|
|
|
|
},
|
2025-06-03 08:08:49 +00:00
|
|
|
|
)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.customLineApp = createApp({
|
2025-06-25 13:58:01 +00:00
|
|
|
|
render: () => vh(CustomLine, { model: this.props.model }),
|
2025-06-03 08:08:49 +00:00
|
|
|
|
})
|
|
|
|
|
|
this.customLineApp?.mount(root)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
protected targetId() {
|
|
|
|
|
|
return `${this.props.graphModel.flowId}:${this.props.model.id}`
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 组件即将卸载勾子
|
|
|
|
|
|
*/
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
|
|
if (super.componentWillUnmount) {
|
|
|
|
|
|
super.componentWillUnmount()
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isActive()) {
|
|
|
|
|
|
disconnect(this.targetId())
|
|
|
|
|
|
}
|
|
|
|
|
|
this.unmountVueComponent()
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 卸载vue
|
|
|
|
|
|
* @returns
|
|
|
|
|
|
*/
|
|
|
|
|
|
protected unmountVueComponent() {
|
|
|
|
|
|
if (this.customLineApp) {
|
|
|
|
|
|
this.customLineApp.unmount()
|
|
|
|
|
|
this.customLineApp = null
|
|
|
|
|
|
}
|
|
|
|
|
|
if (this.root) {
|
|
|
|
|
|
this.root.innerHTML = ''
|
|
|
|
|
|
}
|
|
|
|
|
|
return this.root
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
getEdge() {
|
|
|
|
|
|
const { model } = this.props
|
|
|
|
|
|
const id = model.id
|
|
|
|
|
|
const { customWidth = DEFAULT_WIDTH, customHeight = DEFAULT_HEIGHT } = model.getProperties()
|
|
|
|
|
|
const { startPoint, endPoint, path, isAnimation, arrowConfig } = model
|
|
|
|
|
|
const animationStyle = model.getEdgeAnimationStyle()
|
|
|
|
|
|
const {
|
|
|
|
|
|
strokeDasharray,
|
|
|
|
|
|
stroke,
|
|
|
|
|
|
strokeDashoffset,
|
|
|
|
|
|
animationName,
|
|
|
|
|
|
animationDuration,
|
|
|
|
|
|
animationIterationCount,
|
|
|
|
|
|
animationTimingFunction,
|
2025-06-25 13:58:01 +00:00
|
|
|
|
animationDirection,
|
2025-06-03 08:08:49 +00:00
|
|
|
|
} = animationStyle
|
|
|
|
|
|
const positionData = {
|
|
|
|
|
|
x: (startPoint.x + endPoint.x - customWidth) / 2,
|
|
|
|
|
|
y: (startPoint.y + endPoint.y - customHeight) / 2,
|
|
|
|
|
|
width: customWidth,
|
2025-06-25 13:58:01 +00:00
|
|
|
|
height: customHeight,
|
2025-06-03 08:08:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
const style = model.getEdgeStyle()
|
|
|
|
|
|
const wrapperStyle = {
|
|
|
|
|
|
width: customWidth,
|
2025-06-25 13:58:01 +00:00
|
|
|
|
height: customHeight,
|
2025-06-03 08:08:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
const s = document.getElementById(id)
|
|
|
|
|
|
if (s && !this.isMounted) {
|
|
|
|
|
|
this.isMounted = true
|
|
|
|
|
|
this.renderVueComponent(s)
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 0)
|
|
|
|
|
|
|
|
|
|
|
|
delete style.stroke
|
|
|
|
|
|
|
|
|
|
|
|
return h('g', {}, [
|
|
|
|
|
|
h(
|
|
|
|
|
|
'style' as any,
|
|
|
|
|
|
{ type: 'text/css' },
|
2025-06-25 13:58:01 +00:00
|
|
|
|
'.lf-edge{stroke:#afafaf}.lf-edge:hover{stroke: #3370FF;}',
|
2025-06-03 08:08:49 +00:00
|
|
|
|
),
|
|
|
|
|
|
h('path', {
|
|
|
|
|
|
d: path,
|
|
|
|
|
|
...style,
|
|
|
|
|
|
...arrowConfig,
|
|
|
|
|
|
...(isAnimation
|
|
|
|
|
|
? {
|
|
|
|
|
|
strokeDasharray,
|
|
|
|
|
|
stroke,
|
|
|
|
|
|
style: {
|
|
|
|
|
|
strokeDashoffset,
|
|
|
|
|
|
animationName,
|
|
|
|
|
|
animationDuration,
|
|
|
|
|
|
animationIterationCount,
|
|
|
|
|
|
animationTimingFunction,
|
2025-06-25 13:58:01 +00:00
|
|
|
|
animationDirection,
|
|
|
|
|
|
},
|
2025-06-03 08:08:49 +00:00
|
|
|
|
}
|
2025-06-25 13:58:01 +00:00
|
|
|
|
: {}),
|
2025-06-03 08:08:49 +00:00
|
|
|
|
}),
|
|
|
|
|
|
h(
|
|
|
|
|
|
'foreignObject',
|
|
|
|
|
|
{
|
|
|
|
|
|
...positionData,
|
|
|
|
|
|
y: positionData.y + 5,
|
|
|
|
|
|
x: positionData.x + 5,
|
2025-06-25 13:58:01 +00:00
|
|
|
|
style: {},
|
2025-06-03 08:08:49 +00:00
|
|
|
|
},
|
|
|
|
|
|
[
|
|
|
|
|
|
h('div', {
|
|
|
|
|
|
id,
|
|
|
|
|
|
style: { ...wrapperStyle },
|
2025-06-25 13:58:01 +00:00
|
|
|
|
className: 'lf-custom-edge-wrapper',
|
|
|
|
|
|
}),
|
|
|
|
|
|
],
|
|
|
|
|
|
),
|
2025-06-03 08:08:49 +00:00
|
|
|
|
])
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class CustomEdgeModel2 extends BezierEdgeModel {
|
|
|
|
|
|
getArrowStyle() {
|
|
|
|
|
|
const arrowStyle = super.getArrowStyle()
|
|
|
|
|
|
arrowStyle.offset = 1
|
|
|
|
|
|
arrowStyle.verticalLength = 0
|
|
|
|
|
|
return arrowStyle
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
getEdgeStyle() {
|
|
|
|
|
|
const style = super.getEdgeStyle()
|
|
|
|
|
|
// svg属性
|
|
|
|
|
|
style.strokeWidth = 2
|
|
|
|
|
|
style.stroke = '#BBBFC4'
|
|
|
|
|
|
style.offset = 0
|
|
|
|
|
|
return style
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 重写此方法,使保存数据是能带上锚点数据。
|
|
|
|
|
|
*/
|
|
|
|
|
|
getData() {
|
|
|
|
|
|
const data: any = super.getData()
|
|
|
|
|
|
if (data) {
|
|
|
|
|
|
data.sourceAnchorId = this.sourceAnchorId
|
|
|
|
|
|
data.targetAnchorId = this.targetAnchorId
|
|
|
|
|
|
}
|
|
|
|
|
|
return data
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 给边自定义方案,使其支持基于锚点的位置更新边的路径
|
|
|
|
|
|
*/
|
|
|
|
|
|
updatePathByAnchor() {
|
|
|
|
|
|
const sourceNodeModel = this.graphModel.getNodeModelById(this.sourceNodeId)
|
|
|
|
|
|
const sourceAnchor = sourceNodeModel
|
|
|
|
|
|
.getDefaultAnchor()
|
|
|
|
|
|
.find((anchor: any) => anchor.id === this.sourceAnchorId)
|
|
|
|
|
|
|
|
|
|
|
|
const targetNodeModel = this.graphModel.getNodeModelById(this.targetNodeId)
|
|
|
|
|
|
const targetAnchor = targetNodeModel
|
|
|
|
|
|
.getDefaultAnchor()
|
|
|
|
|
|
.find((anchor: any) => anchor.id === this.targetAnchorId)
|
|
|
|
|
|
if (sourceAnchor && targetAnchor) {
|
|
|
|
|
|
const startPoint = {
|
|
|
|
|
|
x: sourceAnchor.x,
|
2025-06-25 13:58:01 +00:00
|
|
|
|
y: sourceAnchor.y,
|
2025-06-03 08:08:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
this.updateStartPoint(startPoint)
|
|
|
|
|
|
const endPoint = {
|
|
|
|
|
|
x: targetAnchor.x,
|
2025-06-25 13:58:01 +00:00
|
|
|
|
y: targetAnchor.y,
|
2025-06-03 08:08:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.updateEndPoint(endPoint)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 这里需要将原有的pointsList设置为空,才能触发bezier的自动计算control点。
|
|
|
|
|
|
this.pointsList = []
|
|
|
|
|
|
this.initPoints()
|
|
|
|
|
|
}
|
|
|
|
|
|
setAttributes(): void {
|
|
|
|
|
|
super.setAttributes()
|
|
|
|
|
|
this.isHitable = true
|
|
|
|
|
|
this.zIndex = 0
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
type: 'app-edge',
|
|
|
|
|
|
view: CustomEdge2,
|
2025-06-25 13:58:01 +00:00
|
|
|
|
model: CustomEdgeModel2,
|
2025-06-03 08:08:49 +00:00
|
|
|
|
}
|