View and Canvas Slot Overview
This example compares three built-in relation-graph slot surfaces inside one graph: `RGSlotOnView`, `RGSlotOnCanvasAbove`, and `RGSlotOnCanvas`. It uses a shared React state value, a view-slot text input, and a canvas-above toggle to show how ordinary HTML can stay interactive while being placed on different graph layers.
Comparing Built-In View and Canvas Slots in One Graph
What This Example Builds
This example builds a full-height relation graph that doubles as a slot-surface comparison board. The graph itself is a small static network, but the visible teaching content is three large color-coded HTML panels rendered through RGSlotOnView, RGSlotOnCanvasAbove, and RGSlotOnCanvas.
The user can type into a text input in the view-layer panel, then watch that same text appear inside the two canvas-based panels. A Show More Info button in the canvas-above panel reveals an extra block, so the example demonstrates both shared state and a simple conditional overlay inside graph-owned layers.
The main point is not graph data editing or business semantics. The important result is a concrete side-by-side comparison of how built-in view and canvas slot surfaces can host ordinary interactive HTML.
How the Data Is Organized
The graph data is created inline inside initializeGraph() as one RGJsonData object with rootId: '2', a flat nodes array, and a flat lines array. Each node carries id, text, and a data.myicon field. Each line already includes its own id, from, to, and text.
There is no separate preprocessing pass before setJsonData(). The object is assembled directly in the shape that relation-graph expects, then loaded into the instance as-is. In a real application, the same structure could represent organizations, systems, dependency links, ownership links, or any other small relationship set where the graph mainly serves as a host surface for layered UI.
How relation-graph Is Used
index.tsx wraps the example in RGProvider, and MyGraph.tsx uses RGHooks.useGraphInstance() to get the active instance. A mount-only useEffect() calls initializeGraph(), which loads the inline dataset and immediately calls moveToCenter() and zoomToFit() so the demo starts in a normalized view.
The RelationGraph itself is configured lightly. The only explicit graph options are defaultJunctionPoint: RGJunctionPoint.border and defaultLineColor: '#666'. The reviewed source does not set an explicit layout, so the node arrangement comes from relation-graph defaults for this data.
The core implementation detail is that all three slot demonstrations are children of the same RelationGraph instance. RGSlotOnView hosts a fixed instructional panel with the text input. RGSlotOnCanvasAbove hosts a second panel with a toggle button and a conditional extra block. RGSlotOnCanvas hosts a third panel that continuously shows the mirrored text. Each panel uses pointer-events-auto, which allows ordinary HTML controls to remain interactive inside the graph scene.
No graph editing APIs, node events, or line events are used. The local SCSS file mostly provides empty selector scaffolding, so the visible teaching effect comes from inline absolute positioning, bright background colors, and the built-in slot surfaces themselves. The Show More Info control is a shared local SimpleUIButton component imported from DraggableWindow.tsx, not a special relation-graph widget.
Key Interactions
- Typing in the
RGSlotOnViewinput updatessearchText. - The current
searchTextvalue is rendered again inside theRGSlotOnCanvasAbovereveal area and inside theRGSlotOnCanvaspreview area. - Clicking
Show More Infotoggles the conditional block in the canvas-above slot. - The example is structured so users can compare a view-layer panel with two canvas-layer panels inside the same graph scene rather than opening a separate demo for each surface.
Key Code Fragments
This wrapper shows that the whole demo runs inside one relation-graph provider context.
const Demo = () => {
return (
<RGProvider>
<MyGraph />
</RGProvider>
);
};
This block shows that the example uses hook-based instance access and only minimal graph-level options.
const MyGraph = () => {
const [searchText, setSearchText] = useState('You can use this search box to search for nodes');
const [showBackgroundGraph, setShowBackgroundGraph] = useState(false);
const graphInstance = RGHooks.useGraphInstance();
const graphOptions: RGOptions = {
defaultJunctionPoint: RGJunctionPoint.border,
defaultLineColor: '#666'
};
This fragment proves that the graph payload is assembled inline as flat nodes and lines.
const myJsonData: RGJsonData = {
rootId: '2',
nodes: [
{ id: '1', text: 'Node-1', data: { myicon: 'el-icon-star-on' } },
{ id: '2', text: 'Node-2', data: { myicon: 'el-icon-setting' } },
{ id: '3', text: 'Node-3', data: { myicon: 'el-icon-setting' } },
// ... more nodes ...
],
lines: [
{ id: 'l1', from: '7', to: '71', text: 'Investment' },
{ id: 'l2', from: '7', to: '72', text: 'Investment' },
// ... more lines ...
]
};
This initialization sequence is the only graph-instance workflow: load the data, center it, then fit it.
if (graphInstance) {
await graphInstance.setJsonData(myJsonData);
await graphInstance.moveToCenter();
await graphInstance.zoomToFit();
}
This slot fragment shows the view-layer panel and the input that drives shared React state.
<RGSlotOnView>
<div className="pointer-events-auto" style={{ top: '0px', left: '0px', position: 'absolute', width: '600px', border: '#efefef solid 1px', zIndex: 22 }}>
<div style={{ backgroundColor: '#fa7b7e', padding: '10px', width: '100%', fontSize: '18px' }}>This is the view slot(RGSlotOnView)</div>
<div style={{ backgroundColor: '#7a9ef8', padding: '10px', width: '100%', fontSize: '12px' }}>
You can customize the content here, such as putting a search box:
<input type="text" defaultValue={searchText} onChange={(e) => { setSearchText(e.target.value); }} />
</div>
</div>
</RGSlotOnView>
This fragment shows the canvas-above slot using a local button to reveal extra content that reuses the same text state.
<RGSlotOnCanvasAbove>
<div className="pointer-events-auto" style={{ top: '-300px', left: '-300px', position: 'absolute', width: '600px', border: '#efefef solid 1px' }}>
<div style={{ backgroundColor: '#f5df7a', padding: '10px', width: '100%', fontSize: '12px' }}>
You can put anything here, these contents will move and scale with the canvas.
<SimpleUIButton onClick={toggleGraph}>Show More Info</SimpleUIButton>
</div>
{showBackgroundGraph && (
<div className="flex justify-center place-items-center text-2xl text-red-900" style={{ backgroundColor: '#cb7ffd', width: '600px', height: '600px', overflow: 'hidden' }}>
<div>{searchText}</div>
</div>
)}
</div>
</RGSlotOnCanvasAbove>
This final slot keeps the mirrored text visible all the time in the canvas-layer panel.
<RGSlotOnCanvas>
<div className="pointer-events-auto" style={{ top: '100px', left: '-100px', position: 'absolute', width: '600px', border: '#efefef solid 1px' }}>
<div style={{ backgroundColor: '#f5df7a', padding: '10px', width: '100%', fontSize: '12px' }}>
You can put anything here, even another graph, these contents will move and scale with the canvas.
</div>
<div className="flex justify-center place-items-center text-2xl text-red-900" style={{ backgroundColor: 'rgba(127,201,253)', width: '600px', height: '400px', overflow: 'hidden' }}>
<div>{searchText}</div>
</div>
</div>
</RGSlotOnCanvas>
What Makes This Example Distinct
The comparison data makes the distinguishing point explicit: this example is unusual because it compares RGSlotOnView, RGSlotOnCanvasAbove, and RGSlotOnCanvas side by side inside one RelationGraph. Nearby examples such as node-menu and node-menu-2 also use view-layer HTML, but they focus on node-triggered menus and transient overlays. This example keeps multiple teaching panels visible at once and does not depend on selecting a node, line, or canvas target.
It also differs from scene-network-use-canvas-slot, which uses a canvas slot as part of a finished dashboard-like composition. Here, the canvas slot is only one part of a three-surface comparison, and its content is intentionally simple so the layer behavior stays readable. Against customize-fullscreen-action, the main integration lesson moves inside the graph container rather than around it in a wrapper layout.
The most distinctive feature combination is a single shared React state flowing through three built-in slot surfaces: a view-slot input, a canvas-above reveal panel, and a canvas-slot readout. That makes this example a stronger starting point when the requirement is coordinated HTML overlays across graph layers rather than menus, fullscreen behavior, or graph editing.
Where Else This Pattern Applies
This pattern fits graph screens that need both fixed controls and graph-bound overlays at the same time. Examples include a search or filter box pinned to the viewport, annotation cards that should move with the canvas, and instructional panels that explain zoom or pan behavior directly inside the graph scene.
It also transfers well to monitoring boards, architecture diagrams, relationship inspection tools, and onboarding demos. In those cases, the underlying nodes and lines can come from real business data, while the slot composition pattern stays the same: one state source, ordinary HTML controls, and separate placement rules for view-level and canvas-level content.