Custom View and Background (#view / #background)
#view, #background, and #canvas-above are all extension layers outside or above the main graph body, but their coordinate systems and use cases are different.
#view: fixed relative to the RelationGraph component viewport. It does not follow canvas pan/zoom. Suitable for toolbars, menus, and panels.#background: fixed relative to the viewport and located at the bottom of the canvas area. Suitable for background images, watermarks, and themed textures.#canvas-above: uses canvas coordinates, follows canvas pan/zoom, and appears above nodes/lines.
1. #view Viewport Layer
#view is rendered into:
<div class="rg-graph-plugs">
<div class="rg-view-slot">
<!-- #view -->
</div>
</div>
It is the top layer of the graph viewport and does not change with canvasOffset or canvasZoom.
| Feature | Description |
|---|---|
| Coordinate system | RelationGraph component viewport coordinates, with (0, 0) at the top-left corner. |
| Follows canvas zoom/pan | No. |
| Default events | Outer .rg-graph-plugs uses pointer-events: none. |
| Suitable content | Toolbar, context menu, property panel, minimap, editing controller, floating hint. |
| Unsuitable content | Group boxes, annotations, or regions that should move with nodes/canvas. |
Platform Syntax
| Platform | Syntax |
|---|---|
| Vue 3 / Vue 2 | <template #view>...</template> |
| React | <RGSlotOnView>...</RGSlotOnView> |
| Svelte | <div slot="view">...</div> |
Event Notes
The outer layer of #view uses pointer-events: none by default. If you place clickable UI there, enable events on the actual UI element:
<div class="my-panel rg-events-all">...</div>
Or:
<div class="my-panel" style="pointer-events: auto;">...</div>
Do not enable events on a full-screen overlay unless you intentionally want to block graph operations. Otherwise, it will block canvas dragging, node dragging, and line clicks.
2. #view Example: Fixed Toolbar
Vue3 example:
<script setup lang="ts">
import { shallowRef } from 'vue';
import type { RelationGraphInstance } from '@relation-graph/vue';
const graphInstance = shallowRef<RelationGraphInstance | null>(null);
function onReady(instance: RelationGraphInstance) {
graphInstance.value = instance;
}
function centerGraph() {
graphInstance.value?.moveToCenter();
}
function zoomIn() {
graphInstance.value?.zoom(20);
}
function zoomOut() {
graphInstance.value?.zoom(-20);
}
</script>
<template>
<RelationGraph
:options="graphOptions"
:initial-data="graphData"
@onReady="onReady"
>
<template #view>
<div class="floating-toolbar rg-events-all">
<button @click="centerGraph">Center</button>
<button @click="zoomIn">Zoom In</button>
<button @click="zoomOut">Zoom Out</button>
</div>
</template>
</RelationGraph>
</template>
.floating-toolbar {
position: absolute;
right: 12px;
top: 12px;
display: flex;
gap: 6px;
padding: 6px;
border-radius: 6px;
background: #ffffff;
box-shadow: 0 2px 10px rgba(15, 23, 42, 0.16);
}
Notes:
position: absoluteis positioned relative to the RelationGraph component viewport.- The toolbar does not zoom with the canvas.
rg-events-allmakes the buttons clickable.
3. #view Example: Context Menu
A context menu belongs in the viewport layer because it should appear at the mouse position on the screen, not be fixed to a canvas coordinate.
<script setup lang="ts">
import { ref, shallowRef } from 'vue';
import type { RelationGraphInstance } from '@relation-graph/vue';
const graphInstance = shallowRef<RelationGraphInstance | null>(null);
const menu = ref({
visible: false,
x: 0,
y: 0,
canvasX: 0,
canvasY: 0
});
function onReady(instance: RelationGraphInstance) {
graphInstance.value = instance;
}
function onContextmenu(
event,
objectType,
object,
eventPositionOnCanvas,
eventPositionOnView
) {
menu.value = {
visible: true,
x: eventPositionOnView.x,
y: eventPositionOnView.y,
canvasX: eventPositionOnCanvas.x,
canvasY: eventPositionOnCanvas.y
};
}
function createNodeHere() {
if (!graphInstance.value) return;
graphInstance.value.addNodes([
{
id: `node-${Date.now()}`,
text: 'New Node',
x: menu.value.canvasX,
y: menu.value.canvasY
}
]);
menu.value.visible = false;
}
</script>
<template>
<RelationGraph
:options="graphOptions"
:initial-data="graphData"
@onReady="onReady"
@onContextmenu="onContextmenu"
>
<template #view>
<div
v-if="menu.visible"
class="context-menu rg-events-all"
:style="{ left: menu.x + 'px', top: menu.y + 'px' }"
>
<button @click="createNodeHere">Create node here</button>
</div>
</template>
</RelationGraph>
</template>
The onContextmenu event parameters provide the target type, target object, canvas coordinates, and viewport coordinates. This example stores both viewport coordinates and canvas coordinates:
| Coordinate | Use |
|---|---|
menu.x/menu.y |
Position the context menu. |
menu.canvasX/menu.canvasY |
Use as node canvas coordinates when creating a node. |
4. #canvas-above Canvas Foreground Layer
#canvas-above uses the same canvas coordinate system as #canvas, but it is rendered at a higher layer.
Current render position:
<div class="rg-map-canvas rg-canvas-above">
<div class="rg-canvas-slot rg-canvas-slot-above">
<!-- #canvas-above -->
</div>
</div>
| Feature | Description |
|---|---|
| Coordinate system | Canvas coordinates. |
| Follows canvas zoom/pan | Yes. |
| Layer | Above nodes/lines. |
| Default events | Affected by .rg-map-canvas { pointer-events: none; }. |
| Suitable content | Selection hints, drag previews, alignment guides, temporary anchors above nodes. |
Example: show a temporary selection box in canvas coordinates:
<template #canvas-above>
<div
v-if="selectionBox.visible"
class="selection-box"
:style="{
left: selectionBox.x + 'px',
top: selectionBox.y + 'px',
width: selectionBox.width + 'px',
height: selectionBox.height + 'px'
}"
/>
</template>
.selection-box {
position: absolute;
box-sizing: border-box;
border: 1px solid #3b82f6;
background: rgba(59, 130, 246, 0.12);
pointer-events: none;
}
If foreground content needs to be clicked, also add rg-events-all or pointer-events: auto.
5. #background Background Layer
#background is rendered into:
<div class="rg-map-background">
<!-- #background -->
</div>
| Feature | Description |
|---|---|
| Coordinate system | RelationGraph component viewport coordinates. |
| Follows canvas zoom/pan | No. |
| Layer | Bottom of the canvas area. |
| Default events | .rg-map-background uses pointer-events: none. |
| Suitable content | Background images, watermarks, themed textures, static decoration. |
Vue syntax:
<template #background>
<div class="graph-background">
<div class="watermark">Relation Graph</div>
</div>
</template>
React syntax:
import { RelationGraph, RGBackground } from '@relation-graph/react';
<RelationGraph options={graphOptions} initialData={graphData}>
<RGBackground>
<div className="graph-background">
<div className="watermark">Relation Graph</div>
</div>
</RGBackground>
</RelationGraph>
Styles:
.graph-background {
position: absolute;
inset: 0;
background:
linear-gradient(rgba(148, 163, 184, 0.16) 1px, transparent 1px),
linear-gradient(90deg, rgba(148, 163, 184, 0.16) 1px, transparent 1px);
background-size: 24px 24px;
}
.graph-background .watermark {
position: absolute;
right: 18px;
bottom: 14px;
font-size: 12px;
color: rgba(100, 116, 139, 0.5);
}
Notes:
- The background layer does not zoom with the canvas, so it is suitable for a “screen background”, not for a grid in graph coordinates. If the grid should move and scale with nodes, put it in
#canvas. - The current background is part of the graph DOM. Custom backgrounds usually participate in image export. If the background uses cross-origin images, browser canvas tainting rules still apply.
6. Which Layer Built-in Components Belong To
relation-graph exposes several built-in components. They are usually more suitable for #view.
| Component | Recommended layer | Description |
|---|---|---|
RGToolBar / RGMiniToolBar |
#view |
Fixed toolbar; it should not zoom with the canvas. |
RGMiniView |
#view |
The minimap is usually fixed in a corner. |
RGEditingNodeController |
#view or internal editing layer |
Node editing controller, usually maps node position to viewport coordinates. |
RGEditingLineController |
#view or internal editing layer |
Line editing controller. |
RGEditingConnectController |
#view or internal editing layer |
Line creation/connection controller. |
RGWatermark |
#background or #view |
Put pure background watermarks in background; put fixed overlay watermarks in view. |
RGBackground |
#background / React children |
Used by React to identify the background slot. |
Specific usage can vary slightly by platform wrapper. The principle is: fixed UI goes in #view, background decoration goes in #background, and canvas-coordinate content goes in #canvas or #canvas-above.
7. Relationship with showToolBar
options.showToolBar controls whether the built-in small toolbar is shown. In the source, when showToolBar is true, the built-in GraphXsToolBar is rendered automatically.
| Option | Behavior |
|---|---|
showToolBar: true |
Show the built-in toolbar. |
showToolBar: false |
Hide the built-in toolbar; you can place a custom toolbar in #view. |
If you want a fully custom toolbar, usually set:
const graphOptions = {
showToolBar: false
};
Then implement your own zoom, centering, refresh, export, and other operations in #view.
8. Layer Selection Guide
| Requirement | Recommended layer | Reason |
|---|---|---|
| Toolbar fixed in the top-right corner | #view |
Does not follow canvas zoom. |
| Business floating card to the right of a node, moving with the node | #canvas-above or node slot |
Needs canvas coordinates. |
| Context menu | #view |
Menu position comes from mouse viewport coordinates. |
| Coordinate hint while creating a node | #view + coordinate conversion |
UI is fixed; business coordinates are converted through APIs. |
| Group background or lane | #canvas |
Belongs to graph coordinates and should be below nodes. |
| Selection rectangle | #canvas-above |
Belongs to graph coordinates and should be above nodes. |
| Static watermark | #background |
Does not need interaction and does not move with the canvas. |
| Grid that follows graph zoom | #canvas |
Uses canvas coordinates. |
| Background grid that does not follow graph zoom | #background |
Uses viewport coordinates. |
9. FAQ
Why cannot I click a button inside #view?
Because the outer .rg-graph-plugs uses pointer-events: none by default. Add class="rg-events-all" or style="pointer-events:auto" to the actual panel or button.
Why is the context menu positioned incorrectly after zooming?
The context menu itself should use viewport coordinates: getViewXyByEvent(event). If a menu action needs to create a node on the canvas, additionally convert the viewport coordinates to canvas coordinates with getCanvasXyByViewXy(viewPoint).
Why does the background image not move with the graph?
#background is a viewport background and does not follow the canvas. If the background image should move and scale with nodes, put it in #canvas.
Why does #canvas-above content block nodes?
It is designed to be above nodes/lines. If it is only a visual hint, set pointer-events: none; if only a small local area needs interaction, enable events only on the specific button or anchor.
Can #view read the current zoom and offset?
Yes. Read graph state through hooks or instance APIs, such as RGHooks.useGraphInstance() and RGHooks.useViewInformation(). Vue3 currently also exports RGHooks.useGraphOptions(). React/Svelte can use useGraphStore() or more specific state hooks according to their platform. If you need to map canvas coordinates to the viewport, prefer getViewXyByCanvasXy.