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");
Navigation
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",
})
link
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');
// ...
}