Node Data Model (JsonNode / RGNode)
Nodes are the most basic data unit in relation-graph. A node is both a business entity and the base object used for layout, rendering, hit testing, and interaction.
In real projects you will usually work with two node object shapes:
JsonNode: the input data object you pass into the graph. It appears innodes,children,addNode,addNodes, andsetJsonData.RGNode: the runtime node object generated by relation-graph. It appears ingetNodeById,getNodes, event callbacks, slot props, and editor components.
JsonNode is the input format; RGNode is the runtime format. Do not persist a full runtime object as business data. For export or persistence, use getGraphJsonData() or transRGNodeToJsonObject().
1. Minimal Node
A minimal node only needs id:
const node = {
id: 'user-1'
};
In real projects you normally also set text:
const node = {
id: 'user-1',
text: 'John Smith'
};
Rules:
idmust be unique and stable. The graph uses it to build node indexes, line endpoints, expand/collapse relationships, and update targets.textis the displayed node text. relation-graph usestext, notlabel.- The current source code keeps compatibility with older data: when a new node has no
textbut haslabel,labelis used astextand a warning is printed; when neither exists,idmay be used as text. New code should not rely on this compatibility behavior.
2. JsonNode Fields
Identity And Business Fields
| Field | Type | Default | Description |
|---|---|---|---|
id |
string |
Required | Unique node id. Line from/to, update APIs, and query APIs all depend on it. |
text |
string |
'', or compatible fallback to label/id |
Node text. The default node template displays it; custom node slots also usually read it as the title. |
type |
string |
'' |
Business type. It can be used to dispatch slot templates and affects node type class names for CSS. |
data |
Record<string, any> |
{} |
Business extension data. Put business attributes here instead of mixing them into relation-graph structural fields. |
targetType |
string |
RGInnerConnectTargetType.Node |
Type marker when the node is used as a connect target. Normal nodes usually do not need this; it matters mainly for FakeLine or editor extensions. |
Visibility, Expansion, And Interaction Fields
| Field | Type | Default | Description |
|---|---|---|---|
expanded |
boolean |
true |
Whether this node is expanded in tree-like relationships. When collapsed, descendant nodes are hidden during visibility calculation. |
hidden |
boolean |
false |
Explicitly hides this node. A hidden node is not rendered normally and affects related line visibility. |
selected |
boolean |
false |
The node’s selected/multi-selected state, often used by editors for batch operations. It is not the same as the single checked state stored by checkedNodeId. |
disablePointEvent |
boolean |
Follows options.disableNodePointEvent when unset |
Disables mouse/touch hit testing for this node. Useful for decorative nodes or click-through behavior. |
disableDrag |
boolean |
false |
Disables dragging for this node. Actual draggability is also affected by global options.disableDragNode. |
expandHolderPosition |
'hide' | 'left' | 'top' | 'right' | 'bottom' | string |
Follows options.defaultExpandHolderPosition when unset |
Per-node expand/collapse button position. Use hide to hide the button for this node. |
alwaysRender |
boolean |
Unset | Rendering hint in performance mode. The source code treats it specially during visible-item calculation so the node is more likely to remain rendered. Normal business nodes usually do not need it. |
Difference between expanded and hidden:
hiddenhides the node itself.expanded: falsecollapses a tree relationship and makes descendants invisible.- If you directly batch-modify
hiddenorexpanded, callupdateNodesVisibleProperty()when needed so runtime visibility is recalculated.
Shape And Appearance Fields
| Field | Type | Default | Description |
|---|---|---|---|
nodeShape |
RGNodeShape |
options.defaultNodeShape, default RGNodeShape.rect |
Node geometry. It affects the default node appearance, line-to-node intersection calculation, and MiniView/EasyView drawing. |
color |
string |
options.defaultNodeColor, default #ffffff |
Node background color. Use a valid CSS color value. |
borderColor |
string |
options.defaultNodeBorderColor, default #666666 |
Node border color. |
borderWidth |
number |
options.defaultNodeBorderWidth, default 1 |
Node border width, interpreted as pixels. |
borderRadius |
number |
options.defaultNodeBorderRadius, default 4 |
Node corner radius, mainly for rectangular nodes. |
fontColor |
string |
CSS default variable | Default node text color. When using a fully custom node slot, this only works if your slot uses these variables/fields. |
fontSize |
number |
CSS default variable | Default node font size. |
opacity |
number |
1 |
Node opacity. Recommended range is 0 to 1. |
className |
string |
'' |
Extra class added to the node DOM. Useful for theme-level style overrides. |
zIndex |
number |
0 |
Node stacking order. Controls overlap between nodes. |
RGNodeShape values:
| Enum | Value | Description |
|---|---|---|
RGNodeShape.circle |
0 |
Circular node. Line intersections are calculated against a circle/ellipse boundary; MiniView draws it as a circle. |
RGNodeShape.rect |
1 |
Rectangular node. Default value. Line intersections are calculated against a rectangle boundary or a specified side. |
Size And Coordinate Fields
| Field | Type | Default | Description |
|---|---|---|---|
x |
number |
0 |
X coordinate of the node’s top-left corner in canvas coordinates. Automatic layout rewrites it. |
y |
number |
0 |
Y coordinate of the node’s top-left corner in canvas coordinates. Automatic layout rewrites it. |
width |
number |
options.defaultNodeWidth or DOM measurement |
Logical node width. Setting it also affects the initial el_W. |
height |
number |
options.defaultNodeHeight or DOM measurement |
Logical node height. Setting it also affects the initial el_H. |
el_W |
number |
Runtime measurement | Actual rendered node width. It can be provided as an initial measurement, but is usually updated from the DOM by the graph. |
el_H |
number |
Runtime measurement | Actual rendered node height. It can be provided as an initial measurement, but is usually updated from the DOM by the graph. |
fixed |
boolean |
false |
Fixes the node position. Layout processing for additional groups skips fixed nodes; force layouts often use it to keep a node from moving automatically. |
force_weight |
number |
Unset | Node weight/mass-like value in force layouts. Higher values usually make the node “heavier” in the force simulation; exact behavior depends on the layout implementation. |
Coordinate and size notes:
x/yare canvas coordinates, not page coordinates.width/heightexpress the size you want the node to have.el_W/el_Hare runtime measurements. Many layouts and line calculations depend on them.- If you use complex custom node slots without setting
width/height, layout usually needs to wait until the first DOM measurement is complete.
Tree Input Field
| Field | Type | Default | Description |
|---|---|---|---|
children |
JsonNode[] |
None | Shortcut for tree-shaped input data. During import, it is flattened into nodes and lines. |
children is only for the input stage:
const data = {
rootId: 'root',
nodes: [
{
id: 'root',
text: 'Root',
children: [
{ id: 'child-1', text: 'Child 1' },
{ id: 'child-2', text: 'Child 2' }
]
}
],
lines: []
};
await graphInstance.setJsonData(data);
After import, runtime data is managed through flat nodes, lines, and internal lot structures. Do not modify node.children at runtime and expect the graph to automatically add or remove nodes.
3. RGNode Runtime Fields
RGNode inherits most JsonNode fields and adds runtime-calculated information.
| Field | Type | Description |
|---|---|---|
type |
string |
Always exists at runtime. Empty string when unset. |
x / y |
number |
Always exists at runtime. Defaults to 0 when unset. |
nodeShape |
RGNodeShape |
Always exists at runtime, resolved from the node itself or defaultNodeShape. |
data |
Record<string, any> |
Always exists at runtime. Defaults to {}. |
lot |
object |
Internal layout/tree relationship structure. Contains parent/child nodes, depth, order, strength, and other layout fields. Do not persist it as business data. |
rgChildrenSize |
number |
Runtime count related to child size/expandability. |
rgShouldRender |
boolean |
Whether the node should be rendered after performance mode or viewport culling. |
rgCalcedVisibility |
boolean |
Calculated visibility after combining hidden, parent collapse, and runtime rules. |
Typical read:
const node = graphInstance.getNodeById('user-1');
if (node?.rgCalcedVisibility) {
console.log(node.x, node.y, node.el_W, node.el_H);
}
Fields you should avoid relying on directly:
lot: internal layout relationship field. Its shape may change between versions.rgShouldRender: result of a performance rendering strategy, not business visibility.el_W/el_H: useful for reading layout/helper-line information, but usually not worth persisting.
4. Create, Query, Update, Delete Nodes
Create Nodes
graphInstance.addNode({
id: 'n1',
text: 'Node 1'
});
graphInstance.addNodes([
{ id: 'n2', text: 'Node 2' },
{ id: 'n3', text: 'Node 3', x: 200, y: 80 }
]);
addNodes skips nodes whose id already exists. It does not overwrite an existing node with the same id. Use updateNode to modify an existing node.
Query Nodes
const node = graphInstance.getNodeById('n1');
const nodes = graphInstance.getNodes();
const checkedNode = graphInstance.getCheckedNode();
const selectedNodes = graphInstance.getSelectedNodes();
Update Nodes
graphInstance.updateNode('n1', {
text: 'Node 1 (updated)',
color: '#dbeafe',
borderColor: '#2563eb'
});
graphInstance.updateNodePosition('n1', 320, 160);
graphInstance.updateNodeData('n1', {
owner: 'team-a',
status: 'running'
});
Update rules:
updateNode(id, partial)shallow-merges fields.- To merge business data only, prefer
updateNodeData. - To change position, prefer
updateNodePosition; while a force layout is running, it also syncs the layout’s internal cache.
Delete Nodes
graphInstance.removeNodeById('n1');
graphInstance.removeNodesByIds(['n2', 'n3']);
const node = graphInstance.getNodeById('n4');
if (node) {
graphInstance.removeNode(node);
}
Deleting a node is handled by the data provider together with related runtime data. In business applications, confirm whether associated lines should also be removed according to your own rules before deleting.
5. Recommended Data Style
const nodes = [
{
id: 'service-api',
text: 'API Service',
type: 'service',
nodeShape: RGNodeShape.rect,
color: '#eff6ff',
borderColor: '#2563eb',
borderWidth: 1,
borderRadius: 8,
width: 160,
height: 56,
data: {
owner: 'Platform Team',
level: 'Core System'
}
},
{
id: 'cache',
text: 'Redis',
type: 'middleware',
fixed: true,
x: 360,
y: 120,
data: {
cluster: 'cache-prod'
}
}
];
Recommended principles:
- Use
id/text/type/datato describe the business entity. - Use
color/borderColor/borderWidth/borderRadius/nodeShapefor core visual semantics. - Use
classNamefor theme extension; do not put every visual meaning only in CSS. - Use
width/heightto stabilize layout, especially with custom node slots. - Use
fixedto distinguish manually positioned nodes from automatically laid-out nodes.
6. FAQ
Why Did My Node Position Change?
Calling setJsonData(), doLayout(), or appendJsonData(..., true) causes the layout engine to recalculate node positions. If you need fully manual placement, use layoutName: 'fixed' or avoid automatic relayout after updates.
Why Did Lines Disappear When A Node Was Hidden?
Normal line visibility references the calculated visibility of its start and end nodes. If either endpoint is invisible, the related RGLink usually does not render.
Why Does My Custom Node Slot Not Match MiniView?
MiniView/EasyView reads node data fields such as nodeShape, color, borderColor, and borderWidth. If you only set background and border in slot CSS, MiniView cannot infer that visual meaning.
What Is The Difference Between selected And Checked?
selectedis a field on the node itself. It is suitable for multi-select and batch editing.- Checked state is managed by
options.checkedNodeId/checkedItem, and usually represents the current focused node.