Skip to main content

GraphXR API Reference

Camera

flyToCenter

Fly the camera to the center of a slice of nodes, optionally with an offset, optionally with a custom duration or tween function

@synonyms centerTo

gxr.flyToCenter();
gxr.flyToCenter(gxr.nodes().slice(0, 10).ids())
gxr.flyToCenter(gxr.nodes().slice(0, 10).ids(), { duration: 0, offset: -3 }));

flyToPosition

Fly the camera to a position, optionally with an offset, optionally with a custom duration or tween function

const position = gxr.nodes({name: "Flo"}).at(0).position;
gxr.flyToPosition(position); // no offset
gxr.flyToPosition(position, {offset: -3}); // with an offset
gxr.flyToPosition(position, {duration: 0}); // instantly

flyOut

Zoom out until all nodes are visible

gxr.flyOut();

zoomIn

Zoom the camera in by a delta value, optionally with animation

gxr.zoomIn(); // zoom in by 1.0
gxr.zoomIn(2.0); // zoom in by 2.0
gxr.zoomIn(1.5, { duration: 500 }); // zoom in by 1.5 with animation

zoomOut

Zoom the camera out by a delta value, optionally with animation

gxr.zoomOut(); // zoom out by 1.0
gxr.zoomOut(0.5); // zoom out by 0.5
gxr.zoomOut(0.5, { duration: 300 }); // zoom out by 0.5 with animation

setCameraOptions

gxr.setCameraOptions({
hideAxes: true,
rotating: true,
speed: 0.5,
});

setCameraRotating

gxr.setCameraRotating(true);

Captions

captionNodesByProperties

gxr.captionNodesByProperties({category: "Person", properties: ["name", "age"]});

Events

onGraphDataUpdate

gxr.onGraphDataUpdate(() => console.log("Graph data updated"));

useGraphDataUpdate

React hook that subscribes to graph data changes. Returns a value that changes whenever graph data is updated.

const dataVersion = gxr.useGraphDataUpdate();
useEffect(() => {
// Re-run when graph data changes
}, [dataVersion]);

onSelect

gxr.onSelect((event) => console.log("Selected nodes/edges", event));

Files

files

gxr.files.upload({
path: "/documents/story.pdf",
file: new File(["Once upon a time..."], "story.pdf"),
})
gxr.files.ls("/documents");
gxr.files.rmrf("/documents");

setCurrentPanel

@deprecated Use gxr.workspace.setActiveTab(panelId, ${panelId}.${subTab}) instead.

gxr.setCurrentPanel("algorithm");
gxr.setCurrentPanel("algorithm", "centrality");
gxr.setCurrentPanel("Grove");

As a convenience, you can pass the name of the extension as the first argument
instead of the extension's id, because extension ids are random and hard to remember.

setSubTab

@deprecated Use setCurrentPanel(panelId, subTab) instead.

gxr.setSubTab("centrality");
// Prefer: gxr.setCurrentPanel("algorithm", "centrality");

Graph

add

@deprecated

DEPRECATED: DO NOT USE THIS FUNCTION. Prefer addNode, addNodes, addEdge, or addEdges instead. Why are we deprecating this function?

  • It's too complicated.
  • Too many conditions.
  • AI messes up using it. We should prefer the simpler functions like addNode, addNodes, addEdge, or addEdges instead.
// DEPRECATED: DO NOT USE THIS FUNCTION.
gxr.add("A") -> Node with id "A"
gxr.add("A", "B") -> Edge
gxr.add(["A", "B"]) -> Node[]
gxr.add({ id: "A", category: "Person", properties: {name: "Flo"} }) -> Node
gxr.add([{ id: "A", category: "Person", properties: {name: "Flo"} }]) -> Node[]
gxr.add({ sourceId: "A", targetId: "B" }) -> Edge
gxr.add([{ sourceId: "A", targetId: "B" }]) -> Edge[]
gxr.add([{ source: {...}, edge: {...}, target: {...} }], {...}) -> Edge[] // mergeRelationships
gxr.add({ name: "Flo" }, { category: "Person" }) -> Node
gxr.add([{ name: "Flo" }], { category: "Person" }) -> Node[]
gxr.add([{ name: "Flo" }]) -> Node[]
gxr.add({ id: "A" }, { id: "B" }) -> Edge
gxr.add({ id: "A" }, { id: "B" }, { relationship: "LINK" }) -> Edge with relationship "LINK"

