JavaScript is required

选中线条效果预设

这个示例构建了一个从左到右的小型树形查看器,核心要点是对选中连线进行强调。图会加载一棵固定的图标树,立即将其中一条边标记为选中,并允许用户在一个浮动控制窗口中,在四种样式预设和四种动画预设之间切换这条已选中的边。

选中连线样式与动画预设

此示例构建的内容

这个示例构建了一个从左到右的小型树形查看器,核心要点是对选中连线进行强调。图会加载一棵固定的图标树,立即将其中一条边标记为选中,并允许用户在一个浮动控制窗口中,在四种样式预设和四种动画预设之间切换这条已选中的边。

可见效果被有意控制在一个明确范围内。默认连线保持原本外观,而当前处于选中状态的连线则会根据所选预设,获得更宽的光晕、虚线模式、文字颜色覆盖或动画效果。围绕这一核心行为,示例还包含绿色渐变画布、半透明的内置工具栏,以及一个用于画布设置和导出图片的共享辅助窗口。

数据是如何组织的

图数据在 initializeGraph() 内联组装为一个 RGJsonData 对象,其中包含 rootId、扁平的 nodes 数组和扁平的 lines 数组。每个节点在 node.data.icon 中保存一个图标键,每条连线只需要 idfromtotext

在调用 setJsonData() 之前没有任何预处理步骤。数据集会直接传给 relation-graph,随后图实例会将视图居中、让内容适配视口,并在加载完成后将 line-1 标记为选中。在真实应用中,这种结构同样可以表示服务依赖、审批流转、路由分段,或任何其他需要让某条活动连接比其他连接获得更强反馈的关系集合。

relation-graph 的使用方式

index.tsx 使用 RGProvider 包裹整个示例,而 MyGraph.tsx 则把 RGHooks.useGraphInstance() 作为主要控制入口。图被配置为从左到右的树布局,具有较大的间距、曲线连线、左右连接点,以及 defaultLineTextOnPath: true,因此在不替换原生渲染器的前提下,选中连线的效果仍然便于比较。

这个示例没有使用自定义连线插槽。相反,它保留了 relation-graph 的内置连线图层,并通过 SCSS 针对选中状态进行处理。本地 React 状态只会切换外层包装类 my-line-style-*my-line-animation-*;随后样式表会把覆盖规则限定到 .rg-line-peel.rg-line-checked。这就是核心实现思路:选中连线的表现由容器类和内置的选中态选择器共同驱动,而不是通过逐条重写 SVG 连线来实现。

节点渲染通过 RGSlotOnNode 自定义。该插槽会把 node.data.icon 映射到 Lucide 组件,并将每个节点渲染为一个大型圆形图标徽标,这样既能让这棵小树保持清晰可读,又能让连线状态继续作为主要展示重点。

浮动辅助窗口来自共享的 DraggableWindow 组件。这个辅助窗口使用 RGHooks.useGraphStore() 读取当前滚轮和拖拽设置,使用 graphInstance.setOptions() 在运行时修改这些设置,并通过 prepareForImageGeneration()restoreAfterImageGeneration() 将图导出为图片。设置和导出操作属于辅助能力,但它们也是这个示例交付交互界面的一部分。

关键交互

  • 挂载时,图会加载其静态数据集,将镜头居中,让内容适配视口,并预先选中 line-1,使样式预设一开始就有明确的可见目标。
  • “Line style when checked” 选择器会在四种选中连线样式包装类之间切换,而不会重建图数据。
  • “Line animation when checked” 选择器会在四种动画包装类之间切换,并且只影响当前处于选中状态的连线。
  • 浮动辅助窗口可以被拖动、最小化,并切换到设置面板。
  • 设置面板会在运行时修改滚轮和拖拽行为,并可将当前图视图导出为图片。

关键代码片段

下面这个 options 配置块表明,该示例保持使用 relation-graph 原生的树布局和连线渲染器,同时调整布局和默认的选中项视觉 token。

