feat(flowEditor): 优化自定义边组件的标签定位功能

master
钟良源 3 weeks ago
parent 994fe3fa36
commit 43d9872757

@ -1,5 +1,5 @@
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 { getTopicList } from '@/api/event';
import { useSelector } from 'react-redux';
@ -51,7 +51,92 @@ const DataDisplayEdge: React.FC<EdgeProps> = ({
const lineType = data?.lineType || 'data'; // 默认为data类型
// 使用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) => {
@ -133,10 +218,11 @@ const DataDisplayEdge: React.FC<EdgeProps> = ({
<div
style={{
position: 'absolute',
transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
transform: `translate(-50%, -50%) translate(${smartPosition.x}px,${smartPosition.y}px)`,
fontSize: 12,
pointerEvents: 'all',
opacity: style?.opacity || 1 // 应用透明度样式到标签容器
opacity: style?.opacity || 1, // 应用透明度样式到标签容器
zIndex: selected ? 1000 : 100 // 选中的边标签显示在最上层
}}
className="nodrag nopan"
>

Loading…
Cancel
Save