You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React Flow中防止连线与节点相交?

React Flow 自定义连线避障实现

问题场景

业务要求使用节点的垂直连接点(底部连顶部),但默认贝塞尔连线会直接穿过中间节点,导致流程可视化混乱。需要实现:

  • 垂直上下节点的连线自动绕开节点,不相交
  • 非垂直方向的连接,保留原有的贝塞尔曲线样式

解决方案代码

import { BaseEdge, EdgeLabelRenderer, EdgeProps, getBezierPath } from 'reactflow'
import './styles.scss'
import { useDispatch } from 'react-redux'
import { setSelectedWorkflowItem } from '../../../../redux/slices/WorkflowReducer'

function CustomEdges(props) {
  const {
    id,
    sourceX,
    sourceY,
    targetX,
    targetY,
    sourcePosition,
    targetPosition,
    style = {},
    markerEnd,
    data,
    selected,
  }: EdgeProps = props
  const dispatch = useDispatch()

  let edgePath, labelX, labelY;
  // 判断是否为需要绕路的垂直上下连接(可根据节点宽度调整x坐标差值阈值)
  const isVerticalTopConnect = sourcePosition === 'bottom' && targetPosition === 'top' && Math.abs(sourceX - targetX) < 50;
  
  if (isVerticalTopConnect) {
    // 设定偏移距离,可根据布局需求调整
    const offset = 100;
    // 决定偏移方向,避免连线穿过节点
    const direction = sourceX > targetX ? -1 : 1;
    // 构造绕开节点的贝塞尔路径
    edgePath = `M ${sourceX} ${sourceY} 
                C ${sourceX + direction * offset} ${sourceY}, 
                  ${targetX + direction * offset} ${targetY}, 
                  ${targetX} ${targetY}`;
    // 计算标签的中间位置
    labelX = (sourceX + targetX) / 2 + direction * offset;
    labelY = (sourceY + targetY) / 2;
  } else {
    // 非垂直连接保留原有贝塞尔曲线逻辑
    [edgePath, labelX, labelY] = getBezierPath({
      sourceX,
      sourceY,
      sourcePosition,
      targetX,
      targetY,
      targetPosition,
    })
  }

  const onEdgeClick = (evt, id) => {
    evt.stopPropagation()
    dispatch(setSelectedWorkflowItem({ item: props }))
  }
  
  const styleProps = data.isDefault
    ? {...style, strokeWidth: 3}
    : data.selected
    ? {...style, strokeWidth: 2}
    : {...style, strokeWidth: 1.5}

  return (
    <>
      <BaseEdge path={edgePath} markerEnd={markerEnd} style={styleProps} />
      <EdgeLabelRenderer>
        <div
          style={{
            position: 'absolute',
            transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
            fontSize: 12,
            pointerEvents: 'all',
          }}
          className='nodrag nopan'
        >
          <button
            className={`edgebutton background-workflow ${
              data.selected && 'background-workflow-active'
            }`}
            onClick={(event) => onEdgeClick(event, id)}
          >
            {data?.displayName}
          </button>
        </div>
      </EdgeLabelRenderer>
    </>
  )
}

export default CustomEdges

关键修改说明

  1. 垂直连接判定:通过连接点位置、节点坐标差值,识别需要绕路的垂直上下连接场景
  2. 自定义绕路路径:生成带左右偏移控制点的贝塞尔曲线,让连线避开节点区域
  3. 标签位置适配:同步调整标签坐标,确保标签显示在绕路连线的中间位置
  4. 兼容原有逻辑:非垂直连接仍沿用原getBezierPath生成曲线,不影响其他连接场景

内容的提问来源于stack exchange,提问作者Yunus YAVUZ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 17:15:27