添加测试信息
This commit is contained in:
1344
AI_COLLABORATION.md
Normal file
1344
AI_COLLABORATION.md
Normal file
File diff suppressed because it is too large
Load Diff
159
ARCHITECTURE.md
159
ARCHITECTURE.md
@@ -1,159 +0,0 @@
|
|||||||
# Engine3DManager 架构设计说明
|
|
||||||
|
|
||||||
## 🎯 设计目标
|
|
||||||
|
|
||||||
将第三方 3D 引擎封装为管理器组件,并通过**依赖注入**实现解耦。
|
|
||||||
|
|
||||||
## 🏗️ 架构模式
|
|
||||||
|
|
||||||
### 依赖注入 (Dependency Injection)
|
|
||||||
|
|
||||||
`Engine3DManager` 不直接依赖具体的 `createEngine` 实现,而是通过参数接收引擎创建函数。
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Engine3DManager 定义工厂函数类型
|
|
||||||
export type Engine3DFactory = (config: {
|
|
||||||
containerId: string;
|
|
||||||
backgroundColor?: number;
|
|
||||||
version?: 'v1' | 'v2';
|
|
||||||
showStats?: boolean;
|
|
||||||
showViewCube?: boolean;
|
|
||||||
}) => any;
|
|
||||||
|
|
||||||
// initialize 方法接受外部传入的创建函数
|
|
||||||
public initialize(createEngine: Engine3DFactory, options?: Engine3DOptions): boolean {
|
|
||||||
this.engine = createEngine({ /* config */ });
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 职责分离
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────┐
|
|
||||||
│ BimEngine (总控制器) │
|
|
||||||
│ - 导入 createEngine │
|
|
||||||
│ - 组合各个 Manager │
|
|
||||||
│ - 提供简洁的 API │
|
|
||||||
└──────────────┬──────────────────────────────┘
|
|
||||||
│ 传入 createEngine
|
|
||||||
▼
|
|
||||||
┌─────────────────────────────────────────────┐
|
|
||||||
│ Engine3DManager (3D引擎管理器) │
|
|
||||||
│ - ❌ 不导入 createEngine │
|
|
||||||
│ - ✅ 接受外部传入的创建函数 │
|
|
||||||
│ - 管理引擎生命周期 │
|
|
||||||
│ - 提供统一接口 │
|
|
||||||
└──────────────┬──────────────────────────────┘
|
|
||||||
│ 调用
|
|
||||||
▼
|
|
||||||
┌─────────────────────────────────────────────┐
|
|
||||||
│ createEngine (第三方3D引擎) │
|
|
||||||
│ - bim-engine-sdk.es.js │
|
|
||||||
│ - 被完全封装 │
|
|
||||||
└─────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
## 💡 优势
|
|
||||||
|
|
||||||
### 1. **解耦 (Decoupling)**
|
|
||||||
- `Engine3DManager` 不依赖具体的 3D 引擎实现
|
|
||||||
- 可以轻松切换不同的 3D 引擎,只需更改 `BimEngine` 中的导入
|
|
||||||
|
|
||||||
### 2. **可测试性 (Testability)**
|
|
||||||
```typescript
|
|
||||||
// 测试时可以注入 mock 引擎
|
|
||||||
const mockCreateEngine = (config) => ({
|
|
||||||
loader: { loadModel: jest.fn() }
|
|
||||||
});
|
|
||||||
|
|
||||||
manager.initialize(mockCreateEngine, options);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. **灵活性 (Flexibility)**
|
|
||||||
```typescript
|
|
||||||
// 可以在运行时决定使用哪个引擎
|
|
||||||
import { createEngineV1 } from './engine-v1';
|
|
||||||
import { createEngineV2 } from './engine-v2';
|
|
||||||
|
|
||||||
const engineFactory = useV2 ? createEngineV2 : createEngineV1;
|
|
||||||
manager.initialize(engineFactory, options);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. **单一职责 (Single Responsibility)**
|
|
||||||
- **BimEngine**: 负责集成和协调
|
|
||||||
- **Engine3DManager**: 负责管理 3D 引擎的生命周期
|
|
||||||
- **createEngine**: 负责创建引擎实例
|
|
||||||
|
|
||||||
## 📊 调用流程
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 1. 用户创建 BimEngine
|
|
||||||
const engine = new BimEngine('container');
|
|
||||||
|
|
||||||
// 2. 用户调用 initEngine3D
|
|
||||||
engine.initEngine3D({ backgroundColor: 0x333333 });
|
|
||||||
|
|
||||||
// 3. BimEngine 内部执行
|
|
||||||
// ↓
|
|
||||||
// 导入 createEngine
|
|
||||||
// ↓
|
|
||||||
// 调用 engine3D.initialize(createEngine, options)
|
|
||||||
// ↓
|
|
||||||
// Engine3DManager 使用传入的 createEngine 创建引擎实例
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔄 与其他 Manager 的对比
|
|
||||||
|
|
||||||
### DialogManager / ToolbarManager
|
|
||||||
```typescript
|
|
||||||
// 自包含,不依赖外部函数
|
|
||||||
constructor(container: HTMLElement) {
|
|
||||||
this.init(); // 直接初始化
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Engine3DManager
|
|
||||||
```typescript
|
|
||||||
// 依赖注入,接受外部函数
|
|
||||||
constructor(container: HTMLElement) {
|
|
||||||
this.createContainer(); // 只创建容器
|
|
||||||
}
|
|
||||||
|
|
||||||
initialize(createEngine: Engine3DFactory, options) {
|
|
||||||
this.engine = createEngine(config); // 使用注入的函数
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🎓 设计模式
|
|
||||||
|
|
||||||
采用的设计模式:
|
|
||||||
1. **工厂模式 (Factory Pattern)** - `Engine3DFactory` 类型
|
|
||||||
2. **依赖注入 (Dependency Injection)** - `createEngine` 通过参数传入
|
|
||||||
3. **延迟初始化 (Lazy Initialization)** - 构造时不创建引擎
|
|
||||||
|
|
||||||
## 🚀 未来扩展
|
|
||||||
|
|
||||||
### 支持多引擎
|
|
||||||
```typescript
|
|
||||||
engine.initEngine3D(createThreeJSEngine, options);
|
|
||||||
// 或
|
|
||||||
engine.initEngine3D(createBabylonEngine, options);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 条件加载
|
|
||||||
```typescript
|
|
||||||
// 根据设备性能选择引擎
|
|
||||||
const factory = isHighPerformance
|
|
||||||
? createAdvancedEngine
|
|
||||||
: createLightweightEngine;
|
|
||||||
|
|
||||||
engine.initEngine3D(factory, options);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📝 总结
|
|
||||||
|
|
||||||
通过依赖注入模式,`Engine3DManager` 实现了:
|
|
||||||
- ✅ 与具体 3D 引擎解耦
|
|
||||||
- ✅ 易于测试和维护
|
|
||||||
- ✅ 支持灵活切换引擎
|
|
||||||
- ✅ 保持职责单一清晰
|
|
||||||
207
USAGE_EXAMPLE.md
207
USAGE_EXAMPLE.md
@@ -1,207 +0,0 @@
|
|||||||
# BimEngine 使用示例
|
|
||||||
|
|
||||||
## 基础使用
|
|
||||||
|
|
||||||
### 1. 创建 BimEngine 实例
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { BimEngine } from './src/bim-engine';
|
|
||||||
|
|
||||||
// 方式 1: 使用 DOM 元素 ID
|
|
||||||
const engine = new BimEngine('my-container', {
|
|
||||||
locale: 'zh-CN',
|
|
||||||
theme: 'dark'
|
|
||||||
});
|
|
||||||
|
|
||||||
// 方式 2: 使用 DOM 元素引用
|
|
||||||
const containerEl = document.getElementById('my-container');
|
|
||||||
const engine2 = new BimEngine(containerEl, {
|
|
||||||
locale: 'en-US',
|
|
||||||
theme: 'light'
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 初始化 3D 引擎(延迟初始化)
|
|
||||||
|
|
||||||
**重要**: 3D 引擎采用延迟初始化模式,需要用户主动调用 `initEngine3D()` 方法。
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 先创建 BimEngine 实例
|
|
||||||
const engine = new BimEngine('my-container');
|
|
||||||
|
|
||||||
// 稍后在需要时初始化 3D 引擎
|
|
||||||
const success = engine.initEngine3D({
|
|
||||||
backgroundColor: 0x333333,
|
|
||||||
version: 'v1',
|
|
||||||
showStats: true,
|
|
||||||
showViewCube: true
|
|
||||||
});
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
console.log('3D 引擎初始化成功!');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查引擎是否已初始化
|
|
||||||
if (engine.isEngine3DInitialized()) {
|
|
||||||
// 可以加载模型了
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 加载 3D 模型
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 确保先初始化 3D 引擎
|
|
||||||
engine.initEngine3D({
|
|
||||||
backgroundColor: 0x1a1a1a,
|
|
||||||
showStats: true
|
|
||||||
});
|
|
||||||
|
|
||||||
// 加载模型 - 使用默认参数
|
|
||||||
engine.loadModel('/model/building.glb');
|
|
||||||
|
|
||||||
// 加载模型 - 自定义位置、旋转、缩放
|
|
||||||
engine.loadModel('/model/gujianzhu.glb', {
|
|
||||||
position: [10, -5, 0],
|
|
||||||
rotation: [0, Math.PI / 4, 0],
|
|
||||||
scale: [2, 2, 2]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 动态切换主题和语言
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 切换主题
|
|
||||||
engine.setTheme('dark');
|
|
||||||
engine.setTheme('light');
|
|
||||||
|
|
||||||
// 切换语言
|
|
||||||
engine.setLocale('zh-CN');
|
|
||||||
engine.setLocale('en-US');
|
|
||||||
|
|
||||||
// 设置自定义主题
|
|
||||||
engine.setCustomTheme({
|
|
||||||
background: '#1a1a1a',
|
|
||||||
textPrimary: '#ffffff',
|
|
||||||
textSecondary: '#999999',
|
|
||||||
// ... 其他主题配置
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 访问 3D 引擎实例
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 直接访问底层 3D 引擎
|
|
||||||
if (engine.engine3D) {
|
|
||||||
// 调用第三方 3D 引擎的其他方法
|
|
||||||
engine.engine3D.someOtherMethod();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 在 HTML 中使用
|
|
||||||
|
|
||||||
```html
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<style>
|
|
||||||
#bim-container {
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="bim-container"></div>
|
|
||||||
|
|
||||||
<script type="module">
|
|
||||||
import { BimEngine } from './dist/bim-engine-sdk.es.js';
|
|
||||||
|
|
||||||
const engine = new BimEngine('bim-container', {
|
|
||||||
engine3D: {
|
|
||||||
backgroundColor: 0x1a1a1a,
|
|
||||||
showStats: true,
|
|
||||||
showViewCube: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 加载模型
|
|
||||||
engine.loadModel('/models/building.glb', {
|
|
||||||
position: [0, 0, 0],
|
|
||||||
scale: [1.5, 1.5, 1.5]
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
## 在 Vue 3 中使用
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<template>
|
|
||||||
<div ref="containerRef" class="bim-container"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, onMounted, onUnmounted } from 'vue';
|
|
||||||
import { BimEngine } from 'bim-engine-sdk';
|
|
||||||
|
|
||||||
const containerRef = ref<HTMLElement>();
|
|
||||||
let engine: BimEngine | null = null;
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (containerRef.value) {
|
|
||||||
engine = new BimEngine(containerRef.value, {
|
|
||||||
locale: 'zh-CN',
|
|
||||||
theme: 'dark',
|
|
||||||
engine3D: {
|
|
||||||
backgroundColor: 0x202020,
|
|
||||||
showStats: true,
|
|
||||||
showViewCube: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 加载模型
|
|
||||||
engine.loadModel('/models/building.glb');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
engine?.destroy();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.bim-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
```
|
|
||||||
|
|
||||||
## 配置选项说明
|
|
||||||
|
|
||||||
### Engine3DOptions
|
|
||||||
|
|
||||||
| 参数 | 类型 | 默认值 | 说明 |
|
|
||||||
|------|------|--------|------|
|
|
||||||
| `backgroundColor` | `number` | `0x333333` | 3D 场景背景色(十六进制颜色值) |
|
|
||||||
| `version` | `'v1' \| 'v2'` | `'v1'` | WebGL 版本 |
|
|
||||||
| `showStats` | `boolean` | `false` | 是否显示性能统计 |
|
|
||||||
| `showViewCube` | `boolean` | `true` | 是否显示视图立方体 |
|
|
||||||
|
|
||||||
### LoadModel Options
|
|
||||||
|
|
||||||
| 参数 | 类型 | 默认值 | 说明 |
|
|
||||||
|------|------|--------|------|
|
|
||||||
| `position` | `[number, number, number]` | `[0, 0, 0]` | 模型位置 [x, y, z] |
|
|
||||||
| `rotation` | `[number, number, number]` | `[0, 0, 0]` | 模型旋转(弧度)[x, y, z] |
|
|
||||||
| `scale` | `[number, number, number]` | `[1, 1, 1]` | 模型缩放 [x, y, z] |
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
1. **容器尺寸**: 确保容器元素有明确的宽高,否则 3D 引擎无法正常渲染
|
|
||||||
2. **模型路径**: 模型文件路径需要是可访问的 URL 或相对路径
|
|
||||||
3. **销毁实例**: 组件卸载时记得调用 `engine.destroy()` 释放资源
|
|
||||||
4. **z-index 层级**: UI 组件会自动叠加在 3D 场景之上(z-index: 100+)
|
|
||||||
89
dev.sh
89
dev.sh
@@ -1,89 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# 颜色输出
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
RED='\033[0;31m'
|
|
||||||
NC='\033[0m' # No Color
|
|
||||||
|
|
||||||
echo -e "${GREEN}🚀 开始自动化构建和启动流程...${NC}\n"
|
|
||||||
|
|
||||||
# 1. 构建 SDK
|
|
||||||
echo -e "${YELLOW}📦 步骤 1/3: 构建 SDK...${NC}"
|
|
||||||
npm run build
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo -e "${RED}❌ SDK 构建失败!${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}✅ SDK 构建成功${NC}\n"
|
|
||||||
|
|
||||||
# 2. 复制 SDK 文件到 demo 目录
|
|
||||||
echo -e "${YELLOW}📋 步骤 2/3: 复制 SDK 文件到 demo 目录...${NC}"
|
|
||||||
|
|
||||||
# 复制到 demo/lib
|
|
||||||
echo " 复制到 demo/lib..."
|
|
||||||
cd demo
|
|
||||||
npm run copy-sdk
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo -e "${RED}❌ 复制到 demo/lib 失败!${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
# 复制到 demo-vue/public/lib
|
|
||||||
echo " 复制到 demo-vue/public/lib..."
|
|
||||||
cd demo-vue
|
|
||||||
npm run copy-sdk
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo -e "${RED}❌ 复制到 demo-vue/public/lib 失败!${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
echo -e "${GREEN}✅ SDK 文件复制完成${NC}\n"
|
|
||||||
|
|
||||||
# 3. 启动开发服务器
|
|
||||||
echo -e "${YELLOW}🌐 步骤 3/3: 启动开发服务器...${NC}\n"
|
|
||||||
|
|
||||||
# 清理函数:当脚本退出时停止所有后台进程
|
|
||||||
cleanup() {
|
|
||||||
echo -e "\n${YELLOW}🛑 正在停止开发服务器...${NC}"
|
|
||||||
kill $DEMO_PID $DEMO_VUE_PID 2>/dev/null
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# 注册清理函数
|
|
||||||
trap cleanup SIGINT SIGTERM
|
|
||||||
|
|
||||||
# 启动 demo (端口 8080)
|
|
||||||
echo -e "${GREEN}启动 demo (http://localhost:8080)...${NC}"
|
|
||||||
cd demo
|
|
||||||
npm run dev &
|
|
||||||
DEMO_PID=$!
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
# 等待一下确保服务器启动
|
|
||||||
sleep 3
|
|
||||||
|
|
||||||
# 启动 demo-vue (端口 8081)
|
|
||||||
echo -e "${GREEN}启动 demo-vue (http://localhost:8081)...${NC}"
|
|
||||||
cd demo-vue
|
|
||||||
npm run dev &
|
|
||||||
DEMO_VUE_PID=$!
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
# 等待一下确保服务器启动
|
|
||||||
sleep 3
|
|
||||||
|
|
||||||
echo -e "\n${GREEN}✅ 所有服务已启动!${NC}"
|
|
||||||
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
||||||
echo -e "${GREEN}📱 Demo (HTML): http://localhost:8080${NC}"
|
|
||||||
echo -e "${GREEN}📱 Demo (Vue3): http://localhost:8081${NC}"
|
|
||||||
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
||||||
echo -e "${YELLOW}💡 按 Ctrl+C 停止所有服务器${NC}\n"
|
|
||||||
|
|
||||||
# 等待用户中断
|
|
||||||
wait
|
|
||||||
|
|
||||||
2991
dist/bim-engine-sdk.es.js
vendored
2991
dist/bim-engine-sdk.es.js
vendored
File diff suppressed because one or more lines are too long
2
dist/bim-engine-sdk.es.js.map
vendored
2
dist/bim-engine-sdk.es.js.map
vendored
File diff suppressed because one or more lines are too long
362
dist/bim-engine-sdk.umd.js
vendored
362
dist/bim-engine-sdk.umd.js
vendored
File diff suppressed because one or more lines are too long
2
dist/bim-engine-sdk.umd.js.map
vendored
2
dist/bim-engine-sdk.umd.js.map
vendored
File diff suppressed because one or more lines are too long
99
dist/index.d.ts
vendored
99
dist/index.d.ts
vendored
@@ -12,8 +12,11 @@ export declare class BimButtonGroup implements IBimComponent {
|
|||||||
private customColors;
|
private customColors;
|
||||||
private unsubscribeLocale;
|
private unsubscribeLocale;
|
||||||
private unsubscribeTheme;
|
private unsubscribeTheme;
|
||||||
|
protected engine: BimEngine | null;
|
||||||
private readonly DEFAULT_ICON;
|
private readonly DEFAULT_ICON;
|
||||||
constructor(options: ButtonGroupOptions);
|
constructor(options: ButtonGroupOptions);
|
||||||
|
setEngine(engine: BimEngine): void;
|
||||||
|
protected emit<K extends keyof EngineEvents>(event: K, payload: EngineEvents[K]): void;
|
||||||
private initContainer;
|
private initContainer;
|
||||||
private updatePosition;
|
private updatePosition;
|
||||||
/**
|
/**
|
||||||
@@ -55,6 +58,21 @@ export declare class BimButtonGroup implements IBimComponent {
|
|||||||
destroy(): void;
|
destroy(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare abstract class BimComponent {
|
||||||
|
protected engine: BimEngine;
|
||||||
|
constructor(engine: BimEngine);
|
||||||
|
/**
|
||||||
|
* Helper to send events easily
|
||||||
|
*/
|
||||||
|
protected emit<K extends keyof EngineEvents>(event: K, payload: EngineEvents[K]): void;
|
||||||
|
/**
|
||||||
|
* Helper to listen to events easily
|
||||||
|
* Returns an unsubscribe function
|
||||||
|
*/
|
||||||
|
protected on<K extends keyof EngineEvents>(event: K, listener: (payload: EngineEvents[K]) => void): () => void;
|
||||||
|
abstract destroy(): void;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通用弹窗组件类
|
* 通用弹窗组件类
|
||||||
* 支持拖拽、缩放、自定义内容和位置。
|
* 支持拖拽、缩放、自定义内容和位置。
|
||||||
@@ -120,7 +138,7 @@ declare class BimDialog implements IBimComponent {
|
|||||||
destroy(): void;
|
destroy(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare class BimEngine {
|
export declare class BimEngine extends EventEmitter {
|
||||||
private container;
|
private container;
|
||||||
private wrapper;
|
private wrapper;
|
||||||
private topLeftGroup;
|
private topLeftGroup;
|
||||||
@@ -134,6 +152,8 @@ export declare class BimEngine {
|
|||||||
locale?: LocaleType;
|
locale?: LocaleType;
|
||||||
theme?: ThemeType;
|
theme?: ThemeType;
|
||||||
});
|
});
|
||||||
|
emit<K extends keyof EngineEvents>(event: K, payload: EngineEvents[K]): void;
|
||||||
|
on<K extends keyof EngineEvents>(event: K, listener: (payload: EngineEvents[K]) => void): () => void;
|
||||||
setLocale(locale: LocaleType): void;
|
setLocale(locale: LocaleType): void;
|
||||||
getLocale(): LocaleType;
|
getLocale(): LocaleType;
|
||||||
setTheme(theme: 'dark' | 'light'): void;
|
setTheme(theme: 'dark' | 'light'): void;
|
||||||
@@ -189,19 +209,16 @@ declare interface ButtonGroupColors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通用按钮组管理器
|
* 通用按钮组管理器 (ButtonGroupManager)
|
||||||
* 负责创建和管理除底部工具栏以外的其他按钮组。
|
* 负责创建和管理通用的按钮组实例。
|
||||||
*/
|
*/
|
||||||
declare class ButtonGroupManager {
|
declare class ButtonGroupManager extends BimComponent {
|
||||||
private activeGroups;
|
private groups;
|
||||||
private container;
|
private container;
|
||||||
constructor(container: HTMLElement);
|
constructor(engine: BimEngine, container: HTMLElement);
|
||||||
/**
|
create(id: string, options: Omit<ButtonGroupOptions, 'container'>): BimButtonGroup;
|
||||||
* 创建一个新的按钮组
|
get(id: string): BimButtonGroup | undefined;
|
||||||
*/
|
|
||||||
create(options: Omit<ButtonGroupOptions, 'container'>): BimButtonGroup;
|
|
||||||
updateTheme(theme: ThemeConfig): void;
|
updateTheme(theme: ThemeConfig): void;
|
||||||
refresh(): void;
|
|
||||||
destroy(): void;
|
destroy(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,11 +249,11 @@ export declare function createEngine(r) {
|
|||||||
const e = r.version || "v1";
|
const e = r.version || "v1";
|
||||||
switch (e) {
|
switch (e) {
|
||||||
case "v2":
|
case "v2":
|
||||||
return new Uc(r);
|
return new Nc(r);
|
||||||
case "v1":
|
case "v1":
|
||||||
return new L_(r);
|
return new I_(r);
|
||||||
:
|
:
|
||||||
return console.warn(`Version '${e}' not found. Falling back to v2.`), new Uc(r);
|
return console.warn(`Version '${e}' not found. Falling back to v2.`), new Nc(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,16 +277,17 @@ declare interface DialogColors {
|
|||||||
* 弹窗管理器
|
* 弹窗管理器
|
||||||
* 负责创建和管理应用中的各类弹窗。
|
* 负责创建和管理应用中的各类弹窗。
|
||||||
*/
|
*/
|
||||||
declare class DialogManager {
|
declare class DialogManager extends BimComponent {
|
||||||
/** 弹窗挂载的父容器 */
|
/** 弹窗挂载的父容器 */
|
||||||
private container;
|
private container;
|
||||||
/** 活跃的弹窗实例列表 */
|
/** 活跃的弹窗实例列表 */
|
||||||
private activeDialogs;
|
private activeDialogs;
|
||||||
/**
|
/**
|
||||||
* 构造函数
|
* 构造函数
|
||||||
|
* @param engine 引擎实例
|
||||||
* @param container 弹窗挂载的目标容器
|
* @param container 弹窗挂载的目标容器
|
||||||
*/
|
*/
|
||||||
constructor(container: HTMLElement);
|
constructor(engine: BimEngine, container: HTMLElement);
|
||||||
/**
|
/**
|
||||||
* 创建一个通用弹窗
|
* 创建一个通用弹窗
|
||||||
* @param options 弹窗配置选项(不需要传 container,自动使用管理器绑定的容器)
|
* @param options 弹窗配置选项(不需要传 container,自动使用管理器绑定的容器)
|
||||||
@@ -286,6 +304,7 @@ declare class DialogManager {
|
|||||||
* @param theme 全局主题配置
|
* @param theme 全局主题配置
|
||||||
*/
|
*/
|
||||||
updateTheme(theme: ThemeConfig): void;
|
updateTheme(theme: ThemeConfig): void;
|
||||||
|
destroy(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -330,21 +349,49 @@ declare type DialogPosition = 'center' | 'top-left' | 'top-center' | 'top-right'
|
|||||||
y: number;
|
y: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
declare interface EngineEvents {
|
||||||
|
'ui:open-dialog': {
|
||||||
|
id: string;
|
||||||
|
data?: any;
|
||||||
|
};
|
||||||
|
'ui:close-dialog': {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
'engine:model-loaded': {
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
'engine:object-clicked': {
|
||||||
|
objectId: string;
|
||||||
|
position: {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
z: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
'sys:theme-changed': {
|
||||||
|
theme: string;
|
||||||
|
};
|
||||||
|
'sys:locale-changed': {
|
||||||
|
locale: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 3D 引擎管理器
|
* 3D 引擎管理器
|
||||||
* 负责连接 Engine 组件和 BimEngine,向外部暴露简化的 API
|
* 负责连接 Engine 组件和 BimEngine,向外部暴露简化的 API
|
||||||
* 采用延迟初始化模式,用户需主动调用 initialize() 方法
|
* 采用延迟初始化模式,用户需主动调用 initialize() 方法
|
||||||
*/
|
*/
|
||||||
declare class EngineManager {
|
declare class EngineManager extends BimComponent {
|
||||||
/** 3D 引擎挂载的父容器 */
|
/** 3D 引擎挂载的父容器 */
|
||||||
private container;
|
private container;
|
||||||
/** 3D 引擎组件实例 */
|
/** 3D 引擎组件实例 */
|
||||||
private engine;
|
private engineInstance;
|
||||||
/**
|
/**
|
||||||
* 构造函数
|
* 构造函数
|
||||||
|
* @param engine 引擎实例
|
||||||
* @param container 3D 引擎挂载的目标容器
|
* @param container 3D 引擎挂载的目标容器
|
||||||
*/
|
*/
|
||||||
constructor(container: HTMLElement);
|
constructor(engine: BimEngine, container: HTMLElement);
|
||||||
/**
|
/**
|
||||||
* 初始化 3D 引擎
|
* 初始化 3D 引擎
|
||||||
* @param options 引擎配置选项(可选,如果不提供则使用默认配置)
|
* @param options 引擎配置选项(可选,如果不提供则使用默认配置)
|
||||||
@@ -389,6 +436,14 @@ export declare interface EngineOptions {
|
|||||||
showViewCube?: boolean;
|
showViewCube?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare class EventEmitter {
|
||||||
|
private events;
|
||||||
|
on(event: string, listener: Listener): () => void;
|
||||||
|
off(event: string, listener: Listener): void;
|
||||||
|
emit(event: string, payload?: any): void;
|
||||||
|
clear(): void;
|
||||||
|
}
|
||||||
|
|
||||||
/** 二级菜单展开方向 */
|
/** 二级菜单展开方向 */
|
||||||
declare type ExpandDirection = 'up' | 'down' | 'left' | 'right';
|
declare type ExpandDirection = 'up' | 'down' | 'left' | 'right';
|
||||||
|
|
||||||
@@ -428,6 +483,8 @@ declare interface IBimComponent {
|
|||||||
destroy(): void;
|
destroy(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare type Listener<T = any> = (payload: T) => void;
|
||||||
|
|
||||||
declare type LocaleChangeListener = (locale: LocaleType) => void;
|
declare type LocaleChangeListener = (locale: LocaleType) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -568,11 +625,11 @@ export declare class Toolbar extends BimButtonGroup {
|
|||||||
* 底部工具栏管理器 (ToolbarManager)
|
* 底部工具栏管理器 (ToolbarManager)
|
||||||
* 仅负责管理底部工具栏实例。
|
* 仅负责管理底部工具栏实例。
|
||||||
*/
|
*/
|
||||||
declare class ToolbarManager {
|
declare class ToolbarManager extends BimComponent {
|
||||||
private toolbar;
|
private toolbar;
|
||||||
private toolbarContainer;
|
private toolbarContainer;
|
||||||
private container;
|
private container;
|
||||||
constructor(container: HTMLElement);
|
constructor(engine: BimEngine, container: HTMLElement);
|
||||||
private init;
|
private init;
|
||||||
updateTheme(theme: ThemeConfig): void;
|
updateTheme(theme: ThemeConfig): void;
|
||||||
refresh(): void;
|
refresh(): void;
|
||||||
|
|||||||
@@ -18,9 +18,9 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"dev:all": "./dev.sh",
|
"dev:demo": "cd demo && npm run dev",
|
||||||
"dev:demo": "cd demo && npm run copy-sdk && npm run dev",
|
"dev:demo-vue": "cd demo-vue && npm run dev",
|
||||||
"dev:demo-vue": "cd demo-vue && npm run copy-sdk && npm run dev"
|
"dev:all": "npm run dev:demo & npm run dev:demo-vue"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"bim",
|
"bim",
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ import { localeManager } from './services/locale';
|
|||||||
import { themeManager } from './services/theme';
|
import { themeManager } from './services/theme';
|
||||||
import type { LocaleType } from './locales/types';
|
import type { LocaleType } from './locales/types';
|
||||||
import type { ThemeType, ThemeConfig } from './themes/types';
|
import type { ThemeType, ThemeConfig } from './themes/types';
|
||||||
|
import { EventEmitter } from './core/event-emitter';
|
||||||
|
import { EngineEvents } from './types/events';
|
||||||
|
|
||||||
export type { EngineOptions, ModelLoadOptions };
|
export type { EngineOptions, ModelLoadOptions };
|
||||||
|
|
||||||
|
export class BimEngine extends EventEmitter {
|
||||||
|
|
||||||
export class BimEngine {
|
|
||||||
private container: HTMLElement;
|
private container: HTMLElement;
|
||||||
private wrapper: HTMLElement | null = null;
|
private wrapper: HTMLElement | null = null;
|
||||||
private topLeftGroup: any = null; // 保存左上角按钮组的引用
|
private topLeftGroup: any = null; // 保存左上角按钮组的引用
|
||||||
@@ -33,6 +33,7 @@ export class BimEngine {
|
|||||||
theme?: ThemeType;
|
theme?: ThemeType;
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
super();
|
||||||
const el = typeof container === 'string' ? document.getElementById(container) : container;
|
const el = typeof container === 'string' ? document.getElementById(container) : container;
|
||||||
if (!el) throw new Error('Container not found');
|
if (!el) throw new Error('Container not found');
|
||||||
this.container = el;
|
this.container = el;
|
||||||
@@ -49,6 +50,15 @@ export class BimEngine {
|
|||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Typed wrappers for events
|
||||||
|
public emit<K extends keyof EngineEvents>(event: K, payload: EngineEvents[K]) {
|
||||||
|
super.emit(event, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
public on<K extends keyof EngineEvents>(event: K, listener: (payload: EngineEvents[K]) => void): () => void {
|
||||||
|
return super.on(event, listener);
|
||||||
|
}
|
||||||
|
|
||||||
public setLocale(locale: LocaleType) { localeManager.setLocale(locale); }
|
public setLocale(locale: LocaleType) { localeManager.setLocale(locale); }
|
||||||
public getLocale(): LocaleType { return localeManager.getLocale(); }
|
public getLocale(): LocaleType { return localeManager.getLocale(); }
|
||||||
public setTheme(theme: 'dark' | 'light') { themeManager.setTheme(theme); }
|
public setTheme(theme: 'dark' | 'light') { themeManager.setTheme(theme); }
|
||||||
@@ -61,12 +71,12 @@ export class BimEngine {
|
|||||||
this.container.appendChild(this.wrapper);
|
this.container.appendChild(this.wrapper);
|
||||||
|
|
||||||
// 创建 3D 引擎管理器
|
// 创建 3D 引擎管理器
|
||||||
this.engine = new EngineManager(this.wrapper);
|
this.engine = new EngineManager(this, this.wrapper);
|
||||||
|
|
||||||
// 初始化其他管理器
|
// 初始化其他管理器
|
||||||
this.dialog = new DialogManager(this.wrapper);
|
this.dialog = new DialogManager(this, this.wrapper);
|
||||||
this.toolbar = new ToolbarManager(this.wrapper);
|
this.toolbar = new ToolbarManager(this, this.wrapper);
|
||||||
this.buttonGroup = new ButtonGroupManager(this.wrapper);
|
this.buttonGroup = new ButtonGroupManager(this, this.wrapper);
|
||||||
|
|
||||||
|
|
||||||
// 初始主题
|
// 初始主题
|
||||||
@@ -112,5 +122,6 @@ export class BimEngine {
|
|||||||
this.engine?.destroy();
|
this.engine?.destroy();
|
||||||
this.dialog = null;
|
this.dialog = null;
|
||||||
this.container.innerHTML = '';
|
this.container.innerHTML = '';
|
||||||
|
this.clear(); // Clear all events
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import { t, localeManager } from '../../services/locale';
|
|||||||
import { themeManager } from '../../services/theme';
|
import { themeManager } from '../../services/theme';
|
||||||
import type { ThemeConfig } from '../../themes/types';
|
import type { ThemeConfig } from '../../themes/types';
|
||||||
import { IBimComponent } from '../../types/component';
|
import { IBimComponent } from '../../types/component';
|
||||||
|
import type { BimEngine } from '../../bim-engine';
|
||||||
|
import { EngineEvents } from '../../types/events';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通用按钮组组件 (BimButtonGroup)
|
* 通用按钮组组件 (BimButtonGroup)
|
||||||
@@ -26,6 +28,8 @@ export class BimButtonGroup implements IBimComponent {
|
|||||||
private unsubscribeLocale: (() => void) | null = null;
|
private unsubscribeLocale: (() => void) | null = null;
|
||||||
private unsubscribeTheme: (() => void) | null = null;
|
private unsubscribeTheme: (() => void) | null = null;
|
||||||
|
|
||||||
|
protected engine: BimEngine | null = null;
|
||||||
|
|
||||||
private readonly DEFAULT_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect></svg>';
|
private readonly DEFAULT_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect></svg>';
|
||||||
|
|
||||||
constructor(options: ButtonGroupOptions) {
|
constructor(options: ButtonGroupOptions) {
|
||||||
@@ -63,6 +67,18 @@ export class BimButtonGroup implements IBimComponent {
|
|||||||
this.applyStyles();
|
this.applyStyles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setEngine(engine: BimEngine) {
|
||||||
|
this.engine = engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected emit<K extends keyof EngineEvents>(event: K, payload: EngineEvents[K]) {
|
||||||
|
if (this.engine) {
|
||||||
|
this.engine.emit(event, payload);
|
||||||
|
} else {
|
||||||
|
console.warn('[BimButtonGroup] Engine not set, cannot emit event:', event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private initContainer(): void {
|
private initContainer(): void {
|
||||||
this.container.innerHTML = '';
|
this.container.innerHTML = '';
|
||||||
this.container.classList.add('bim-btn-group-root');
|
this.container.classList.add('bim-btn-group-root');
|
||||||
|
|||||||
@@ -1,16 +1,28 @@
|
|||||||
import type { ButtonConfig } from '../../../index.type';
|
import type { ButtonConfig } from '../../../index.type';
|
||||||
|
import type { BimEngine } from '../../../../../bim-engine';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 首页按钮配置
|
* 首页按钮配置
|
||||||
|
* 使用工厂函数模式,注入 engine 实例
|
||||||
*/
|
*/
|
||||||
export const homeButton: ButtonConfig = {
|
export const createHomeButton = (engine: BimEngine): ButtonConfig => {
|
||||||
id: 'home',
|
return {
|
||||||
groupId: 'group-1',
|
id: 'home',
|
||||||
type: 'button',
|
groupId: 'group-1',
|
||||||
label: 'toolbar.home',
|
type: 'button',
|
||||||
icon: '<svg width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M4 21V9l8-6l8 6v12h-6v-7h-4v7z"/></svg>',
|
label: 'toolbar.home',
|
||||||
keepActive: true,
|
icon: '<svg width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M4 21V9l8-6l8 6v12h-6v-7h-4v7z"/></svg>',
|
||||||
onClick: (button) => {
|
keepActive: true,
|
||||||
console.log('首页按钮被点击:', button.id);
|
onClick: (button) => {
|
||||||
}
|
console.log('首页按钮被点击:', button.id);
|
||||||
|
// 演示:使用 engine 发送事件
|
||||||
|
// engine.dialog?.showInfoDialog()
|
||||||
|
engine.emit('ui:open-dialog', { id: 'home-info' });
|
||||||
|
|
||||||
|
// 或者直接调用 engine 的方法
|
||||||
|
// if (engine.engine) {
|
||||||
|
// engine.engine.loadModel('...');
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export class Toolbar extends BimButtonGroup {
|
|||||||
await super.init();
|
await super.init();
|
||||||
|
|
||||||
// 动态加载默认按钮配置
|
// 动态加载默认按钮配置
|
||||||
const { homeButton } = await import('./buttons/home');
|
const { createHomeButton } = await import('./buttons/home');
|
||||||
const { locationButton } = await import('./buttons/location');
|
const { locationButton } = await import('./buttons/location');
|
||||||
const { walkMenuButton } = await import('./buttons/walk/walk-menu');
|
const { walkMenuButton } = await import('./buttons/walk/walk-menu');
|
||||||
const { walkPersonButton } = await import('./buttons/walk/walk-person');
|
const { walkPersonButton } = await import('./buttons/walk/walk-person');
|
||||||
@@ -21,7 +21,14 @@ export class Toolbar extends BimButtonGroup {
|
|||||||
const { infoButton } = await import('./buttons/info');
|
const { infoButton } = await import('./buttons/info');
|
||||||
|
|
||||||
this.addGroup('group-1');
|
this.addGroup('group-1');
|
||||||
this.addButton(homeButton);
|
|
||||||
|
// 使用工厂函数创建按钮,并注入 engine
|
||||||
|
if (this.engine) {
|
||||||
|
this.addButton(createHomeButton(this.engine));
|
||||||
|
} else {
|
||||||
|
console.warn('[Toolbar] Engine not available when creating buttons.');
|
||||||
|
}
|
||||||
|
|
||||||
this.addButton(walkMenuButton);
|
this.addButton(walkMenuButton);
|
||||||
this.addButton(walkPersonButton);
|
this.addButton(walkPersonButton);
|
||||||
this.addButton(walkBirdButton);
|
this.addButton(walkBirdButton);
|
||||||
|
|||||||
27
src/core/component.ts
Normal file
27
src/core/component.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { BimEngine } from '../bim-engine';
|
||||||
|
import { EngineEvents } from '../types/events';
|
||||||
|
|
||||||
|
export abstract class BimComponent {
|
||||||
|
protected engine: BimEngine;
|
||||||
|
|
||||||
|
constructor(engine: BimEngine) {
|
||||||
|
this.engine = engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to send events easily
|
||||||
|
*/
|
||||||
|
protected emit<K extends keyof EngineEvents>(event: K, payload: EngineEvents[K]): void {
|
||||||
|
this.engine.emit(event, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to listen to events easily
|
||||||
|
* Returns an unsubscribe function
|
||||||
|
*/
|
||||||
|
protected on<K extends keyof EngineEvents>(event: K, listener: (payload: EngineEvents[K]) => void): () => void {
|
||||||
|
return this.engine.on(event, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract destroy(): void;
|
||||||
|
}
|
||||||
42
src/core/event-emitter.ts
Normal file
42
src/core/event-emitter.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
type Listener<T = any> = (payload: T) => void;
|
||||||
|
|
||||||
|
export class EventEmitter {
|
||||||
|
private events: Map<string, Listener[]> = new Map();
|
||||||
|
|
||||||
|
public on(event: string, listener: Listener): () => void {
|
||||||
|
if (!this.events.has(event)) {
|
||||||
|
this.events.set(event, []);
|
||||||
|
}
|
||||||
|
this.events.get(event)!.push(listener);
|
||||||
|
|
||||||
|
// Return unsubscribe function
|
||||||
|
return () => this.off(event, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public off(event: string, listener: Listener): void {
|
||||||
|
const listeners = this.events.get(event);
|
||||||
|
if (!listeners) return;
|
||||||
|
|
||||||
|
const index = listeners.indexOf(listener);
|
||||||
|
if (index !== -1) {
|
||||||
|
listeners.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public emit(event: string, payload?: any): void {
|
||||||
|
const listeners = this.events.get(event);
|
||||||
|
if (listeners) {
|
||||||
|
listeners.forEach(listener => {
|
||||||
|
try {
|
||||||
|
listener(payload);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[EventEmitter] Error in listener for event "${event}":`, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public clear(): void {
|
||||||
|
this.events.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,48 +1,46 @@
|
|||||||
import { BimButtonGroup } from '../components/button-group';
|
import { BimButtonGroup } from '../components/button-group';
|
||||||
import type { ButtonGroupOptions } from '../components/button-group/index.type';
|
import type { ButtonGroupOptions } from '../components/button-group/index.type';
|
||||||
import type { ThemeConfig } from '../themes/types';
|
import type { ThemeConfig } from '../themes/types';
|
||||||
|
import { BimComponent } from '../core/component';
|
||||||
|
import type { BimEngine } from '../bim-engine';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通用按钮组管理器
|
* 通用按钮组管理器 (ButtonGroupManager)
|
||||||
* 负责创建和管理除底部工具栏以外的其他按钮组。
|
* 负责创建和管理通用的按钮组实例。
|
||||||
*/
|
*/
|
||||||
export class ButtonGroupManager {
|
export class ButtonGroupManager extends BimComponent {
|
||||||
private activeGroups: BimButtonGroup[] = [];
|
private groups: Map<string, BimButtonGroup> = new Map();
|
||||||
private container: HTMLElement;
|
private container: HTMLElement;
|
||||||
|
|
||||||
constructor(container: HTMLElement) {
|
constructor(engine: BimEngine, container: HTMLElement) {
|
||||||
|
super(engine);
|
||||||
this.container = container;
|
this.container = container;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public create(id: string, options: Omit<ButtonGroupOptions, 'container'>): BimButtonGroup {
|
||||||
* 创建一个新的按钮组
|
|
||||||
*/
|
|
||||||
public create(options: Omit<ButtonGroupOptions, 'container'>): BimButtonGroup {
|
|
||||||
// 自动创建一个 div 作为容器
|
|
||||||
const groupContainer = document.createElement('div');
|
|
||||||
this.container.appendChild(groupContainer);
|
|
||||||
|
|
||||||
const group = new BimButtonGroup({
|
const group = new BimButtonGroup({
|
||||||
container: groupContainer,
|
container: this.container,
|
||||||
...options
|
...options
|
||||||
});
|
});
|
||||||
|
|
||||||
// 立即初始化
|
// @ts-ignore
|
||||||
|
group.setEngine(this.engine);
|
||||||
|
|
||||||
group.init();
|
group.init();
|
||||||
this.activeGroups.push(group);
|
this.groups.set(id, group);
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateTheme(theme: ThemeConfig) {
|
public get(id: string): BimButtonGroup | undefined {
|
||||||
this.activeGroups.forEach(g => g.setTheme(theme));
|
return this.groups.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public refresh() {
|
public updateTheme(theme: ThemeConfig) {
|
||||||
this.activeGroups.forEach(g => g.render());
|
this.groups.forEach(group => group.setTheme(theme));
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy() {
|
public destroy() {
|
||||||
this.activeGroups.forEach(g => g.destroy());
|
this.groups.forEach(group => group.destroy());
|
||||||
this.activeGroups = [];
|
this.groups.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,15 @@ import { BimDialog } from '../components/dialog';
|
|||||||
import { BimInfoDialog } from '../components/dialog/bimInfoDialog';
|
import { BimInfoDialog } from '../components/dialog/bimInfoDialog';
|
||||||
import type { DialogOptions } from '../components/dialog/index.type';
|
import type { DialogOptions } from '../components/dialog/index.type';
|
||||||
import type { ThemeConfig } from '../themes/types';
|
import type { ThemeConfig } from '../themes/types';
|
||||||
import { themeManager } from '../services/theme'; // 修正路径
|
import { themeManager } from '../services/theme';
|
||||||
|
import { BimComponent } from '../core/component';
|
||||||
|
import type { BimEngine } from '../bim-engine';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 弹窗管理器
|
* 弹窗管理器
|
||||||
* 负责创建和管理应用中的各类弹窗。
|
* 负责创建和管理应用中的各类弹窗。
|
||||||
*/
|
*/
|
||||||
export class DialogManager {
|
export class DialogManager extends BimComponent {
|
||||||
/** 弹窗挂载的父容器 */
|
/** 弹窗挂载的父容器 */
|
||||||
private container: HTMLElement;
|
private container: HTMLElement;
|
||||||
/** 活跃的弹窗实例列表 */
|
/** 活跃的弹窗实例列表 */
|
||||||
@@ -16,10 +18,22 @@ export class DialogManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造函数
|
* 构造函数
|
||||||
|
* @param engine 引擎实例
|
||||||
* @param container 弹窗挂载的目标容器
|
* @param container 弹窗挂载的目标容器
|
||||||
*/
|
*/
|
||||||
constructor(container: HTMLElement) {
|
constructor(engine: BimEngine, container: HTMLElement) {
|
||||||
|
super(engine);
|
||||||
this.container = container;
|
this.container = container;
|
||||||
|
|
||||||
|
// 监听打开弹窗事件
|
||||||
|
this.on('ui:open-dialog', (payload) => {
|
||||||
|
// 这里可以根据 payload.id 做更复杂的逻辑,目前简单演示
|
||||||
|
console.log('[DialogManager] Received open-dialog event:', payload);
|
||||||
|
// 示例:如果 payload.id 是 'info',则打开 info dialog
|
||||||
|
if (payload.id === 'info') {
|
||||||
|
this.showInfoDialog();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,4 +80,9 @@ export class DialogManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public destroy() {
|
||||||
|
this.activeDialogs.forEach(d => d.destroy());
|
||||||
|
this.activeDialogs = [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,21 +1,25 @@
|
|||||||
import { Engine, type EngineOptions, type ModelLoadOptions } from '../components/engine';
|
import { Engine, type EngineOptions, type ModelLoadOptions } from '../components/engine';
|
||||||
|
import { BimComponent } from '../core/component';
|
||||||
|
import type { BimEngine } from '../bim-engine';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 3D 引擎管理器
|
* 3D 引擎管理器
|
||||||
* 负责连接 Engine 组件和 BimEngine,向外部暴露简化的 API
|
* 负责连接 Engine 组件和 BimEngine,向外部暴露简化的 API
|
||||||
* 采用延迟初始化模式,用户需主动调用 initialize() 方法
|
* 采用延迟初始化模式,用户需主动调用 initialize() 方法
|
||||||
*/
|
*/
|
||||||
export class EngineManager {
|
export class EngineManager extends BimComponent {
|
||||||
/** 3D 引擎挂载的父容器 */
|
/** 3D 引擎挂载的父容器 */
|
||||||
private container: HTMLElement;
|
private container: HTMLElement;
|
||||||
/** 3D 引擎组件实例 */
|
/** 3D 引擎组件实例 */
|
||||||
private engine: Engine | null = null;
|
private engineInstance: Engine | null = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造函数
|
* 构造函数
|
||||||
|
* @param engine 引擎实例
|
||||||
* @param container 3D 引擎挂载的目标容器
|
* @param container 3D 引擎挂载的目标容器
|
||||||
*/
|
*/
|
||||||
constructor(container: HTMLElement) {
|
constructor(engine: BimEngine, container: HTMLElement) {
|
||||||
|
super(engine);
|
||||||
this.container = container;
|
this.container = container;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,27 +30,27 @@ export class EngineManager {
|
|||||||
*/
|
*/
|
||||||
public initialize(options?: Omit<EngineOptions, 'container'>): boolean {
|
public initialize(options?: Omit<EngineOptions, 'container'>): boolean {
|
||||||
// 如果已经初始化,先销毁旧的实例
|
// 如果已经初始化,先销毁旧的实例
|
||||||
if (this.engine && this.engine.isInitialized()) {
|
if (this.engineInstance && this.engineInstance.isInitialized()) {
|
||||||
console.warn('[EngineManager] 3D Engine already initialized. Destroying old instance...');
|
console.warn('[EngineManager] 3D Engine already initialized. Destroying old instance...');
|
||||||
this.engine.destroy();
|
this.engineInstance.destroy();
|
||||||
this.engine = null;
|
this.engineInstance = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 创建 Engine 组件实例
|
// 创建 Engine 组件实例
|
||||||
// options 中的配置会自动复制给 createEngine 使用
|
// options 中的配置会自动复制给 createEngine 使用
|
||||||
this.engine = new Engine({
|
this.engineInstance = new Engine({
|
||||||
container: this.container,
|
container: this.container,
|
||||||
...options, // 合并配置选项
|
...options, // 合并配置选项
|
||||||
});
|
});
|
||||||
|
|
||||||
// 调用组件的 init 方法初始化引擎
|
// 调用组件的 init 方法初始化引擎
|
||||||
this.engine.init();
|
this.engineInstance.init();
|
||||||
|
|
||||||
return this.engine.isInitialized();
|
return this.engineInstance.isInitialized();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[EngineManager] Failed to initialize 3D engine:', error);
|
console.error('[EngineManager] Failed to initialize 3D engine:', error);
|
||||||
this.engine = null;
|
this.engineInstance = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,7 +59,7 @@ export class EngineManager {
|
|||||||
* 检查 3D 引擎是否已初始化
|
* 检查 3D 引擎是否已初始化
|
||||||
*/
|
*/
|
||||||
public isInitialized(): boolean {
|
public isInitialized(): boolean {
|
||||||
return this.engine !== null && this.engine.isInitialized();
|
return this.engineInstance !== null && this.engineInstance.isInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,11 +68,11 @@ export class EngineManager {
|
|||||||
* @param options 加载选项(位置、旋转、缩放)
|
* @param options 加载选项(位置、旋转、缩放)
|
||||||
*/
|
*/
|
||||||
public loadModel(url: string, options?: ModelLoadOptions): void {
|
public loadModel(url: string, options?: ModelLoadOptions): void {
|
||||||
if (!this.engine || !this.engine.isInitialized()) {
|
if (!this.engineInstance || !this.engineInstance.isInitialized()) {
|
||||||
console.error('[EngineManager] 3D Engine not initialized. Please call initialize() first.');
|
console.error('[EngineManager] 3D Engine not initialized. Please call initialize() first.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.engine.loadModel(url, options);
|
this.engineInstance.loadModel(url, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,20 +80,20 @@ export class EngineManager {
|
|||||||
* 用于直接调用第三方引擎的其他 API
|
* 用于直接调用第三方引擎的其他 API
|
||||||
*/
|
*/
|
||||||
public getEngine(): any {
|
public getEngine(): any {
|
||||||
if (!this.engine) {
|
if (!this.engineInstance) {
|
||||||
console.warn('[EngineManager] 3D Engine not initialized.');
|
console.warn('[EngineManager] 3D Engine not initialized.');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return this.engine.getEngine();
|
return this.engineInstance.getEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 销毁 3D 引擎实例
|
* 销毁 3D 引擎实例
|
||||||
*/
|
*/
|
||||||
public destroy(): void {
|
public destroy(): void {
|
||||||
if (this.engine) {
|
if (this.engineInstance) {
|
||||||
this.engine.destroy();
|
this.engineInstance.destroy();
|
||||||
this.engine = null;
|
this.engineInstance = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
import type { ButtonGroupColors, ButtonConfig } from '../components/button-group/index.type';
|
import type { ButtonGroupColors, ButtonConfig } from '../components/button-group/index.type';
|
||||||
import { Toolbar } from '../components/button-group/toolbar';
|
import { Toolbar } from '../components/button-group/toolbar';
|
||||||
import type { ThemeConfig } from '../themes/types';
|
import type { ThemeConfig } from '../themes/types';
|
||||||
|
import { BimComponent } from '../core/component';
|
||||||
|
import type { BimEngine } from '../bim-engine';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 底部工具栏管理器 (ToolbarManager)
|
* 底部工具栏管理器 (ToolbarManager)
|
||||||
* 仅负责管理底部工具栏实例。
|
* 仅负责管理底部工具栏实例。
|
||||||
*/
|
*/
|
||||||
export class ToolbarManager {
|
export class ToolbarManager extends BimComponent {
|
||||||
private toolbar: Toolbar | null = null;
|
private toolbar: Toolbar | null = null;
|
||||||
private toolbarContainer: HTMLElement | null = null;
|
private toolbarContainer: HTMLElement | null = null;
|
||||||
private container: HTMLElement;
|
private container: HTMLElement;
|
||||||
|
|
||||||
constructor(container: HTMLElement) {
|
constructor(engine: BimEngine, container: HTMLElement) {
|
||||||
|
super(engine);
|
||||||
this.container = container;
|
this.container = container;
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
@@ -32,6 +35,10 @@ export class ToolbarManager {
|
|||||||
expand: 'up' // 向上展开
|
expand: 'up' // 向上展开
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 注入 engine 到 Toolbar
|
||||||
|
// @ts-ignore - Toolbar 还没更新类型,暂时忽略
|
||||||
|
this.toolbar.setEngine(this.engine);
|
||||||
|
|
||||||
this.toolbar.init();
|
this.toolbar.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
src/types/events.ts
Normal file
13
src/types/events.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
export interface EngineEvents {
|
||||||
|
// UI Events
|
||||||
|
'ui:open-dialog': { id: string; data?: any };
|
||||||
|
'ui:close-dialog': { id: string };
|
||||||
|
|
||||||
|
// Engine Events
|
||||||
|
'engine:model-loaded': { url: string };
|
||||||
|
'engine:object-clicked': { objectId: string; position: { x: number, y: number, z: number } };
|
||||||
|
|
||||||
|
// System Events
|
||||||
|
'sys:theme-changed': { theme: string };
|
||||||
|
'sys:locale-changed': { locale: string };
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user