Graph theory library for analysis and visualisation of network data with interactive rendering capabilities
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Rich event system supporting user interactions, element lifecycle events, viewport changes, and custom events with delegation, namespacing, and promise-based handling.
Bind event handlers to core instance and element collections.
interface Core {
/**
* Bind event handler
* @param events - Space-separated event names
* @param selector - Optional element selector for delegation
* @param handler - Event handler function
* @returns Core instance for chaining
*/
on(events: string, selector?: string, handler?: EventHandler): Core;
on(events: string, handler: EventHandler): Core;
/**
* Bind one-time event handler
* @param events - Space-separated event names
* @param selector - Optional element selector for delegation
* @param handler - Event handler function
* @returns Core instance for chaining
*/
one(events: string, selector?: string, handler?: EventHandler): Core;
one(events: string, handler: EventHandler): Core;
/**
* Unbind event handler
* @param events - Event names (optional, unbinds all if not specified)
* @param selector - Element selector (optional)
* @param handler - Handler function (optional, unbinds all matching if not specified)
* @returns Core instance for chaining
*/
off(events?: string, selector?: string, handler?: EventHandler): Core;
off(events?: string, handler?: EventHandler): Core;
/**
* Trigger event
* @param events - Space-separated event names
* @param extraParams - Additional parameters to pass to handlers
* @returns Core instance for chaining
*/
emit(events: string, extraParams?: any[]): Core;
/**
* Promise-based event binding (resolves on first event)
* @param events - Space-separated event names
* @returns Promise that resolves when event occurs
*/
pon(events: string): Promise<Event>;
/**
* Remove event listener (alias for off)
* @param events - Event names
* @param selector - Element selector
* @param handler - Handler function
* @returns Core instance for chaining
*/
removeListener(events?: string, selector?: string, handler?: EventHandler): Core;
}
interface Collection {
/**
* Bind event handler to collection elements
* @param events - Space-separated event names
* @param handler - Event handler function
* @returns Collection for chaining
*/
on(events: string, handler: EventHandler): Collection;
/**
* Bind one-time event handler
* @param events - Space-separated event names
* @param handler - Event handler function
* @returns Collection for chaining
*/
one(events: string, handler: EventHandler): Collection;
/**
* Unbind event handler
* @param events - Event names (optional)
* @param handler - Handler function (optional)
* @returns Collection for chaining
*/
off(events?: string, handler?: EventHandler): Collection;
/**
* Trigger event on collection elements
* @param events - Space-separated event names
* @param extraParams - Additional parameters
* @returns Collection for chaining
*/
trigger(events: string, extraParams?: any[]): Collection;
/**
* Promise-based event binding
* @param events - Space-separated event names
* @returns Promise that resolves when event occurs
*/
pon(events: string): Promise<Event>;
}
interface EventHandler {
(event: Event): void;
}Event object passed to event handlers contains contextual information.
interface Event {
/**
* Element that triggered the event
*/
target: Collection;
/**
* Event type name
*/
type: string;
/**
* Model position where event occurred
*/
position: Position;
/**
* Rendered (screen) position where event occurred
*/
renderedPosition: Position;
/**
* Cytoscape instance
*/
cy: Core;
/**
* Original browser event (for user events)
*/
originalEvent?: MouseEvent | TouchEvent | KeyboardEvent;
/**
* Namespace for the event
*/
namespace?: string;
/**
* Additional data passed with event
*/
data?: any;
/**
* Timestamp when event occurred
*/
timeStamp: number;
}Events triggered by user interactions with mouse, touch, and keyboard.
/**
* Mouse events
*/
type MouseEventType =
| "mousedown" // Mouse button pressed
| "mouseup" // Mouse button released
| "click" // Mouse click
| "dblclick" // Double click
| "mouseover" // Mouse enters element
| "mouseout" // Mouse leaves element
| "mousemove" // Mouse moves over element
| "rightclick"; // Right mouse button click
/**
* Touch events
*/
type TouchEventType =
| "touchstart" // Touch begins
| "touchmove" // Touch moves
| "touchend"; // Touch ends
/**
* Normalized gesture events (work for both mouse and touch)
*/
type GestureEventType =
| "tap" // Single tap/click
| "tapstart" // Tap/click begins
| "tapend" // Tap/click ends
| "tapdrag" // Drag during tap
| "taphold" // Long press/hold
| "cxttap"; // Context tap (right-click or long tap)
/**
* Keyboard events
*/
type KeyboardEventType =
| "keydown" // Key pressed down
| "keyup" // Key released
| "keypress"; // Key pressed and releasedUsage Examples:
// Basic click handler
cy.on('tap', 'node', function(evt) {
const node = evt.target;
console.log('Tapped node:', node.id());
console.log('Position:', evt.position);
});
// Mouse hover effects
cy.on('mouseover', 'node', function(evt) {
evt.target.style('background-color', 'red');
});
cy.on('mouseout', 'node', function(evt) {
evt.target.removeStyle('background-color');
});
// Touch handling
cy.on('taphold', 'node', function(evt) {
console.log('Node held for long press');
});
// Keyboard shortcuts
cy.on('keydown', function(evt) {
if (evt.originalEvent.key === 'Delete') {
cy.$(':selected').remove();
}
});Events related to element lifecycle and state changes.
/**
* Lifecycle events
*/
type LifecycleEventType =
| "add" // Element added to graph
| "remove" // Element removed from graph
| "move"; // Element moved to different location
/**
* Selection events
*/
type SelectionEventType =
| "select" // Element selected programmatically
| "unselect" // Element unselected programmatically
| "tapselect" // Element selected by user tap
| "tapunselect" // Element unselected by user tap
| "boxselect" // Elements selected by box selection
| "boxunselect"; // Elements unselected by box selection
/**
* Interaction events
*/
type InteractionEventType =
| "grab" // Node grabbed for dragging
| "drag" // Node being dragged
| "free" // Node released from dragging
| "lock" // Node locked (position fixed)
| "unlock"; // Node unlocked
/**
* Data events
*/
type DataEventType =
| "data" // Element data changed
| "scratch" // Element scratch data changed
| "style" // Element style changed
| "position"; // Element position changed
/**
* Class events
*/
type ClassEventType =
| "class"; // Element classes changedUsage Examples:
// Handle element additions
cy.on('add', 'node', function(evt) {
const node = evt.target;
console.log('Node added:', node.id());
// Apply default styling to new nodes
node.style('background-color', '#666');
});
// Track selection changes
cy.on('select', 'node', function(evt) {
console.log('Selected:', evt.target.id());
});
cy.on('unselect', function(evt) {
console.log('Unselected:', evt.target.id());
});
// Handle dragging
cy.on('grab', 'node', function(evt) {
evt.target.style('background-color', 'red');
});
cy.on('free', 'node', function(evt) {
evt.target.removeStyle('background-color');
});
// Monitor data changes
cy.on('data', function(evt) {
console.log('Data changed on:', evt.target.id());
});Events related to the graph as a whole, including viewport and layout changes.
/**
* Viewport events
*/
type ViewportEventType =
| "pan" // Viewport panned
| "zoom" // Viewport zoomed
| "viewport"; // Viewport changed (pan or zoom)
/**
* Layout events
*/
type LayoutEventType =
| "layoutstart" // Layout started running
| "layoutready" // Layout positions calculated
| "layoutstop"; // Layout finished running
/**
* Core events
*/
type CoreEventType =
| "ready" // Graph fully initialized
| "destroy" // Graph instance destroyed
| "render" // Graph rendered/redrawn
| "resize"; // Container resizedUsage Examples:
// Handle viewport changes
cy.on('zoom', function(evt) {
console.log('Zoom level:', cy.zoom());
});
cy.on('pan', function(evt) {
console.log('Pan position:', cy.pan());
});
// Layout progress tracking
cy.on('layoutstart', function(evt) {
console.log('Layout started:', evt.layout.options.name);
// Show loading indicator
});
cy.on('layoutstop', function(evt) {
console.log('Layout finished');
// Hide loading indicator
});
// Graph initialization
cy.on('ready', function(evt) {
console.log('Graph ready');
// Perform initial setup
});Use namespaces to organize and manage event handlers.
/**
* Namespaced event syntax: "eventname.namespace"
*/
// Bind namespaced events
cy.on('tap.myPlugin', 'node', handler1);
cy.on('tap.myPlugin', 'edge', handler2);
cy.on('select.myPlugin', handler3);
// Unbind all events in namespace
cy.off('.myPlugin');
// Unbind specific namespaced event
cy.off('tap.myPlugin');
// Trigger namespaced event
cy.emit('customEvent.myNamespace');Use selectors to handle events on specific element types without binding to each element.
// Event delegation - handles all current and future nodes
cy.on('tap', 'node', function(evt) {
// This handler applies to all nodes, even ones added later
console.log('Node tapped:', evt.target.id());
});
// Multiple selectors
cy.on('tap', 'node.important, edge.highlighted', function(evt) {
console.log('Important element tapped');
});
// Complex selectors
cy.on('tap', 'node[type="user"]', function(evt) {
console.log('User node tapped');
});Use promises for one-time event handling and async workflows.
/**
* Promise-based event binding
*/
// Wait for next tap event
cy.pon('tap').then(function(evt) {
console.log('Tap occurred on:', evt.target.id());
});
// Wait for layout completion
cy.pon('layoutstop').then(function() {
console.log('Layout finished');
// Continue with next step
});
// Async/await syntax
async function waitForSelection() {
const evt = await cy.pon('select');
console.log('Selected:', evt.target.id());
return evt.target;
}
// Chain promise events
cy.pon('tap')
.then(() => cy.pon('layoutstop'))
.then(() => {
console.log('Tap and layout both completed');
});Create and trigger custom events for application-specific logic.
// Trigger custom events
cy.emit('myCustomEvent', [{ customData: 'value' }]);
// Listen for custom events
cy.on('myCustomEvent', function(evt, data) {
console.log('Custom event triggered with:', data);
});
// Element-specific custom events
const node = cy.$('#myNode');
node.trigger('nodeSpecificEvent', [{ nodeData: node.data() }]);
node.on('nodeSpecificEvent', function(evt, data) {
console.log('Node event with data:', data);
});Optimize event handling for better performance.
// Use event delegation instead of binding to many elements
// Good:
cy.on('tap', 'node', handler);
// Avoid:
cy.nodes().on('tap', handler);
// Batch event bindings
cy.batch(function() {
cy.on('tap', 'node', handler1);
cy.on('tap', 'edge', handler2);
cy.on('select', handler3);
});
// Clean up event handlers when done
function cleanup() {
cy.off('.myApp'); // Remove all namespaced handlers
}
// Throttle or debounce high-frequency events
let panTimeout;
cy.on('pan', function() {
clearTimeout(panTimeout);
panTimeout = setTimeout(function() {
// Handle pan end
console.log('Pan finished');
}, 100);
});Understand event flow and control propagation.
// Events bubble from target to parent elements
cy.on('tap', 'node', function(evt) {
console.log('Node tapped');
// Stop event from bubbling to parent
evt.stopPropagation();
});
// Core-level handler (receives all events)
cy.on('tap', function(evt) {
console.log('Something was tapped:', evt.target);
});
// Event order: specific selector handlers first, then general handlersInstall with Tessl CLI
npx tessl i tessl/npm-cytoscape