or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

behaviors.mddata-management.mdelements.mdevents.mdgraph-runtime.mdindex.mdlayouts.mdplugins.mdtypes.md
tile.json

plugins.mddocs/

Plugin System

G6's plugin system provides extensible UI components and visual enhancements for graph visualizations. Plugins can add interactive widgets, visual effects, and utility features with comprehensive configuration options.

Plugin Configuration

Basic Plugin Setup

import { Graph } from '@antv/g6';
import type { PluginOptions, UpdatePluginOption } from '@antv/g6';

// Simple plugin configuration
const graph = new Graph({
  plugins: [
    { key: 'minimap', type: 'minimap' },
    { key: 'tooltip', type: 'tooltip' },
    { key: 'toolbar', type: 'toolbar' }
  ]
});

// Advanced plugin configuration
const graph = new Graph({
  plugins: [
    {
      key: 'custom-minimap',
      type: 'minimap',
      size: [300, 200],
      position: 'top-right',
      padding: 10
    }
  ]
});

Dynamic Plugin Management

// Update plugins at runtime
graph.setPlugins([
  { key: 'minimap', type: 'minimap', size: [200, 120] },
  { key: 'grid', type: 'grid-line' }
]);

// Update specific plugin
graph.updatePlugin({
  key: 'minimap',
  size: [250, 150],
  position: 'bottom-left'
});

// Get current plugins
const plugins = graph.getPlugins();

// Get plugin instance for direct manipulation
const minimap = graph.getPluginInstance<MinimapPlugin>('minimap');
minimap.show();
minimap.hide();

Built-in Plugins

Navigation and Viewport Plugins

import type { 
  MinimapOptions, 
  Placement, 
  Padding, 
  ElementType 
} from '@antv/g6';

// Minimap Plugin
interface MinimapOptions {
  size?: [number, number];             // Width and height [240, 160]
  padding?: Padding;                   // Internal padding (10)
  position?: Placement;                // Position relative to canvas
  filter?: (id: string, elementType: ElementType) => boolean;
  shape?: 'key' | ((id: string, elementType: ElementType) => DisplayObject);
  className?: string;                  // Canvas class name
  container?: HTMLElement | string;    // Mount container
  refresh?: boolean;                   // Auto refresh on graph changes
}

const minimapPlugin = {
  key: 'minimap',
  type: 'minimap',
  size: [200, 120],
  position: 'right-bottom',
  padding: 8,
  filter: (id, elementType) => {
    // Only show nodes in minimap
    return elementType === 'node';
  },
  shape: 'key'  // Use simplified shapes
};

// Fullscreen Plugin
const fullscreenPlugin = {
  key: 'fullscreen',
  type: 'fullscreen',
  className: 'g6-fullscreen-button',
  container: document.getElementById('toolbar')
};

// Camera Setting Plugin
const cameraSettingPlugin = {
  key: 'camera-setting',
  type: 'camera-setting',
  projectionMode: '3d',                // '2d' | '3d'
  trackballControls: true,
  enableRotate: true,
  enableZoom: true,
  enablePan: true
};

UI and Interaction Plugins

import type { 
  TooltipOptions, 
  ContextmenuOptions,
  ToolbarOptions 
} from '@antv/g6';

// Tooltip Plugin
interface TooltipOptions {
  enable?: boolean | ((event: any) => boolean);
  trigger?: 'hover' | 'click';         // Activation trigger
  enterable?: boolean;                 // Allow mouse enter tooltip
  offset?: [number, number];           // Position offset
  placement?: Placement;               // Tooltip placement
  getContent?: (event: any) => string | HTMLElement;
  className?: string;                  // CSS class name
  style?: Record<string, any>;         // Inline styles
}

const tooltipPlugin = {
  key: 'tooltip',
  type: 'tooltip',
  trigger: 'hover',
  enterable: true,
  placement: 'top',
  getContent: (event) => {
    const { target } = event;
    if (target.elementType === 'node') {
      return `<div>Node: ${target.id}</div>`;
    }
    return null;
  },
  style: {
    backgroundColor: '#fff',
    border: '1px solid #ccc',
    borderRadius: '4px',
    padding: '8px'
  }
};

