JavaScript is required

节点内容目标点连线

这个示例构建了一个由四个矩形面板组成的小型固定位置关系视图。每个面板都不是使用默认图节点来渲染,而是使用自定义表格标记进行渲染;可见连接线也不是落在节点外边框上,而是落在这些表格内部的特定表头或单元格上。

将曲线连接到表格节点内部的精确目标

这个示例构建了什么

这个示例构建了一个由四个矩形面板组成的小型固定位置关系视图。每个面板都不是使用默认图节点来渲染,而是使用自定义表格标记进行渲染;可见连接线也不是落在节点外边框上,而是落在这些表格内部的特定表头或单元格上。

用户看到的是一个全高度画布,其中包含灰色表格卡片、深色标题栏、亮粉色锚点标签,以及在卡片之间交叉穿过的蓝色或粉色曲线。用户可以点击节点或连线,在控制台中查看已绑定的图对象,但这个演示的核心是视觉效果:它展示了如何在节点内容内部暴露精确的连接目标。

数据是如何组织的

图数据直接在 initializeGraph() 中内联构建。它定义了 rootId: 'a'、四个带有明确 xy 坐标的矩形节点、一个空的 lines 数组,以及十条 fakeLines。每条 fake line 都使用诸如 a-r2-c2b-r1-c1 这样的 fromto id,而这些 id 会与节点插槽内容中渲染出来的 RGConnectTarget 组件进行匹配。

在调用 setJsonData() 之前没有单独的预处理步骤,但这里有一个明确的命名约定:fake line 的端点与插槽中渲染的目标 id 必须保持同步。在真实应用中,这种模式可以表示数据表列、表单字段、审批检查点、数据血缘字段、账户映射,或任何需要让连接线落在精确内部行或表头上的结构化面板。

relation-graph 是如何使用的

RGProvider 包裹了这个示例,这样 MyGraph 就可以通过 RGHooks.useGraphInstance() 读取当前活动的图实例。该图运行在 fixed 布局模式下,因此 relation-graph 不会计算节点位置;四个节点已经在内联的 RGJsonData 中自带坐标。配置项保持得很精简:关闭了 debug,并将 defaultJunctionPoint 设为 RGJunctionPoint.lr

主要的集成点是 RGSlotOnNode。示例没有接受默认的节点主体,而是根据 node.id 分支渲染四个不同的表格面板。在这些面板内部,被选中的表头和单元格会包裹在 RGConnectTarget 中,从而注册具名 HTML 目标,供 fakeLines 附着。这就是核心技巧:图仍然负责管理连线路由和视口行为,但实际端点被嵌入在自定义节点 DOM 内部。

图实例 API 负责启动流程。组件挂载时,initializeGraph() 会构建内联数据,调用 setJsonData(...),然后通过 moveToCenter()zoomToFit() 将视图重新居中并适配显示。这里没有编辑器工具、拖拽手柄、覆盖层插槽或运行时数据变更。样式也很轻量且局部:.c-data-table 添加了白色表格背景、深色边框和圆角粉色标签,让可连接片段在视觉上足够明显。

关键交互

  • 点击节点会触发 onNodeClick,并记录被选中的 RGNode 对象以供检查。
  • 点击曲线会触发 onLineClick,并记录被选中的 RGLine 对象,但不会改变图状态。
  • 主要的交互模式是视觉检查:用户沿着连线追踪某个具体表头或单元格标签连接到了另一个面板中的哪个目标。

关键代码片段

这一段展示了该图被有意配置为一个固定位置查看器,并使用左右连接点作为默认值。

const graphOptions: RGOptions = {
    debug: false,
    defaultJunctionPoint: RGJunctionPoint.lr,
    layout: {
        layoutName: 'fixed'
    }
};

这一段展示了内联数据集:包含四个带定位的节点、没有常规 lines,而是使用 fake lines。

