JavaScript is required

拖拽节点对齐参考线

这个示例展示如何挂载 relation-graph 的对齐参考线覆盖层,使拖拽节点时显示临时参考线。它还结合可选吸附开关、选中态协同、运行时画布设置和图片导出,形成紧凑编辑式工作区。

拖拽节点时的对齐参考线与可选吸附

这个示例构建了什么

这个示例构建了一个紧凑的图编辑工作区,在节点被拖拽时显示临时对齐参考线。界面将全高点状画布、浮动说明窗口、小型内联图,以及一个可在运行时开启或关闭对齐辅助吸附行为的复选框组合在一起。

用户可以拖拽节点,点击节点和连线来切换当前编辑目标,点击空白画布清除编辑状态;并且当画布拖拽模式被设置为选择时,还可以用选择框替换当前的编辑节点集合。这个演示的重点并不是通用图编排,而是一个聚焦的参考示例,用最少但足够的周边选择逻辑来支撑拖拽过程中的定位辅助叠加层。

数据是如何组织的

图数据在 initializeGraph() 内以内联方式声明为一个 RGJsonData 对象。它使用单个 rootId、一个包含 idtext 的扁平 nodes 数组,以及一个包含 idfromtolines 数组。大多数连线继承默认图选项,而其中有一条连线会在数据集中直接覆盖自身的形状和连接点。

在 relation-graph 接收这份数据之前,没有任何预处理流程。组件会创建这份数据集,调用 setJsonData(...),然后立即执行 zoomToFit()。这样就能让示例的重点放在运行时交互上,而不是数据转换上。

在生产系统中,同样的数据结构可以表示工作流步骤、拓扑元素、依赖项,或图中那些在渲染完成后仍需要被用户精确重新定位的图块。

relation-graph 的使用方式

这个示例没有引入自定义布局算法。它依赖 relation-graph 对一个小型根节点数据集的常规渲染行为,然后在加载完成后让初始视口自适应显示。

图选项被刻意收窄,以支撑这个演示的视觉基线:defaultLineShapeRGLineShape.StandardCurvedefaultJunctionPointRGJunctionPoint.ltrbdefaultLineColor#00a63e。这样一来,示例的注意力就集中在拖拽行为上,而不是布局配置上。

RGProvider 包裹整个页面,使 RGHooks.useGraphInstance() 可以控制数据加载、视口适配、编辑节点状态、编辑连线状态、checked 状态,以及选择查询。浮动设置面板还会使用 RGHooks.useGraphStore(),这样它就可以读取当前的滚轮模式和拖拽模式,并通过 setOptions(...) 更新它们。

关键的图专属 UI 通过 RGSlotOnView 挂载。这个示例没有用自定义渲染器替换节点或连线,而是在视图层中加入 RGEditingReferenceLine,并传入 adsorption={adsorption},使对齐引导能够响应当前复选框状态。在这个叠加层周围,RelationGraph 绑定了四个处理器:节点点击、连线点击、画布选择结束,以及画布点击。

外围辅助 UI 很小,但很关键。SimpleUIBoolean 暴露了与吸附相关的开关,共享的 DraggableWindow 则可以打开一个设置面板,用于控制 wheelEventActiondragEventAction 和图像导出。本地 SCSS 最后通过 relation-graph 的画布变量绘制出可随缩放变化的点状画布背景,并让被 checked 的连线标签在连线颜色上实现反相显示。

关键交互

  • 拖拽节点时,可以通过 RGEditingReferenceLine 显示对齐参考线,而复选框允许用户在运行时启用或禁用这个叠加层的吸附行为。
  • 点击节点且不带修饰键时,会用该节点替换当前编辑节点集合。带着 ShiftCtrlMeta 且不带 Alt 点击时,则会在当前编辑集合中切换这个被点击节点的状态。
  • 点击连线会将该连线设为当前编辑连线,尽管这个示例并没有额外加入独立的自定义连线编辑控制器。
  • 当画布处于选择模式时,onCanvasSelectionEnd 会把拖出的选择区域转换为节点对象,并用这些结果替换当前编辑节点集合。
  • 点击空白画布会清空编辑节点、清空当前编辑连线,并移除 checked 状态高亮。
  • 浮动窗口可以被拖动、最小化、切换到设置面板,并用于将当前图导出为图像。

关键代码片段

这个片段展示了为整张图建立默认曲线样式、连接点行为和连线颜色的精简选项集。

const graphOptions: RGOptions = {
    defaultLineShape: RGLineShape.StandardCurve,
    defaultJunctionPoint: RGJunctionPoint.ltrb,
    defaultLineColor: '#00a63e'
};

