事件

查询图事件的触发时机和回调参数。

用 graph.on() 监听事件。其他监听方法见图 API,交互示例见事件入门。

元素事件

点击与指针事件

操作节点边Combo画布
单击目标。node:clickedge:clickcombo:clickcanvas:click
双击目标。node:dblclickedge:dblclickcombo:dblclickcanvas:dblclick
右键点击目标,浏览器默认菜单会被阻止。node:contextmenuedge:contextmenucombo:contextmenucanvas:contextmenu
在目标上按下鼠标。node:pointerdownedge:pointerdowncombo:pointerdowncanvas:pointerdown
在窗口松开鼠标,统一由画布通知。———canvas:pointerup
移入目标。node:pointeroveredge:pointerovercombo:pointerover—
紧随 pointerover 触发。node:pointerenteredge:pointerentercombo:pointerenter—
在目标上移动指针。node:pointermoveedge:pointermovecombo:pointermovecanvas:pointermove
离开目标。坐标为离开时的指针位置。node:pointerleaveedge:pointerleavecombo:pointerleave—
在目标上滚动鼠标滚轮,可读取 nativeEvent.deltaY。node:wheeledge:wheel—canvas:wheel

回调参数

字段含义
targetType / targetId目标类型和元素 ID。targetId 仅用于节点、边和 Combo。
nodeId / edgeId / comboId对应元素的 ID。边还提供 edgeIndex、source 和 target。
data节点或边携带的可选业务数据。
client相对浏览器视口的 CSS 像素坐标。
canvas相对画布左上角的 CSS 像素坐标。
graph图坐标,用于图内定位。
nativeEvent鼠标事件为 MouseEvent,滚轮事件为 WheelEvent。

点击节点时,读取目标、业务数据和三种坐标,并从原始鼠标事件判断是否按住 Shift。

graph.on('node:click', (event) => {
  console.log({
    target: { type: event.targetType, id: event.targetId },
    data: event.data,
    client: event.client,
    canvas: event.canvas,
    graph: event.graph,
    shiftKey: event.nativeEvent.shiftKey,
  });
});

命中与手势

命中顺序为节点 → 边 → Combo → 画布。指针换目标时先发旧目标的 pointerleave,再发新目标的 pointerover → pointerenter → pointermove。Combo 背景上还会触发 canvas:pointermove,滚轮由 canvas:wheel 通知。拖拽可能抑制后续单击。

选择事件

启用 click-select、brush-select 或 lasso-select 后可监听对应事件。事件在选中状态写回后触发。

操作节点边整体选择
切换选中状态。node:selectchangeedge:selectchange—
清空非空选择。——selection:clear
框选中命中节点,按节流频率触发。brush:select——
框选结束,结果可为空。brush:end——
套索中命中节点。lasso:select——
套索结束,结果可为空。lasso:end——

回调参数

字段含义
nodeId / edgeId切换选中状态的元素 ID。边还提供 edgeIndex、source 和 target。
selected切换后的选中状态。
idsselection:clear 清除的元素 ID,可同时包含节点和边。
nodeIds框选和套索事件返回的节点 ID。brush:end 返回框选结束时当前选中的节点。
event切换或清空选择时的原始 MouseEvent。

启用 brush-select 后,监听 brush:end 读取框选结束时选中的节点。

graph.on('brush:end', ({ nodeIds }) => {
  console.log('选中的节点', nodeIds);
});

套索事件返回本次套索命中的节点。用 findNodesByState('selected') 和 findEdgesByState('selected') 查询全图选择。 选择与拖拽指南

拖拽事件

节点和 Combo 拖拽由 drag-node 提供,边端点拖拽由 drag-edge 提供。

操作节点边Combo
开始拖拽。节点或 Combo 移动超过 3 CSS 像素时触发,边在按下左键时触发。node:dragstartedge:dragstartcombo:dragstart
拖拽中。节点或 Combo 成员的位置写回后触发。node:dragedge:dragcombo:drag
松开鼠标,结束拖拽。node:dragendedge:dragendcombo:dragend

回调参数

