ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

X6 连线(Connector)完全指南:从内置连线器到自定义贝塞尔与跳线实现

X6 连线(Connector)完全指南:从内置连线器到自定义贝塞尔与跳线实现 X6 连线Connector完全指南从内置连线器到自定义贝塞尔与跳线实现【免费下载链接】X6 JavaScript diagramming library that uses SVG and HTML for rendering.项目地址: https://gitcode.com/GitHub_Trending/x6/X6连线Connector是 X6 图编辑引擎中决定「边Edge如何绘制」的核心概念路由Router负责规划折线路径点而 Connector 负责把路径点与边的起终点串成最终的 SVG Path 曲线。本文以 site/examples/edge/connector 下的官方示例为骨架完整讲解 X6 内置的五种连线器normal、rounded、smooth、jumpover、loop的配置方式与参数并深入源码剖析其实现原理随后带领你通过Graph.registerConnector注册自定义连线器实现二次贝塞尔方向曲线、随机摇摆线和多条平行光滑曲线三类高阶玩法。读完本文你将能够为任意场景流程图、ER 图、电路图、可视化大屏选择或编写合适的连线器。前置准备搭建一个最小 X6 示例页所有示例都基于同一个最小图实例先建立一个包含两个矩形节点与一条边的画布import { Graph } from antv/x6 const graph new Graph({ container: document.getElementById(container), grid: true, }) const source graph.addNode({ x: 120, y: 40, width: 100, height: 40, attrs: { body: { fill: #f5f5f5, stroke: #d9d9d9, }, }, }) const target graph.addNode({ x: 400, y: 260, width: 100, height: 40, attrs: { body: { fill: #f5f5f5, stroke: #d9d9d9, }, }, }) graph.addEdge({ source, target, vertices: [ { x: 200, y: 200 }, { x: 380, y: 120 }, ], connector: { name: normal }, attrs: { line: { stroke: #722ed1, }, }, })要点说明vertices是中间经过点X6 的 Router默认使用normal路由会先依据这些点计算整条路径的完整点序列再交给 Connector 生成 Pathconnector统一为{ name: string, args?: object }结构name指定注册表registry中的连线器名称args传入该连线器的专属参数边的外观通过attrs.line控制示例统一使用紫色#722ed1以便观察曲线形状。上述完整示例见 site/examples/edge/connector/demo/normal.ts其余各内置连线器的可运行示例均位于 site/examples/edge/connector/demo 目录并在 demo/meta.json 中登记了标题与截图。内置连线器全解X6 在 src/registry/connector/main.ts 中统一导出了内置连线器normal、rounded、smooth、jumpover、loop。下面逐一讲解配置方式与实现原理。normal默认直线折线normal是未显式指定时的默认连线器把「起点 → 路由点序列 → 终点」依次连接成折线。connector: { name: normal }从源码 src/registry/connector/normal.ts 可以看到其实现非常轻量export interface NormalConnectorOptions extends ConnectorBaseOptions { split?: boolean | number } export const normal: ConnectorDefinition ( sourcePoint, targetPoint, routePoints, options {}, ) { const points [sourcePoint, ...routePoints, targetPoint] const polyline new Polyline(points) const path new Path(polyline) return options.raw ? path : path.serialize() }实现要点把起点、路由点、终点合并为点数组交给Polyline构建多段线再包装成Path输出接受split参数boolean | number默认false。从源码结构看split用于控制最终输出的d属性是否被切分为多条子路径——例如配合边框动画或虚线流动效果时按线段拆分后逐段设置样式会更容易传数字则按指定点数拆分options.raw为true时返回Path对象而非序列化字符串便于调用方继续做二次处理。rounded圆角折线当折线拐角过于尖锐时使用rounded可以让每个拐点变为圆角视觉上更柔和connector: { name: rounded, args: { radius: 20, }, }radius圆角半径单位 px数值越大拐角越圆润示例 site/examples/edge/connector/demo/rounded.ts 中设为20。底层实现等价于对每个拐角点用半径radius的圆弧替换折线尖角再以直线段衔接圆弧。适合流程图、状态图等需要「规整但不生硬」的连线风格。smooth三次贝塞尔平滑曲线smooth把所有路径点拟合成一条平滑的三次贝塞尔曲线Catmull-Rom 样条彻底消除折线感connector: { name: smooth, }完整示例见 site/examples/edge/connector/demo/smooth.ts。其应用场景包括组织架构图、知识图谱中节点间的关系连线、需要「流动感」的业务链路展示。jumpover跳线桥接线在电路图、流程图等场景中多条连线交叉时会产生歧义。jumpover会在交叉处把上层的连线「拱起」形成跳线从而表达「跨越而非连接」的语义connector: { name: jumpover, args: { type: gap, }, }参考示例 site/examples/edge/connector/demo/jumpover.ts该示例同时演示了两种用法创建边时指定偶数序号的边使用jumpover并配置type: gap描边色#faad14奇数序号的边保持默认连线形成「跳线与普通线共存」的对比动态切换连线器先以默认方式添加一条紫色边随后调用edge.setConnector(jumpover)在运行时把该边切换为跳线模式。setConnector是 X6 边的实例方法接收与connector配置相同的{ name, args }结构适合交互式编辑场景如用户切换连线风格。type参数用于控制跳线拱起的缺口样式除gap缺口式跳线外还支持arc圆弧式等其他形态可根据交叉密集程度选择。loop自环连线当边的起点与终点是同一个节点时需要绘制自环。loop连线器源码位于 src/registry/connector/loop.ts根据节点尺寸与args参数生成环绕节点的环形路径常用参数包括控制环的大小与方向是 UML 状态图、自引用关系建模的标配。自定义连线器三步注册随心所欲内置连线器无法覆盖所有业务形态时可以通过Graph.registerConnector(name, handler, overwrite?)注册自定义连线器。handler 的签名如下type Connector ( sourcePoint: Point.PointLike, targetPoint: Point.PointLike, routePoints: Point.PointLike[], args: Recordstring, any, ) string | Path四个入参的含义sourcePoint起点坐标已经过锚点 anchor 与连接点 connectionPoint 计算详见下文「交互组合」targetPoint终点坐标routePoints路由计算后的中间点序列args边配置connector.args透传进来的自定义参数。返回值为 SVG Path 字符串或返回Path对象此时注册的第三个参数overwrite不影响返回值类型Path对象会被自动序列化。注册后即可在任意边中通过connector: { name: myConnector, args: {...} }使用。二次贝塞尔方向曲线结合节点朝向site/examples/edge/connector/demo/curve.ts 展示了「从节点伸出方向感曲线」的完整思路——边会沿着节点的旋转角度angle方向出发用二次贝塞尔曲线连接到目标节点。这在机器人/自动驾驶ROS拓扑、有向架构图等需要表达「朝向」的场景非常实用。核心注册代码import { Graph, Path } from antv/x6 const degreesToRadians (degrees) degrees * (Math.PI / 180) const transCanvasAngleToRos (angle) angle - 90 // 依据点及其方向角向前偏移 distance 得到辅助点 const calcPoint (p) { const distance 10 const theta degreesToRadians(transCanvasAngleToRos(p.angle)) const x p.x distance * Math.cos(theta) const y p.y distance * Math.sin(theta) return { x, y } } // 计算两条方向辅助线的交点作为贝塞尔控制点 const calcIntersectionPoint (points) { const [p1, p2] points const p11 calcPoint(p1) const p22 calcPoint(p2) const d1 (p1.x - p11.x) * (p2.y - p22.y) const d2 (p1.y - p11.y) * (p2.x - p22.x) const d d1 - d2 if (d 0) { return { x: p1.x, y: p1.y } } const u1 p1.x * p11.y - p1.y * p11.x const u4 p2.x * p22.y - p2.y * p22.x const u2x p2.x - p22.x const u3x p1.x - p11.x const u2y p2.y - p22.y const u3y p1.y - p11.y const px (u1 * u2x - u3x * u4) / d const py (u1 * u2y - u3y * u4) / d return { x: px, y: py } } Graph.registerConnector( curve, (sourcePoint, targetPoint) { const path new Path() path.appendSegment(Path.createSegment(M, sourcePoint)) // 基于方向获取控制点 const controlPoint calcIntersectionPoint([ { ...sourcePoint, angle: graph.getNodesFromPoint(sourcePoint)[0].getAngle(), }, { ...targetPoint, angle: graph.getNodesFromPoint(targetPoint)[0].getAngle(), }, ]) // 基于控制点生成二次贝塞尔曲线 path.appendSegment(path.quadTo(controlPoint, targetPoint)) return path.serialize() }, true, )实现拆解calcPoint把「点坐标 方向角」换算为沿方向延伸distance示例取 10px的辅助点其中transCanvasAngleToRos把 Canvas 坐标系角度转换为 ROS 风格角度减去 90°使得 0° 指向正上方calcIntersectionPoint求解起终点两条方向辅助线的交点交点在两线平行时退化为起点注册函数内通过graph.getNodesFromPoint(sourcePoint)[0].getAngle()拿到该点所属节点的当前旋转角作为曲线出发点方向最后用Path.createSegment(M, ...)建起点、path.quadTo(controlPoint, targetPoint)追加二次贝塞尔段并返回序列化字符串。配套的图配置需要开启节点旋转能力并固定锚点/连接点保证方向计算稳定const graph new Graph({ container: document.getElementById(container), grid: true, connecting: { anchor: nodeCenter, connectionPoint: anchor, }, }) graph.use( new Transform({ rotating: { enabled: true, }, }), )connecting.anchor: nodeCenter锚点固定在节点中心connecting.connectionPoint: anchor连接点与锚点重合避免连接点计算干扰出线方向Transform插件开启rotating后节点可通过交互旋转旋转角即时参与曲线方向计算。随机摇摆线为每段路径加入随机抖动site/examples/edge/connector/demo/wobble.ts 演示了「手绘风格 / 涂鸦感」连线沿着路径以固定间距采样并对每个采样点施加随机偏移import { Graph, Path, Point } from antv/x6 Graph.registerConnector( wobble, (sourcePoint, targetPoint, vertices, args) { const spread args.spread || 20 const points [...vertices, targetPoint].map((p) Point.create(p)) let prev Point.create(sourcePoint) const path new Path() path.appendSegment(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 path }, true, )关键点args.spread为采样间距示例边配置中传入spread: 10间距越小抖动越密集每个采样点沿路径方向偏移-d再叠加[-3, 3]范围的随机平移形成自然的手绘感通过Point的几何方法clone、move、distance、translate完成计算Path.createSegment(L, ...)追加折线段。使用方式与内置连线器完全一致graph.addEdge({ source, target, vertices: [ { x: 200, y: 200 }, { x: 380, y: 120 }, ], connector: { name: wobble, args: { spread: 10, }, }, attrs: { line: { stroke: #722ed1, }, }, })这类抖动连线适合脑暴白板、批注演示、儿童教育类产品等需要「非正式感」的界面。多条平行光滑曲线利用索引参数做偏移当两个节点之间存在大量同向连线如桑基图、批量关系展示时直接叠加多条曲线会完全重合。site/examples/edge/connector/demo/multiple-smooth-edges.ts 通过自定义multi-smooth连线器根据边的序号在垂直方向偏移控制点生成一组平行且互不遮挡的光滑曲线import { Graph, Line, Path, Curve } from antv/x6 Graph.registerConnector( multi-smooth, ( sourcePoint, targetPoint, routePoints, options: { raw?: boolean; index?: number; total?: number; gap?: number }, ) { const { index 0, total 1, gap 12 } options const line new Line(sourcePoint, targetPoint) const centerIndex (total - 1) / 2 const dist index - centerIndex const diff Math.abs(dist) const factor diff 0 ? 1 : diff / dist const vertice line .pointAtLength(line.length() / 2 gap * factor * Math.ceil(diff)) .rotate(90, line.getCenter()) const points [sourcePoint, vertice, targetPoint] const curves Curve.throughPoints(points) const path new Path(curves) return options.raw ? path : path.serialize() }, true, )实现思路通过connector.args向注册函数传入该边的index第几条与total总条数让同一个连线器能感知自身在整组边中的位置取起终点连线的中点向垂直方向偏移gap * factor * ceil(diff)形成随序号递增的错位gap默认 12控制平行间距Curve.throughPoints(points)构造经过三个点起点、偏移控制点、终点的光滑曲线包装为Path返回若options.raw为true返回Path对象否则返回序列化字符串。批量添加边时只需循环传入序号const total 15 for (let i 0; i total; i 1) { graph.addEdge({ source, target, connector: { name: multi-smooth, args: { total, index: i, }, }, attrs: { line: { stroke: #722ed1, strokeWidth: 1, targetMarker: null, }, }, }) }这里设置strokeWidth: 1让细线更精致targetMarker: null去掉箭头适合纯关系展示。组合机制Router、Anchor、ConnectionPoint 与 Connector 的分工要正确使用连线器需要理解它与相邻机制的分工它们分别由 src/registry/router、src/registry/node-anchor、src/registry/connection-point、src/registry/connector 四个注册表提供Anchor锚点确定边在源/目标节点「内部」的挂载位置如nodeCenter节点中心、orth正交边中点由connecting.anchor配置ConnectionPoint连接点在锚点基础上做最终偏移确定实际出线/入线的坐标如anchor表示与锚点重合、boundary表示落在节点边界由connecting.connectionPoint配置Router路由结合障碍物与vertices计算避开节点后的完整点序列如manhattan曼哈顿路由、orth正交路由不关心最终曲线的形状Connector连线器拿到以上步骤产出的起点、终点与点序列负责「画」出最终 Path。因此相同的vertices与connector配置配合不同 Router 会得到完全不同的路径形态而同一 Router 点序列交给normal与smooth也会呈现折线与曲线的差异。官方测试在 src/registry/connector 下针对normal、rounded、smooth、jumpover、loop均有对应的 spec 用例如tests/registry/connector/normal.spec.ts、tests/registry/connector/jumpover.spec.ts可用作理解各连线器输入输出契约的参考。动态切换与运行时修改除了建边时指定X6 边实例还提供运行时 APIedge.setConnector(jumpover)切换连线器名称edge.setConnector({ name: rounded, args: { radius: 30 } })带参数切换修改后路径实时重绘。这在交互式编辑工具栏切换连线风格、动画演示连线形态变化等场景非常实用jumpover.ts 示例末尾正是通过edge.setConnector(jumpover)动态演示了这一能力。小结与选型建议连线器形态典型参数适用场景normal直线折线split通用默认需逐段样式/动画时开启拆分rounded圆角折线radius流程图、状态图等规整连线smooth三次贝塞尔曲线无组织架构、图谱关系、流动感展示jumpover交叉跳线typegap/arc等电路图、密集连线避免交叉歧义loop自环环大小/方向UML 状态图、自引用关系自定义任意 Path自定义args方向曲线、手绘抖动、平行曲线等实际选型时建议需求只是「连起来」直接用默认normal需要更精致但仍是结构化连线rounded 合适的radius表达柔和关系或图谱smooth连线密集且有交叉语义jumpover并注意合理配置type业务形态特殊方向感、手绘风、平行曲线基于Graph.registerConnector自定义注册函数内可自由使用 src/geometry 提供的Path、Point、Line、Curve等几何工具。所有示例代码均可直接运行于任意 X6 项目核心 API 与内置连线器的完整定义可在 src/registry/connector 目录中进一步查阅。【免费下载链接】X6 JavaScript diagramming library that uses SVG and HTML for rendering.项目地址: https://gitcode.com/GitHub_Trending/x6/X6创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表