JavaScript is required

布局旋转角度控制

这个示例展示如何在运行时旋转已挂载的 relation-graph 布局,并在同一数据集上切换内置中心布局与树布局。悬浮工具窗提供角度控制、布局切换、画布行为设置和图片导出,使其成为小型布局调优工作区。

通过实时角度偏移旋转内置布局

本示例构建了什么

本示例构建了一个全视口的 relation graph 工作区,用于研究同一份固定数据集在运行时改变布局角度时会如何重新排布。主视图展示了一个带标签的小型图谱,其中包含圆形节点、沿路径挂载的边标签,以及悬浮在画布上方的控制窗口。

用户可以用滑块或步进按钮旋转当前布局,在内置 centertree 布局之间切换同一张图,打开一个辅助设置面板,并将当前图谱导出为图片。最关键的一点是,这个示例不会为了每次比较而重新加载新的业务数据。它会在内存中保留同一张图,并在已挂载的实例上修改 layout.rotatelayout.layoutName

数据如何组织

图数据在 initializeGraph() 内以内联方式声明为一个 RGJsonData 对象,其中包含 rootId: '2'、15 个已声明节点和 15 条已声明连线。在调用 setJsonData() 之前没有预处理步骤:示例对象会直接构建并加载。

这使得该数据结构很容易替换为真实应用数据,例如所有权图、汇报树、依赖结构,或任何需要以不同布局朝向查看同一组实体的层级结构。有一个细节值得注意:其中一条边从节点 1 指向节点 5,尽管节点列表中并没有声明节点 1,因此这个示例更适合作为布局控制参考,而不是数据校验参考。

relation-graph 的使用方式

index.tsx 使用 RGProvider 包裹页面,MyGraph.tsx 则通过 RGHooks.useGraphInstance() 来控制已挂载的图实例。图谱通过 setJsonData() 初始化一次,随后使用 moveToCenter()zoomToFit() 进行居中和适配。

运行时布局变更通过 updateOptions({ layout }) 再接 doLayout() 来完成。React 状态中保存了两个参数:layoutNamelayoutRotate。当角度变化时,示例会重写 layout.rotate 并重新布局图谱。当布局类型变化时,它会在 centertree 之间切换,将角度状态重置为 0,然后再次触发布局。

图选项被有意保持得很精简:调试模式关闭,线标签渲染在线路径上,默认节点几何形状为圆形 80 x 80。本示例没有使用图谱插槽、图编辑 API,也没有自定义节点渲染。本地 SCSS 文件只保留了空的选择器占位,因此大多数可见行为来自 RelationGraph 选项和共享的悬浮辅助组件,而不是本地样式覆盖。

这个悬浮窗口不是 relation-graph 插槽。它是一个独立的覆盖层组件,通过 RGProvider 共享图上下文。它的设置面板使用 RGHooks.useGraphStore() 读取当前的滚轮和拖拽模式,调用 setOptions() 在运行时修改这些画布行为,并在导出时使用 prepareForImageGeneration()restoreAfterImageGeneration()

关键交互

  • 角度滑块以 0360 的范围、5 度步长写入 layoutRotate,并通过一个 useEffect 触发重新布局。
  • Rotate 5deg CWRotate 5deg CCW 按钮会直接递增或递减同一状态,因此无需拖动滑块也能进行微调旋转。这些按钮更新在代码中没有做边界限制。
  • 分段布局选择器会在 centertree 之间切换同一份数据集,然后对已挂载的图重新布局,而不是重建数据集。
  • 悬浮窗口可以拖动、最小化,并切换到设置覆盖层。
  • 设置覆盖层可以修改 wheelEventActiondragEventAction,同时也为当前画布提供 Download Image 操作。

关键代码片段

下面这段代码表明,该示例保留了一份内联数据集,并只将其加载到实时图实例中一次。

const myJsonData: RGJsonData = {
    rootId: '2',
    nodes: [
        { id: '2', text: 'Root' }, { id: '9', text: 'Node-9' },
        { id: '4', text: 'Node-4' },
        // ...
        { id: '5', text: 'Node-5' }
    ],
    lines: [
        { id: 'l1', from: '2', to: '9', text: 'Executive' },
        // ...
    ]
};
await graphInstance.setJsonData(myJsonData);

下面这段代码是运行时的核心模式:从 React 状态写入布局选项,然后执行 doLayout()

const reLayout = async () => {
    graphInstance.updateOptions({
        layout: {
            layoutName: layoutName,
            rotate: layoutRotate
        }
    });
    await graphInstance.doLayout();
};

下面这段代码展示了 UI 如何通过悬浮窗口驱动角度更新和布局类型切换。

<SimpleUISlider
    max={360}
    min={0}
    step={5}
    currentValue={layoutRotate}
    onChange={(newValue: number) => { setLayoutRotate(newValue); }}
/>
<SimpleUISelect
    data={[{ value: 'center', text: 'Center' }, { value: 'tree', text: 'Tree' }]}
    currentValue={layoutName}
    onChange={(newValue: string) => { setLayoutName(newValue); }}
/>

下面这段代码展示了共享设置覆盖层如何修改画布行为,并使用图实例进行图片导出。

<SettingRow
    label="Wheel Event:"
    options={[
        { label: 'Scroll', value: 'scroll' },
        { label: 'Zoom', value: 'zoom' },
        { label: 'None', value: 'none' },
    ]}
    value={wheelMode}
    onChange={(newValue: string) => { graphInstance.setOptions({ wheelEventAction: newValue }); }}
/>

这个示例的独特之处

根据对比数据,这个示例最适合作为实时 relation graph 中 layout.rotate 的紧凑参考。它的独特组合包括固定数据集、0360 的角度滑块、+/-5 步进按钮、centertree 选择器,以及在一个小型工作区中显式调用 updateOptions({ layout })doLayout()

center-layout-options 相比,它强调的是朝向变化和跨布局对比,而不是单一布局类型中的间距系数。与 switch-layout 相比,它更深入地展示了手动参数调节,而不是在预设布局之间做定时播放。与 drag-and-wheel-event 相比,这里的悬浮设置界面只是次要工具;核心要点是同一张图的轮廓会如何随着布局旋转而变化。

视觉处理也被刻意保持得很克制。对比记录强调,圆形 80 x 80 节点和沿路径挂载的标签充当了中性的重排探针,因此观看者注意到的是布局移动,而不是自定义渲染。

这种模式还能应用在哪里

这种模式可以复用于内部工具场景,在这些场景中,用户需要先比较同一张图的几种可读朝向,再决定默认视图。示例包括组织结构图、所有权结构、依赖树,以及某些在一个角度下拥挤、在另一个角度下更易读的知识图谱分支。

它也很适合迁移到其他 relation-graph 选项的参数调节面板中。真正可复用的关键并不是这份示例数据本身,而是利用 React 状态、updateOptions() 和显式 doLayout() 调用,把已挂载的图谱变成一个可控的布局测试界面。