Skip to content

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

EventTriggerEvent Data
graph-settledLayout finished{ settled: boolean }
data-loadedInitial data loaded{ nodeCount, edgeCount }
data-addedIncremental data added{ nodes, edges }
selection-changedNode selected/deselected{ node, previousNode }
camera-state-changedCamera moved{ state }
style-changedStyles updated{ layers }
node-clickUser clicked node{ node, data, event }
node-hoverMouse entered node{ node, data }
node-drag-startStarted dragging node{ node, position }
node-drag-endFinished dragging node{ node, position }
edge-clickUser clicked edge{ edge, data, event }
errorError 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' fires

Removing 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>

Interactive Examples