const graphOptions: RGOptions = {
    defaultLineColor: 'rgba(255, 255, 255, 0.6)',
    defaultNodeColor: 'transparent',
    defaultNodeBorderWidth: 0,
    checkedItemBackgroundColor: 'rgba(255,255,255,0.3)',
    defaultNodeShape: RGNodeShape.circle,
    toolBarDirection: 'h',
    toolBarPositionH: 'right',
    toolBarPositionV: 'bottom',
    defaultLineShape: RGLineShape.StandardCurve,
    defaultJunctionPoint: RGJunctionPoint.lr,
    defaultLineTextOnPath: true,
    layout: {
        layoutName: 'tree',
        from: 'left',
        treeNodeGapH: 310,
        treeNodeGapV: 70
    }
};

下面这段初始化代码证明,这个示例不会以交互方式切换被选中的目标。它加载的是固定数据集,并在图准备好之后通过程序将 line-1 标记为选中。

await graphInstance.setJsonData(myJsonData);
graphInstance.moveToCenter();
graphInstance.zoomToFit();
graphInstance.setCheckedLine('line-1');

下面这个渲染片段说明,运行时切换是通过包装类和本地状态完成的,而不是通过调用 getLines()updateLine()

<div className={`my-graph my-line-style-${lineStyle} my-line-animation-${lineAnimation}`} style={{ height: '100vh' }}>
    <DraggableWindow width={450}>
        <SimpleUISelect
            data={[
                { value: '', text: 'Default' },
                { value: '1', text: 'Style 1' },
                { value: '2', text: 'Style 2' }
            ]}
            onChange={(newValue: string) => setLineStyle(newValue)}
            currentValue={lineStyle}
        />
    </DraggableWindow>

下面这个节点插槽让图结构保持简单,同时使用从 node.data.icon 选出的图标替换默认节点主体。

<RGSlotOnNode>
    {({ node }: RGNodeSlotProps) => {
        const iconName = node.data?.icon || 'default';
        const IconComponent = IconMapper[iconName] || CircleDot;
        return (
            <div className="my-icon-node h-20 w-20 text-white rounded flex place-items-center justify-center hover:bg-white hover:bg-opacity-40">
                <IconComponent color="#ffffff" size={60} strokeWidth={1.5} />
            </div>
        );
    }}
</RGSlotOnNode>

下面这个 SCSS 片段是最关键的证据,说明这些预设只作用于已选中连线的图层。

.my-line-style-1 {
    .relation-graph {
        .rg-line-peel.rg-line-checked {
            .rg-line-bg {
                stroke: rgba(244, 60, 229, 0.68);
                stroke-width: calc(var(--rg-line-width) + 6px);
                stroke-dasharray: 20, 20, 20;
            }

            .rg-line {
                stroke-dasharray: 20, 20, 20;
            }
        }
    }
}

下面这段共享设置代码展示了辅助窗口如何通过图实例 API 修改查看器行为并支持导出。

const { options } = RGHooks.useGraphStore();
const dragMode = options.dragEventAction;
const wheelMode = options.wheelEventAction;

<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 }); }}
/>

这个示例的独特之处

从对比数据来看,这个示例与 line-style1custom-line-stylecustom-line-animationcustomer-line1 相近,但它的关注点比这些相邻示例更收敛。它最突出的特点是先通过 setCheckedLine('line-1') 预先选中一条边,然后只对这条已选中的边叠加样式和动画预设。图中的其他部分仍然保持默认渲染。

这使它与 line-style1 有明显差异,后者是在数据集本身中并排展示内置连线变体。它也不同于 custom-line-stylecustom-line-animation,后两者会批量更新所有已渲染连线,或进一步扩展到整张图的效果展示。相比 customer-line1,这个示例保留了 relation-graph 的内置边几何,而不是切换到自定义连线插槽。

稀有度和对比记录同样表明,这种组合并不常见:一个小型的从左到右图标树、一个渐变展示画布、一个选中节点背景覆盖,以及两组分别只对当前已选中连线进行重设样式和动画的选择器。

这种模式还适用于哪些场景

  • 依赖关系或拓扑查看器,其中当前正在检查的一条连接需要突出显示,而不必重新设定所有边的主题。
  • 工作流或审批图,需要对当前活动流转提供更强的视觉反馈,同时让流程图其余部分保持中性。
  • 调查、监控或路由工具,操作人员一次只跟踪一条高亮路径,并需要可替换的强调预设来用于演示或产品调优。
  • 设计系统参考页面,用来向团队展示仅凭原生 relation-graph 渲染加 CSS,选中态反馈可以做到什么程度。