跳到主要内容

连接点

连接点 ConnectionPoint 与锚点 Anchor 共同确定了边的起点或终点。

  • 起点:从第一个路径点或目标节点的中心(没有路径点时)画一条参考线到源节点的锚点,然后根据 connectionPoint 指定的交点计算方法,计算参考线与图形的交点,该交点就是边的起点。
  • 终点:从最后一个路径点或源节点的中心(没有路径点时)画一条参考线到目标节点的锚点,然后根据 connectionPoint 指定的交点计算方法,计算参考线与图形的交点,该交点就是边的终点。

X6 内置了以下几种连接点计算方法。

  • boundary 默认值,与链接图形的边框的交点。
  • bbox 与链接元素的包围盒的交点。
  • rect 与链接元素的旋转后的矩形区域的交点。
  • anchor 使用锚点作为连接点。
import './index.less'
import { createRoot } from 'react-dom/client'
import React from 'react'
import { Graph, Edge, Node } from '@antv/x6'
import { Settings, State } from './settings.tsx'

export default class Example extends React.Component {
  private container: HTMLDivElement
  private ellipse: Node
  private edge1: Edge
  private edge2: Edge

  componentDidMount() {
    const graph = new Graph({
      container: this.container,
      background: {
        color: '#F2F7FA',
      },
      interacting: false,
    })

    const rect = graph.addNode({
      x: 160,
      y: 160,
      width: 100,
      height: 40,
      attrs: {
        body: {
          stroke: '#8f8f8f',
          strokeWidth: 1,
          fill: '#fff',
          rx: 6,
          ry: 6,
        },
      },
    })

    const ellipse = graph.addNode({
      shape: 'ellipse',
      x: 460,
      y: 160,
      width: 100,
      height: 40,
      angle: 45,
      markup: [
        { tagName: 'ellipse', selector: 'body' },
        { tagName: 'rect', selector: 'outline' },
      ],
      attrs: {
        body: {
          refWidth: '100%',
          refHeight: '100%',
          stroke: '#8f8f8f',
          strokeWidth: 1,
        },
        outline: {
          refWidth: '100%',
          refHeight: '100%',
          strokeWidth: 1,
          strokeDasharray: '5 5',
          stroke: '#8f8f8f',
          fill: 'none',
        },
      },
    })

    let bbox: Node
    const updateBBox = () => {
      if (bbox) {
        bbox.remove()
      }
      const rect = ellipse.findView(graph)!.getBBox()
      bbox = graph.addNode({
        x: rect.x,
        y: rect.y,
        width: rect.width,
        height: rect.height,
        attrs: {
          body: {
            strokeWidth: 1,
            strokeDasharray: '5 5',
            stroke: '#8f8f8f',
            fill: 'none',
          },
        },
      })
    }

    ellipse.on('change:angle', updateBBox)

    updateBBox()

    const edge1 = graph.addEdge({
      source: { x: 100, y: 180 },
      target: { cell: rect.id },
      attrs: {
        line: {
          stroke: '#8f8f8f',
          strokeWidth: 1,
          targetMarker: 'classic',
        },
      },
    })

    const edge2 = graph.addEdge({
      source: { x: 320, y: 180 },
      target: { cell: ellipse.id },
      attrs: {
        line: {
          stroke: '#8f8f8f',
          strokeWidth: 1,
          targetMarker: 'classic',
        },
      },
    })

    function animate() {
      const animateEdge = (
        edge: Edge,
        origin: { x: number; y: number },
        radius: number,
        steps: number,
      ) => {
        const p = edge.getSourcePoint()
        const start = Math.atan2(p.y - origin.y, p.x - origin.x)
        const xs: number[] = []
        const ys: number[] = []
        for (let i = 0; i < steps; i += 1) {
          const theta = start + (2 * Math.PI * i) / steps
          xs.push(origin.x + radius * Math.cos(theta))
          ys.push(origin.y + radius * Math.sin(theta))
        }
        edge.animate(
          {
            'source/x': xs,
            'source/y': ys,
          },
          {
            duration: 5000,
            easing: 'linear',
            fill: 'forwards',
          },
        )
      }

      const steps = 60
      animateEdge(edge1, { x: 210, y: 180 }, 120, steps)
      animateEdge(edge2, { x: 485, y: 180 }, 120, steps)
    }

    animate()

    edge1.on('animation:finish', animate)

    this.edge1 = edge1
    this.edge2 = edge2
    this.ellipse = ellipse
  }

  updateBBox() {}