addNode

Add node to the graph.

gxr.addNode({ id: "A", category: "Person", properties: {name: "Flo"} });

addNodes

Add multiple nodes to the graph.

gxr.addNodes([{ id: "A", category: "Person" }, { id: "B", category: "Person" }]);

addEdge

Add a single edge to the graph.

gxr.addEdge({ sourceId: "A", targetId: "B", relationship: "KNOWS" });
gxr.addEdge(nodeA, nodeB);
gxr.addEdge(nodeA, nodeB, { relationship: "KNOWS" });

addEdges

Add multiple edges to the graph.

gxr.addEdges([{ sourceId: "A", targetId: "B" }, { sourceId: "B", targetId: "C" }]);

clear

Clear the graph

gxr.clear();

edges

gxr.edges().forEach(console.log);
gxr.edges().property('since', 2023);
gxr.edges().property('since', () => Math.random() * 3000);
gxr.edges().style('width', 10)
gxr.edges({relationship: 'LINKS'}).style('width', 10);
gxr.edges({properties: {since: 2023}}).style('width', 10);

getCanvasSchema

Get schema from the visible nodes and edges on the canvas.

const schema = gxr.getCanvasSchema();
console.log(schema.nodes); // [{label: "Person", properties: [...]}]
console.log(schema.relationships); // [{label: "KNOWS", sourceNodeLabel: "Person", targetNodeLabel: "Person", properties: [...]}]

getCategoryConfig

gxr.getCategoryConfig('Person');

getNode

gxr.getNode("A")

getRelationshipConfig

gxr.getRelationshipConfig("RELATED_TO");

graph

// Add a node with id "A"
gxr.graph().add("A");

// Generate a random graph, run degree algorithm, and then run ego layout for a duration of 1 second.
gxr
.graph()
.clear()
.generate()
.degree()
.ego(
{
properties: { degree: (value) => value >= 3 },
depth: 5,
mode: "tree",
orientation: "down",
edgeLength: 0.5,
sortByProperty: "degree",
},
{ duration: 1000 }
);

makeGraph

gxr.makeGraph().add("A").add("B").add("C").add("A", "B").add("B", "C").add("C", "A");

nodes

Get an IterableNodes object with an optional filter, sort, or reverse that can be used to iterate over the nodes in the graph.

gxr.nodes().forEach(console.log);
gxr.nodes().property('age', 24);
gxr.nodes().property('age', () => Math.random() * 100);
gxr.nodes({category: "Person"}).style('selected', true);
gxr.nodes({properties: {age: 24}}).style('selected', true);
gxr.nodes({properties: {age: (age) => age > 24}}).style('selected', true);

selectNodes

Select nodes in the graph based on a filter predicate or options.

// Select nodes using a predicate function
gxr.selectNodes((n) => n.id === "hub");
gxr.selectNodes((n) => n.category === "Person");
gxr.selectNodes((n) => n.properties.age > 30);

// Select nodes by ID
gxr.selectNodes("nodeId");
gxr.selectNodes(["nodeId1", "nodeId2"]);

// Select nodes by category
gxr.selectNodes({ category: "Person" });

// Select nodes by properties
gxr.selectNodes({ properties: { name: "Alice" } });

// Select all nodes
gxr.selectNodes(() => true);

// Deselect all (select none)
gxr.selectNodes(() => false);

deselectNodes

Deselect nodes in the graph based on a filter predicate or options.

// Deselect all nodes
gxr.deselectNodes();

// Deselect nodes using a predicate function
gxr.deselectNodes((n) => n.id === "hub");
gxr.deselectNodes((n) => n.category === "Person");

// Deselect nodes by ID
gxr.deselectNodes("nodeId");
gxr.deselectNodes(["nodeId1", "nodeId2"]);

// Deselect nodes by category
gxr.deselectNodes({ category: "Person" });

randomGraph

Generate a random graph and add it to the canvas.

gxr.randomGraph({nodeCount: 100, edgeCount: 200, categories: ["Person", "Company"], relationships: ["WORKS_FOR", "KNOWS"]});
gxr.forceLayout();

makeInMemoryRandomGraph

Generate an in-memory random graph.

const randomGraph = gxr.makeRandomGraph({nodeCount: 100, edgeCount: 200, categories: ["Person", "Company"], relationships: ["WORKS_FOR", "KNOWS"]});
gxr.add(randomGraph);
gxr.forceLayout();