// Context Menu Plugin
const contextmenuPlugin = {
  key: 'contextmenu',
  type: 'contextmenu',
  enable: true,
  trigger: 'contextmenu',
  getItems: (event) => {
    const { target, targetType } = event;
    if (targetType === 'node') {
      return [
        { key: 'delete', label: 'Delete Node' },
        { key: 'edit', label: 'Edit Node' },
        { key: 'focus', label: 'Focus' }
      ];
    }
    return [];
  },
  onItemClick: (key, event) => {
    console.log(`Menu item ${key} clicked`, event);
  }
};

// Toolbar Plugin  
const toolbarPlugin = {
  key: 'toolbar',
  type: 'toolbar',
  position: 'top-left',
  items: [
    {
      key: 'zoom-in',
      type: 'button', 
      icon: 'zoom-in',
      tooltip: 'Zoom In',
      onClick: () => graph.zoomBy(1.2)
    },
    {
      key: 'zoom-out',
      type: 'button',
      icon: 'zoom-out', 
      tooltip: 'Zoom Out',
      onClick: () => graph.zoomBy(0.8)
    },
    {
      key: 'fit-view',
      type: 'button',
      icon: 'fit-view',
      tooltip: 'Fit View',
      onClick: () => graph.fitView()
    }
  ]
};

Visual Enhancement Plugins

// Background Plugin
const backgroundPlugin = {
  key: 'background',
  type: 'background',
  background: '#f5f5f5',               // Background color
  backgroundImage: 'url(pattern.png)', // Background image
  backgroundSize: 'cover',             // 'cover' | 'contain' | 'auto'
  backgroundRepeat: 'no-repeat',       // 'repeat' | 'no-repeat'
  backgroundPosition: 'center'         // Background position
};

// Grid Line Plugin
const gridLinePlugin = {
  key: 'grid-line',
  type: 'grid-line',
  follow: true,                        // Follow viewport transform
  line: {
    stroke: '#e8e8e8',
    lineWidth: 1
  },
  size: 20,                           // Grid size
  visible: true                       // Initial visibility
};

// Watermark Plugin
const watermarkPlugin = {
  key: 'watermark',
  type: 'watermark',
  text: 'G6 Graph',                   // Watermark text
  textStyle: {
    fontSize: 16,
    fill: '#000',
    opacity: 0.1
  },
  position: 'bottom-right',
  offset: [20, 20],
  rotate: -Math.PI / 12               // Rotation angle
};

// Legend Plugin
const legendPlugin = {
  key: 'legend',
  type: 'legend',
  position: 'top-left',
  orientation: 'vertical',             // 'horizontal' | 'vertical'
  data: [
    { label: 'Type A', color: '#1890FF', marker: 'circle' },
    { label: 'Type B', color: '#52C41A', marker: 'rect' },
    { label: 'Type C', color: '#FAAD14', marker: 'diamond' }
  ],
  onItemClick: (item, index) => {
    console.log('Legend item clicked:', item);
  }
};

Advanced Visual Plugins

// Hull Plugin (Contour/Convex Hull)
const hullPlugin = {
  key: 'hull',
  type: 'hull',
  members: ['node1', 'node2', 'node3'], // Hull members
  type: 'round-convex',                // 'convex' | 'round-convex' | 'smooth-convex'
  style: {
    fill: '#1890FF',
    fillOpacity: 0.1,
    stroke: '#1890FF',
    strokeOpacity: 0.5,
    lineWidth: 1
  },
  padding: 10,                         // Padding around members
  animate: true,                       // Animate hull changes
  duration: 300
};

// Bubble Sets Plugin
const bubbleSetsPlugin = {
  key: 'bubble-sets',
  type: 'bubble-sets',
  groups: [
    {
      key: 'group1',
      members: ['node1', 'node2'],
      style: {
        fill: '#1890FF',
        fillOpacity: 0.2
      }
    }
  ],
  nonMemberInfluence: 10,              // Influence on non-members
  memberInfluence: 40,                 // Influence on members
  threshold: 6                         // Threshold for bubble generation
};

