Events
Guide to subscribing to graph events.
Overview
Graphty uses an event-driven architecture. Subscribe to events for user interactions, data changes, and state updates.
Available Events
| Event | Trigger | Event Data |
|---|---|---|
graph-settled | Layout finished | { settled: boolean } |
data-loaded | Initial data loaded | { nodeCount, edgeCount } |
data-added | Incremental data added | { nodes, edges } |
selection-changed | Node selected/deselected | { node, previousNode } |
camera-state-changed | Camera moved | { state } |
style-changed | Styles updated | { layers } |
node-click | User clicked node | { node, data, event } |
node-hover | Mouse entered node | { node, data } |
node-drag-start | Started dragging node | { node, position } |
node-drag-end | Finished dragging node | { node, position } |
edge-click | User clicked edge | { edge, data, event } |
error | Error occurred | { error, context } |
JavaScript API
Subscribe using the on() method on the Graph instance:
typescript
const graph = element.graph;
// Layout complete
graph.on('graph-settled', () => {
console.log('Layout complete!');
graph.zoomToFit();
});
// Node clicked
graph.on('node-click', ({ node }) => {
console.log('Clicked:', node.id);
graph.selectNode(node.id);
});
// Node hover
graph.on('node-hover', ({ node }) => {
console.log('Hovering:', node.id);
});
// Node drag events
graph.on('node-drag-start', ({ node, position }) => {
console.log('Started dragging:', node.id, 'at', position);
});
graph.on('node-drag-end', ({ node, position }) => {
console.log('Finished dragging:', node.id, 'at', position);
});
// Selection changed
graph.on('selection-changed', ({ node, previousNode }) => {
if (node) {
console.log('Selected:', node.id);
} else {
console.log('Deselected');
}
});
// Data loaded
graph.on('data-loaded', ({ nodeCount, edgeCount }) => {
console.log(`Loaded ${nodeCount} nodes, ${edgeCount} edges`);
});
// Error handling
graph.on('error', ({ error, context }) => {
console.error('Graph error:', error, 'in', context);
});DOM Events
Listen via standard addEventListener on the Web Component:
javascript
const element = document.querySelector('graphty-element');
element.addEventListener('graph-settled', (e) => {
console.log('Settled!', e.detail);
});
element.addEventListener('node-click', (e) => {
console.log('Clicked node:', e.detail.node);
});
element.addEventListener('selection-changed', (e) => {
const { node, previousNode } = e.detail;
console.log('Selection:', node?.id, 'Previous:', previousNode?.id);
});Event Timing
Some events fire asynchronously. Understand the order:
typescript
// Data loading sequence
graph.on('data-loaded', () => console.log('1. Data loaded'));
graph.on('graph-settled', () => console.log('2. Layout settled'));
// When you add data
await graph.addNodes(nodes); // 'data-loaded' or 'data-added' fires
await graph.addEdges(edges);
await graph.waitForSettled(); // 'graph-settled' firesRemoving Listeners
Clean up event listeners when done:
typescript
// JavaScript API
const handler = () => console.log('Settled');
graph.on('graph-settled', handler);
// Later, remove it
graph.off('graph-settled', handler);javascript
// DOM API
const handler = (e) => console.log('Settled', e.detail);
element.addEventListener('graph-settled', handler);
// Later, remove it
element.removeEventListener('graph-settled', handler);Common Patterns
Zoom After Layout
typescript
graph.on('graph-settled', () => {
graph.zoomToFit();
});Show Node Details
typescript
graph.on('node-click', ({ node }) => {
showDetailsPanel(node);
graph.selectNode(node.id);
});
graph.on('selection-changed', ({ node }) => {
if (!node) {
hideDetailsPanel();
}
});Track Node Dragging
typescript
graph.on('node-drag-start', ({ node, position }) => {
console.log(`Started dragging ${node.id} at`, position);
});
graph.on('node-drag-end', ({ node, position }) => {
console.log(`Dropped ${node.id} at`, position);
// Save new position or trigger layout update
});Loading Indicator
typescript
let isLoading = false;
graph.on('data-added', () => {
isLoading = true;
showLoadingSpinner();
});
graph.on('graph-settled', () => {
if (isLoading) {
isLoading = false;
hideLoadingSpinner();
}
});Error Handling
typescript
graph.on('error', ({ error, context }) => {
if (context === 'data-loading') {
showError('Failed to load data');
} else if (context === 'algorithm') {
showError('Algorithm failed');
} else {
showError('An error occurred');
}
console.error(error);
});Camera Tracking
typescript
graph.on('camera-state-changed', ({ state }) => {
// Save camera state for later restoration
localStorage.setItem('camera-state', JSON.stringify(state));
});
// Restore on load
const savedState = localStorage.getItem('camera-state');
if (savedState) {
graph.setCameraState(JSON.parse(savedState));
}React Integration
tsx
import { useEffect, useRef } from 'react';
import '@graphty/graphty-element';
function GraphComponent({ onNodeClick }) {
const graphRef = useRef(null);
useEffect(() => {
const element = graphRef.current;
if (!element) return;
const graph = element.graph;
const handleClick = ({ node }) => {
onNodeClick(node);
};
graph.on('node-click', handleClick);
return () => {
graph.off('node-click', handleClick);
};
}, [onNodeClick]);
return <graphty-element ref={graphRef} />;
}Vue Integration
vue
<script setup>
import '@graphty/graphty-element';
import { ref, onMounted, onUnmounted } from 'vue';
const graphRef = ref(null);
const emit = defineEmits(['nodeClick']);
let cleanup = null;
onMounted(() => {
const graph = graphRef.value.graph;
const handler = ({ node }) => emit('nodeClick', node);
graph.on('node-click', handler);
cleanup = () => graph.off('node-click', handler);
});
onUnmounted(() => {
if (cleanup) cleanup();
});
</script>
<template>
<graphty-element ref="graphRef" />
</template>