Layout

alignBy

Given one of x, y, or z, find the center of that dimension and align all Nodes to that center on that dimension only.

await gxr.alignBy({
dimension: 'x',
})

circle

All the nodes spread on a circle

await gxr.circle();

cube

All the nodes spread on a cube.

await gxr.cube();

distributionBy

Equally space Nodes on one of the x, y, or z axes while keeping the other two dimensions constant. Optionally bin the Nodes by a property value. Optionally scale the spacing by a "spread" factor (the higher the spread, the farther apart).

// Distribute nodes on the x-axis by a property
await gxr.distributionBy('similarity')

// Order nodes by a date property and spread them out
await gxr.distributionBy({
bin: 'episodeAirDate',
binType: 'date',
spread: 6,
})

// Equally space Nodes on the x-axis
await gxr.distributionBy({
dimension: 'x', // y, or z
})

// Equally space Nodes on the x-axis and bin the Nodes by "seasonNumber"
await gxr.distributionBy({
bin: 'seasonNumber',
dimension: 'x',
})

// Equally space Nodes on the x-axis and bin the Nodes by "seasonNumber" in descending order
await gxr.distributionBy({
bin: 'seasonNumber',
dimension: 'x',
reverse: true,
})

ego

Ego reveals hierarchal data by arranging nodes in a tree, where a node's depth in the tree is equal to the length of the shortest path to the node. The tree projects linearly in one direction, or radially around the root[s].

await gxr.nodes("a").ego({
depth: 3, // maximum depth of the tree; default 100
edgeLength: 1 // visual length of the edges in the tree; default 0.2
mode: 'rings' // 'tree' or 'rings'; default 'tree'
orientation: 'down' // 'up', 'down', 'left', or 'right'; default 'right'
sortByProperty: 'ComponentName' // arrange child nodes in ascending order by a property
[sortByProperty: sortByProperty({property: "ComponentName", ascending: false})] // same as above, but descending
}))

grid

Equally space Nodes on the x-axis, y-axis, z=0.

await gxr.grid();

line

Equally space Nodes on the x-axis, y=0, z=0.

await gxr.line();

// Animate the layout over 1 second
await gxr.line({
tween: {
duration: 1000,
},
});

parametric

Map the x, y, and/or z dimensions to the range [-2, 2] by applying a linear scale to all or a subset of the domain of a property.

If a dimension is omitted, it is flattened to align with the grid.

// Line up Nodes on the x-axis, ordered by seasonNumber.
// Also set y and z to 0
await gxr.parametric({
x: 'seasonNumber',
y: 0,
z: 0,
})

// Line up Nodes on the x-axis, ordered by seasonNumber descending. Align y and z to the grid.
await gxr.parametric({
x: 'seasonNumber',
reverse: true,
})

// Linearly scale seasonNumber, episodeNumber, and millionViewers on the x, y, and z dimensions respectively
await gxr.parametric({
x: 'seasonNumber',
y: 'episodeNumber',
z: 'millionViewers',
})

rotate

Given one of the x, y, or z dimensions, find the center point of all the Nodes and rotate all Nodes around the axis passing through the center point and lying on the dimension given.

await gxr.rotate({
dimension: 'x',
theta: 90,
})

await gxr.rotate({
dimension: 'z',
theta: 45
})

scale

Scale the distance of each node from a computed center by a constant factor.

await gxr.scale({
x: 2,
y: 2,
z: 2,
})

scatter

Set each node to a random point.

await gxr.scatter()

shift

Add a constant vector to the position of each node.

await gxr.shift({
x: 1,
})

toast

Get the toast function

gxr.toast("Hello, world!");
gxr.toast().info("Hello, world!");
gxr.toast().success("Hello, world!");
gxr.toast().error("Hello, world!");
gxr.toast().warn("Hello, world!");
await gxr.toast().promise(fetch(), "Hello, world!");

setParametricAxesOptions

gxr.setParametricAxesOptions({
showAxes: false,
})

spiral

All the nodes spread on a spiral

gxr.spiral()

sphere

All the nodes spread on a sphere using Fibonacci sphere (golden spiral) algorithm

await gxr.sphere();

// Custom radius and density
await gxr.sphere({
radius: 2,
density: 3,
tween: { duration: 1000 }
});

forceLayout

Run a force layout on the graph.

// Run force layout
gxr.forceLayout();