// Fisheye Plugin
const fisheyePlugin = {
  key: 'fisheye',
  type: 'fisheye',
  trigger: 'mousemove',                // 'mousemove' | 'click' | 'drag'
  d: 1.5,                             // Distortion factor
  range: 200,                         // Effect range
  showLabel: 2,                       // Show labels at zoom level
  scaleRBy: 'radius'                  // Scale by radius or unzoom
};

// Edge Bundling Plugin
const edgeBundlingPlugin = {
  key: 'edge-bundling',
  type: 'edge-bundling',
  K: 100,                             // Bundling strength
  lambda: 0.1,                        // Edge length factor
  divisions: 1,                       // Number of division points
  cycles: 6,                          // Number of cycles
  iterations: 90,                     // Iterations per cycle
  iterationsRate: 0.6666667          // Iteration rate decay
};

// Edge Filter Lens Plugin
const edgeFilterLensPlugin = {
  key: 'edge-filter-lens',
  type: 'edge-filter-lens',
  trigger: 'mousemove',
  r1: 60,                             // Inner radius
  r2: 120,                            // Outer radius
  showLabel: true
};

Utility Plugins

// History Plugin (Undo/Redo)
const historyPlugin = {
  key: 'history',
  type: 'history',
  stackSize: 20,                      // Maximum history stack size
  enableStack: true,                   // Enable history stack
  ignoreAdd: false,                   // Ignore add operations
  ignoreRemove: false,                // Ignore remove operations
  ignoreUpdate: false,                // Ignore update operations  
  ignoreStateChange: true,            // Ignore state changes
  ignoreLayoutChange: false           // Ignore layout changes
};

// Access history operations
const history = graph.getPluginInstance('history');
history.undo();                      // Undo last operation
history.redo();                      // Redo last undone operation
history.clear();                     // Clear history
const canUndo = history.canUndo();   // Check if can undo
const canRedo = history.canRedo();   // Check if can redo

// Snapline Plugin
const snaplinePlugin = {
  key: 'snapline',
  type: 'snapline',
  enable: true,
  line: {
    stroke: '#1890FF',
    lineWidth: 1,
    lineDash: [5, 5]
  },
  tolerance: 5,                       // Snap tolerance in pixels
  autoSnap: true,                     // Auto snap when close
  itemAlignType: true                 // Align to item centers
};

// Timebar Plugin
const timebarPlugin = {
  key: 'timebar',
  type: 'timebar',
  position: 'bottom',
  height: 50,
  range: [0, 100],                    // Time range
  trend: {
    data: timeData,                   // Time series data
    smooth: true,
    isArea: false
  },
  controllerStyle: {
    fill: '#1890FF',
    fillOpacity: 0.2
  },
  onTimeChange: (time) => {
    console.log('Time changed:', time);
    // Update graph based on time
  }
};

Custom Plugin Development

Creating Custom Plugins

import { BasePlugin } from '@antv/g6';
import type { PluginOptions } from '@antv/g6';

class CustomPlugin extends BasePlugin {
  static defaultOptions: Partial<PluginOptions> = {
    position: 'top-right',
    size: [100, 50],
    className: 'custom-plugin'
  };

  private container: HTMLDivElement;

  constructor(options: PluginOptions) {
    super(options);
  }

  onEnable(): void {
    // Create plugin UI
    this.container = document.createElement('div');
    this.container.className = this.options.className;
    this.container.style.position = 'absolute';
    this.container.innerHTML = '<button>Custom Action</button>';
    
    // Position the plugin
    this.positionContainer();
    
    // Add to graph container
    const graphContainer = this.context.graph.getCanvas().getContainer();
    graphContainer.appendChild(this.container);
    
    // Bind events
    this.bindEvents();
  }

  onDisable(): void {
    // Remove UI and cleanup
    if (this.container && this.container.parentNode) {
      this.container.parentNode.removeChild(this.container);
    }
    this.unbindEvents();
  }

  onResize(): void {
    // Handle container resize
    this.positionContainer();
  }

