news 2026/9/17 20:03:47

X6 连接器(Connector)完全指南:内置连接器使用、自定义注册与 SVG 路径生成原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
X6 连接器(Connector)完全指南:内置连接器使用、自定义注册与 SVG 路径生成原理

X6 连接器(Connector)完全指南:内置连接器使用、自定义注册与 SVG 路径生成原理

【免费下载链接】X6🚀 JavaScript diagramming library that uses SVG and HTML for rendering.项目地址: https://gitcode.com/GitHub_Trending/x6/X6

导读

在 X6 中,连接器(Connector)负责把边的起点、路由(Router)返回的中间点与终点加工为 SVG<path>元素的d属性,是决定边渲染形态(直线、贝塞尔曲线、圆角、跳线等)的核心一环。本文以官方文档 connector.zh.md 为骨架,结合仓库源码(src/registry/connector)与模型层实现,完整讲解内置连接器的参数用法、全局/局部配置方式、自定义连接器的函数签名与注册流程,并深入剖析每种内置连接器的底层几何实现,帮助你在实际项目中精确控制边的视觉表现。

什么是连接器

连接器在 X6 的渲染管线中扮演"最后成型"的角色:路由(Router)负责计算折线经过的拐点,连接器则将这些离散的点位转换成可供 SVG 渲染的路径数据。在 src/registry/connector/index.ts 中,连接器的类型定义如下:

export type ConnectorDefinition< T extends ConnectorBaseOptions = ConnectorBaseOptions, > = ( this: EdgeView, sourcePoint: PointLike, targetPoint: PointLike, routePoints: PointLike[], options: T, edgeView: EdgeView, ) => Path | string

其核心语义是:输入sourcePoint(起点)、targetPoint(终点)、routePoints(路由返回的点),输出一个几何Path对象或序列化后的路径字符串。连接器的返回值最终会写入<path>元素的d属性,从而决定边渲染到画布后的样式。

X6 内置了以下几种连接器:

连接器说明
normal简单连接器,用直线连接起点、路由点和终点。
smooth平滑连接器,用三次贝塞尔曲线连接起点、路由点和终点。
rounded圆角连接器,用直线连接起点、路由点和终点,并在线段连接处用圆弧链接(倒圆角)。
jumpover跳线连接器,用直线连接起点、路由点和终点,并在边与边的交叉处用跳线符号链接。

连接器的三种配置方式

1. 在创建边时指定

const edge = graph.addEdge({ source, target, connector: { name: 'rounded', args: { radius: 20, }, }, })

当没有连接器参数时,可以简化为:

const edge = graph.addEdge({ source, target, connector: 'rounded', })

2. 通过边实例方法动态设置

edge.setConnector('rounded', { radius: 20 })

setConnector定义于 src/model/edge.ts,支持两种重载形式:既可以传(name, args),也可以直接传完整的ConnectorData对象;对应的getConnector()方法用于读取当前边的连接器配置。与之配套的还有removeConnector(),用于移除连接器设置。

3. 创建画布时设置全局默认

new Graph({ connecting: { connector: { name: 'rounded', args: { radius: 20, }, }, }, })

同样可以简化为:

new Graph({ connecting: { connector: 'rounded', }, })

全局默认连接器为'normal',即所有未单独指定连接器的边默认以直线连接。

提示:从源码结构看(src/registry/connector/jumpover.ts),跳线连接器还会读取graph.options.connecting.connector作为回退的默认连接器配置,说明connecting.connector同时承担"默认外观"与"交叉检测过滤依据"两个职责。

内置连接器详解

normal —— 简单直线连接器

系统的默认连接器,将起点、路由点、终点通过直线按顺序连接。其实现位于 src/registry/connector/normal.ts,核心逻辑是把所有点组成一个Polyline再转换为Path

const points = [sourcePoint, ...routePoints, targetPoint] const polyline = new Polyline(points) const path = new Path(polyline) return options.raw ? path : path.serialize()

支持的参数如下表:

参数名参数类型是否必选默认值参数说明
rawbooleanfalse是否返回一个Path对象,默认值为false返回序列化后的字符串。

