HTML元素连线
这个示例在 `RGSlotOnCanvas` 中渲染兴趣小组卡片列表和地图标记,并在选中配对之间重绘一条动画假连线。它是“用 relation-graph 连接普通 HTML 元素”而非“连接图节点”的聚焦参考。
使用 Fake Line 连接 HTML 卡片与地图标记
这个示例构建了什么
这个示例在 relation-graph 画布内部构建了一个双面板界面。左侧显示兴趣小组列表,右侧在背景图片上显示固定的地图标记。选择任意一侧时,都会在匹配的卡片与标记之间重绘一条带动画的连接线。
重点并不在节点渲染。可见的端点都是放置在 RGSlotOnCanvas 中的普通 HTML 元素,然后被注册为可连接目标,这样 relation-graph 就可以在它们之间绘制连线。一个悬浮辅助窗口提供了画布设置和图片导出功能,但这个示例的核心在于 DOM 到 DOM 的连接模式。
数据是如何组织的
这个示例使用了一个小型的内存 InterestGroup[] 数组。每条记录包含:
groupIdgroupNamelocation: { x, y }
loadDataFromRemote() 会填充六条记录,然后在渲染期间,同一个数组会被投影两次:
- 一次投影为左侧的
group-*目标 - 一次投影为右侧的
location-*目标
这种投影方式让一对一连接模式保持简单。在真实应用中,这份数据可以替换为门店位置、楼层平面图上的部门、拓扑图上的设备,或者两个面板之间的匹配记录。
relation-graph 是如何使用的
- 图使用固定布局,因为真正有意义的位置来自画布插槽中绝对定位的 HTML,而不是自动节点布局。
RelationGraph提供画布宿主,RGProvider启用了基于 hook 的工具能力,例如悬浮设置面板。RGSlotOnCanvas承载了整个列表加地图场景,因此 relation-graph 在这里扮演的是自定义 UI 组合之下的连接层。- 每张卡片和每个标记都包裹在
RGConnectTarget中,这样每个 HTML 元素都会获得一个稳定的targetId。 RGHooks.useGraphInstance()用于启动时的视口处理、fake line 替换、运行时选项变更以及导出前准备。RGHooks.useGraphStore()用于共享设置面板,以便 UI 能反映当前的拖拽和滚轮模式。- 关键的实例 API 包括
moveToCenter()、zoomToFit()、setEditingLine(null)、clearFakeLines()和addFakeLines(...)。 - 共享辅助窗口还会使用
prepareForImageGeneration()、getOptions()和restoreAfterImageGeneration()来导出当前图视图。 - 样式大多在 relation-graph 之外通过 SCSS 类处理,包括紫色列表卡片、选中光环、脉冲标记以及带动画的曲线连接线。
关键交互
- 挂载后,示例会加载六个小组,将视口居中、适配画布,并自动选中小组
a。 - 点击某个小组卡片会高亮该卡片,并将连接线重绘到与之匹配的地图标记。
- 点击地图标记会从对侧面板触发同样的选择流程。
- 悬浮说明窗口可以被拖动、最小化和展开。
- 设置浮层可以将滚轮行为切换为
scroll、zoom或none。 - 同一个浮层也可以将拖拽行为切换为
selection、move或none。 Download Image操作会把当前图画布导出为图片。
关键代码片段
这个片段展示了图被配置为一个固定布局宿主,用来承载画布插槽中的内容。
const graphOptions: RGOptions = {
debug: false,
defaultJunctionPoint: RGJunctionPoint.border,
wheelEventAction: 'zoom',
dragEventAction: 'move',
layout: {
layoutName: 'fixed'
}
};
这个片段是核心选择逻辑:一个当前激活的小组 id 会被转换为一条 fake line,连接两个 HTML 目标 id。
const myFakeLines: JsonLine[] = [{
id: `fl-${groupId}`,
from: 'group-' + groupId,
to: 'location-' + groupId,
color: 'rgba(159,23,227,0.65)',
lineWidth: 3,
lineShape: RGLineShape.StandardCurve,
fromJunctionPoint: RGJunctionPoint.lr,
toJunctionPoint: RGJunctionPoint.border,
animation: 2
}];
这个片段展示了如何先清除上一条连接线,再替换为新的连接线,而不是维护一个持久存在的多边图。
graphInstance.setEditingLine(null);
graphInstance.clearFakeLines();
graphInstance.addFakeLines(myFakeLines);
这个片段展示了左侧 HTML 端点如何在画布插槽内部被注册为连接目标。
<RGConnectTarget
key={group.groupId}
targetId={`group-${group.groupId}`}
junctionPoint={RGJunctionPoint.lr}
disableDrag={true}
disableDrop={true}
>
<div
className={`w-full pointer-events-auto c-i-group cursor-point ${activeGroupId === group.groupId ? 'c-i-group-checked' : ''}`}
onClick={() => onGroupClick(group.groupId)}
>
这个片段展示了滚轮和拖拽行为是在运行时通过图实例动态修改的,而不是通过重建整个示例来实现。
<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 }); }}
/>
这个示例的独特之处
与附近的其他示例相比,这个示例是一个专门用于连接普通 HTML 元素与另一个普通 HTML 元素的参考实现。它不会把目标端转换为图节点,也不会维持一个更大、可编辑的关系模型。
- 与
element-connect-to-node相比,两端都通过RGConnectTarget保持为 HTML,而不是混合使用 DOM 端点与基于节点的锚点。 - 与
element-line-edit相比,地图标记不是图节点,因此这个示例更像是一种查看器式的匹配模式,而不是节点锚点调整演示。 - 与
interest-group相比,这里的范围被有意收窄了:一个选中的小组 id、一个选中的标记,以及一条激活的连接线。 - 与
scene-network-use-canvas-slot相比,重点不在静态仪表板式的画板,而是在两个 UI 区域之间由点击驱动的焦点转移。
这种少见的组合才是关键:固定布局的画布插槽、成对的 DOM 端点、一条带动画的曲线 fake line、同步的选择状态,以及一个共享的悬浮工具面板。这让这个示例成为一个非常实用的起点,适用于 relation-graph 需要连接界面元素,而不是可视化传统节点连接数据集的场景。
这种模式还适用于哪里
- 将门店、教室、展位或房间列表链接到楼层平面图或校园地图上的标记。
- 在不把背景标记转换为图节点的情况下,同时在摘要面板和空间背景中展示一个被选中的资源。
- 构建主从式仪表板,让某一条被选中的记录高亮自定义画布场景中的匹配元素。
- 在保持可见场景完全自定义的前提下,跨不同 UI 区域连接普通 DOM 卡片、徽标或标签。