import { Vector } from "../../common/entities/Core/Vector"; import { ContentType, MindNode } from './MindNode'; import { EventEmitter } from "../../common/entities/Core/EventEmitter"; import { MouseButton } from "../../common/entities/Abilities/Draggable/BaseDraggable"; import { AlignOptions } from "../algorithm/Alignment"; export { MindNode, MouseButton }; /** * 思维导图核心类 * 提供思维导图的创建、布局计算、渲染和交互能力 */ export declare class MindMap extends EventEmitter { private _rootNode; private _outerContainer; private _rootContainer; private _elementToMindNodeMap; private _linesMap; private _mindNodeToOriginalDataMap; private _isHorizontal; private _siblingSeparation; private _levelSeparation; private _initialOffset?; private _lineShape; private _debugOptions?; private _isNativeFullscreen; private _fullscreenTransitioning; private _isPseudoFullscreen; private _originalBodyStyle?; private _align; private _style; private _fullscreenOptions; private _draggableManager?; private _dragOptions; private _wheelManager?; private _zoomOptions; /** 存储构造函数传入的 contentCallback */ private _nodeContentCallback?; /** 全屏状态变化监听器 */ private _fullscreenChangeListener?; /** * 创建思维导图实例 * @param data - 思维导图初始数据,可以是 MindNode 实例、TreeNode 对象或 FlatNode 数组 * @param containerDom - 承载思维导图的 DOM 容器元素 * @param options - 思维导图配置选项 * @param options.isHorizontal - 是否水平布局,默认为 true * @param options.siblingSeparation - 同级节点间距(边界到边界),默认为 16 * @param options.levelSeparation - 层级间的最小距离(边界到边界),默认为 32 * @param options.initialOffset - 初始偏移量,可选 * @param options.lineShape - 连接线形状,可选值为 'straight'|'curved'|'zigzag',默认为 'curved' * @param options.contentCallback - 节点显示内容回调函数 * @param options.align - 思维导图对齐选项 * @param options.style - 思维导图样式配置 * @param options.fullscreenOptions - 全屏相关配置 * @param options.dragOptions - 拖拽相关配置 * @param options.zoomOptions - 缩放相关配置 * @param options.debugOptions - 调试选项 */ constructor(data: MindNode | TreeNode | FlatNode[], containerDom: HTMLElement, options?: { isHorizontal?: boolean; siblingSeparation?: number; levelSeparation?: number; initialOffset?: { x?: number; y?: number; }; lineShape?: 'straight' | 'curved' | 'zigzag'; contentCallback?: (originalData: NodeLike) => string | HTMLElement | HTMLElement[]; align?: MindMapAlign; style?: MindMapStyle; fullscreenOptions?: FullscreenOptions; dragOptions?: MindMapDragOptions; zoomOptions?: MindMapZoomOptions; debugOptions?: DebugOptions; }); /** * 销毁思维导图实例,释放所有相关资源。 * 调用此方法后,MindMap 实例将不可用。 */ destroy(): void; /** * 清空思维导图实例的所有内容和状态 * 包括清除容器、映射以及释放事件监听器 * @todo 考虑是否设置为私有 */ clear(): void; /** * 获取思维导图当前布局方向 * @returns 是否为水平布局 */ get isHorizontal(): boolean; /** * 获取当前是否处于全屏状态 (包括原生或模拟) * @returns 是否处于全屏状态 */ get isFullscreen(): boolean; /** * 获取当前是否处于原生全屏状态 * @returns 是否处于原生全屏状态 */ get isNativeFullscreen(): boolean; /** * 获取当前是否处于模拟全屏状态 * @returns 是否处于模拟全屏状态 */ get isPseudoFullscreen(): boolean; /** * 设置新的思维导图数据 * 这将会清空当前的思维导图,并使用新的数据重新构建和渲染 * @param data - 新的思维导图数据,可以是 MindNode 实例、TreeNode 对象或 FlatNode 数组 */ setRootNodeData(data: MindNode | TreeNode | FlatNode[]): void; /** * 从外部树形对象创建 MindNode 树结构 * @param data - 树形节点数据 * @returns 构建的根 MindNode 实例 */ private _createMindNodesFromTreeData; /** * 从扁平数据数组创建 MindNode 树结构 * @param flatNodes - 扁平结构的节点数组 * @returns 构建的根 MindNode 实例 */ private _createMindNodesFromFlatData; /** * 获取与给定 MindNode 关联的原始数据对象 (TreeNode 或 FlatNode) * 如果 MindMap 是直接用 MindNode 实例初始化的,则返回该 MindNode 实例本身 * @param node - 要获取原始数据的 MindNode 实例 * @returns 关联的原始数据对象,或者 MindNode 实例本身 */ private _getOriginalDataForNode; /** * 根据 ID 查找 MindNode * @param nodeId - 要查找的节点 ID * @returns 找到的 MindNode,如果未找到则返回 undefined */ findNodeById(nodeId: string): MindNode | undefined; /** * 递归查找具有指定 ID 的 MindNode * @param node - 当前开始搜索的节点 * @param nodeId - 要查找的节点 ID * @returns 找到的 MindNode,如果未找到则返回 undefined */ private _findNodeByIdRecursive; /** * 设置指定节点的尺寸 * @param nodeId - 要设置尺寸的节点 ID * @param size - 新的尺寸配置,可以只设置宽度或高度 * @param size.width - 新的宽度,可选 * @param size.height - 新的高度,可选 * @returns 如果节点找到并成功设置尺寸,则返回 true;否则返回 false */ setNodeSize(nodeId: string, size: { width?: number; height?: number; }): boolean; /** * 更新指定节点的内容 * 此方法会根据传入的节点 ID 数组,并根据节点自身的 `content` 属性或外部传入的 `contentCallback` * 来重新解析和设置节点内部的内容。 * @param nodeIds - 要更新内容的节点 ID 数组,不传参时默认更新所有节点 * @returns 成功更新的节点个数 */ updateNodeContents(nodeIds?: string[]): number; /** * 切换节点的折叠状态 * @param nodeId - 要切换折叠状态的节点 ID * @returns 如果节点找到并成功切换状态,则返回 true;否则返回 false */ toggleNodeCollapse(nodeId: string): boolean; /** * 设置节点的折叠状态 * @param nodeId - 要设置折叠状态的节点 ID * @param collapsed - 要设置的折叠状态 * @returns 如果节点找到并成功设置状态,则返回 true;否则返回 false */ setNodeCollapsed(nodeId: string, collapsed: boolean): boolean; /** * 获取节点的折叠状态 * @param nodeId - 要查询的节点 ID * @returns 节点的折叠状态,如果节点不存在则返回 undefined */ getNodeCollapsed(nodeId: string): boolean | undefined; /** * 展开所有节点 * @returns 成功展开的节点数量 */ expandAllNodes(): number; /** * 折叠所有非根节点 * @returns 成功折叠的节点数量 */ collapseAllNodes(): number; /** * 设置思维导图布局方向 * @param isHorizontal - 是否水平布局 */ setHorizontal(isHorizontal: boolean): void; /** * 将指定 ID 的节点聚焦到视口中心 * @param nodeId - 要聚焦的节点的 ID * @returns 如果节点找到并成功聚焦,则返回 true;否则返回 false */ focusOnNode(nodeId: string): boolean; /** * 放大思维导图 * @param cx - 缩放中心点的 X 坐标,默认为 0 * @param cy - 缩放中心点的 Y 坐标,默认为 0 */ zoomIn(cx?: number, cy?: number): void; /** * 缩小思维导图 * @param cx - 缩放中心点的 X 坐标,默认为 0 * @param cy - 缩放中心点的 Y 坐标,默认为 0 */ zoomOut(cx?: number, cy?: number): void; /** * 重置思维导图缩放比例至默认值 * @param cx - 缩放中心点的 X 坐标,默认为 0 * @param cy - 缩放中心点的 Y 坐标,默认为 0 */ resetZoom(cx?: number, cy?: number): void; /** * 内部放大方法,支持传入原始事件 * @param cx - 缩放中心点的 X 坐标 * @param cy - 缩放中心点的 Y 坐标 * @param originalEvent - 原始滚轮事件,可选 */ private _zoomIn; /** * 内部缩小方法,支持传入原始事件 * @param cx - 缩放中心点的 X 坐标 * @param cy - 缩放中心点的 Y 坐标 * @param originalEvent - 原始滚轮事件,可选 */ private _zoomOut; /** * 重置思维导图布局并重新渲染 * @todo 考虑是否设置为私有 */ rebuild(): void; /** * 计算思维导图布局 * @returns 布局计算后的根节点 */ private _calculateLayoutInternal; /** * 当节点尺寸变化时,重新计算布局并更新受影响的节点位置 * @param changedNode - 尺寸发生变化的节点 */ private _updateLayoutForNodeSizeChange; /** * 执行布局计算、创建元素和连接线,添加元素到容器并渲染思维导图 */ private _layoutAndCreateElementsAndRender; /** * 将 MindNode 转换为 Element 和 Line 数组 * @param node - 要转换的思维导图节点 * @param isHorizontal - 是否为水平布局 * @returns 包含元素和连接线的元组 */ private _mindNodeToElementsAndLinesRecursive; /** * 创建节点元素 * @param node - 节点对象 * @returns 节点元素对象 */ private _createNodeElement; /** * 解析节点内容。 * 此方法会决定最终用于节点显示的内容。 * 如果原始数据 nodeData.content 提供了内容定义,并且与 mindNode.content 中缓存的定义不同, * 则会使用 nodeData.content 更新 mindNode.content。 * @param mindNode - 思维导图节点 * @returns 解析后的节点显示内容 (字符串、HTML元素或其数组) */ private _resolveNodeContent; /** * 创建连接线 * @param from - 起始节点 * @param to - 结束节点 * @param isHorizontal - 是否水平连接 * @returns 连接线对象 */ private _createConnectionLine; /** * 基于两个节点的位置和尺寸计算边缘连接点 * @param from - 起始节点 * @param to - 结束节点 * @param isHorizontal - 是否水平连接,否则为垂直连接 * @returns 起始点和结束点的坐标 */ private _calculateConnectionPoint; /** * 更新所有 Element 的位置以匹配其对应 MindNode 的位置 */ private _updateAllElementPositions; /** * 更新所有连接线的位置 */ private _updateAllConnectionLines; /** * 更新指定节点相关的连接线(到父节点和到子节点) * @param node - 需要更新连接线的节点 */ private _updateConnectionsForNode; /** * 更新容器边界以适应新的内容尺寸 */ private _updateContainerBounds; /** * 初始化或重新初始化拖拽管理器 * 配置节点和画布的拖拽行为并绑定相关事件 */ private _initializeDraggableManager; /** * 初始化鼠标滚轮管理器 * 配置滚轮缩放行为并绑定相关事件 */ private _initializeWheelManager; /** * 设置容器尺寸变化监听器 */ private _setupContainerResizeListener; /** * 处理节点拖拽的逻辑 * @param draggedElement - 被拖拽的 DOM 元素对应的 Element 对象 * @param deltaX - X 轴拖拽距离 * @param deltaY - Y 轴拖拽距离 */ private _handleNodeDrag; /** * 处理画布拖拽的逻辑 * @param deltaX - X 轴拖拽距离 * @param deltaY - Y 轴拖拽距离 */ private _handleCanvasDrag; /** * 输出思维导图容器的调试信息 */ debug(): void; /** * 进入全屏模式 * @param mode - 全屏模式 ('native' 或 'pseudo')。如果未提供,则使用构造函数中配置的默认模式 * @returns Promise,成功时 resolve true,失败时 reject error */ enterFullscreen(mode?: 'native' | 'pseudo'): Promise; /** * 退出全屏模式 * 会自动检测并退出当前激活的全屏模式 (原生或模拟) * @returns Promise,成功时 resolve true,失败时 reject error */ exitFullscreen(): Promise; /** * 切换全屏状态 * @param mode - 全屏模式 ('native' 或 'pseudo')。如果未提供,则使用构造函数中配置的默认模式 * @returns Promise,成功时 resolve 新的全屏状态 (true 为进入,false 为退出) */ toggleFullscreen(mode?: 'native' | 'pseudo'): Promise; /** * 进入原生全屏模式 * @private */ private _enterNativeFullscreen; /** * 退出原生全屏模式 * @private */ private _exitNativeFullscreen; /** * 初始化原生全屏状态监听器 * @private */ private _initializeFullscreenListener; /** * 进入模拟全屏模式 * @private */ private _enterPseudoFullscreen; /** * 退出模拟全屏模式 * @private */ private _exitPseudoFullscreen; } /** * 思维导图树形数据类型(用于描述思维导图节点的结构和内容) * 通过 children 数组直接表示层级关系 */ export interface TreeNode { /** 节点唯一标识符 */ id?: string; /** 节点位置坐标,可以是对象或 Vector 实例 */ position?: { x: number; y: number; } | Vector; /** 节点尺寸,可以是对象或 Vector 实例 */ size?: { x: number; y: number; } | Vector; /** 子节点数组 */ children?: TreeNode[]; /** 节点是否折叠,默认为 false (不折叠) */ collapsed?: boolean; /** * 节点内容,可以是文本、HTML 元素、HTML 元素数组,或一个返回文本/HTML元素/HTML元素数组的回调函数 * 如果是函数,它将接收原始的 TreeNode 数据作为参数 * 优先级比传入 MindMap 的 contentCallback 高 */ content?: ContentType; /** 允许任意额外属性 */ [key: string]: any; } /** * 思维导图扁平数据类型(用于描述思维导图节点的结构和内容) * 通过 parentId 间接表示层级关系 */ export interface FlatNode { /** 节点唯一标识符 */ id?: string; /** 父节点ID */ parentId?: string; /** 节点位置坐标,可以是对象或 Vector 实例 */ position?: { x: number; y: number; } | Vector; /** 节点尺寸,可以是对象或 Vector 实例 */ size?: { x: number; y: number; } | Vector; /** 节点是否折叠,默认为 false (不折叠) */ collapsed?: boolean; /** * 节点内容,可以是文本、HTML 元素、HTML 元素数组,或一个返回文本/HTML元素/HTML元素数组的回调函数 * 如果是函数,它将接收原始的 FlatNode 数据作为参数 * 优先级比传入 MindMap 的 contentCallback 高 */ content?: ContentType; /** 允许任意额外属性 */ [key: string]: any; } /** * 思维导图样式配置类型 * 用于定制思维导图的视觉外观 */ export declare type MindMapStyle = { /** 连接线宽度 */ lineWidth?: number; /** 连接线颜色 */ lineColor?: string; /** 节点边框宽度 */ nodeBorderWidth?: number; /** 节点背景颜色 */ nodeBgColor?: string; /** 节点边框颜色 */ nodeBorderColor?: string; }; /** * 思维导图对齐选项类型 * 控制思维导图节点的对齐方式 */ export declare type MindMapAlign = { /** * 对齐模式 * - cross-axis-start-edge: 交叉轴起始边与视口起始边对齐 * - cross-axis-center: 交叉轴居中对齐到视口中心 * - node-center: 节点中心居中对齐到视口中心 */ mode: AlignOptions['mode']; /** 目标节点ID,仅用于 'node-center' 模式 */ targetNodeId?: AlignOptions['targetNodeId']; }; /** * 思维导图拖拽配置类型 * 定制思维导图的拖拽行为 */ export declare type MindMapDragOptions = { /** 是否启用节点拖拽 */ enableNodeDrag?: boolean; /** 是否启用画布拖拽 */ enableCanvasDrag?: boolean; /** 拖拽节点的鼠标按钮 */ dragNodeButton?: MouseButton[] | MouseButton; /** 拖拽画布的鼠标按钮 */ dragCanvasButton?: MouseButton[] | MouseButton; /** 是否使用节流减少事件触发频率 */ useThrottle?: boolean; /** 节流函数的等待时间 */ throttleWait?: number; }; /** * 思维导图缩放配置类型 * 定制思维导图的缩放行为 */ export declare type MindMapZoomOptions = { /** 是否启用滚轮缩放 */ enableWheelZoom?: boolean; /** 每次缩放步长,如 0.1 表示 10% */ zoomStep?: number; /** 是否反转滚轮方向 */ invertWheelDirection?: boolean; /** 最小缩放比例,如 0.1 表示最小缩放到 10% */ minZoom?: number; /** 最大缩放比例,如 5.0 表示最大缩放到 500% */ maxZoom?: number; /** 是否使用节流减少事件触发频率 */ useThrottle?: boolean; /** 节流函数的等待时间 */ throttleWait?: number; }; export declare type FullscreenOptions = { /** 全屏时背景颜色(可以设置为任何有效的 CSS 颜色值) */ fullscreenBgColor?: string; /** * 全屏模式 * - 'native': 使用浏览器原生全屏 API * - 'pseudo': 使用 CSS 模拟全屏效果 * @default 'native' */ fullscreenMode?: 'native' | 'pseudo'; }; /** * 思维导图调试选项类型 * 不对外公开,仅用于开发和调试 */ export declare type DebugOptions = { rootContainerBgColor?: string; drawGridBackground?: boolean; }; /** * 思维导图全屏选项的默认配置 */ export declare const DEFAULT_FULLSCREEN_OPTIONS: Required; /** * 思维导图拖拽选项的默认配置 */ export declare const DEFAULT_DRAG_OPTIONS: Required; /** * 思维导图缩放选项的默认配置 */ export declare const DEFAULT_ZOOM_OPTIONS: Required; export declare type NodeLike = MindNode | TreeNode | FlatNode; /** * MindMap 节点拖拽事件数据 */ export interface MindMapNodeEvent { /** 原始鼠标事件 */ originalEvent: MouseEvent; /** 按下的鼠标按钮 */ button: MouseButton | null; /** 被拖拽的 MindNode 节点 */ node: MindNode; /** 拖拽开始时鼠标在容器内的 X 坐标 */ mouseX: number; /** 拖拽开始时鼠标在容器内的 Y 坐标 */ mouseY: number; /** X 轴拖拽距离 (仅 NODE_DRAG 事件) */ deltaX?: number; /** Y 轴拖拽距离 (仅 NODE_DRAG 事件) */ deltaY?: number; } /** * MindMap 容器尺寸变化事件数据 */ export interface MindMapContainerResizeEvent { /** 新的容器宽度 */ width: number; /** 新的容器高度 */ height: number; } /** * MindMap 画布拖拽事件数据 */ export interface MindMapCanvasEvent { /** 原始鼠标事件 */ originalEvent: MouseEvent; /** 按下的鼠标按钮 */ button: MouseButton | null; /** 拖拽开始时鼠标在容器内的 X 坐标 */ mouseX: number; /** 拖拽开始时鼠标在容器内的 Y 坐标 */ mouseY: number; /** X 轴拖拽距离 (仅 CANVAS_DRAG 事件) */ deltaX?: number; /** Y 轴拖拽距离 (仅 CANVAS_DRAG 事件) */ deltaY?: number; } /** * MindMap 缩放事件数据 */ export interface MindMapZoomEvent { /** 原始滚轮事件 (可选) */ originalEvent?: WheelEvent; /** 当前的缩放比例向量 {x, y} */ scale: Vector; /** 缩放中心在容器内的 X 坐标 */ mouseX: number; /** 缩放中心在容器内的 Y 坐标 */ mouseY: number; } /** * MindMap 布局更新事件数据 * 当思维导图的布局(例如,从水平切换到垂直)发生变化并更新完成后触发 */ export interface MindMapLayoutEvent { direction: 'horizontal' | 'vertical'; } /** * MindMap 节点销毁事件数据 */ export interface MindMapNodeDestroyEvent { /** 被销毁节点对应的原始数据 */ node: NodeLike; } /** * MindMap 节点折叠事件数据 */ export interface MindMapNodeCollapseEvent { /** 折叠状态发生变化的节点 ID */ nodeId: string; /** 当前折叠状态 */ collapsed: boolean; /** 被折叠/展开的节点对应的原始数据 */ node: NodeLike; } /** * 全屏事件数据 */ export interface MindMapFullscreenEvent { /** 是否进入全屏状态 */ isFullscreen: boolean; /** 全屏容器元素 */ element: HTMLElement; } /** * 思维导图事件枚举 */ export declare enum MindMapEvents { /** 画布开始拖拽事件,抛出 {@link MindMapCanvasEvent} 类型事件对象 */ CANVAS_DRAG_START = "mindmap:canvas-dragstart", /** 画布拖拽中事件,抛出 {@link MindMapCanvasEvent} 类型事件对象 */ CANVAS_DRAG = "mindmap:canvas-drag", /** 画布结束拖拽事件,抛出 {@link MindMapCanvasEvent} 类型事件对象 */ CANVAS_DRAG_END = "mindmap:canvas-dragend", /** 缩放变化事件,抛出 {@link MindMapZoomEvent} 类型事件对象 */ ZOOM_CHANGE = "mindmap:zoom-change", /** 容器尺寸变化事件,抛出 {@link MindMapContainerResizeEvent} 类型事件对象 */ CONTAINER_RESIZE = "mindmap:container-resize", /** 布局更新完成事件,抛出 {@link MindMapLayoutEvent} 类型事件对象 */ LAYOUT_UPDATED = "mindmap:layout-updated", /** 节点折叠状态切换事件事件,抛出 {@link MindMapNodeCollapseEvent} 类型事件对象 */ NODE_COLLAPSE_CHANGED = "mindmap:node-collapse-changed", /** 节点销毁事件,抛出 {@link MindMapNodeDestroyEvent} 类型事件对象 */ NODE_DESTROYED = "node:destroyed", /** 思维导图销毁事件 */ MINDMAP_DESTROYED = "mindmap:destroyed", /** 全屏状态变化事件,抛出 {@link MindMapFullscreenEvent} 类型事件对象 */ FULLSCREEN_CHANGE = "mindmap:fullscreen-change" } /** * MindMap 事件名称到事件数据类型的映射 */ export interface MindMapEventMap { [MindMapEvents.CANVAS_DRAG_START]: MindMapCanvasEvent; [MindMapEvents.CANVAS_DRAG]: MindMapCanvasEvent; [MindMapEvents.CANVAS_DRAG_END]: MindMapCanvasEvent; [MindMapEvents.ZOOM_CHANGE]: MindMapZoomEvent; [MindMapEvents.CONTAINER_RESIZE]: MindMapContainerResizeEvent; [MindMapEvents.LAYOUT_UPDATED]: MindMapLayoutEvent; [MindMapEvents.NODE_COLLAPSE_CHANGED]: MindMapNodeCollapseEvent; [MindMapEvents.NODE_DESTROYED]: MindMapNodeDestroyEvent; [MindMapEvents.MINDMAP_DESTROYED]: void; [MindMapEvents.FULLSCREEN_CHANGE]: MindMapFullscreenEvent; }