  private positionContainer(): void {
    const [width, height] = this.context.graph.getSize();
    const [pluginWidth, pluginHeight] = this.options.size;
    
    // Position based on options.position
    switch (this.options.position) {
      case 'top-right':
        this.container.style.top = '10px';
        this.container.style.right = '10px';
        break;
      // Add other positioning logic
    }
  }

  private bindEvents(): void {
    const button = this.container.querySelector('button');
    button?.addEventListener('click', this.handleButtonClick);
    
    // Listen to graph events
    this.context.graph.on('node:click', this.handleNodeClick);
  }

  private unbindEvents(): void {
    this.context.graph.off('node:click', this.handleNodeClick);
  }

  private handleButtonClick = (): void => {
    console.log('Custom plugin button clicked');
    // Custom logic here
  };

  private handleNodeClick = (event: any): void => {
    console.log('Node clicked in custom plugin:', event.target.id);
  };
}

// Register custom plugin
import { register } from '@antv/g6';

register('plugin', 'custom-plugin', CustomPlugin);

// Use custom plugin
const graph = new Graph({
  plugins: [
    {
      key: 'my-custom-plugin',
      type: 'custom-plugin',
      position: 'top-left',
      size: [120, 60]
    }
  ]
});

Plugin Lifecycle Methods

abstract class BasePlugin {
  protected options: PluginOptions;
  protected context: { graph: Graph };
  
  // Lifecycle methods to override
  abstract onEnable(): void;           // Plugin enabled
  abstract onDisable(): void;          // Plugin disabled  
  onResize?(): void;                   // Container resized
  onDestroy?(): void;                  // Plugin destroyed
  
  // Utility methods available
  protected getGraphSize(): [number, number];
  protected getContainer(): HTMLElement;
  protected emit(event: string, data?: any): void;
}

Plugin Communication

// Plugin-to-plugin communication via graph events
class PublisherPlugin extends BasePlugin {
  onEnable(): void {
    // Emit custom events
    this.context.graph.emit('publisher:action', { data: 'hello' });
  }
}

class SubscriberPlugin extends BasePlugin {
  onEnable(): void {
    // Listen to custom events
    this.context.graph.on('publisher:action', this.handlePublisherAction);
  }
  
  private handlePublisherAction = (event: any): void => {
    console.log('Received from publisher:', event.data);
  };
}

Plugin Event System

Plugin Events

// Plugins can listen to these graph events
interface PluginEvents {
  // Graph lifecycle
  'render': () => void;
  'destroy': () => void;
  'resize': (size: [number, number]) => void;
  
  // Data changes
  'data:change': (event: { type: string, data: any }) => void;
  'node:add': (event: { nodes: NodeData[] }) => void;
  'edge:add': (event: { edges: EdgeData[] }) => void;
  
  // User interactions
  'node:click': (event: IElementEvent) => void;
  'canvas:click': (event: IPointerEvent) => void;
  'viewport:transform': (event: IViewportEvent) => void;
  
  // Custom events
  [key: string]: (...args: any[]) => void;
}

Type Definitions

interface PluginOptions {
  key?: string;                        // Unique plugin key
  type: string;                        // Plugin type
  [key: string]: any;                  // Additional options
}

interface UpdatePluginOption {
  key: string;                         // Plugin key to update
  [key: string]: any;                  // Options to update
}

type Placement = 
  | 'top' | 'top-left' | 'top-right'
  | 'bottom' | 'bottom-left' | 'bottom-right'
  | 'left' | 'left-top' | 'left-bottom'
  | 'right' | 'right-top' | 'right-bottom'
  | 'center';

abstract class BasePlugin {
  protected options: PluginOptions;
  protected context: { graph: Graph };
  
  abstract onEnable(): void;
  abstract onDisable(): void;
  onResize?(): void;
  onDestroy?(): void;
}

interface MinimapPlugin extends BasePlugin {
  show(): void;
  hide(): void;
  refresh(): void;
}

interface HistoryPlugin extends BasePlugin {
  undo(): void;
  redo(): void;
  clear(): void;
  canUndo(): boolean;
  canRedo(): boolean;
}