- ThemeConfig 接口扩展至 60+ 语义化属性 - 新增深浅主题预设 (glassPill overrides) - button-group 支持 glass-pill 样式变体 - 默认主题改为浅色 - 移除 toolbar 容器硬编码定位 - 统一组件 CSS 变量命名规范 - 暂时隐藏下拉箭头
387 lines
12 KiB
TypeScript
387 lines
12 KiB
TypeScript
import type { ThemeConfig } from '../../themes/types';
|
||
import { IBimComponent } from '../../types/component';
|
||
import { themeManager } from '../../services/theme';
|
||
import type { EngineOptions, ModelLoadOptions } from './types';
|
||
import type { MeasureMode } from '../../types/measure';
|
||
// 导入第三方 SDK 的 createEngine 函数
|
||
import { createEngine as createEngineSDK } from '../../engine_base/bim-engine-sdk.es.js';
|
||
|
||
// 重新导出类型,方便外部引用
|
||
export type { EngineOptions, ModelLoadOptions };
|
||
|
||
/**
|
||
* 创建 Engine 实例的工厂函数
|
||
* 兼容旧代码直接 import { createEngine } 的方式
|
||
*/
|
||
export const createEngine = (options: EngineOptions) => {
|
||
return new Engine(options);
|
||
};
|
||
|
||
/**
|
||
* 3D 引擎组件
|
||
* 负责创建和管理第三方 3D 引擎实例
|
||
*/
|
||
export class Engine implements IBimComponent {
|
||
/** 第三方 3D 引擎实例 */
|
||
private engine: any = null;
|
||
/** 引擎挂载的容器元素 */
|
||
private container: HTMLElement;
|
||
/** 引擎容器 ID(用于传递给 createEngine) */
|
||
private containerId: string;
|
||
/** 引擎配置选项(不包含 container) */
|
||
private options: Omit<EngineOptions, 'container'>;
|
||
/** 是否已初始化 */
|
||
private _isInitialized = false;
|
||
/** 是否已销毁 */
|
||
private _isDestroyed = false;
|
||
/** 主题订阅取消函数 */
|
||
private unsubscribeTheme: (() => void) | null = null;
|
||
/** 当前激活的测量类型 */
|
||
private currentMeasureType: MeasureMode | null = null;
|
||
/** 主测量功能是否已激活 */
|
||
private isMeasureActive: boolean = false;
|
||
|
||
/**
|
||
* 构造函数
|
||
* @param options 3D 引擎配置选项
|
||
*/
|
||
constructor(options: EngineOptions) {
|
||
// 解析容器元素
|
||
this.container = options.container;
|
||
// 如果容器没有 id,生成一个唯一的 id
|
||
if (!this.container.id) {
|
||
this.containerId = `engine-container-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||
this.container.id = this.containerId;
|
||
} else {
|
||
this.containerId = this.container.id;
|
||
}
|
||
|
||
// 保存配置选项(设置默认值)
|
||
this.options = {
|
||
backgroundColor: 'linear-gradient(to bottom, rgb(214, 224, 235), rgb(246, 250, 255))', // 固定背景渐变色
|
||
version: options.version ?? 'v1', // 默认使用 v1 版本
|
||
showStats: options.showStats ?? false, // 默认不显示统计
|
||
showViewCube: options.showViewCube ?? true, // 默认显示视图立方体
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 初始化组件 (接口实现)
|
||
* 创建 div 容器并初始化引擎
|
||
*/
|
||
public init(): void {
|
||
if (this._isInitialized) {
|
||
console.warn('[Engine] Engine already initialized.');
|
||
return;
|
||
}
|
||
|
||
if (this._isDestroyed) {
|
||
console.error('[Engine] Cannot initialize destroyed engine.');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// 应用背景色到容器
|
||
if (typeof this.options.backgroundColor === 'string') {
|
||
this.container.style.background = this.options.backgroundColor;
|
||
}
|
||
|
||
// 创建引擎配置对象
|
||
const engineConfig = {
|
||
containerId: this.containerId,
|
||
backgroundColor: this.options.backgroundColor,
|
||
version: this.options.version,
|
||
showStats: this.options.showStats,
|
||
showViewCube: this.options.showViewCube,
|
||
};
|
||
|
||
// 输出配置信息
|
||
console.log('引擎配置信息:', engineConfig);
|
||
|
||
// 调用引擎创建函数创建引擎实例
|
||
// 将 options 中的配置复制给 createEngine
|
||
this.engine = createEngineSDK(engineConfig);
|
||
|
||
if (!this.engine) {
|
||
throw new Error('Failed to create engine instance');
|
||
}
|
||
|
||
// 标记为已初始化
|
||
this._isInitialized = true;
|
||
|
||
// 订阅主题变化
|
||
this.unsubscribeTheme = themeManager.subscribe((theme) => {
|
||
this.setTheme(theme);
|
||
});
|
||
|
||
// 应用当前主题
|
||
this.setTheme(themeManager.getTheme());
|
||
} catch (error) {
|
||
console.error('[Engine] Failed to initialize engine:', error);
|
||
this._isInitialized = false;
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 设置主题 (接口实现)
|
||
* 根据主题调整 3D 引擎的视觉效果(如背景色)
|
||
* @param theme 全局主题配置
|
||
*/
|
||
public setTheme(_theme: ThemeConfig): void {
|
||
|
||
}
|
||
|
||
/**
|
||
* 设置语言 (接口实现)
|
||
*/
|
||
public setLocales(): void {
|
||
// 3D 引擎组件暂时不需要本地化
|
||
}
|
||
|
||
/**
|
||
* 检查是否已初始化
|
||
*/
|
||
public isInitialized(): boolean {
|
||
return this._isInitialized;
|
||
}
|
||
|
||
|
||
/**
|
||
* 加载 3D 模型
|
||
* @param url 模型文件 URL
|
||
* @param options 加载选项(位置、旋转、缩放)
|
||
*/
|
||
public loadModel(url: string, options?: ModelLoadOptions): void {
|
||
if (!this._isInitialized || !this.engine) {
|
||
console.error('[Engine] Engine not initialized. Please call init() first.');
|
||
return;
|
||
}
|
||
if (!url) {
|
||
console.error('[Engine] Model URL is required.');
|
||
return;
|
||
}
|
||
this.engine.loaderModule.loadModels([url], options);
|
||
}
|
||
|
||
/**
|
||
* 回到主视角
|
||
* @returns
|
||
*/
|
||
public CameraGoHome() {
|
||
this.engine.viewCube.CameraGoHome();
|
||
}
|
||
|
||
/**
|
||
* 获取原始 3D 引擎实例
|
||
*/
|
||
public getEngine(): any {
|
||
return this.engine;
|
||
}
|
||
|
||
// ==================== 测量功能方法 ====================
|
||
|
||
/**
|
||
* 激活具体测量类型的统一入口(私有方法)
|
||
* @param type 测量类型
|
||
* @param activateFunc 第三方引擎的激活函数
|
||
*/
|
||
private activateMeasureType(type: MeasureMode, activateFunc: () => void): void {
|
||
// 1. 检查引擎是否初始化
|
||
if (!this._isInitialized || !this.engine) {
|
||
console.error('Cannot activate measure: engine not initialized.');
|
||
return;
|
||
}
|
||
|
||
// 2. 检查 measure 模块是否存在
|
||
if (!this.engine.measure) {
|
||
console.error('Measure module not available.');
|
||
return;
|
||
}
|
||
|
||
// 3. 如果主功能未激活,先激活主功能
|
||
if (!this.isMeasureActive) {
|
||
console.log(`激活测测量功能`);
|
||
this.engine.measure.active();
|
||
this.isMeasureActive = true;
|
||
}
|
||
|
||
// 4. 激活具体的测量类型(直接切换,不需要停用前一个)
|
||
activateFunc();
|
||
this.currentMeasureType = type;
|
||
}
|
||
|
||
/**
|
||
* 激活距离测量
|
||
*/
|
||
public activateDistanceMeasure(): void {
|
||
this.activateMeasureType('distance', () => {
|
||
console.log(`激活距离测量`);
|
||
this.engine.measure.distanceMeasure.active();
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 激活最小距离测量
|
||
*/
|
||
public activateMinDistanceMeasure(): void {
|
||
this.activateMeasureType('minDistance', () => {
|
||
console.log(`激活最小距离测量`);
|
||
this.engine.measure.minDistanceMeasure.active();
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 激活角度测量
|
||
*/
|
||
public activateAngleMeasure(): void {
|
||
this.activateMeasureType('angle', () => {
|
||
console.log(`激活角度测量`);
|
||
this.engine.measure.angleMeasure.active();
|
||
console.log('[Engine] Angle measure activated (placeholder)');
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 激活标高测量
|
||
*/
|
||
public activateElevationMeasure(): void {
|
||
this.activateMeasureType('elevation', () => {
|
||
console.log(`激活标高测量`);
|
||
this.engine.measure.elevationMeasure.active();
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 激活体积测量
|
||
*/
|
||
public activateVolumeMeasure(): void {
|
||
this.activateMeasureType('volume', () => {
|
||
console.log(`激活体积测量`);
|
||
this.engine.measure.volumeMeasure.active();
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 激活激光测距
|
||
*/
|
||
public activateLaserDistanceMeasure(): void {
|
||
this.activateMeasureType('laserDistance', () => {
|
||
// TODO: 调用第三方引擎方法(当前先空着)
|
||
// this.engine.measure.laserDistanceMeasure.active();
|
||
console.log('[Engine] Laser distance measure activated (placeholder)');
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 激活坡度测量
|
||
*/
|
||
public activateSlopeMeasure(): void {
|
||
this.activateMeasureType('slope', () => {
|
||
console.log(`激活坡度测量`);
|
||
this.engine.measure.slopeMeasure.active();
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 激活空间体积测量
|
||
*/
|
||
public activateSpaceVolumeMeasure(): void {
|
||
this.activateMeasureType('spaceVolume', () => {
|
||
// TODO: 调用第三方引擎方法(当前先空着)
|
||
// this.engine.measure.spaceVolumeMeasure.active();
|
||
console.log('[Engine] Space volume measure activated (placeholder)');
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 激活测量功能(根据类型统一入口)
|
||
* @param mode 测量类型
|
||
*/
|
||
public activateMeasure(mode: MeasureMode): void {
|
||
switch (mode) {
|
||
case 'distance':
|
||
this.activateDistanceMeasure();
|
||
break;
|
||
case 'minDistance':
|
||
this.activateMinDistanceMeasure();
|
||
break;
|
||
case 'angle':
|
||
this.activateAngleMeasure();
|
||
break;
|
||
case 'elevation':
|
||
this.activateElevationMeasure();
|
||
break;
|
||
case 'volume':
|
||
this.activateVolumeMeasure();
|
||
break;
|
||
case 'laserDistance':
|
||
this.activateLaserDistanceMeasure();
|
||
break;
|
||
case 'slope':
|
||
this.activateSlopeMeasure();
|
||
break;
|
||
case 'spaceVolume':
|
||
this.activateSpaceVolumeMeasure();
|
||
break;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 停用测量功能(关闭测量时调用)
|
||
*/
|
||
public deactivateMeasure(): void {
|
||
if (!this._isInitialized || !this.engine?.measure) {
|
||
return;
|
||
}
|
||
|
||
if (!this.isMeasureActive) {
|
||
return; // 已经是停用状态
|
||
}
|
||
console.log('停用测量功能');
|
||
this.engine.measure.disActive();
|
||
this.isMeasureActive = false;
|
||
this.currentMeasureType = null;
|
||
}
|
||
|
||
/**
|
||
* 获取当前激活的测量类型
|
||
* @returns 当前测量类型,如果未激活则返回 null
|
||
*/
|
||
public getCurrentMeasureType(): MeasureMode | null {
|
||
return this.currentMeasureType;
|
||
}
|
||
|
||
// ==================== 结束:测量功能方法 ====================
|
||
|
||
/**
|
||
* 销毁组件 (接口实现)
|
||
* 清理资源、取消订阅、销毁引擎实例
|
||
*/
|
||
public destroy(): void {
|
||
if (this._isDestroyed) {
|
||
return;
|
||
}
|
||
|
||
// 停用测量功能
|
||
this.deactivateMeasure();
|
||
|
||
// 取消主题订阅
|
||
if (this.unsubscribeTheme) {
|
||
this.unsubscribeTheme();
|
||
this.unsubscribeTheme = null;
|
||
}
|
||
|
||
// 清理容器(可选,根据需求决定是否清空容器)
|
||
this.container.innerHTML = '';
|
||
|
||
// 更新状态
|
||
this.currentMeasureType = null;
|
||
this.isMeasureActive = false;
|
||
this._isDestroyed = true;
|
||
this._isInitialized = false;
|
||
}
|
||
}
|
||
|
||
|