完全指南:内置连接器使用、自定义注册与 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返回的中间点与终点加工为 SVGpath元素的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再转换为Pathconst points [sourcePoint, ...routePoints, targetPoint] const polyline new Polyline(points) const path new Path(polyline) return options.raw ? path : path.serialize()支持的参数如下表参数名参数类型是否必选默认值参数说明rawboolean否false是否返回一个Path对象默认值为false返回序列化后的字符串。补充说明在源码的NormalConnectorOptionsnormal.ts中还声明了split?: boolean | number选项用于控制路径分段行为具体效果以实际版本为准。raw是全部内置连接器共有的基础选项定义于 index.ts 的ConnectorBaseOptions当需要直接拿到几何对象做二次加工如旋转、裁剪时非常有用。smooth —— 平滑连接器平滑连接器通过三次贝塞尔曲线连接起点、路由点和终点。实现位于 src/registry/connector/smooth.ts其内部逻辑分为两条路径存在路由点时使用Curve.throughPoints(points)生成贯穿所有点的光滑曲线没有路由点时退化为一条默认的三次贝塞尔曲线两个控制点的x坐标位于起点与终点的中点位置形成经典的 S 形曲线。支持的参数如下表参数名参数类型是否必选默认值参数说明rawboolean否false是否返回一个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))支持的参数如下表参数名参数类型是否必选默认值参数说明radiusnumber否10倒角半径。rawboolean否false是否返回一个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整体工作流程为注册更新钩子setupUpdating将当前边的视图加入graph._jumpOverUpdateList更新列表当其他边发生变化cell:mouseup、model:reseted时自动触发重算保证跳线位置始终正确。筛选交叉对象遍历图中所有边跳过ignoreConnectors中指定的连接器类型默认忽略smooth并且对于排在该边之后的同类型 jumpover 边不再重复检测避免交叉处出现双重跳线环。求交与分段使用findLineIntersections计算当前边线段与其他边线段的交点再通过createJumps在交点两侧按size距离截断线段生成标记为跳线的子线段。路径组装buildPath普通线段直接L连接跳线线段则按type生成不同符号——arc用两段三次贝塞尔曲线近似半圆弧默认gap直接抬起画笔制造缺口cubic用单条三次贝塞尔曲线生成抛物线状跳线。支持的参数如下表参数名参数类型是否必选默认值参数说明typearc | gap | cubic否arc跳线类型。sizenumber否5跳线大小。radiusnumber否0倒角半径。rawboolean否false是否返回一个Path对象默认值为false返回序列化后的字符串。其中radius参数会作用于非跳线段落的拐角复用与 rounded 相同的buildRoundedSegment倒角算法当radius为0时则退化为纯直线。此外源码中的JumpoverConnectorOptions还暴露了ignoreConnectors?: string[]选项可自定义不做跳线处理的连接器名称列表默认值为[smooth]。实战建议跳线效果依赖整张图中所有边的交叉检测因此只有当边数量较多、交叉频繁时才建议使用同时要注意它会为每个交叉边视图建立监听关系在超大规模图中需评估性能开销。自定义连接器函数签名连接器本质上是一个普通函数签名为export type DefinitionT ( 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)registerConnector是Graph的静态方法直接代理到连接器注册表connectorRegistry.register见 src/graph/graph.ts并配有对应的Graph.unregisterConnectorsrc/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 })也可以在addEdge的connector配置或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),仅供参考