Files
bim_engine/.sisyphus/drafts/TOOLBAR_API_CALLCHAIN.md
2026-01-28 11:24:35 +08:00

734 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 - 属性面板
```