Neo4j

neo4j

await gxr.neo4j("MATCH (n) RETURN n LIMIT 10");

Query

query

// Execute a query. Results appear in the graph workspace
await gxr.query("MATCH (n) RETURN n LIMIT 10");

// Execute a query. Results are not shown in the graph workspace
await gxr.query("MATCH (n) RETURN n LIMIT 10", { saveToGraph: false });

// Explicitly query a local Kuzu file
await gxr.query("MATCH (n) RETURN n LIMIT 10", { type: "localKuzuFile", name: "default" });

// Execute a query. Results are not shown in the graph workspace
const result = await gxr.query("MATCH (n) RETURN n LIMIT 10", { type: "localKuzuFile", name: "default", saveToGraph: false });
console.log(result);

Views

loadView

await gxr.loadView({
id: "123",
})

Project

getProjectId

Get the current project's id.

gxr.getProjectId();

getProjectName

Get the current project's name.

gxr.getProjectName();

Version

getGxrVersion

Get the current GraphXR version.

gxr.getGxrVersion(); // e.g. "2.15.0"

Settings

setTipsEnabled

gxr.setTipsEnabled(false);

setAutoShowImage

gxr.setAutoShowImage(true);

setEdgeScale

gxr.setEdgeScale(0.5);

setEdgeArrowVisibility

gxr.setEdgeArrowVisibility(true);

setBlendEdge

gxr.setBlendEdge(false);

setAutoCaption

gxr.setAutoCaption(true);

setFullscreen

gxr.setFullscreen(true);

setPinIconVisible

gxr.setPinIconVisible(false);

setAlternateCaption

gxr.setAlternateCaption(false);

setDashline

gxr.setDashline(false);

setTheme

gxr.setTheme("light")
gxr.setTheme("dark")

setUseCurveLine

//use curve line
gxr.setUseCurveLine(true)
//use straight line
gxr.setUseCurveLine(false)

setRelationshipNameVisibility

gxr.setRelationshipNameVisibility(true)

setGraphMode

gxr.setGraphMode("2D")

setCaptionScale

gxr.setCaptionScale(0.5)

Styles

colorNodesByProperty

// Color nodes by property using default scale
gxr.colorNodesByProperty('age');

// Color nodes by property using default scale (object syntax)
gxr.colorNodesByProperty({property: 'age'});

// Color nodes by property using a specific color scale
gxr.colorNodesByProperty({property: 'age', scale: 'BuGn'});

// Color specific property values with custom colors
gxr.colorNodesByProperty({
property: 'type',
colorMap: {
'Person': 'red',
'Company': 'blue',
'Location': 'green'
}
});

// Color nodes by status with hex colors
gxr.colorNodesByProperty({
property: 'status',
colorMap: {
'active': '#00FF00',
'inactive': '#FF0000',
'pending': '#FFA500'
}
});

// Combine color scale with specific value overrides
gxr.colorNodesByProperty({
property: 'category',
scale: 'Viridis',
colorMap: {
'important': '#FF0000' // Override specific values
}
});

getIcons

Get a list of available icons

const icons = await gxr.getIcons();

getIconByName

Get an icon by name

const icon = await gxr.getIconByName("person");

setCategoryColor

Set a category's color by hex

gxr.setCategoryColor("Person", "#00ff00");

setCategoryIcon

Set a category's icon

const icon = await gxr.getIconByName("person");
gxr.setCategoryIcon("Person", icon);

setCategoryIconByName

Set a category's icon by name

gxr.setCategoryIconByName("Person", "person");

setCategoryVisibility

gxr.setCategoryVisibility("Person", false);

setRelationshipColor

gxr.setRelationshipColor("KNOWS", "#00ff00");

setRelationshipVisibility

gxr.setRelationshipVisibility("KNOWS", false);

sizeNodesByProperty

gxr.sizeNodesByProperty({category: "Person", property: 'age'});

traceNeighbor

gxr.traceNeighbor()

Transform

aggregate

Pull data to root nodes from their neighborhoods up to a certain depth.

gxr.aggregate({
formula: 'sum',
property: "age",
})

gxr.aggregate({
formula: 'concatenate',
separator: ",",
property: "name",
along: "KNOWS",
startNodeId: "A",
[depth: 3], // optional. Default is 1
})

gxr.aggregate({
// Formula can also be a function
formula: (values) => values.reduce((a, b) => a + b, 0),
...
}))

