# Toolbar 按钮调用链文档 本文档详细记录 Toolbar 中每个按钮的完整调用链,从用户点击到底层 3D 引擎 API。 --- ## 目录 1. [首页 (Home)](#1-首页-home) 2. [框选放大 (Zoom Box)](#2-框选放大-zoom-box) 3. [测量 (Measure)](#3-测量-measure) 4. [剖切菜单 (Section)](#4-剖切菜单-section) - [拾取面剖切 (Section Plane)](#41-拾取面剖切-section-plane) - [轴向剖切 (Section Axis)](#42-轴向剖切-section-axis) - [剖切盒 (Section Box)](#43-剖切盒-section-box) 5. [漫游 (Walk)](#5-漫游-walk) 6. [地图 (Map)](#6-地图-map) 7. [构件详情 (Property)](#7-构件详情-property) 8. [设置 (Setting)](#8-设置-setting) 9. [信息 (Info)](#9-信息-info) 10. [全屏 (Fullscreen)](#10-全屏-fullscreen) --- ## 1. 首页 (Home) **按钮 ID**: `home` **功能**: 相机回到初始位置(主视角) **保持激活**: 否 ### 调用链 ``` 用户点击 [首页] 按钮 │ ▼ Button onClick (buttons/home/index.ts) │ registry.engine3d?.CameraGoHome() ▼ EngineManager.CameraGoHome() (managers/engine-manager.ts) │ this.engineInstance.CameraGoHome() ▼ Engine.CameraGoHome() (components/engine/index.ts) │ this.engine.viewCube.CameraGoHome() ▼ 底层引擎 API: engine.viewCube.CameraGoHome() ``` ### 代码摘要 **按钮定义** (`buttons/home/index.ts`): ```typescript onClick: (button) => { const registry = ManagerRegistry.getInstance(); registry.engine3d?.CameraGoHome(); } ``` **EngineManager** (`managers/engine-manager.ts`): ```typescript public CameraGoHome(): void { this.engineInstance.CameraGoHome(); } ``` **Engine 组件** (`components/engine/index.ts`): ```typescript public CameraGoHome() { this.engine.viewCube.CameraGoHome(); } ``` --- ## 2. 框选放大 (Zoom Box) **按钮 ID**: `zoom-box` **功能**: 激活框选放大模式,用户可以框选区域进行放大 **保持激活**: 否 ### 调用链 ``` 用户点击 [框选放大] 按钮 │ ▼ Button onClick (buttons/zoom-box/index.ts) │ registry.engine3d?.activateZoomBox() ▼ EngineManager.activateZoomBox() (managers/engine-manager.ts) │ this.engineInstance.activateZoomBox() ▼ Engine.activateZoomBox() (components/engine/index.ts) │ this.engine.rangeScale?.active() ▼ 底层引擎 API: engine.rangeScale.active() ``` ### 代码摘要 **按钮定义** (`buttons/zoom-box/index.ts`): ```typescript onClick: () => { const registry = ManagerRegistry.getInstance(); registry.engine3d?.activateZoomBox(); } ``` **EngineManager** (`managers/engine-manager.ts`): ```typescript public activateZoomBox(): void { this.engineInstance.activateZoomBox(); } ``` **Engine 组件** (`components/engine/index.ts`): ```typescript public activateZoomBox(): void { this.engine.rangeScale?.active(); } ``` --- ## 3. 测量 (Measure) **按钮 ID**: `measure` **功能**: 打开测量对话框,支持距离、角度、标高、体积等多种测量 **保持激活**: 是 ### 调用链 #### 3.1 打开测量对话框 ``` 用户点击 [测量] 按钮(激活) │ ▼ Button onClick (buttons/measure/index.ts) │ registry.measure?.show() ▼ MeasureDialogManager.show() (继承自 BaseDialogManager) │ createContent() → 创建 MeasurePanel │ onDialogCreated() ▼ 对话框显示,等待用户选择测量模式 ``` #### 3.2 用户选择测量模式 ``` 用户在 Panel 中选择测量模式(如:距离测量) │ ▼ MeasurePanel.onModeChange('distance') │ ▼ MeasureDialogManager 回调 (managers/measure-dialog-manager.ts) │ registry.engine3d?.activateMeasure(mode) ▼ EngineManager.activateMeasure('distance') (managers/engine-manager.ts) │ this.engineInstance.activateMeasure(mode) ▼ Engine.activateMeasure('distance') (components/engine/index.ts) │ switch(mode) → activateDistanceMeasure() ▼ Engine.activateDistanceMeasure() │ this.engine.measure.active() // 激活主测量模块 │ this.engine.measure.distanceMeasure.active() // 激活距离测量 ▼ 底层引擎 API: - engine.measure.active() - engine.measure.distanceMeasure.active() ``` #### 3.3 清除所有测量 ``` 用户点击 [删除全部] 按钮 │ ▼ MeasurePanel.onClearAll() │ ▼ MeasureDialogManager 回调 │ registry.engine3d?.clearAllMeasures() ▼ EngineManager.clearAllMeasures() │ this.engineInstance.clearAllMeasures() ▼ Engine.clearAllMeasures() │ this.engine.measure.clearAll() ▼ 底层引擎 API: engine.measure.clearAll() ``` #### 3.4 关闭测量对话框 ``` 用户关闭对话框 / 再次点击按钮 │ ▼ MeasureDialogManager.onBeforeDestroy() │ registry.engine3d.deactivateMeasure() ▼ EngineManager.deactivateMeasure() │ this.engineInstance.deactivateMeasure() ▼ Engine.deactivateMeasure() │ this.engine.measure.disActive() ▼ 底层引擎 API: engine.measure.disActive() ``` ### 测量模式与底层 API 对照表 | 模式 | Engine 方法 | 底层 API | |------|-------------|----------| | distance (距离) | `activateDistanceMeasure()` | `engine.measure.distanceMeasure.active()` | | minDistance (最小距离) | `activateMinDistanceMeasure()` | `engine.measure.clearDistanceMeasure.active()` | | angle (角度) | `activateAngleMeasure()` | `engine.measure.angleMeasure.active()` | | elevation (标高) | `activateElevationMeasure()` | `engine.measure.elevationMeasure.active()` | | volume (体积) | `activateVolumeMeasure()` | `engine.measure.areaMeasure.active()` | | slope (坡度) | `activateSlopeMeasure()` | `engine.measure.slopeMeasure.active()` | | laserDistance (激光测距) | `activateLaserDistanceMeasure()` | ⚠️ 暂未实现 | | spaceVolume (空间体积) | `activateSpaceVolumeMeasure()` | ⚠️ 暂未实现 | --- ## 4. 剖切菜单 (Section) **按钮 ID**: `section` **类型**: 菜单按钮,展开后显示子按钮 ### 4.1 拾取面剖切 (Section Plane) **按钮 ID**: `section-plane` **功能**: 拾取模型表面进行剖切 **保持激活**: 是 **互斥**: 是(同一时间只能激活一种剖切) #### 调用链 ``` 用户点击 [拾取面剖切] 按钮(激活) │ ▼ Button onClick (buttons/section/section-plane/index.ts) │ registry.sectionPlane?.show() ▼ SectionPlaneDialogManager.show() (继承自 BaseDialogManager) │ createContent() → 创建 SectionPlanePanel │ onDialogCreated() ▼ 对话框显示(拾取面剖切需要用户在3D场景中点击表面) ``` > ⚠️ **注意**: 拾取面剖切的底层 API 对接尚未完成,目前仅显示 UI 面板。 --- ### 4.2 轴向剖切 (Section Axis) **按钮 ID**: `section-axis` **功能**: 沿 X/Y/Z 轴向进行剖切 **保持激活**: 是 **互斥**: 是 #### 调用链 - 打开对话框 ``` 用户点击 [轴向剖切] 按钮(激活) │ ▼ Button onClick (buttons/section/section-axis/index.ts) │ registry.sectionAxis?.show() ▼ SectionAxisDialogManager.show() (继承自 BaseDialogManager) │ createContent() → 创建 SectionAxisPanel │ onDialogCreated() │ └── registry.engine3d.activateSectionAxis('x') // 默认激活 X 轴 ▼ EngineManager.activateSectionAxis('x') │ this.engineInstance.activateSectionAxis(axis) ▼ Engine.activateSectionAxis('x') │ this.engine.clipping.sectionPlaneX.active() ▼ 底层引擎 API: engine.clipping.sectionPlaneX.active() ``` #### 调用链 - 切换轴向 ``` 用户在 Panel 中切换轴向(如:Y 轴) │ ▼ SectionAxisPanel.onAxisChange('y') │ ▼ SectionAxisDialogManager 回调 │ registry.engine3d?.activateSectionAxis('y') ▼ EngineManager.activateSectionAxis('y') │ this.engineInstance.activateSectionAxis(axis) ▼ Engine.activateSectionAxis('y') │ // 1. 先停用当前轴向 (X) │ this.engine.clipping.sectionPlaneX.disActive() │ // 2. 再激活新轴向 (Y) │ this.engine.clipping.sectionPlaneY.active() ▼ 底层引擎 API: - engine.clipping.sectionPlaneX.disActive() - engine.clipping.sectionPlaneY.active() ``` #### 调用链 - 关闭对话框 ``` 用户关闭对话框 / 再次点击按钮 │ ▼ SectionAxisDialogManager.onBeforeDestroy() │ registry.engine3d?.deactivateSectionAxis() ▼ EngineManager.deactivateSectionAxis() │ this.engineInstance.deactivateSectionAxis() ▼ Engine.deactivateSectionAxis() │ this.engine.clipping.disActive() ▼ 底层引擎 API: engine.clipping.disActive() ``` #### 轴向与底层 API 对照表 | 轴向 | Engine 内部调用 | 底层 API | |------|----------------|----------| | x | `planeMap['x']` | `engine.clipping.sectionPlaneX.active()` | | y | `planeMap['y']` | `engine.clipping.sectionPlaneY.active()` | | z | `planeMap['z']` | `engine.clipping.sectionPlaneZ.active()` | --- ### 4.3 剖切盒 (Section Box) **按钮 ID**: `section-box` **功能**: 六面体剖切盒,可调节 X/Y/Z 轴的最小/最大范围 **保持激活**: 是 **互斥**: 是 #### 调用链 - 打开对话框 ``` 用户点击 [剖切盒] 按钮(激活) │ ▼ Button onClick (buttons/section/section-box/index.ts) │ registry.sectionBox?.show() ▼ SectionBoxDialogManager.show() (继承自 BaseDialogManager) │ createContent() → 创建 SectionBoxPanel │ onDialogCreated() │ └── registry.engine3d?.activateSectionBox() ▼ EngineManager.activateSectionBox() │ this.engineInstance.activateSectionBox() ▼ Engine.activateSectionBox() │ this.engine.clipping.sectionBox.active() ▼ 底层引擎 API: engine.clipping.sectionBox.active() ``` #### 调用链 - 调整范围(拖动滑块) ``` 用户拖动 X/Y/Z 轴滑块调整范围 │ ▼ SectionBoxPanel.onRangeChange(range) │ range = { x: {min, max}, y: {min, max}, z: {min, max} } // 百分比 0-100 ▼ SectionBoxDialogManager 回调 │ registry.engine3d?.setSectionBoxRange(range) ▼ EngineManager.setSectionBoxRange(range) │ this.engineInstance.setSectionBoxRange(range) ▼ Engine.setSectionBoxRange(range) │ this.engine.clipping.sectionBox.setboxPercent(range) // 直传百分比 ▼ 底层引擎 API: engine.clipping.sectionBox.setboxPercent(range) │ (底层负责百分比→坐标转换) ``` #### 调用链 - 适应到模型 ``` 用户点击 [适应到模型] 按钮 │ ▼ SectionBoxPanel.onFitToModel() │ ▼ SectionBoxDialogManager 回调 │ registry.engine3d?.fitSectionBoxToModel() ▼ EngineManager.fitSectionBoxToModel() │ this.engineInstance.fitSectionBoxToModel() ▼ Engine.fitSectionBoxToModel() │ const box = this.engine.octreeBox?.getBoundingBox() │ this.engine.clipping.sectionBox.setBox(box) ▼ 底层引擎 API: - engine.octreeBox.getBoundingBox() - engine.clipping.sectionBox.setBox(box) ``` #### 调用链 - 重置 ``` 用户点击 [重置] 按钮 │ ▼ SectionBoxPanel.onReset() │ ▼ SectionBoxDialogManager 回调 │ registry.engine3d?.resetSectionBox() ▼ EngineManager.resetSectionBox() │ this.engineInstance.resetSectionBox() ▼ Engine.resetSectionBox() │ this.fitSectionBoxToModel() // 内部调用适应到模型 ▼ (同上 "适应到模型" 流程) ``` #### 调用链 - 关闭对话框 ``` 用户关闭对话框 / 再次点击按钮 │ ▼ SectionBoxDialogManager.onBeforeDestroy() │ registry.engine3d?.deactivateSectionBox() ▼ EngineManager.deactivateSectionBox() │ this.engineInstance.deactivateSectionBox() ▼ Engine.deactivateSectionBox() │ this.engine.clipping.sectionBox.disActive() ▼ 底层引擎 API: engine.clipping.sectionBox.disActive() ``` #### 剖切盒 API 汇总 | 操作 | Engine 方法 | 底层 API | |------|-------------|----------| | 激活 | `activateSectionBox()` | `engine.clipping.sectionBox.active()` | | 停用 | `deactivateSectionBox()` | `engine.clipping.sectionBox.disActive()` | | 设置范围(百分比) | `setSectionBoxRange(range)` | `engine.clipping.sectionBox.setboxPercent(range)` | | 设置范围(坐标) | - | `engine.clipping.sectionBox.setboxXyz(xyz)` | | 适应到模型 | `fitSectionBoxToModel()` | `engine.clipping.sectionBox.setBox(box)` | | 获取包围盒 | - | `engine.octreeBox.getBoundingBox()` | #### 数据格式说明 | 层级 | 数据格式 | 示例 | |------|----------|------| | UI / SDK | 百分比 (0-100) | `{ x: {min: 20, max: 80}, y: {...}, z: {...} }` | | 底层引擎 | 百分比 → 内部转换为坐标 | 底层负责转换 | --- ## 5. 漫游 (Walk) - 第一人称漫游 > 标注说明: `[SDK]` = SDK 层代码, `[底层]` = bim_engine_base 底层引擎 **按钮 ID**: `walk` **功能**: 打开漫游控制面板,支持第一人称漫游模式 **保持激活**: 否 ### 5.1 第一人称漫游模式开关 ``` UI 点击漫游按钮 → [SDK] WalkControlPanel.onWalkModeToggle(isActive) → [SDK] WalkControlManager.onWalkModeToggle → [SDK] EngineManager.activateFirstPersonMode() / deactivateFirstPersonMode() → [SDK] Engine.activateFirstPersonMode() / deactivateFirstPersonMode() → [底层] engine.controlModule.switchFirstPersonMode() / switchDefaultMode() ``` ### 5.2 速度调节 ``` UI 速度按钮 (1-10) → [SDK] WalkControlPanel.onSpeedChange(speed) → [SDK] WalkControlManager.onSpeedChange → [SDK] EngineManager.setWalkSpeed(speed * 0.01) // 值转换: UI 1-10 → 引擎 0.01-0.1 → [SDK] Engine.setWalkSpeed(speed) → [底层] engine.controlModule.firstPersonControls.moveSpeed = speed ``` ### 5.3 重力开关 ``` UI 重力复选框 → [SDK] WalkControlPanel.onGravityToggle(enabled) → [SDK] WalkControlManager.onGravityToggle → [SDK] EngineManager.setWalkGravity(enabled) → [SDK] Engine.setWalkGravity(enabled) → [底层] engine.controlModule.firstPersonControls.applyGravity = enabled ``` ### 5.4 碰撞检测开关 ``` UI 碰撞复选框 → [SDK] WalkControlPanel.onCollisionToggle(enabled) → [SDK] WalkControlManager.onCollisionToggle → [SDK] EngineManager.setWalkCollision(enabled) → [SDK] Engine.setWalkCollision(enabled) → [底层] engine.controlModule.firstPersonControls.applyCollision = enabled ``` --- ## 6. 地图 (Map) **按钮 ID**: `map` **功能**: 打开/关闭地图对话框 **保持激活**: 是 ### 调用链 ``` 用户点击 [地图] 按钮 │ ▼ Button onClick (buttons/map/index.ts) │ if (registry.map?.isOpen()) { │ registry.map?.hide() │ } else { │ registry.map?.show() │ } ▼ MapDialogManager.show() / hide() │ ▼ 地图对话框显示/隐藏 ``` ### 事件监听 ```typescript // 按钮定义中监听地图开关事件,同步按钮激活状态 registry.on('map:opened', () => { registry.toolbar?.setBtnActive('map', true); }); registry.on('map:closed', () => { registry.toolbar?.setBtnActive('map', false); }); ``` --- ## 7. 构件详情 (Property) **按钮 ID**: `property` **功能**: 打开构件属性面板 **保持激活**: 否 ### 调用链 ``` 用户点击 [构件详情] 按钮 │ ▼ Button onClick (buttons/property/index.ts) │ registry.propertyPanel?.show() ▼ PropertyPanelManager.show() │ ▼ 属性面板显示 ``` --- ## 8. 设置 (Setting) **按钮 ID**: `setting` **功能**: 打开设置面板 **保持激活**: 否 ### 调用链 ``` 用户点击 [设置] 按钮 │ ▼ Button onClick (buttons/setting/index.ts) │ console.log('设置按钮被点击') ▼ ⚠️ 暂未实现具体功能 ``` --- ## 9. 信息 (Info) **按钮 ID**: `info` **功能**: 打开信息对话框 **保持激活**: 否 ### 调用链 ``` 用户点击 [信息] 按钮 │ ▼ Button onClick (buttons/info/index.ts) │ registry.emit('ui:open-dialog', { id: 'info' }) ▼ 事件系统广播 'ui:open-dialog' 事件 │ ▼ 监听该事件的组件响应并打开信息对话框 ``` --- ## 10. 全屏 (Fullscreen) **按钮 ID**: `fullscreen` **功能**: 切换全屏模式 **保持激活**: 否 ### 调用链 ``` 用户点击 [全屏] 按钮 │ ▼ Button onClick (buttons/fullscreen/index.ts) │ // 检测当前是否全屏 │ const isFullscreen = !!document.fullscreenElement │ ├── 如果不是全屏: │ targetElem.requestFullscreen({ navigationUI: 'hide' }) │ ▼ │ 浏览器 API: Element.requestFullscreen() │ └── 如果是全屏: document.exitFullscreen() ▼ 浏览器 API: Document.exitFullscreen() ``` ### 注意事项 - 全屏功能使用浏览器原生 API,不涉及底层 3D 引擎 - 支持多种浏览器前缀:`webkitRequestFullscreen`、`mozRequestFullScreen`、`msRequestFullscreen` - 在 iframe 中使用需要父级 iframe 标签添加 `allow="fullscreen"` 属性 --- ## 附录:调用链层级说明 ``` ┌─────────────────────────────────────────────────────────────────────┐ │ L1: Toolbar Button │ │ 文件: src/components/button-group/toolbar/buttons/*/index.ts │ │ 职责: 定义按钮配置,处理 onClick 事件 │ └────────────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ L2: DialogManager │ │ 文件: src/managers/*-dialog-manager.ts │ │ 职责: 管理对话框生命周期,绑定 Panel 回调到 EngineManager │ └────────────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ L3: EngineManager │ │ 文件: src/managers/engine-manager.ts │ │ 职责: 代理 Engine 组件,提供统一 API,检查初始化状态 │ └────────────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ L4: Engine Component │ │ 文件: src/components/engine/index.ts │ │ 职责: 封装底层引擎,维护状态,进行数据转换 │ └────────────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ L5: 底层 3D 引擎 (iflow-engine-base) │ │ 来源: 第三方 SDK │ │ 职责: 实际 3D 渲染和功能实现 │ └─────────────────────────────────────────────────────────────────────┘ ``` --- ## 附录:ManagerRegistry 访问方式 ```typescript // 在 Button 中获取 Registry const registry = ManagerRegistry.getInstance(); // 访问各个 Manager registry.engine3d // EngineManager - 3D 引擎 registry.toolbar // ToolbarManager - 工具栏 registry.dialog // DialogManager - 对话框 registry.measure // MeasureDialogManager - 测量 registry.sectionPlane // SectionPlaneDialogManager - 拾取面剖切 registry.sectionAxis // SectionAxisDialogManager - 轴向剖切 registry.sectionBox // SectionBoxDialogManager - 剖切盒 registry.walkControl // WalkControlManager - 漫游控制 registry.map // MapDialogManager - 地图 registry.propertyPanel // PropertyPanelManager - 属性面板 ```