JavaScript is required

Link Runtime Object (RGLink)

RGLink is a runtime relationship-context object calculated by relation-graph from lines and nodes. It is not input data. It is a derived object created internally after the graph associates an RGLine with its two endpoint RGNode objects.

In one sentence:

  • RGLine describes what the line itself is.
  • RGNode describes what a node itself is.
  • RGLink describes which two nodes the line connects, and how that connection should participate in runtime rendering or analysis.

1. RGLink vs RGLine

Comparison RGLine RGLink
Source Converted from JsonLine Calculated from RGLine and the node index
Created by users Yes, through lines / addLines No, generated at runtime
Suitable for persistence Yes No
Contains endpoint node objects No, only from/to ids Yes, contains fromNode/toNode
Contains multi-line indexes No Yes, contains totalLinesBetweenNodes/currentLineIndex
Directly writable Modify through updateLine Should not be directly modified

2. Get RGLink

const links = graphInstance.getLinks();
const link = graphInstance.getLinkByLineId('line-a-b');

Line events also receive it directly:

const onLineClick = (line, link, event) => {
  console.log(line.id);
  console.log(link.fromNode.id, link.toNode.id);
};

Notes:

  • getLinks() returns RGLink[] for normal lines.
  • FakeLine usually does not appear in normal getLinks() results. Some internal analysis logic can temporarily convert FakeLines that resolve back to nodes into link-like context.
  • getLinkByLineId(id) targets normal line ids.

3. Fields

Field Type Description
lineId string Corresponding line id, usually equal to line.id.
line RGLine Runtime line object for this relationship. Modify it with updateLine(line.id, partial).
fromNode RGNode Start node object, corresponding to line.from.
toNode RGNode End node object, corresponding to line.to.
totalLinesBetweenNodes number Total number of lines between the same start and end nodes. Used for multi-line offset calculation.
currentLineIndex number Index of the current line among lines between the same node pair, starting from 0.
rgShouldRender boolean | undefined Whether this link should enter the rendering list after performance/view calculations.
rgCalcedVisibility boolean | undefined Runtime visibility after combining node visibility and line hidden state.

4. Multi-Line Indexes

When multiple lines exist between the same pair of nodes, RGLink provides ordering information:

graphInstance.addLines([
  { id: 'a-b-1', from: 'a', to: 'b', text: 'Primary link' },
  { id: 'a-b-2', from: 'a', to: 'b', text: 'Backup link' },
  { id: 'a-b-3', from: 'a', to: 'b', text: 'Audit link' }
]);

const link = graphInstance.getLinkByLineId('a-b-2');
console.log(link.totalLinesBetweenNodes); // 3
console.log(link.currentLineIndex);       // for example 1

The path generator combines these fields with options.multiLineDistance to separate multiple lines and avoid complete overlap.

You can also use these fields in business UI:

  • Show “which connection number” in an inspector.
  • Assign different styles to different lines between the same node pair.
  • Calculate offsets or label positions in a custom line slot.

5. Visibility Fields

rgCalcedVisibility

This is the runtime calculated visibility. It is usually affected by:

  • line.hidden
  • fromNode.rgCalcedVisibility
  • toNode.rgCalcedVisibility
  • Descendant hiding caused by parent collapse
  • Data provider visibility refresh

Typical check:

const link = graphInstance.getLinkByLineId('line-a-b');

if (link?.rgCalcedVisibility) {
  // This relationship should currently be visible in the graph.
}

rgShouldRender

This indicates whether the link should actually enter the current rendering batch. It is more about performance and viewport-culling results, and is not the same as business existence or business visibility.

Practical rules:

  • To check whether a business relationship exists: query line or link.
  • To check whether it is currently visible: prefer rgCalcedVisibility.
  • To check whether it is in the current render batch: use rgShouldRender.

6. Correct Uses Of RGLink

Use RGLink when you need to:

  • Read endpoint nodes in a line-click event.
  • Build a relationship inspector.
  • Count how many lines exist between a pair of nodes.
  • Read currentLineIndex in custom line rendering.
  • Run runtime graph analysis, such as finding lines among a group of nodes.

Example: show endpoint information after clicking a line.

const onLineClick = (line, link) => {
  inspector.value = {
    lineId: link.lineId,
    from: {
      id: link.fromNode.id,
      text: link.fromNode.text
    },
    to: {
      id: link.toNode.id,
      text: link.toNode.text
    },
    index: link.currentLineIndex,
    total: link.totalLinesBetweenNodes
  };
};

7. Do Not Treat RGLink As Writable Data

Wrong:

const link = graphInstance.getLinkByLineId('line-a-b');
link.fromNode = anotherNode; // Do not do this.
link.totalLinesBetweenNodes = 99; // Do not do this.

Correct:

// Update line text, style, or business data.
graphInstance.updateLine('line-a-b', {
  text: 'New relationship',
  color: '#2563eb'
});

// Update node properties.
graphInstance.updateNode('a', {
  text: 'New node name'
});

// Change relationship endpoint: delete the old line and add a new one.
graphInstance.removeLineById('line-a-b');
graphInstance.addLines([
  {
    id: 'line-a-c',
    from: 'a',
    to: 'c',
    text: 'New relationship'
  }
]);

8. RGLink In Relationship Analysis APIs

Common relationship queries:

const node = graphInstance.getNodeById('a');

const relatedLines = graphInstance.getRelatedLinesByNode(node);
const relatedNodes = graphInstance.getNodeRelatedNodes(node);
const incomingNodes = graphInstance.getNodeIncomingNodes(node);
const outgoingNodes = graphInstance.getNodeOutgoingNodes(node);
const networkNodes = graphInstance.getNetworkNodesByNode(node);

const linksBetween = graphInstance.getLinksBetweenNodes([nodeA, nodeB, nodeC]);
const linesBetween = graphInstance.getLinesBetweenNodes([nodeA, nodeB, nodeC]);

Boundaries:

  • getNodeRelatedNodes(node) includes both incoming and outgoing nodes by default.
  • Direction can be controlled with { incoming: true/false, outgoing: true/false }.
  • Lines with forDisplayOnly are skipped by some relationship analysis logic.
  • FakeLines that can resolve back to nodes may participate in some relationship analysis. HTML elements or purely custom targets should not be treated as normal structural relationships by default.

9. Export And Persistence

Do not persist RGLink. Recommended:

const jsonData = graphInstance.getGraphJsonData();

Or convert as needed:

const link = graphInstance.getLinkByLineId('line-a-b');

if (link) {
  const lineJson = graphInstance.transRGLinkToJsonObject(link);
  const effectiveLineJson = graphInstance.transRGLinkToJsonObject(link, {
    mode: 'effective'
  });
}

Difference between mode: 'compact' and mode: 'effective':

  • Compact mode tries to omit default values and runtime fields.
  • effective resolves global defaults into the result, such as default line color, default line width, and default junction point. It is useful for debugging and full configuration snapshots.

10. FAQ

Why Does getLinkByLineId Return Empty?

Common causes:

  • The id belongs to a FakeLine.
  • The normal line failed to be created, for example because from/to nodes do not exist.
  • A duplicated line id caused the add operation to be skipped.
  • Graph data has not finished loading.

Why Is line.hidden false But The Link Invisible?

Link visibility also references both endpoint nodes. If a node is hidden, a parent is collapsed, or runtime visibility has not refreshed, rgCalcedVisibility may still be false.

Why Did Updating link.line Not Reliably Update The UI?

Do not directly mutate runtime objects. Use instance APIs such as updateLine, updateLineData, and updateNode so the data provider can trigger state refresh and relationship recalculation.

11. Next