这个片段展示了图数据是在本地以内联方式创建,并在挂载时直接加载的。

const myJsonData: RGJsonData = {
    rootId: 'a',
    nodes: [
        { id: 'a', text: 'Border color' },
        { id: 'a1', text: 'No border' },
        { id: 'a2', text: 'Plain' },
        { id: 'a1-1', text: 'Text Node' }
    ]
};

这个片段展示了在挂载时如何把数据交给 relation-graph,并立即执行视口适配。

// setJsonData is async
await graphInstance.setJsonData(myJsonData);
graphInstance.zoomToFit();

这个片段展示了普通点击和带修饰键点击是如何共同接入同一个编辑节点模型的。

const onNodeClick = (nodeObject: RGNode, $event: RGUserEvent) => {
    if ($event.shiftKey || $event.ctrlKey || ($event.metaKey && !$event.altKey)) {
        graphInstance.toggleEditingNode(nodeObject);
    } else {
        graphInstance.setEditingNodes([nodeObject]);
    }
    graphInstance.setEditingLine(null);
};

这个片段展示了框选完成时如何委托给 relation-graph 处理,而不是手写命中测试。

const onCanvasSelectionEnd = (selectionView: RGSelectionView) => {
    const willSelectedNodes = graphInstance.getNodesInSelectionView(selectionView) || [];
    // 3.x recommends directly setting editing node set, not recommended to manually modify node.selected
    graphInstance.setEditingNodes(willSelectedNodes);
};

这个片段展示了使拖拽过程中的对齐引导可见、且可在运行时配置的那一层精确视图叠加组件。

<DraggableWindow>
    When dragging a node, it will look for a position close to the dragged node and display alignment reference lines.
    <br />
    You can set whether to enable adsorption effect.
    <SimpleUIBoolean currentValue={adsorption} onChange={setAdsorption} label="Enable Adsorption Effect" />
</DraggableWindow>

这个片段展示了对齐参考线组件在图视图层中的挂载位置。

<RGSlotOnView>
    {/* Node alignment reference line when dragging */}
    <RGEditingReferenceLine adsorption={adsorption} />
</RGSlotOnView>

这个片段展示了共享浮动面板同时暴露了运行时画布模式切换和图像导出。

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

这个片段展示了 SCSS 如何把图区域变成一个始终与 relation-graph 画布变换对齐的点状编辑表面。

background-position: var(--rg-canvas-offset-x) var(--rg-canvas-offset-y);
background-size: calc(var(--rg-canvas-scale) * 15px) calc(var(--rg-canvas-scale) * 15px);
background-image: radial-gradient(
    circle,
    rgb(197, 197, 197) calc(var(--rg-canvas-scale) * 1px),
    transparent 0
);

这个示例的独特之处

对比数据把这个示例放在 gee-node-resizebatch-operations-on-nodescanvas-selectionchange-line-pathline-vertex-on-node 附近,这些示例都会复用同一类点状画布和浮动窗口编辑器脚手架。这个示例的区别在于它所聚焦的教学点是节点拖拽期间的视图层对齐引导,并且还带有一个运行时吸附开关,而不是尺寸调整手柄、批量变更命令、选择状态可视化、连线路径编辑或连接创建。

它的另一个独特优势在于,多种编辑状态输入都围绕这一层叠加组件被协调起来。节点点击、基于修饰键的多选、连线点击、框选完成和空白画布清除,全都汇入同一个共享编辑模型,而对齐工作流就运行在这个模型之中。因此,当目标是在现有编辑器中加入定位辅助,而不是同时引入更大范围的变更面时,它会比那些更宽泛的邻近示例更适合作为起点。

对比数据也为这一说法划出了一条有用的边界。这并不是一个完整的编排演示,选择框也不是主要特性。这里真正持久可复用的模式,是拖拽过程中的定位辅助,以及围绕它展开的轻量级选择管理。

这种模式还适用于哪里

这种模式非常适合工作流构建器、拓扑编辑器、流程设计器以及各种制图工具。在这些场景里,用户经常会拖动已有节点,并需要在不切换到单独布局步骤的情况下获得对齐帮助。相同的叠加层加开关模式,也可以帮助团队在不重建整个编辑器的前提下,为现有图工作区补充可选吸附能力。

它同样适用于把自动布局与最终人工微调结合起来的整理工具。在图根据后端数据生成后,操作人员仍然可以做精细的视觉修正,同时保持图模型不变,并继续复用同一套选择处理 API 来承载相关编辑功能。