补充说明:在源码的NormalConnectorOptions(normal.ts)中还声明了split?: boolean | number选项,用于控制路径分段行为,具体效果以实际版本为准。raw是全部内置连接器共有的基础选项(定义于 index.ts 的ConnectorBaseOptions),当需要直接拿到几何对象做二次加工(如旋转、裁剪)时非常有用。

smooth —— 平滑连接器

平滑连接器通过三次贝塞尔曲线连接起点、路由点和终点。实现位于 src/registry/connector/smooth.ts,其内部逻辑分为两条路径:

  • 存在路由点时,使用Curve.throughPoints(points)生成贯穿所有点的光滑曲线;
  • 没有路由点时,退化为一条默认的三次贝塞尔曲线,两个控制点的x坐标位于起点与终点的中点位置,形成经典的 S 形曲线。

支持的参数如下表:

参数名参数类型是否必选默认值参数说明
rawbooleanfalse是否返回一个Path对象,默认值为false返回序列化后的字符串。
directionH|V-保持水平连接或者保持垂直连接,不设置会根据起点和终点位置动态计算。

direction的动态判定逻辑(smooth.ts):当起点与终点的水平距离不小于垂直距离时自动选择'H',否则选择'V';手动指定后,控制点会分别固定在水平/垂直方向的中点上,从而得到更"顺滑直出"的 S 形曲线。

示例:

graph.addEdge({ source: rect1, target: rect2, vertices: [ { x: 100, y: 200 }, { x: 300, y: 120 }, ], connector: 'smooth', })

rounded —— 圆角连接器

圆角连接器将起点、路由点、终点通过直线按顺序连接,并在线段连接处通过圆弧连接(倒圆角)。实现位于 src/registry/connector/rounded.ts,其关键技巧是:在每个路由点处先用Math.min(radius, prevDistance)Math.min(radius, nextDistance)计算实际倒角半径(避免半径超过相邻线段长度的一半),然后通过L直线段接近拐点、再用C三次贝塞尔曲线平滑过渡:

const startMove = -Math.min(radius, prevDistance) const endMove = -Math.min(radius, nextDistance) const roundedStart = curr.clone().move(prev, startMove).round() const roundedEnd = curr.clone().move(next, endMove).round() path.appendSegment(Path.createSegment('L', roundedStart)) path.appendSegment(Path.createSegment('C', control1, control2, roundedEnd))

支持的参数如下表:

参数名参数类型是否必选默认值参数说明
radiusnumber10倒角半径。
rawbooleanfalse是否返回一个Path对象,默认值为false返回序列化后的字符串。

示例:

graph.addEdge({ source: rect1, target: rect2, vertices: [ { x: 100, y: 200 }, { x: 300, y: 120 }, ], connector: { name: 'rounded', args: { radius: 10, }, }, })

jumpover —— 跳线连接器

跳线连接器用直线连接起点、路由点和终点,并在边与边的交叉处用跳线符号链接,是绘制 ER 图、电路图等"多线交叉"场景的利器。它的实现是内置连接器中最复杂的(src/registry/connector/jumpover.ts),整体工作流程为:

  1. 注册更新钩子setupUpdating):将当前边的视图加入graph._jumpOverUpdateList更新列表,当其他边发生变化(cell:mouseupmodel:reseted)时自动触发重算,保证跳线位置始终正确。
  2. 筛选交叉对象:遍历图中所有边,跳过ignoreConnectors中指定的连接器类型(默认忽略'smooth'),并且对于排在该边之后的同类型 jumpover 边不再重复检测,避免交叉处出现"双重跳线环"。
  3. 求交与分段:使用findLineIntersections计算当前边线段与其他边线段的交点,再通过createJumps在交点两侧按size距离截断线段,生成标记为跳线的子线段。
  4. 路径组装buildPath):普通线段直接L连接;跳线线段则按type生成不同符号——arc用两段三次贝塞尔曲线近似半圆弧(默认),gap直接抬起画笔制造缺口,cubic用单条三次贝塞尔曲线生成抛物线状跳线。

支持的参数如下表:

参数名参数类型是否必选默认值参数说明
type'arc' | 'gap' | 'cubic''arc'跳线类型。
sizenumber5跳线大小。
radiusnumber0倒角半径。
rawbooleanfalse是否返回一个Path对象,默认值为false返回序列化后的字符串。

