G6's behavior system provides a comprehensive set of interactive behaviors for graph manipulation. Behaviors handle user input events and translate them into graph operations with extensive customization options.
import { Graph } from '@antv/g6';
import type { BehaviorOptions, UpdateBehaviorOption } from '@antv/g6';
// Simple behavior configuration
const graph = new Graph({
behaviors: [
'drag-canvas', // String-based configuration
'zoom-canvas',
'drag-element'
]
});
// Advanced behavior configuration
const graph = new Graph({
behaviors: [
{
key: 'drag-canvas-custom',
type: 'drag-canvas',
enable: true,
direction: 'both'
},
{
key: 'selective-drag',
type: 'drag-element',
enable: (event) => event.targetType === 'node'
}
]
});// Update behaviors at runtime
graph.setBehaviors([
'drag-canvas',
'zoom-canvas',
{ key: 'hover', type: 'hover-activate' }
]);
// Update specific behavior
graph.updateBehavior({
key: 'drag-canvas',
enable: false
});
// Get current behaviors
const behaviors = graph.getBehaviors();import type {
DragCanvasOptions,
ViewportAnimationEffectTiming,
ShortcutKey
} from '@antv/g6';
// Drag Canvas Behavior
interface DragCanvasOptions {
animation?: ViewportAnimationEffectTiming;
enable?: boolean | ((event: any) => boolean);
direction?: 'x' | 'y' | 'both';
range?: number | number[]; // Draggable viewport range
trigger?: { // Keyboard triggers
up: ShortcutKey;
down: ShortcutKey;
left: ShortcutKey;
right: ShortcutKey;
};
sensitivity?: number; // Key movement distance
onFinish?: () => void; // Completion callback
}
const dragCanvasBehavior = {
key: 'drag-canvas',
type: 'drag-canvas',
direction: 'both',
range: [-1000, -1000, 1000, 1000],
trigger: {
up: ['ArrowUp'],
down: ['ArrowDown'],
left: ['ArrowLeft'],
right: ['ArrowRight']
},
sensitivity: 10,
onFinish: () => console.log('Canvas drag completed')
};
// Zoom Canvas Behavior
const zoomCanvasBehavior = {
key: 'zoom-canvas',
type: 'zoom-canvas',
enable: true,
sensitivity: 0.5,
optimizeByTimeSlice: true,
trigger: {
zoomIn: ['Control', '='],
zoomOut: ['Control', '-'],
reset: ['Control', '0']
}
};
// Scroll Canvas Behavior
const scrollCanvasBehavior = {
key: 'scroll-canvas',
type: 'scroll-canvas',
enable: true,
direction: 'both',
sensitivity: 1
};// Drag Element Behavior
const dragElementBehavior = {
key: 'drag-element',
type: 'drag-element',
enable: (event) => {
// Only allow dragging nodes
return event.targetType === 'node';
},
animation: {
duration: 200,
easing: 'ease-out'
},
shadow: true, // Show drag shadow
updateRelatedEdge: true, // Update connected edges
onStart: (event) => console.log('Drag started'),
onDrag: (event) => console.log('Dragging'),
onEnd: (event) => console.log('Drag ended')
};
// Drag Element Force Behavior (for force-directed layouts)
const dragElementForceBehavior = {
key: 'drag-element-force',
type: 'drag-element-force',
damping: 0.9, // Damping factor for physics
maxSpeed: 1000, // Maximum drag speed
minMovement: 0.5 // Minimum movement threshold
};
// Hover Activate Behavior
const hoverActivateBehavior = {
key: 'hover-activate',
type: 'hover-activate',
enable: true,
activateState: 'hover', // State to apply on hover
inactiveState: 'default', // State to apply when not hovering
onHover: (event) => console.log('Element hovered'),
onUnhover: (event) => console.log('Element unhovered')
};// Click Select Behavior
const clickSelectBehavior = {
key: 'click-select',
type: 'click-select',
enable: true,
multiple: true, // Allow multiple selection
selectState: 'selected', // State for selected elements
unselectState: 'default', // State for unselected elements
trigger: 'click', // 'click' | 'dblclick'
onSelect: (event) => console.log('Element selected'),
onUnselect: (event) => console.log('Element unselected')
};
// Brush Select Behavior
const brushSelectBehavior = {
key: 'brush-select',
type: 'brush-select',
enable: true,
trigger: 'drag', // 'drag' | 'shift+drag'
mode: 'intersect', // 'intersect' | 'contain'
selectState: 'selected',
brushStyle: {
fill: '#EBF2FF',
stroke: '#DEEAFF',
lineWidth: 1
},
onStart: (event) => console.log('Brush started'),
onEnd: (event) => console.log('Brush ended')
};
// Lasso Select Behavior
const lassoSelectBehavior = {
key: 'lasso-select',
type: 'lasso-select',
enable: true,
trigger: 'shift+drag',
selectState: 'selected',
lassoStyle: {
stroke: '#1890FF',
lineWidth: 2,
lineDash: [5, 5]
}
};import type { CollapseExpandNodeOptions } from '@antv/g6';
// Collapse Expand Behavior
const collapseExpandBehavior = {
key: 'collapse-expand',
type: 'collapse-expand',
enable: true,
trigger: 'dblclick', // 'click' | 'dblclick'
animate: true,
duration: 300,
onCollapse: (event) => console.log('Node collapsed'),
onExpand: (event) => console.log('Node expanded')
};
// Focus Element Behavior
const focusElementBehavior = {
key: 'focus-element',
type: 'focus-element',
enable: true,
trigger: 'dblclick',
animation: {
duration: 500,
easing: 'ease-in-out'
},
scaleRatio: 1.2 // Scale factor when focusing
};// Create Edge Behavior
const createEdgeBehavior = {
key: 'create-edge',
type: 'create-edge',
enable: true,
trigger: 'shift+drag', // Activation trigger
edgeConfig: {
type: 'line',
style: {
stroke: '#1890FF',
lineWidth: 2,
lineDash: [5, 5] // Preview edge style
}
},
onCreate: (event) => console.log('Edge created'),
onCancel: (event) => console.log('Edge creation cancelled')
};
// Auto Adapt Label Behavior
const autoAdaptLabelBehavior = {
key: 'auto-adapt-label',
type: 'auto-adapt-label',
enable: true,
minZoom: 0.5, // Minimum zoom to show labels
maxZoom: 3, // Maximum zoom to show labels
hideRatio: 0.3, // Hide labels when zoom < hideRatio
showRatio: 0.7 // Show labels when zoom > showRatio
};
// Fix Element Size Behavior
const fixElementSizeBehavior = {
key: 'fix-element-size',
type: 'fix-element-size',
enable: true,
fixAll: false, // Fix all elements or just nodes
fixLineWidth: true, // Fix line width during zoom
fixLabel: true // Fix label size during zoom
};
// Optimize Viewport Transform Behavior
const optimizeViewportBehavior = {
key: 'optimize-viewport-transform',
type: 'optimize-viewport-transform',
enable: true,
hideEdge: true, // Hide edges during transform
hideLabel: true, // Hide labels during transform
threshold: 16 // Animation frame threshold
};import { BaseBehavior } from '@antv/g6';
import type { BehaviorOptions } from '@antv/g6';
class CustomBehavior extends BaseBehavior {
static defaultOptions: Partial<BehaviorOptions> = {
enable: true,
sensitivity: 1
};
constructor(options: BehaviorOptions) {
super(options);
}
onEnable(): void {
// Setup event listeners
this.bindEvents({
'node:click': this.onNodeClick,
'edge:hover': this.onEdgeHover
});
}
onDisable(): void {
// Remove event listeners
this.unbindEvents();
}
private onNodeClick = (event: any) => {
console.log('Custom node click behavior', event);
// Custom logic here
};
private onEdgeHover = (event: any) => {
console.log('Custom edge hover behavior', event);
// Custom logic here
};
}
// Register custom behavior
import { register } from '@antv/g6';
register('behavior', 'custom-behavior', CustomBehavior);
// Use custom behavior
const graph = new Graph({
behaviors: [
{
key: 'my-custom-behavior',
type: 'custom-behavior',
sensitivity: 2
}
]
});// Event binding patterns in behaviors
class ExampleBehavior extends BaseBehavior {
onEnable(): void {
// Single event binding
this.bindEvents({
'node:click': this.handleNodeClick
});
// Multiple event binding
this.bindEvents({
'node:mouseenter': this.handleMouseEnter,
'node:mouseleave': this.handleMouseLeave,
'canvas:drag': this.handleCanvasDrag
});
// Conditional event binding
if (this.options.enableKeyboard) {
this.bindEvents({
'key:down': this.handleKeyDown
});
}
}
private handleNodeClick = (event: any) => {
// Access graph instance
const graph = this.context.graph;
// Access event properties
const { target, targetType, client } = event;
// Conditional behavior execution
if (!this.options.enable(event)) return;
// Behavior logic here
};
}// Behavior can listen to these event types
interface BehaviorEvents {
// Element events
'node:click': (event: IElementEvent) => void;
'node:dblclick': (event: IElementEvent) => void;
'node:mouseenter': (event: IElementEvent) => void;
'node:mouseleave': (event: IElementEvent) => void;
'node:dragstart': (event: IElementDragEvent) => void;
'node:drag': (event: IElementDragEvent) => void;
'node:dragend': (event: IElementDragEvent) => void;
'edge:click': (event: IElementEvent) => void;
'edge:hover': (event: IElementEvent) => void;
// Canvas events
'canvas:click': (event: IPointerEvent) => void;
'canvas:drag': (event: IDragEvent) => void;
'canvas:wheel': (event: IWheelEvent) => void;
// Keyboard events
'key:down': (event: IKeyboardEvent) => void;
'key:up': (event: IKeyboardEvent) => void;
// Viewport events
'viewport:transform': (event: IViewportEvent) => void;
}interface IElementEvent {
target: Element; // Target element
targetType: ElementType; // 'node' | 'edge' | 'combo'
client: Point; // Client coordinates
canvas: Point; // Canvas coordinates
viewport: Point; // Viewport coordinates
originalEvent: Event; // Original DOM event
}
interface IDragEvent extends IElementEvent {
movement: Point; // Movement delta
cumulative: Point; // Cumulative movement
}
interface IKeyboardEvent {
key: string; // Key pressed
code: string; // Key code
ctrlKey: boolean; // Modifier keys
shiftKey: boolean;
altKey: boolean;
metaKey: boolean;
}interface BehaviorOptions {
key?: string; // Unique behavior key
type: string; // Behavior type
enable?: boolean | ((event: any) => boolean);
[key: string]: any; // Additional options
}
interface UpdateBehaviorOption {
key: string; // Behavior key to update
[key: string]: any; // Options to update
}
type ShortcutKey = string | string[];
interface ViewportAnimationEffectTiming {
duration?: number;
easing?: string | ((t: number) => number);
delay?: number;
fill?: 'none' | 'forwards' | 'backwards' | 'both';
}
abstract class BaseBehavior {
protected options: BehaviorOptions;
protected context: { graph: Graph };
abstract onEnable(): void;
abstract onDisable(): void;
protected bindEvents(events: Record<string, Function>): void;
protected unbindEvents(): void;
}