JavaScript is required

力导向布局中通过隐藏辅助线保留孤点

这个示例展示如何在 relation-graph 力导布局中保留孤立或其他不连通节点。它从首节点推导根节点,在加载前添加隐藏辅助连线,然后在全高查看器中居中并适配结果图。

在力导布局中保持孤立节点可见

这个示例构建了什么

这个示例构建了一个全高度的 relation-graph 查看器,用于展示一个稀疏网络。这个网络既包含小型连通簇,也包含原本会断开的节点。可见效果是一个由力导驱动的画布,其中有统一的圆形节点、少量深色直线连接,以及许多看起来像独立存在但仍属于已加载图的数据节点。这个示例的重点不在于领域建模或编辑,而在于一种预处理模式:在不把额外结构边绘制到屏幕上的前提下,让孤立节点在 force 布局中仍然保留。

数据如何组织

图数据直接在 initializeGraph() 内以内联方式声明为一个 RGJsonData 对象。它起始包含 20 个节点和 5 条可见连线,然后在执行 setJsonData(...) 之前,代码会进行一次预处理:从数组中的第一个节点推导出 rootId,将该值回写到数据集中,并通过生成的 l-hidden-* id 和 opacity: 0,从这个根节点向其他每个节点追加一条隐藏连线。

这意味着运行时图结构比可见图结构更连通。在真实应用中,同样的结构可以表示当前没有协作关系的人、拓扑数据不完整的设备,或即使缺少显式关系也仍应保持可见的目录实体。

relation-graph 的使用方式

index.tsx 使用 RGProvider 包裹整个示例,而 MyGraph.tsx 则通过 RGHooks.useGraphInstance() 获取已经挂载的图实例。图选项定义了该示例的全部可视行为:边界连接点、圆形节点、直线连线、默认 60 x 60 的节点尺寸、深灰色可见边,以及内置的 force 布局,并设置 force_node_repulsion: 0.5

除 provider 和主 RelationGraph 画布之外,这个示例没有使用插槽、编辑 API 或自定义子组件。它的运行时流程也刻意保持精简:仅在挂载时触发的 useEffect(...) 会调用 initializeGraph(),数据先在内存中被补充,然后图实例依次执行 setJsonData(...)moveToCenter()zoomToFit()。本地 SCSS 文件只是一些空选择器的骨架,且 MyGraph.tsx 并未导入它,因此可见表现主要来自图选项和内联的 height: '100vh' 容器。

关键交互

第一个交互是自动发生的,而不是由用户触发:组件挂载后,图会加载、自动居中,并适配到视口。之后,这个示例暴露了节点点击和连线点击处理器,但二者都只是用于检查的钩子。它们会把被点击的对象记录到控制台,不会修改图、打开面板,也不会启动编辑。

关键代码片段

下面这段选项配置表明,这个示例明确是一个使用圆形节点和深灰色直线可见连线的 force 布局查看器。

const graphOptions: RGOptions = {
    debug: false,
    defaultJunctionPoint: RGJunctionPoint.border,
    defaultNodeShape: RGNodeShape.circle,
    defaultLineShape: RGLineShape.StandardStraight,
    defaultNodeWidth: 60,
    defaultNodeHeight: 60,
    defaultLineWidth: 2,
    defaultLineColor: '#333333',
    layout: {
        layoutName: 'force',
        force_node_repulsion: 0.5
    }
};

这一步预处理是核心的变通方案:它先推导出一个根节点,再在数据集加载之前注入不可见的辅助连线。

const rootId = myJsonData.nodes[0].id;
myJsonData.rootId = rootId;

myJsonData.nodes.forEach(n => {
    if (n.id !== rootId) {
        myJsonData.lines.push({
            id: `l-hidden-${n.id}`,
            from: rootId,
            to: n.id,
            opacity: 0
        });
    }
});

下面这段代码展示了最小化的图实例初始化流程,它会把准备好的数据转换为初始视口状态。

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

这个包装组件让基于 Hook 的图实例能够在 MyGraph 中使用。

const Demo = () => {
    return (
        <RGProvider>
            <MyGraph />
        </RGProvider>
    );
};

这个示例的独特之处

根据整理好的对比数据,这个示例的独特之处在于,它把隐藏辅助边的变通方案专门应用到了 relation-graph 内置的 force 布局中。与它最接近的示例 show-single-nodesshow-single-nodes3 也使用了相同的根节点推导和不可见连线策略,但它们围绕的是 circle 布局变体,而不是 force 行为。因此,当那些看起来断开的节点仍需要在一个力导场景中保留下来时,这个示例会是更合适的起点。

对比数据也把它与更广义的碎片化图示例区分开来,例如 multi-group-2。后者更直接地渲染断开的多个分组,而这个示例则是在加载前重写数据载荷,人为构造出一条不可见的连通骨架。与 advanced-line-usage 相比,关注点也不同:这里额外添加的连线是隐藏的结构性边,而不是可见的连线样式特性。这个相对少见的组合包括:一个小型内联数据集、只记录日志的点击处理器、60 x 60 的圆形节点、深灰色直线可见边,以及一段让稀疏数据可用于 force 布局的预处理过程。

这一模式还适用于哪里

这一模式非常适合那些关系数据不完整、但又不应让记录从布局中消失的图视图。典型场景包括:必须仍然显示未分配员工的员工关系图、存在孤立设备的基础设施图、链接仅部分导入的产品或客户图,以及在关系清洗完成前就需要把所有候选实体显示在屏幕上的分析仪表板。

它也可以作为更丰富图查看器的扩展点。隐藏辅助连线可以继续作为内部加载策略保留,而可见连线、过滤、详情面板或选中态样式等能力,则可以在同一预处理步骤之上继续叠加。