import { type Graph as G6Graph } from '@antv/g6'; import type { GraphNode, GraphEdge } from '../@types'; export interface GraphInitOptions { container: HTMLElement; width?: number; height?: number; } export interface EditCallbacks { onAddNode?: (x: number, y: number) => void; /** @deprecated 使用 onProposeConnection */ onAddEdge?: (sourceId: string, targetId: string) => void; /** 用户完成一次连线操作(两节点已选定),由 UI 层弹窗确认后再调用 addEdge */ onProposeConnection?: (sourceId: string, targetId: string) => void; onDeleteNode?: (nodeId: string) => void; onDeleteEdge?: (edgeId: string) => void; onDataChange?: (nodes: GraphNode[], edges: GraphEdge[]) => void; /** 右键节点菜单回调 */ onNodeContextMenu?: (nodeId: string, label: string, color: string, menuX: number, menuY: number, clientX: number, clientY: number) => void; /** 右键边菜单回调 */ onEdgeContextMenu?: (edgeId: string, sourceId: string, targetId: string, label: string, menuX: number, menuY: number, clientX: number, clientY: number) => void; } export interface InitOptions { editMode?: boolean; onAddNode?: (x: number, y: number) => void; onAddEdge?: (sourceId: string, targetId: string) => void; onProposeConnection?: (sourceId: string, targetId: string) => void; onDeleteNode?: (nodeId: string) => void; onDeleteEdge?: (edgeId: string) => void; onDataChange?: (nodes: GraphNode[], edges: GraphEdge[]) => void; onNodeContextMenu?: (nodeId: string, label: string, color: string, menuX: number, menuY: number, clientX: number, clientY: number) => void; onEdgeContextMenu?: (edgeId: string, sourceId: string, targetId: string, label: string, menuX: number, menuY: number, clientX: number, clientY: number) => void; } /** * G6 图谱基础类:负责 Graph 生命周期、尺寸、fitView 等通用能力 */ export declare class BaseG6Graph { protected graph: G6Graph | null; protected container: HTMLElement | null; private resizeHandler; protected createGraph(config: Omit[0], 'container' | 'width' | 'height'>, options: GraphInitOptions): void; private setupResizeHandler; private cleanupResizeHandler; hasGraph(): boolean; fitView(padding?: number): void; destroy(): void; } /** * 具体的知识图谱实现:白底黑字 + 实体/关系配色 + 力导布局 */ /** 布局类型 */ export type LayoutType = 'force' | 'circular'; export type GraphTheme = 'light' | 'dark'; /** 编辑工具类型 */ export type ToolType = 'select' | 'addNode' | 'addEdge' | 'deleteNode' | 'deleteEdge'; /** 工具交互回调 */ export interface EditToolCallbacks { onNodeClick?: (nodeId: string) => void; onCanvasClick?: (x: number, y: number) => void; } export declare class KnowledgeGraph extends BaseG6Graph { private contextMenuHandler; private globalMouseUpHandler; private globalKeyDownHandler; /** 当前布局类型,用于切换布局 */ private currentLayoutType; /** 图谱主题 */ private theme; /** ========== 编辑模式相关 ========== */ private isEditMode; private editCallbacks; private pendingEdge; private editEventsBound; private linkPreviewSvg; private linkPreviewLine; private pendingPreviewMove; private altLinkDrag; private altLinkMove; private altLinkUp; /** Alt 拖线松手后 G6 仍会触发 node:click,用此标志吞掉一次点击 */ private suppressNextNodeClick; /** ========== 工具模式相关 ========== */ private toolType; private editToolCallbacks; /** addEdge 模式:已选中的源节点 */ private edgeSourceNodeId; /** addEdge 模式:预览连线源节点坐标 */ private edgeSourcePos; /** 设置编辑回调函数 */ setEditCallbacks(callbacks: EditCallbacks): void; /** 设置工具交互回调(用于工具模式下的节点/画布点击通知) */ setEditToolCallbacks(callbacks: EditToolCallbacks): void; setTheme(theme: GraphTheme): void; private getThemePalette; private applyThemeToExistingGraph; /** 设置当前工具类型,同时更新 canvas cursor */ setToolType(type: ToolType): void; /** 获取当前工具类型 */ getToolType(): ToolType; private resetEdgeSelectState; /** 工具模式节点点击处理(由 GraphVisualization 调用) */ handleToolNodeClick(nodeId: string, x: number, y: number): void; /** 工具模式画布点击处理(由 GraphVisualization 调用) */ handleToolCanvasClick(x: number, y: number): void; /** 设置编辑模式 */ setEditMode(enabled: boolean): void; /** 获取当前数据(用于保存) */ getEditData(): { nodes: GraphNode[]; edges: GraphEdge[]; }; /** * 更新指定节点的标签 */ updateNodeLabel(nodeId: string, newLabel: string): void; /** * 更新指定节点的颜色(fill + stroke) */ updateNodeColor(nodeId: string, color: string): void; /** * 更新指定边的属性(label、source、target) */ updateEdge(edgeId: string, updates: { label?: string; source?: string; target?: string; }): void; /** * 删除节点 */ deleteNode(nodeId: string): void; /** * 删除边 */ deleteEdge(edgeId: string): void; /** * 在画布上新增节点(编辑模式) */ addNodeAt(x: number, y: number, label: string, type?: string): void; /** * 新增一条有向边(编辑模式) */ addEdgeBetween(sourceId: string, targetId: string, label?: string): void; /** 从指定节点开始「拉出连线」状态(等价于第一次点选源节点) */ startConnectFrom(nodeId: string): void; /** 画布视口中心对应的图坐标(用于在中心添加节点) */ getViewportCenterGraphPoint(): { x: number; y: number; } | null; getNodeDisplayLabel(nodeId: string): string; private fireProposeConnection; private ensureLinkPreviewLayer; private hideLinkPreview; private showLinkPreviewLine; /** * 将图数据坐标 (model.x / model.y) 转为浏览器视口 client 坐标。 * 注意:keyShape.getBBox() 是节点局部坐标,不能当作图坐标使用。 * refClientX/refClientY 在无 getClientByPoint 时用于局部线性反推(通常取当前鼠标位置)。 */ private graphPointToViewportClient; private updateLinkPreviewToClient; private findNodeIdAtClient; private attachPendingPreviewListeners; private detachPendingPreviewListeners; private beginAltLinkDrag; private onAltLinkMouseUp; private endAltLinkDrag; private clearPendingEdgeOnly; private clearPendingConnection; /** 获取布局配置:力导向(更分散、少重叠)或环形(中心放射,适合枢纽图) */ private getLayoutConfig; private getColorByType; private getColorByRelation; init(options: GraphInitOptions, nodes: GraphNode[], edges: GraphEdge[], editOptions?: InitOptions): void; update(nodes: GraphNode[], edges: GraphEdge[]): void; resetLayout(): void; /** 切换布局类型:力导向(更分散)或环形(中心放射,适合枢纽图) */ switchLayout(type: LayoutType): void; /** 当前布局类型 */ getLayoutType(): LayoutType; /** * G6 圆形节点直径(像素)。接口常把 `size` 当权重/等级给 1~10,若直接当直径会极小; * 低度数时原公式最小为 15,编辑模式下点选困难,故设下限并仅在大于等于下限时采信 `node.size`。 */ private resolveNodeVisualSize; private processData; private setupEvents; private setupEditModeEvents; /** addEdge 工具的节点点击处理:链式选择两个节点后触发连线 */ private handleEdgeToolClick; destroy(): void; }