|
|
|
@ -1,5 +1,5 @@
|
|
|
|
import React, { useState, useEffect, useRef } from 'react';
|
|
|
|
import React, { useState, useEffect, useRef } from 'react';
|
|
|
|
import { BaseEdge, EdgeLabelRenderer, EdgeProps, getSmoothStepPath, useReactFlow } from '@xyflow/react';
|
|
|
|
import { BaseEdge, EdgeLabelRenderer, EdgeProps, getSmoothStepPath, useReactFlow, getEdgeCenter } from '@xyflow/react';
|
|
|
|
import EdgeAddNodeButton from '@/pages/flowEditor/components/edgeAddNodeButton';
|
|
|
|
import EdgeAddNodeButton from '@/pages/flowEditor/components/edgeAddNodeButton';
|
|
|
|
import { getTopicList } from '@/api/event';
|
|
|
|
import { getTopicList } from '@/api/event';
|
|
|
|
import { useSelector } from 'react-redux';
|
|
|
|
import { useSelector } from 'react-redux';
|
|
|
|
@ -51,7 +51,92 @@ const DataDisplayEdge: React.FC<EdgeProps> = ({
|
|
|
|
const lineType = data?.lineType || 'data'; // 默认为data类型
|
|
|
|
const lineType = data?.lineType || 'data'; // 默认为data类型
|
|
|
|
|
|
|
|
|
|
|
|
// 使用useReactFlow钩子获取setEdges方法
|
|
|
|
// 使用useReactFlow钩子获取setEdges方法
|
|
|
|
const { setEdges } = useReactFlow();
|
|
|
|
const { setEdges, getEdges, getNodes } = useReactFlow();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算智能标签位置,避免重叠
|
|
|
|
|
|
|
|
const calculateSmartLabelPosition = () => {
|
|
|
|
|
|
|
|
const edges = getEdges();
|
|
|
|
|
|
|
|
const nodes = getNodes();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前边
|
|
|
|
|
|
|
|
const currentEdge = edges.find(e => e.id === id);
|
|
|
|
|
|
|
|
if (!currentEdge) return { x: labelX, y: labelY };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取源节点和目标节点
|
|
|
|
|
|
|
|
const sourceNode = nodes.find(n => n.id === currentEdge.source);
|
|
|
|
|
|
|
|
const targetNode = nodes.find(n => n.id === currentEdge.target);
|
|
|
|
|
|
|
|
if (!sourceNode || !targetNode) return { x: labelX, y: labelY };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算当前边的中心位置
|
|
|
|
|
|
|
|
const [centerX, centerY] = getEdgeCenter({
|
|
|
|
|
|
|
|
sourceX,
|
|
|
|
|
|
|
|
sourceY,
|
|
|
|
|
|
|
|
targetX,
|
|
|
|
|
|
|
|
targetY
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 查找所有可能重叠的边(中心点距离很近的边)
|
|
|
|
|
|
|
|
const overlappingEdges = edges.filter(edge => {
|
|
|
|
|
|
|
|
if (edge.id === id || !edge.source || !edge.target) return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const edgeSourceNode = nodes.find(n => n.id === edge.source);
|
|
|
|
|
|
|
|
const edgeTargetNode = nodes.find(n => n.id === edge.target);
|
|
|
|
|
|
|
|
if (!edgeSourceNode || !edgeTargetNode) return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算该边的中心位置
|
|
|
|
|
|
|
|
const [edgeCenterX, edgeCenterY] = getEdgeCenter({
|
|
|
|
|
|
|
|
sourceX: edgeSourceNode.position.x,
|
|
|
|
|
|
|
|
sourceY: edgeSourceNode.position.y,
|
|
|
|
|
|
|
|
targetX: edgeTargetNode.position.x,
|
|
|
|
|
|
|
|
targetY: edgeTargetNode.position.y
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算距离
|
|
|
|
|
|
|
|
const distance = Math.sqrt(
|
|
|
|
|
|
|
|
Math.pow(centerX - edgeCenterX, 2) +
|
|
|
|
|
|
|
|
Math.pow(centerY - edgeCenterY, 2)
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 距离小于120px认为可能重叠
|
|
|
|
|
|
|
|
return distance < 120;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有重叠,使用默认中心位置
|
|
|
|
|
|
|
|
if (overlappingEdges.length === 0) {
|
|
|
|
|
|
|
|
return { x: labelX, y: labelY };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 将当前边加入并排序
|
|
|
|
|
|
|
|
const allOverlappingEdges = [...overlappingEdges, currentEdge].sort((a, b) =>
|
|
|
|
|
|
|
|
a.id.localeCompare(b.id)
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 找到当前边的索引
|
|
|
|
|
|
|
|
const currentIndex = allOverlappingEdges.findIndex(e => e.id === id);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 根据索引沿着边的路径分配位置
|
|
|
|
|
|
|
|
// 第1条边在中心(0.5),其他边向两侧分散
|
|
|
|
|
|
|
|
let positionRatio = 0.5;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (currentIndex > 0) {
|
|
|
|
|
|
|
|
// 奇数索引向源节点方向,偶数索引向目标节点方向
|
|
|
|
|
|
|
|
const direction = currentIndex % 2 === 1 ? -1 : 1;
|
|
|
|
|
|
|
|
const step = Math.ceil(currentIndex / 2);
|
|
|
|
|
|
|
|
const offset = step * 0.15 * direction; // 每次偏移15%
|
|
|
|
|
|
|
|
positionRatio = Math.max(0.2, Math.min(0.8, 0.5 + offset));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算沿边路径的实际坐标
|
|
|
|
|
|
|
|
const actualX = sourceX + (targetX - sourceX) * positionRatio;
|
|
|
|
|
|
|
|
const actualY = sourceY + (targetY - sourceY) * positionRatio;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return { x: actualX, y: actualY };
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取智能位置(支持手动覆盖)
|
|
|
|
|
|
|
|
const smartPosition = data?.labelPosition
|
|
|
|
|
|
|
|
? { x: sourceX + (targetX - sourceX) * data.labelPosition, y: sourceY + (targetY - sourceY) * data.labelPosition }
|
|
|
|
|
|
|
|
: calculateSmartLabelPosition();
|
|
|
|
|
|
|
|
|
|
|
|
// 边点击处理函数
|
|
|
|
// 边点击处理函数
|
|
|
|
const handleEdgeAddNode = (e) => {
|
|
|
|
const handleEdgeAddNode = (e) => {
|
|
|
|
@ -133,10 +218,11 @@ const DataDisplayEdge: React.FC<EdgeProps> = ({
|
|
|
|
<div
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
style={{
|
|
|
|
position: 'absolute',
|
|
|
|
position: 'absolute',
|
|
|
|
transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
|
|
|
|
transform: `translate(-50%, -50%) translate(${smartPosition.x}px,${smartPosition.y}px)`,
|
|
|
|
fontSize: 12,
|
|
|
|
fontSize: 12,
|
|
|
|
pointerEvents: 'all',
|
|
|
|
pointerEvents: 'all',
|
|
|
|
opacity: style?.opacity || 1 // 应用透明度样式到标签容器
|
|
|
|
opacity: style?.opacity || 1, // 应用透明度样式到标签容器
|
|
|
|
|
|
|
|
zIndex: selected ? 1000 : 100 // 选中的边标签显示在最上层
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
className="nodrag nopan"
|
|
|
|
className="nodrag nopan"
|
|
|
|
>
|
|
|
|
>
|
|
|
|
|