UnisKB/ui/src/workflow/common/edge.ts

243 lines
6.0 KiB
TypeScript
Raw Normal View History

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
}