G6 provides comprehensive APIs for managing graph data with support for incremental updates, relationship queries, and data transformations. The system handles nodes, edges, and combos with efficient CRUD operations and relationship traversal.
import type {
GraphData,
NodeData,
EdgeData,
ComboData,
ID,
ElementDatum,
PartialGraphData
} from '@antv/g6';
interface GraphData {
nodes?: NodeData[]; // Node definitions
edges?: EdgeData[]; // Edge definitions
combos?: ComboData[]; // Combo definitions
}
interface NodeData {
id: ID; // Unique identifier
type?: string; // Node type
data?: Record<string, unknown>; // Custom properties
style?: NodeStyle; // Visual style overrides
states?: State[]; // Applied states
combo?: ID | null; // Parent combo
children?: ID[]; // Child nodes (tree mode)
}
interface EdgeData {
id?: ID; // Optional unique identifier
source: ID; // Source node ID
target: ID; // Target node ID
type?: string; // Edge type
data?: Record<string, unknown>; // Custom properties
style?: EdgeStyle; // Visual style overrides
states?: State[]; // Applied states
}
interface ComboData {
id: ID; // Unique identifier
type?: string; // Combo type
data?: Record<string, unknown>; // Custom properties
style?: ComboStyle; // Visual style overrides
states?: State[]; // Applied states
combo?: ID | null; // Parent combo (nested)
children?: ID[]; // Child elements
}import { Graph } from '@antv/g6';
// Initialize graph with data
const graph = new Graph({
data: {
nodes: [
{
id: 'node1',
data: { name: 'Alice', department: 'Engineering' },
style: { x: 100, y: 100, fill: '#1890ff' }
},
{
id: 'node2',
data: { name: 'Bob', department: 'Marketing' },
style: { x: 300, y: 200, fill: '#52c41a' }
}
],
edges: [
{
source: 'node1',
target: 'node2',
data: { relationship: 'colleague', weight: 0.8 }
}
],
combos: [
{
id: 'team1',
data: { name: 'Alpha Team' },
children: ['node1', 'node2']
}
]
}
});
// Set data after initialization
graph.setData({
nodes: newNodeData,
edges: newEdgeData,
combos: newComboData
});// Get complete graph data
const completeData: Required<GraphData> = graph.getData();
// Get specific element data by ID
const nodeData = graph.getElementData('node1');
const multipleElements = graph.getElementData(['node1', 'edge1', 'combo1']);
// Type-specific data retrieval
const allNodes = graph.getNodeData();
const specificNode = graph.getNodeData('node1');
const multipleNodes = graph.getNodeData(['node1', 'node2']);
const allEdges = graph.getEdgeData();
const specificEdge = graph.getEdgeData('edge1');
const allCombos = graph.getComboData();
const specificCombo = graph.getComboData('combo1');// Add complete graph data (incremental)
await graph.addData({
nodes: [
{
id: 'newNode',
data: { name: 'Charlie', role: 'Manager' },
style: { x: 200, y: 150 }
}
],
edges: [
{
source: 'node1',
target: 'newNode',
data: { type: 'reports-to' }
}
]
});
// Add type-specific data
await graph.addNodeData([
{
id: 'node3',
data: { name: 'Diana', department: 'HR' },
style: { x: 400, y: 250 }
},
{
id: 'node4',
data: { name: 'Eve', department: 'Finance' },
style: { x: 150, y: 300 }
}
]);
await graph.addEdgeData([
{ source: 'node2', target: 'node3' },
{ source: 'node3', target: 'node4', data: { weight: 0.9 } }
]);
await graph.addComboData([
{
id: 'team2',
data: { name: 'Beta Team' },
children: ['node3', 'node4']
}
]);
// Add child nodes to tree structures
await graph.addChildrenData('parentNode', [
{
id: 'child1',
data: { name: 'Child 1' },
style: { fill: '#faad14' }
},
{
id: 'child2',
data: { name: 'Child 2' },
style: { fill: '#f759ab' }
}
]);import type {
PartialNodeLikeData,
PartialEdgeData
} from '@antv/g6';
// Update complete graph data (partial)
await graph.updateData({
nodes: [
{
id: 'node1',
data: { department: 'Senior Engineering' },
style: { fill: '#722ed1' }
}
],
edges: [
{
source: 'node1',
target: 'node2',
style: { stroke: '#ff4d4f', lineWidth: 3 }
}
]
});
// Type-specific updates
await graph.updateNodeData([
{
id: 'node1',
data: { lastLogin: new Date(), status: 'active' },
style: { size: 25 }
},
{
id: 'node2',
style: { x: 350, y: 220 } // Update position
}
]);
await graph.updateEdgeData([
{
source: 'node1',
target: 'node2',
data: { lastInteraction: Date.now() },
style: { lineWidth: 2 }
}
]);
await graph.updateComboData([
{
id: 'team1',
data: { budget: 500000, members: 5 },
style: { fill: '#e6f7ff' }
}
]);import type { DataID } from '@antv/g6';
// Remove elements by ID (mixed types)
await graph.removeData(['node1', 'edge1', 'combo1']);
// Type-specific removal
await graph.removeNodeData(['node2', 'node3']);
await graph.removeEdgeData(['edge1', 'edge2']);
await graph.removeComboData(['combo1']);
// Cascade removal (removes connected edges automatically)
await graph.removeNodeData(['node1']); // Also removes connected edgesimport type { ElementType, EdgeDirection, HierarchyKey } from '@antv/g6';
// Get element type
const elementType: ElementType = graph.getElementType('node1'); // 'node' | 'edge' | 'combo'
// Get related edges
const allRelatedEdges = graph.getRelatedEdgesData('node1');
const incomingEdges = graph.getRelatedEdgesData('node1', 'in');
const outgoingEdges = graph.getRelatedEdgesData('node1', 'out');
// Get neighbor nodes (directly connected)
const neighbors = graph.getNeighborNodesData('node1');// Get parent element in combo hierarchy
const parentCombo = graph.getParentData('node1', 'combo');
// Get all ancestors (up the hierarchy)
const ancestors = graph.getAncestorsData('node1', 'combo');
// Get direct children
const children = graph.getChildrenData('combo1');
// Get all descendants (down the hierarchy)
const descendants = graph.getDescendantsData('combo1');
// Tree-specific relationships (for tree graphs)
const treeParent = graph.getParentData('node1', 'tree');
const treeAncestors = graph.getAncestorsData('node1', 'tree');import type { State } from '@antv/g6';
// Get elements by state
const selectedNodes = graph.getElementDataByState('node', 'selected');
const hoveredEdges = graph.getElementDataByState('edge', 'hover');
const activeCombos = graph.getElementDataByState('combo', 'active');
// Multi-state queries
const highlightedElements = graph.getElementDataByState('node', 'highlight');import { treeToGraphData } from '@antv/g6';
// Convert hierarchical tree data to graph format
interface TreeData {
id: string;
children?: TreeData[];
[key: string]: any;
}
const treeData: TreeData = {
id: 'root',
name: 'CEO',
children: [
{
id: 'manager1',
name: 'Engineering Manager',
children: [
{ id: 'dev1', name: 'Developer 1' },
{ id: 'dev2', name: 'Developer 2' }
]
},
{
id: 'manager2',
name: 'Marketing Manager',
children: [
{ id: 'marketing1', name: 'Marketing Specialist' }
]
}
]
};
// Convert to G6 graph data format
const graphData: GraphData = treeToGraphData(treeData, {
childrenKey: 'children', // Key for children array
addEdges: true, // Add parent-child edges
edgeType: 'line' // Edge type for connections
});
await graph.setData(graphData);import { idOf, positionOf, isCollapsed } from '@antv/g6';
// Extract element ID safely
const nodeId = idOf(nodeData); // Gets ID from NodeData
const edgeId = idOf(edgeData); // Gets ID from EdgeData
// Extract position from node-like data
const position = positionOf(nodeData); // Returns [x, y] or undefined
// Check collapse state (for tree nodes and combos)
const collapsed = isCollapsed(nodeData);
const comboCollapsed = isCollapsed(comboData);
// Utility for custom data processing
const processData = (data: GraphData) => {
return {
nodes: data.nodes?.map(node => ({
...node,
data: {
...node.data,
processed: true,
timestamp: Date.now()
}
})),
edges: data.edges?.map(edge => ({
...edge,
data: {
...edge.data,
weight: edge.data?.weight || 1
}
}))
};
};// Efficient batch updates
const batchUpdates = await Promise.all([
graph.updateNodeData([
{ id: 'node1', style: { fill: 'red' } },
{ id: 'node2', style: { fill: 'blue' } }
]),
graph.updateEdgeData([
{ source: 'node1', target: 'node2', style: { stroke: 'green' } }
])
]);
// Batch data retrieval
const [nodes, edges, combos] = await Promise.all([
graph.getNodeData(),
graph.getEdgeData(),
graph.getComboData()
]);// Filter data based on custom criteria
const engineeringNodes = graph.getNodeData().filter(
node => node.data?.department === 'Engineering'
);
const strongConnections = graph.getEdgeData().filter(
edge => (edge.data?.weight || 0) > 0.7
);
// Get data for specific element sets
const specificElements = ['node1', 'node2', 'combo1'];
const elementData = specificElements.map(id => graph.getElementData(id));
// Conditional data operations
const updateActiveNodes = async () => {
const activeNodes = graph.getElementDataByState('node', 'active');
const updates = activeNodes.map(node => ({
id: node.id,
data: { ...node.data, lastActive: Date.now() }
}));
await graph.updateNodeData(updates);
};// Load data from external sources
const loadGraphData = async (source: string) => {
const response = await fetch(source);
const data = await response.json();
// Transform external data format to G6 format
const graphData: GraphData = {
nodes: data.vertices?.map((vertex: any) => ({
id: vertex.id,
data: vertex.properties,
style: { x: vertex.x, y: vertex.y }
})),
edges: data.connections?.map((conn: any) => ({
source: conn.from,
target: conn.to,
data: conn.attributes
}))
};
await graph.setData(graphData);
};
// Real-time data updates
const subscribeToDataUpdates = (websocket: WebSocket) => {
websocket.onmessage = async (event) => {
const update = JSON.parse(event.data);
switch (update.type) {
case 'nodeAdded':
await graph.addNodeData([update.data]);
break;
case 'nodeUpdated':
await graph.updateNodeData([update.data]);
break;
case 'nodeRemoved':
await graph.removeNodeData([update.id]);
break;
}
};
};// Use incremental updates instead of full replacement
// ❌ Inefficient - full data replacement
await graph.setData(newCompleteData);
// ✅ Efficient - incremental updates
await graph.addNodeData(newNodes);
await graph.updateNodeData(modifiedNodes);
await graph.removeNodeData(removedNodeIds);
// Batch similar operations
const updates = changedNodes.map(node => ({ id: node.id, ...node.changes }));
await graph.updateNodeData(updates);
// Use specific data getters when possible
// ❌ Less efficient
const allData = graph.getData();
const targetNode = allData.nodes.find(n => n.id === 'target');
// ✅ More efficient
const targetNode = graph.getNodeData('target');// Clean up large datasets
const cleanupData = () => {
// Remove unused custom data
const nodes = graph.getNodeData().map(node => ({
...node,
data: Object.fromEntries(
Object.entries(node.data || {}).filter(([key]) =>
['name', 'type', 'priority'].includes(key) // Keep only essential data
)
)
}));
graph.updateNodeData(nodes);
};
// Implement data pagination for large graphs
const loadDataPage = async (page: number, pageSize: number) => {
const startIndex = page * pageSize;
const endIndex = startIndex + pageSize;
const pageData = fullDataset.slice(startIndex, endIndex);
await graph.addData(pageData);
};type ID = string | number;
type State = string;
interface PartialGraphData {
nodes?: PartialNodeLikeData<NodeData>[];
edges?: PartialEdgeData<EdgeData>[];
combos?: PartialNodeLikeData<ComboData>[];
}
interface PartialNodeLikeData<T> {
id: ID;
type?: string;
data?: Partial<T['data']>;
style?: Partial<T['style']>;
states?: State[];
[key: string]: any;
}
interface PartialEdgeData<T> {
source?: ID;
target?: ID;
id?: ID;
type?: string;
data?: Partial<T['data']>;
style?: Partial<T['style']>;
states?: State[];
}
type ElementDatum = NodeData | EdgeData | ComboData;
type NodeLikeData = NodeData | ComboData;
type ElementType = 'node' | 'edge' | 'combo';
type EdgeDirection = 'in' | 'out' | 'both';
type HierarchyKey = 'combo' | 'tree';
type DataID = ID | ID[];
// Utility type for data retrieval overloads
interface DataRetrieval {
getNodeData(): NodeData[];
getNodeData(id: ID): NodeData | undefined;
getNodeData(ids: ID[]): NodeData[];
getEdgeData(): EdgeData[];
getEdgeData(id: ID): EdgeData | undefined;
getEdgeData(ids: ID[]): EdgeData[];
getComboData(): ComboData[];
getComboData(id: ID): ComboData | undefined;
getComboData(ids: ID[]): ComboData[];
}