其中radius参数会作用于非跳线段落的拐角,复用与 rounded 相同的buildRoundedSegment倒角算法;当radius0时则退化为纯直线。此外,源码中的JumpoverConnectorOptions还暴露了ignoreConnectors?: string[]选项,可自定义"不做跳线处理"的连接器名称列表,默认值为['smooth']

实战建议:跳线效果依赖"整张图中所有边"的交叉检测,因此只有当边数量较多、交叉频繁时才建议使用;同时要注意它会为每个交叉边视图建立监听关系,在超大规模图中需评估性能开销。

自定义连接器

函数签名

连接器本质上是一个普通函数,签名为:

export type Definition<T> = ( this: EdgeView, // 边的视图 sourcePoint: Point.PointLike, // 起点 targetPoint: Point.PointLike, // 终点 routePoints: Point.PointLike[], // 路由返回的点 args: T, // 参数 edgeView: EdgeView, // 边的视图 ) => Path | string

参数说明:

参数名参数类型参数说明
thisEdgeView边的视图。
sourcePointPoint.PointLike起点。
targetPointPoint.PointLike终点。
routePointsPoint.PointLike[]路由返回的点。
argsT连接器参数。
edgeViewEdgeView边的视图。

注意函数体可以通过this拿到EdgeView实例(如 jumpover 正是借助this.graph访问整张图的边集合),而edgeView参数与this指向同一对象,可互为补充。

编写一个 wobble 连接器

下面定义一个在路径上叠加随机抖动的wobble连接器:

export interface WobbleArgs { spread?: number raw?: boolean } function wobble( sourcePoint: Point.PointLike, targetPoint: Point.PointLike, vertices: Point.PointLike[], args: WobbleArgs, ) { const spread = args.spread || 20 const points = [...vertices, targetPoint].map((p) => Point.create(p)) let prev = Point.create(sourcePoint) const path = new Path(Path.createSegment('M', prev)) for (let i = 0, n = points.length; i < n; i += 1) { const next = points[i] const distance = prev.distance(next) let d = spread while (d < distance) { const current = prev.clone().move(next, -d) current.translate( Math.floor(7 * Math.random()) - 3, Math.floor(7 * Math.random()) - 3, ) path.appendSegment(Path.createSegment('L', current)) d += spread } path.appendSegment(Path.createSegment('L', next)) prev = next } return args.raw ? path : path.serialize() }

其思路是:从起点出发,沿"当前点 → 目标点"方向以spread为步长逐步推进,每步在水平、垂直方向各施加 ±3 像素的随机偏移,从而生成一条"手绘抖动"风格的折线;支持raw参数决定返回Path对象还是序列化字符串,与内置连接器保持一致的约定。

注册并使用自定义连接器

Graph.registerConnector('wobble', wobble)

registerConnectorGraph的静态方法,直接代理到连接器注册表connectorRegistry.register(见 src/graph/graph.ts),并配有对应的Graph.unregisterConnector(src/graph/graph.ts)用于反注册。注册表由 src/registry/connector/index.ts 中的Registry.create创建,内置的 5 个连接器(normal、smooth、rounded、jumpover、loop)在模块加载时以connectorRegistry.register(connectorPresets, true)的方式预注册。

注册后即可通过连接器名称使用:

edge.setConnector('wobble', { spread: 16 })

也可以在addEdgeconnector配置或connecting.connector全局默认中直接引用'wobble'。当传入未注册的名称时,注册表会抛出拼写建议错误(见 src/registry/registry.ts 的onNotFound逻辑),帮助快速定位笔误。

深入:连接器与几何库的协作

所有内置连接器都构建在 X6 几何库(src/geometry)之上,理解这些基础类型有助于编写更强大的自定义连接器:

  • Path:路径容器,通过Path.createSegment('M' | 'L' | 'C' | 'Q', ...)追加各类路径段,最终serialize()输出 SVGd字符串;
  • Point:二维点,提供clone()move()rotate()translate()distance()等常用几何运算;
  • Polyline/Curve/Line:分别被 normal(直线段)、smooth(贯穿曲线)、jumpover(线段求交)使用,其中 jumpover 通过Line.intersectsWithLine完成交叉检测;
  • Path.parse:可将 SVG 路径字符串反向解析为Path对象,loop 连接器(src/registry/connector/loop.ts)即用模板字符串构造二次贝塞尔路径后调用Path.parse返回Path实例。

从 src/registry/connector/main.ts 可以看到,仓库还内置了一个文档未单独展开的loop连接器,用于自环边(起点与终点相同)的绘制,说明连接器注册表本身是开放可扩展的——你可以基于同样的机制注册任意自定义实现。

小结

连接器是 X6 边渲染体系的"最后一公里":通过connector边配置、edge.setConnector()connecting.connector全局默认三种方式即可无缝切换内置的 normal / smooth / rounded / jumpover 四种外观;当内置方案无法满足需求时,按照(sourcePoint, targetPoint, routePoints, args) => Path | string的函数签名编写实现,再经Graph.registerConnector注册即可,整个过程与内置连接器共享同一套几何库与注册机制。相关参考实现与测试可继续阅读 src/registry/connector 目录及tests/registry/connector 下的测试用例。

【免费下载链接】X6🚀 JavaScript diagramming library that uses SVG and HTML for rendering.项目地址: https://gitcode.com/GitHub_Trending/x6/X6

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 20:03:23

版权登记去哪儿办?这篇讲透

版权保护&#xff0c;到底在保护什么 很多企业主第一次接触版权&#xff0c;往往是从一张设计图、一段宣传片或一套软件代码开始的。版权保护的核心&#xff0c;是让原创成果在产生纠纷时能拿出确凿的权利证明。我国唯一的软件著作权登记、著作权质权登记机构&#xff0c;就是中…

作者头像 李华
网站建设 2026/9/17 20:03:01

Abaqus焊接仿真:热-力耦合建模与dflux子程序实战

简介&#xff1a;本资源是一份面向结构仿真工程师与焊接工艺研究人员的Abaqus热力耦合建模实战指南&#xff0c;聚焦于使用Dflux子程序实现双椭球热源焊接温度场模拟的核心技术路径。内容以平板焊接为典型算例&#xff0c;系统拆解建模、材料定义、装配、分析步设置、边界条件施…

作者头像 李华
网站建设 2026/9/17 20:01:25

Security-101 第一课:深入理解 CIA 三元组与网络安全核心概念

Security-101 第一课&#xff1a;深入理解 CIA 三元组与网络安全核心概念 【免费下载链接】Security-101 8 Lessons, Kick-start Your Cybersecurity Learning. 项目地址: https://gitcode.com/GitHub_Trending/se/Security-101 本文基于 Security-101 课程的第 1.1 课&a…

作者头像 李华
网站建设 2026/9/17 20:00:09

如何构建MathModelAgent桌面版?Electron打包macOS与Windows完整指南

如何构建MathModelAgent桌面版&#xff1f;Electron打包macOS与Windows完整指南 【免费下载链接】MathModelAgent &#x1f916;&#x1f4d0;专为数学建模设计的 Agent & skills ,自动完成数学建模&#xff0c;生成一份完整的可以直接提交的论文。 An Agent Designed for …

作者头像 李华
网站建设 2026/9/17 19:59:26

linux-tutorial 之 Kibana 实战:从 Discover 查询语法到可视化与仪表盘

linux-tutorial 之 Kibana 实战&#xff1a;从 Discover 查询语法到可视化与仪表盘 【免费下载链接】linux-tutorial :penguin: Linux教程&#xff0c;主要内容&#xff1a;Linux 命令、Linux 系统运维、软件运维、精选常用Shell脚本 项目地址: https://gitcode.com/GitHub_T…

作者头像 李华
网站建设 2026/9/17 19:58:57

Linux内核分析实战:从环境搭建到性能调优全指南

简介&#xff1a;《Linux操作系统内核分析与研究》是一份面向系统开发、嵌入式开发及计算机专业学生的内核学习资料&#xff0c;帮助读者理解内核如何管理硬件资源、调度进程并提供安全服务。PDF文档以清晰结构覆盖内存管理、进程管理、文件系统、设备驱动、网络支持和安全机制…

作者头像 李华