const myJsonData: RGJsonData = {
    rootId: 'a',
    nodes: [
        { id: 'a', text: 'A区内配矿', nodeShape: RGNodeShape.rect, x: -500, y: -200 },
        { id: 'b', text: 'B区内洗选贸易企业', nodeShape: RGNodeShape.rect, x: 0, y: -400 },
        { id: 'c', text: 'C区内电场焦化企业', nodeShape: RGNodeShape.rect, x: 500, y: -200 },
        { id: 'd', text: 'D区外企业', nodeShape: RGNodeShape.rect, x: 0, y: 0 }
    ],
    lines: [],
    fakeLines: [

这一段展示了端点映射模式:fake lines 引用的 id,正是后续在节点内容内部注册的那些 id。

fakeLines: [
    { id: 'fl-1', from: 'a-r2-c2', to: 'b-r1-c1', text: '', lineShape: RGLineShape.StandardCurve, color: 'rgba(29,169,245,0.76)', lineWidth: 3 },
    { id: 'fl-2', from: 'a-r2-c2', to: 'b-r2-c1', text: '', lineShape: RGLineShape.StandardCurve, color: 'rgba(29,169,245,0.76)', lineWidth: 3 },
    { id: 'fl-3', from: 'a-r3-c2', to: 'b-r3-c1', text: '', lineShape: RGLineShape.StandardCurve, color: '#e85f84', lineWidth: 3 },
    { id: 'fl-4', from: 'a-r3-c2', to: 'd-r2-c1', text: '', lineShape: RGLineShape.StandardCurve, color: '#e85f84', lineWidth: 3 },
    { id: 'fl-5', from: 'a-r3-c2', to: 'c-r4-c1', text: '', lineShape: RGLineShape.Curve5, color: '#e85f84', lineWidth: 3 },
    // ...
]

这一段展示了通过图实例 API 在挂载时完成初始化的流程。

await graphInstance.setJsonData(myJsonData);
graphInstance.moveToCenter();
graphInstance.zoomToFit();

useEffect(() => {
    initializeGraph();
}, []);

这一段展示了 relation-graph 如何接收点击处理器以及自定义节点插槽。

<RelationGraph
    options={graphOptions}
    onNodeClick={onNodeClick}
    onLineClick={onLineClick}
>
    <RGSlotOnNode>
        {({ node }: RGNodeSlotProps) => (

这一段展示了一个真实的节点内容锚点:可见标签被包裹在 RGConnectTarget 中,因此 fake line 可以终止在这个精确的表格单元格上。

<td>
    <RGConnectTarget targetId="a-r2-c2">
        <div>a-r2-c2</div>
    </RGConnectTarget>
</td>

这一段展示了本地样式如何让这些目标标签看起来像明确的连接点。

.c-data-table {
    width: 100%;
    background-color: #ffffff;
    td, th {
        border: 1px solid #4a5568;
        color: #000000;
        padding: 5px;
    }
    td div, th div {
        background-color: #e85f84;
        padding: 2px 10px;
        border-radius: 5px;
        color: #fff;
    }
}

这个示例的独特之处

对比数据将这个示例识别为一个关于节点内部锚点连线的紧凑型技巧参考。它的独特之处不仅在于自定义了节点内容,还在于它把具名的 RGConnectTarget 端点分布到了表头和表体单元格中,然后在一个小型固定布局查看器里用曲线 fakeLines 将这些端点连接起来。

table-relationship 相比,这个示例更轻量,也更通用。它只保留了四个手工编写的面板模板,避免了额外的工具窗口,并且混合了不同的目标位置,而不是重复单一种类的 schema 卡片模式。与 advanced-line-usage 相比,这里的重点不是默认节点上的线元数据或箭头变体,而是如何把曲线附着到插槽渲染节点主体内部的精确 DOM 位置上。与 node-menu-2node-tips 相比,这里的插槽 DOM 是结构性的,而不是偏覆盖层用途的:它存在的目的是让连线落在内部目标上,而不是让菜单或提示出现在指针附近。

fixed 布局、按节点定制的表格 JSX、混合的表头与单元格目标,以及按颜色区分的曲线 fake lines 共同组成了这个示例的特色。因此,当真实问题是在复杂节点内容内部进行精确端点定位时,它比附近的其他示例更适合作为起点。

这个模式还能应用到哪里

这种模式适用于数据表浏览器、字段映射工具、策略覆盖矩阵、流程交接面板、物料清单表以及数据血缘视图等场景,因为这些场景中的连接线通常需要落在结构化卡片内部的某一条具体行、列或标签上。当你希望把现有的 HTML 面板设计迁移到 relation-graph 中,同时又不想把所有关系都压平成“每个节点只有一个连接点”时,它也同样有用。

这种方法也可以扩展到表格之外。任何能够渲染稳定内部片段并为其提供可预测 id 的自定义节点主体,都可以将这些片段暴露为 RGConnectTarget,并让 relation-graph 把可见曲线布线到它们上面。