字段含义
nodeId / nodeIds节点拖拽事件中的第一个节点 ID 和全部被拖动的节点 ID。
comboIdCombo 拖拽事件中被拖动的 Combo ID。
dx / dynode:drag 和 combo:drag 中从起点累计的图坐标位移。
edgeId / edgeIndex边拖拽事件中的边 ID 和索引,edgeId 为可选字段。
source / target边拖拽的两端节点 ID。edge:dragend 有效落点时返回建议端点,由应用验证后写回。
dragEndedge:dragstart 和 edge:drag 中被拖动的端点(source 或 target)。取离按下点较近的端点,等距时取 target。
originalSource / originalTargetedge:dragend 中拖拽前的端点 ID。
reconnected / newEndpointedge:dragend 中是否命中有效落点,以及该节点的 ID(如有)。
event原始 MouseEvent。节点和 Combo 的 dragend 只提供拖拽结果。

拖拽结束时,用 nodeIds 查询全部被拖动节点的位置。

graph.on('node:dragend', ({ nodeIds }) => {
  const positions = nodeIds.map((id) => graph.getElementPosition(id));
  console.log(positions);
});

生命周期与数据事件

用这些事件跟踪图的布局、绘制和数据变化。渲染、布局与数据更新

布局与渲染

事件触发时机回调参数
beforelayout有布局配置且节点非空时,在计算前触发。nodeCount: number
layout:start紧随 beforelayout,仍在计算前。nodeCount: number
layout:end有效计算结束,坐标尚未写回。duration 单位为毫秒。duration: number、nodeCount: number
afterlayout紧随 layout:end。读取最终位置请等待 await graph.layout()。duration: number、nodeCount: number
beforerender显式 render() 中,适配视口和绘制之前。nodeCount: number、edgeCount: number
afterrender显式 render() 的同步绘制之后。首次修改数据前,先等待 await graph.render()。nodeCount: number、edgeCount: number
resize调整画布尺寸并完成可选的视口适配后。尺寸单位为 CSS 像素。width: number、height: number
destroy首次销毁实例时,先于画布和监听清理。无参数

实际计算布局时,render()、layout() 和 setData() 都会触发布局事件。取消布局时可能收不到结束事件。

在首次 render() 前监听一次 afterrender,再用 datachange 读取每次替换数据后的节点数和边数。

graph.once('afterrender', ({ nodeCount, edgeCount }) => {
  console.log('首次绘制', nodeCount, edgeCount);
});
await graph.render();

graph.on('datachange', ({ nodeCount, edgeCount }) => {
  console.log('数据已替换', nodeCount, edgeCount);
});
await graph.setData({
  nodes: [{ id: 'A', x: 0, y: 0 }, { id: 'B', x: 120, y: 0 }],
  edges: [{ source: 'A', target: 'B' }],
});

数据更新与分组

事件触发时机回调参数
datachangesetData() 写回整份数据后。nodeCount: number、edgeCount: number
afteradditem添加节点或边后按项触发。type: 'node'、id: string 或 type: 'edge'、id: string、source: string、target: string
afterremoveitem删除节点或边时按传入 ID 触发,包括缺失 ID。节点的关联边不另发事件。type(node / edge)、id: string
afterupdateitem更新节点坐标、节点数据或边数据后按项触发。updateNodePosition() 传入缺失节点或相同坐标时也会触发。type(node / edge)、id: string、action(节点为 position 或 data,边为 data)
combo:collapseCombo 折叠状态改变后。comboId: string
combo:expandCombo 展开状态改变后。comboId: string

EventEmitter

用 EventEmitter 在界面组件之间传递自定义事件。下面把已渲染的图、工具栏的「重置视图」按钮和状态栏传给 bindResetView()。点击按钮时,图恢复初始视图,状态栏显示提示。页面卸载时调用返回的清理函数。

import { EventEmitter, type Graph } from '@antv/g6-lite';

export function bindResetView(graph: Graph, button: HTMLButtonElement, status: HTMLElement) {
  const events = new EventEmitter();
  const resetCamera = () => graph.resetCamera();
  const showStatus = () => {
    status.textContent = '视图已重置';
  };
  const onClick = () => events.emit('view:reset');

  events.on('view:reset', resetCamera);
  events.on('view:reset', showStatus);
  button.addEventListener('click', onClick);

  return () => {
    button.removeEventListener('click', onClick);
    events.off('view:reset', resetCamera);
    events.off('view:reset', showStatus);
  };
}