  onAttrsChanged = ({ anchor, connectionPoint, angle }: State) => {
    this.edge1.prop('target/anchor', { name: anchor })
    this.edge1.prop('target/connectionPoint', { name: connectionPoint })
    this.edge2.prop('target/anchonr', { name: anchor })
    this.edge2.prop('target/connectionPoint', { name: connectionPoint })
    this.ellipse.rotate(angle, { absolute: true })
  }

  refContainer = (container: HTMLDivElement) => {
    this.container = container
  }

  render() {
    return (
      <div className="connection-point-app">
        <div className="app-side">
          <Settings onChange={this.onAttrsChanged} />
        </div>
        <div className="app-content" ref={this.refContainer} />
      </div>
    )
  }
}

const root = createRoot(document.getElementById('container')!)
root.render(<Example />)
window.addEventListener('pagehide', () => root.unmount(), { once: true })

可以在创建边时指定连接点:

const edge = graph.addEdge({
  source: {
    cell: 'source-id',
    connectionPoint: {
      name: 'boundary',
      args: {
        sticky: true,
      },
    },
  },
  target: {
    cell: 'target-id',
    connectionPoint: 'boundary', // 没有参数时可以简化写法
  },
})

创建之后可以调用 edge.setSource 和 edge.setTarget 方法来修改连接点:

edge.setSource({
  cell: 'source-id',
  connectionPoint: {
    name: 'boundary',
    args: {
      sticky: true,
    },
  },
})

在创建画布时,可以通过 connecting 选项来设置全局默认的连接点:

new Graph({
  connecting: {
    connectionPoint: {
      name: 'boundary',
      args: {
        sticky: true,
      },
    },
  },
})

没有参数时可以简化为:

new Graph({
  connecting: {
    connectionPoint: 'boundary',
  },
})

内置连接点

boundary

自动识别链接图形的边框,并计算参照点与锚点(Anchor)形成的直线与边框的交点。如 <ellipse> 元素将被识别为椭圆,并求椭圆与直线的交点,求得的交点为边的连接点。不能识别的元素(text、<path> 等)使用图形的包围盒代替,这与使用 'bbox' 求得的连接点一样。

支持的参数如下表:

参数名 参数类型 是否必选 默认值 参数说明
offset number | Point.PointLike 否 0 连接点的偏移量。
stroked boolean 否 true 是否考虑图形的边框宽度。
insideout boolean 否 true 当参考线位于图形内部且没有交点时,是否延长参考线求交点,默认为 true。
extrapolate boolean 否 false 当参考线位于图形外部且没有交点时,是否延长参考线求交点,延长后也可能没有交点,默认为 false。此参数的优先级高于 sticky。
sticky boolean 否 false 当参考线位于图形外部且没有交点时,是否使用边框上离参考线最最近的点作为交点,默认为 false。
precision number 否 2 交点计算的精度。
selector string 否 undefined 选择器,用于标识一个元素,使用该元素的边框来计算交点。默认使用节点中第一个不在 <g> 元素内的子元素。

anchor

将锚点作为连接点,支持如下参数:

参数名 参数类型 是否必选 默认值 参数说明
offset number | Point.PointLike 否 0 连接点的偏移量。

bbox

图形的包围盒与参考线的交点,支持如下参数:

参数名 参数类型 是否必选 默认值 参数说明
offset number | Point.PointLike 否 0 连接点的偏移量。
stroked boolean 否 false 是否考虑图形的边框宽度。

rect

图形旋转后的矩形区域与参考线的交点,支持如下参数:

参数名 参数类型 是否必选 默认值 参数说明
offset number | Point.PointLike 否 0 连接点的偏移量。
stroked boolean 否 false 是否考虑图形的边框宽度。

自定义连接点

连接点定义是一个具有如下签名的函数,返回连接点。

export type Definition<T> = (
  line: Line,
  view: NodeView,
  magnet: SVGElement,
  args: T,
) => Point
参数名 参数类型 参数说明
line Line 参考线。
nodeView NodeView 连接的节点视图。
magnet SVGElement 连接的节点上的元素。
args T 参数。

完成连接点定义后,我们先注册连接点:

Graph.registerConnectionPoint('custom-connection-point', ...)

注册以后我们就可以通过连接点名称来使用:

new Graph({
  connecting: {
    connectionPoint: 'custom-connection-point'
  },
})
© Copyright 2026 Ant Group Co., Ltd..备案号:京ICP备15032932号-38
全站搜索
文档与示例输入关键词开始搜索

输入关键词,查找文档、API 与示例

↑↓选择↵打开Esc关闭