extract

gxr.extract({
sourceCategory: "Episodes",
targetCategory: "Season",
props: [
{
name: "seasonNumber",
isKey: true,
},
{
name: "millionViewers",
},
{
name: "episodeAirDate",
},
],
relationship: "IN_SEASON",
})

Create new edges between nodes which have matching values for the specified property.

// Exact match (default)
gxr.link({ sourceProperty: "id", targetProperty: "id" })

gxr.link({
sourceCategory: "Roles",
sourceProperty: "ParentName",
targetCategory: "Roles",
targetProperty: "ComponentName",
relationship: "IS_PARENT_OF"
})

// Case-insensitive match
gxr.link({
sourceCategory: "Person",
targetCategory: "Person",
sourceProperty: "email",
targetProperty: "email",
relationship: "SAME_EMAIL",
match: {
type: "case-insensitive"
}
})


// Custom function match
gxr.link({
sourceCategory: "Product",
targetCategory: "Product",
sourceProperty: "price",
targetProperty: "price",
relationship: "SIMILAR_PRICE",
match: {
type: "function",
options: {
fn: (priceA, priceB) => {
const diff = Math.abs(Number(priceA) - Number(priceB));
return diff <= 10; // Within $10
}
}
}
})

// Bidirectional linking (edges in both directions)
gxr.link({
sourceCategory: "Person",
targetCategory: "Person",
sourceProperty: "id",
targetProperty: "id",
relationship: { name: "CONNECTED", direction: "any" }
})

// Reverse direction (edges go from target to source)
gxr.link({
sourceCategory: "Person",
targetCategory: "Person",
sourceProperty: "id",
targetProperty: "id",
relationship: { name: "CONNECTED", direction: "reverse" }
})

merge

Combine nodes or edges which have equivalent key properties.

@param options Merge options (category, relationship, keys, etc.)

gxr.merge({
keys: ['seasonNumber'],
})

gxr.merge({
category: "Episode",
keys: ['seasonNumber'],
})

// Combine all emails between two persons sent on the same day (thus removing directionality)
gxr.merge({
relationship: "SENT_MAIL_TO"
keys: ['sendDate'],
})

// Combine all emails between two persons sent on the same day and preserve directionality
gxr.merge({
relationship: "SENT_MAIL_TO"
keys: ['sendDate'],
directional: true,
})

mergeNodes

Create new nodes, or update existing nodes, based on the specified key properties.

gxr.mergeNodes({
data: [{ name: "Flo", age: 32 }],
category: "Person",
keys: ["name"]
})

mergeRelationships

Create new edges, or update existing edges, based on the specified key properties.

gxr.mergeRelationships({
data: [
{ source: {name: "Flo"}, edge: {since: 2010}, target: {name: "Aiden"} },
{ source: {name: "Flo"}, edge: {since: 2010}, target: {name: "Georgio"} },
],
source: { category: "Person", keys: ["name"] },
edge: { relationship: "KNOWS", keys: ["SINCE"] },
target: { category: "Person", keys: ["name"] },
})

quickInfoEnabled

Enables/disables quick info

gxr.quickInfoEnabled(true);

showQuickInfo

Shows the quick info panel for the given node.

gxr.showQuickInfo(gxr.nodes().at(0));

hideQuickInfo

Hides the quick info panel

gxr.showQuickInfo(gxr.nodes().at(0));

shortcut

Given R1, B, and R2, Shortcut finds all unique paths from node A to node C, traveling first along R1, passing through B (center category), and travelling lastly through R2 to arrive at C. Once it finds all unique paths from A to C, Shortcut creates an edge A -> C (or C -> A if R3.direction is 'reverse') with properties aggregated from the center nodes.

More simply, A -R1-> [B] -R2-> C => A -R3-> C where R1 is the first relationship, B is centerCategory, R2 is the second relationship, and R3 is the new relationship. [B] means the set of all nodes B which are between A and C.

Options:

  • A (optional): constrain source nodes to this category
  • C (optional): constrain target nodes to this category
  • B (required): the center category

Direction options for R1, R2:

  • 'any' (default): follow edges regardless of direction
  • 'forward': only follow edges in their natural direction (source → target)
  • 'reverse': only follow edges in reverse direction (target ← source)

If antisymmetric is true, then if A-B-C, only A->C will be created in some total order (default by node.index ascending).

