节点数据模型(JsonNode / RGNode)
节点是 relation-graph 中最基础的数据单元。它既承担“业务实体”的角色,也承担布局、渲染、交互命中的基础载体。
实际开发中会遇到两种节点对象:
JsonNode:你传入图谱的数据对象,常见于nodes、children、addNode、addNodes、setJsonData。RGNode:图谱运行时生成的节点对象,常见于getNodeById、getNodes、事件回调、插槽参数、编辑器组件。
JsonNode 是输入格式,RGNode 是运行时格式。不要把运行时对象完整保存为业务数据;导出或持久化时应使用 getGraphJsonData() 或 transRGNodeToJsonObject()。
1. 最小可用节点
最小节点只需要 id:
const node = {
id: 'user-1'
};
实际项目中通常会同时设置 text:
const node = {
id: 'user-1',
text: '张三'
};
字段规则:
id必须唯一且稳定。图谱内部通过它建立节点索引、连线端点、展开折叠关系和更新定位。text是节点显示文本。relation-graph 使用text,不是label。- 当前源码对历史数据有兼容:如果新增节点时没有
text但存在label,会把label当作text使用并输出警告;如果text也没有,则可能使用id作为文本。新代码不建议依赖这种兼容行为。
2. JsonNode 字段说明
标识与业务字段
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
id |
string |
必填 | 节点唯一标识。连线的 from/to、更新 API、查询 API 都依赖它。 |
text |
string |
'' 或兼容使用 label/id |
节点文本。默认节点模板会显示它;自定义节点插槽也通常从这里读取标题。 |
type |
string |
'' |
业务类型。可用于插槽模板分发,也会影响节点类型类名,例如按类型写 CSS。 |
data |
Record<string, any> |
{} |
业务扩展数据。推荐把业务属性放在这里,不要塞进 relation-graph 的结构字段。 |
targetType |
string |
RGInnerConnectTargetType.Node |
节点作为连接目标时的类型标识。普通节点通常不用设置;FakeLine 或连接编辑器扩展时才需要关注。 |
显示、展开与交互字段
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
expanded |
boolean |
true |
控制树形关系中该节点是否展开。折叠后,后代节点会在可见性计算中被隐藏。 |
hidden |
boolean |
false |
主动隐藏节点。隐藏节点不会正常渲染,并会影响关联线的可见性计算。 |
selected |
boolean |
false |
节点的“选中/多选”状态,常用于编辑器批量操作。和 checkedNodeId 这种单个 checked 状态不是同一概念。 |
disablePointEvent |
boolean |
未设置时跟随 options.disableNodePointEvent |
禁用该节点的鼠标/触摸事件命中。适合装饰性节点或希望点击穿透的场景。 |
disableDrag |
boolean |
false |
禁止拖拽该节点。实际是否可拖还会受到全局 options.disableDragNode 影响。 |
expandHolderPosition |
`‘hide’ | ‘left’ | ‘top’ |
alwaysRender |
boolean |
未设置 | 性能模式下的渲染提示。源码在可见项计算中会特殊处理它,使节点更倾向于保留渲染。普通业务节点通常不需要设置。 |
expanded 和 hidden 的区别:
hidden是节点自身隐藏。expanded: false是树关系中的折叠,会使其后代不可见。- 如果你直接批量修改节点的
hidden/expanded,必要时调用updateNodesVisibleProperty()让运行时可见性重新计算。
节点形状与外观字段
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
nodeShape |
RGNodeShape |
options.defaultNodeShape,默认 RGNodeShape.rect |
节点几何形状。影响默认节点外观、连线与节点的交点计算、缩略图/EasyView 绘制。 |
color |
string |
options.defaultNodeColor,默认 #ffffff |
节点背景色。建议使用 CSS 颜色值。 |
borderColor |
string |
options.defaultNodeBorderColor,默认 #666666 |
节点边框颜色。 |
borderWidth |
number |
options.defaultNodeBorderWidth,默认 1 |
节点边框宽度,单位按像素理解。 |
borderRadius |
number |
options.defaultNodeBorderRadius,默认 4 |
节点圆角,主要影响矩形节点。 |
fontColor |
string |
CSS 默认变量 | 默认节点文本颜色。使用完全自定义节点插槽时,是否生效取决于你的插槽是否使用这些变量/字段。 |
fontSize |
number |
CSS 默认变量 | 默认节点文本字号。 |
opacity |
number |
1 |
节点透明度。建议取值 0 到 1。 |
className |
string |
'' |
附加到节点 DOM 的类名。适合做主题级样式覆盖。 |
zIndex |
number |
0 |
节点层级。用于控制节点之间的覆盖顺序。 |
RGNodeShape 可选值:
| 枚举 | 数值 | 说明 |
|---|---|---|
RGNodeShape.circle |
0 |
圆形节点。连线交点按圆/椭圆边界计算,缩略图中按圆形绘制。 |
RGNodeShape.rect |
1 |
矩形节点。默认值。连线交点按矩形边界或指定方向计算。 |
尺寸与坐标字段
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
x |
number |
0 |
节点左上角在画布坐标系中的 X 坐标。自动布局会改写它。 |
y |
number |
0 |
节点左上角在画布坐标系中的 Y 坐标。自动布局会改写它。 |
width |
number |
options.defaultNodeWidth 或由 DOM 测量 |
节点逻辑宽度。设置后也会影响 el_W 初始值。 |
height |
number |
options.defaultNodeHeight 或由 DOM 测量 |
节点逻辑高度。设置后也会影响 el_H 初始值。 |
el_W |
number |
运行时测量 | 节点实际渲染宽度。输入时可作为初始测量值,但通常由图谱根据 DOM 更新。 |
el_H |
number |
运行时测量 | 节点实际渲染高度。输入时可作为初始测量值,但通常由图谱根据 DOM 更新。 |
fixed |
boolean |
false |
固定节点坐标。布局附加处理其他分组时会跳过固定节点;力导向布局中也常用于控制节点不被自动移动。 |
force_weight |
number |
未设置 | 力导向布局中的节点权重/质量类参数。值越高通常意味着节点在力学计算中更“重”,具体效果取决于当前布局实现。 |
坐标与尺寸要点:
x/y是画布坐标,不是页面坐标。width/height更适合表达“你希望节点多大”。el_W/el_H是运行时测量值,很多布局和连线计算依赖它。- 如果使用复杂自定义节点插槽且不设置
width/height,布局通常需要等首轮渲染测量完成后再执行。
树结构输入字段
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
children |
JsonNode[] |
无 | 树形数据快捷写法。导入时会被展开成扁平节点与连线。 |
children 只适合输入阶段:
const data = {
rootId: 'root',
nodes: [
{
id: 'root',
text: '根节点',
children: [
{ id: 'child-1', text: '子节点 1' },
{ id: 'child-2', text: '子节点 2' }
]
}
],
lines: []
};
await graphInstance.setJsonData(data);
导入后,运行时会使用扁平的 nodes、lines 和内部 lot 结构管理父子关系。不要在运行时直接修改 node.children 来期望图谱自动增删节点。
3. RGNode 运行时字段
RGNode 继承大部分 JsonNode 字段,并补充运行时计算信息。
| 字段 | 类型 | 说明 |
|---|---|---|
type |
string |
运行时一定存在,未设置时为空字符串。 |
x / y |
number |
运行时一定存在,未设置时为 0。 |
nodeShape |
RGNodeShape |
运行时一定存在,由节点自身或 defaultNodeShape 解析得到。 |
data |
Record<string, any> |
运行时一定存在,未设置时为 {}。 |
lot |
object |
布局与树关系内部结构,包含父子节点、层级、排序、强度等信息。不要作为业务数据持久化。 |
rgChildrenSize |
number |
当前节点的子节点数量/可展开规模相关运行时统计。 |
rgShouldRender |
boolean |
性能模式或视口裁剪后的“是否应该渲染”判断。 |
rgCalcedVisibility |
boolean |
综合 hidden、父级折叠、运行时计算后的可见性。 |
典型读取:
const node = graphInstance.getNodeById('user-1');
if (node?.rgCalcedVisibility) {
console.log(node.x, node.y, node.el_W, node.el_H);
}
不建议直接依赖的字段:
lot:内部布局关系字段,结构可能随版本调整。rgShouldRender:性能渲染策略结果,不等同于业务可见。el_W/el_H:可读取用于布局/辅助线,但持久化时通常不需要保存。
4. 节点创建、查询、更新、删除
创建节点
graphInstance.addNode({
id: 'n1',
text: '节点 1'
});
graphInstance.addNodes([
{ id: 'n2', text: '节点 2' },
{ id: 'n3', text: '节点 3', x: 200, y: 80 }
]);
addNodes 会跳过已经存在的节点 id,不会用同 id 新对象覆盖旧节点。要修改旧节点,请使用 updateNode。
查询节点
const node = graphInstance.getNodeById('n1');
const nodes = graphInstance.getNodes();
const checkedNode = graphInstance.getCheckedNode();
const selectedNodes = graphInstance.getSelectedNodes();
更新节点
graphInstance.updateNode('n1', {
text: '节点 1(已更新)',
color: '#dbeafe',
borderColor: '#2563eb'
});
graphInstance.updateNodePosition('n1', 320, 160);
graphInstance.updateNodeData('n1', {
owner: 'team-a',
status: 'running'
});
更新规则:
updateNode(id, partial)是浅合并字段。- 更新
data时,如果只想合并业务字段,优先使用updateNodeData。 - 修改位置时优先使用
updateNodePosition,力导向布局运行中它会同步布局器内部缓存。
删除节点
graphInstance.removeNodeById('n1');
graphInstance.removeNodesByIds(['n2', 'n3']);
const node = graphInstance.getNodeById('n4');
if (node) {
graphInstance.removeNode(node);
}
删除节点会由数据提供者处理相关运行时数据。实际业务中建议在删除前自行确认关联线是否也符合你的业务预期。
5. 推荐数据写法
const nodes = [
{
id: 'service-api',
text: 'API 服务',
type: 'service',
nodeShape: RGNodeShape.rect,
color: '#eff6ff',
borderColor: '#2563eb',
borderWidth: 1,
borderRadius: 8,
width: 160,
height: 56,
data: {
owner: '平台组',
level: '核心系统'
}
},
{
id: 'cache',
text: 'Redis',
type: 'middleware',
fixed: true,
x: 360,
y: 120,
data: {
cluster: 'cache-prod'
}
}
];
推荐原则:
- 用
id/text/type/data表达业务实体。 - 用
color/borderColor/borderWidth/borderRadius/nodeShape表达核心视觉语义。 - 用
className做主题扩展,不要把所有视觉语义只写在 CSS 里。 - 用
width/height稳定布局,尤其是自定义节点插槽。 - 用
fixed区分手动坐标节点与自动布局节点。
6. 常见问题
为什么我的节点位置被改掉了?
调用 setJsonData()、doLayout() 或 appendJsonData(..., true) 时,布局器会重新计算节点位置。需要完全手动摆放时,使用 layoutName: 'fixed',或者避免在更新后自动重排。
为什么节点隐藏了,连线也不见了?
普通连线的可见性会参考起点/终点节点的 rgCalcedVisibility。如果任一端不可见,相关 RGLink 通常也不会渲染。
为什么自定义节点插槽样式和缩略图不一致?
缩略图/EasyView 依赖节点数据字段,例如 nodeShape、color、borderColor、borderWidth。如果只在插槽内部 CSS 写背景和边框,缩略图无法知道这些语义。
selected 和 checked 有什么区别?
selected是节点自身字段,适合多选和批量编辑。- checked 状态由
options.checkedNodeId/checkedItem管理,通常表示当前焦点节点。