shortcut({
A: 'Person',
R1: { name: 'IS_PARENT_OF', direction: 'forward' },
B: 'Node',
R2: { name: 'IS_PARENT_OF', direction: 'forward' },
C: 'Person',
R3: "IS_GRANDPARENT_OF",
antisymmetric: true,
aggregate: [
{
sourceProperty: "age",
targetProperty: "averageAge",
formula: "average",
},
],
countPaths: false,
})

Traversal

traverse

for (const {node, edge, depth} of gxr.traverse({ startNodeId: "A", depth: 3 })) {
console.log(node, edge, depth);
}

UI

addContextMenuItem

Add a custom menu item to the context menu.

gxr.addContextMenuItem({
name: "Find Similar",
text: "Find Similar",
icon: "iconfont icon-similar",
hide: () => false,
enable: () => true,
action: (name, nodeId, edgeId, props) => {
console.log("Finding similar to", name, nodeId, edgeId, props);
},
})

Utility

dispatchGraphDataUpdate

Force the UI to update. Sometimes necessary when using the API to update the graph.

gxr.dispatchGraphDataUpdate();

randomId

gxr.randomId() -> "lijfsleifjzlse";

sleep

gxr.sleep(1000);

snapshot

Get the graph as JSON, or apply a JSON snapshot to the current graph.

// Get snapshot
const mySnapshot = gxr.snapshot()

// Apply snapshot
gxr.snapshot(mySnapshot)

vector

gxr.vector() -> Vector3 {x: 0, y: 0, z: 0}
gxr.vector(1) -> undefined
gxr.vector(1, 2) -> Vector2 {x: 1, y: 2}
gxr.vector({x: 1, y: 2, z: 3}) -> Vector3 {x: 1, y: 2, z: 3}
gxr.vector([1, 2, 3]) -> Vector3 {x: 1, y: 2, z: 3}
gxr.vector(1, 2, 3) -> Vector3 {x: 1, y: 2, z: 3}
gxr.vector({x: 1, y: 2, z: 3, w: 4}) -> Vector4 {x: 1, y: 2, z: 3, w: 4}

User

getCurrentUser

const currentUser = gxr.getCurrentUser();
console.log(currentUser);

Undo / Redo

undo

gxr.undo();

redo

gxr.redo();

LLM

embed

// Call default embedding model with a string. Result is a vector.
const vector = await gxr.embed("Hello, world!");

// Call default embedding model with an array of strings. Result is an array of vectors.
const vector = await gxr.embed(["Hello, world!"]);

// Call local Ollama.
const vector = await gxr.embed(input, {provider: "ollama"});

// Call default embedding model configured in GraphXR backend.
const vector = await gxr.embed(input, {provider: "gxr"});

// Call a specific embedding model using the default LLM provider.
const vector = await gxr.embed(input, {provider: "gxr", model: "text-embedding-3-large"});

// Call a specific embedding model using a specific LLM provider.
const vector = await gxr.embed(input, {provider: "gxr", model: "text-embedding-3-small", llm: "my_openai"});

// Call a remote embedding model by providing config.
const vector = await gxr.embed(input, {provider: "gxr", model: "text-embedding-3-small", config: {provider: "openai", baseUrl: "https://api.openai.com/v1", apiKey: "sk-..."}})

llm

const response = await gxr.llm({
messages: [{role: 'user', content: 'Hello, how are you?'}],
});
console.log(response);

ask

const response = await gxr.ask(
'Hello, how are you?',
);
console.log(response);

const response = await gxr.ask(
JSON.stringify(gxr.nodes("[[selected]]").properties()),
{
systemPrompt: 'Summarize the context.',
},
);
console.log(response);

Chat

chat

Chat API for managing conversation threads.

// List all threads
const threads = gxr.chat.listThreads();

// Create a new thread
const newThread = gxr.chat.createThread("My Chat");

// Get messages from current thread
const messages = gxr.chat.getCurrentThread().messages;

// Add a message to the current thread
gxr.chat.addMessage(gxr.chat.getCurrentThreadId(), {
id: Date.now().toString(),
content: "Hello, AI!",
role: "user",
timestamp: Date.now()
});

getDatabaseSchema

Get schema from the connected database. Returns null if no database schema is available.

const schema = gxr.getDatabaseSchema();
if (schema) {
console.log(schema.nodes); // [{label: "Person", properties: [...]}]
console.log(schema.relationships); // [{label: "KNOWS", sourceNodeLabel: "Person", targetNodeLabel: "Person", properties: [...]}]
}

database

Database operation APIs

// Get database schema
const schema = await gxr.database.getSchema();

// Execute query
const results = await gxr.database.query("MATCH (n:Person) RETURN n LIMIT 10");

Info Panel

showNodeInfoPanel

gxr.showNodeInfoPanel("A");

showEdgeInfoPanel

gxr.showEdgeInfoPanel("AB");

Tour

driver

A wrapper for driver.js.

Example 1

// Create a simple tutorial with multiple steps
// The 'element' option accepts: CSS selector string, HTMLElement, or function
const tutorial = gxr.driver.createTutorial({
id: 'my-tutorial',
showProgress: true,
allowClose: true,
steps: [
{
element: '#menu-project', // CSS selector string
title: 'Project Menu',
description: 'Click here to open the project menu',
side: 'left',
align: 'start',
advanceOnError: true,
},
{
element: '.tour-extensions', // CSS selector string
title: 'Extension Tab',
description: 'Click here to view extensions',
side: 'top',
align: 'start',
advanceOnError: true,
},
],
});

// Run the tutorial
gxr.driver.runTutorial(tutorial);

Example 2

// All steps automatically use clickable proxies (transparent to user)
// Use a function for custom element finding
const tutorial = gxr.driver.createTutorial({
id: 'button-tutorial',
steps: [
{
element: (doc) => doc.querySelector('.my-button'), // Function
proxyId: 'my-button-proxy', // Optional: custom proxy ID
title: 'Click This Button',
description: 'Click the button to continue',
autoAdvance: false,
finishOnComplete: true,
},
],
});

gxr.driver.runTutorial(tutorial);

Example 3

// Create a tutorial with custom element finder (for iframes, etc.)
const findMyElement = (doc) => {
const iframe = doc.querySelector('iframe.share-extension-iframe');
const iframeDoc = iframe?.contentDocument || iframe?.contentWindow?.document;
return iframeDoc?.querySelector('.target-element') || null;
};

const tutorial = gxr.driver.createTutorial({
id: 'custom-finder-tutorial',
steps: [
{
element: findMyElement, // Custom function
title: 'Custom Element',
description: 'This element is found using a custom function',
},
],
});

gxr.driver.runTutorial(tutorial);

Path Finding

dijkstra

// Find the shortest path between nodes A and B, and select the nodes in the path
const paths = gxr.dijkstra("A", "B");
gxr.graph(paths).nodes().select()

yens

// Find k shortest paths between nodes A and B, and select the nodes in the paths
const paths = gxr.yens("A", "B");
gxr.graph(paths).nodes().select()

Canvas

isCanvasLoaded

gxr.isCanvasLoaded();

onCanvasLoaded

gxr.onCanvasLoaded(() => {
console.log("Canvas loaded");
});

screenshot

Take a screenshot of the graph canvas

// Basic usage - frames all nodes and captures canvas only (no UI panels)
const blob = await gxr.screenshot();

// Capture full UI including panels and legends
const blob = await gxr.screenshot({
frameNodes: true,
hidePanels: false,
includeLegends: true,
format: 'png',
quality: 1.0
});

// Canvas-only screenshot without framing, with legends included
const blob = await gxr.screenshot({
frameNodes: false,
hidePanels: true,
includeLegends: true,
format: 'jpeg',
quality: 0.8
});

// Canvas-only screenshot without legends
const blob = await gxr.screenshot({
frameNodes: false,
hidePanels: true,
includeLegends: false,
format: 'jpeg',
quality: 0.8
});

// Download the screenshot
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'graph-screenshot.png';
link.click();
URL.revokeObjectURL(url);

Workspace

workspace

Workspace API for managing panel registrations and state.

// Register a panel
gxr.workspace.registerPanel({
id: "transform.extract",
target: "transform",
title: "Extract",
render: () => <ExtractPanel />
});

// Get panels for a target
const transformPanels = gxr.workspace.usePanelsByTarget('transform');

// Get a specific registration
const reg = gxr.workspace.getPanelRegistration('transform.extract');

export function getGxrApi()

React hook to access the GxrApi. Use this in React components to get a type-safe reference to the gxr object.

function MyComponent() {
const gxr = getGxrApi();
const panels = gxr.workspace.usePanelsByTarget('transform');
// ...
}