Files
bim_engine/src/cus-bim-engine.ts

289 lines
10 KiB
TypeScript

declare const __APP_VERSION__: string;
import './bim-engine.css';
import { DialogManager } from './managers/dialog-manager';
import { EngineManager } from './managers/engine-manager';
import { RightKeyManager } from './managers/right-key-manager';
import { RadialToolbarManager } from './managers/radial-toolbar-manager';
import { BottomDockManager } from './managers/bottom-dock-manager';
import { MeasureDockManager } from './managers/measure-dock-manager';
import { SectionDockManager } from './managers/section-dock-manager';
import { WalkDockManager } from './managers/walk-dock-manager';
import { MeasureDialogManager } from './managers/measure-dialog-manager';
import { SectionPlaneDialogManager } from './managers/section-plane-dialog-manager';
import { SectionAxisDialogManager } from './managers/section-axis-dialog-manager';
import { SectionBoxDialogManager } from './managers/section-box-dialog-manager';
import { WalkControlManager } from './managers/walk-control-manager';
import { EngineInfoDialogManager } from './managers/engine-info-dialog-manager';
import { SettingDialogManager } from './managers/setting-dialog-manager';
import { ComponentDetailManager } from './managers/component-detail-manager';
import { AiChatManager } from './managers/ai-chat-manager';
import type { EngineOptions, ModelLoadOptions } from './components/engine';
import { localeManager } from './services/locale';
import { themeManager } from './services/theme';
import type { LocaleType } from './locales/types';
import type { ThemeType, ThemeConfig } from './themes/types';
import { ManagerRegistry } from './core/manager-registry';
import { EngineEvents } from './types/events';
export type { EngineOptions, ModelLoadOptions };
/**
* CusBimEngine - 定制版 BIM 引擎
* 移除了 ButtonGroupManager、ConstructTreeManagerBtn 和 ToolbarManager
*/
export class CusBimEngine {
public container: HTMLElement;
private wrapper: HTMLElement | null = null;
private sizeEl: HTMLElement | null = null;
private resizeObserver: ResizeObserver | null = null;
private lastSyncedWidth = -1;
private lastSyncedHeight = -1;
private unsubscribeTheme: (() => void) | null = null;
private registry: ManagerRegistry;
public dialog: DialogManager | null = null;
public engine: EngineManager | null = null;
public rightKey: RightKeyManager | null = null;
public radialToolbar: RadialToolbarManager | null = null;
public bottomDock: BottomDockManager | null = null;
public measureDock: MeasureDockManager | null = null;
public sectionDock: SectionDockManager | null = null;
public walkDock: WalkDockManager | null = null;
public measure: MeasureDialogManager | null = null;
public sectionPlane: SectionPlaneDialogManager | null = null;
public sectionAxis: SectionAxisDialogManager | null = null;
public sectionBox: SectionBoxDialogManager | null = null;
public walkControl: WalkControlManager | null = null;
public engineInfo: EngineInfoDialogManager | null = null;
public componentDetail: ComponentDetailManager | null = null;
public aiChat: AiChatManager | null = null;
public setting: SettingDialogManager | null = null;
private readonly handleWindowResize = () => {
this.updateClientSizeDisplay();
};
constructor(
container: HTMLElement | string,
options?: {
locale?: LocaleType;
theme?: ThemeType;
}
) {
const el = typeof container === 'string' ? document.getElementById(container) : container;
if (!el) throw new Error('Container not found');
this.container = el;
this.registry = new ManagerRegistry();
if (options?.locale) localeManager.setLocale(options.locale);
if (options?.theme) {
if (options.theme === 'custom') {
console.warn('Custom theme should be set via setCustomTheme().');
} else {
themeManager.setTheme(options.theme);
}
}
this.init();
}
public emit<K extends keyof EngineEvents>(event: K, payload: EngineEvents[K]) {
this.registry.emit(event, payload);
}
/**
* 订阅事件
* @param event 事件名称
* @param listener 事件监听器
* @returns 取消订阅函数
*/
public on<K extends keyof EngineEvents>(event: K, listener: (payload: EngineEvents[K]) => void): () => void {
return this.registry.on(event, listener);
}
public setLocale(locale: LocaleType) {
localeManager.setLocale(locale);
}
public getLocale(): LocaleType {
return localeManager.getLocale();
}
public setTheme(theme: 'dark' | 'light') {
themeManager.setTheme(theme);
}
public setCustomTheme(theme: ThemeConfig) {
themeManager.setCustomTheme(theme);
}
private init() {
this.container.innerHTML = '';
this.wrapper = document.createElement('div');
this.wrapper.className = 'bim-engine-wrapper';
this.container.appendChild(this.wrapper);
const versionEl = document.createElement('div');
versionEl.className = 'bim-engine-version';
versionEl.textContent = `v${__APP_VERSION__}`;
this.wrapper.appendChild(versionEl);
this.sizeEl = document.createElement('div');
this.sizeEl.className = 'bim-engine-size';
this.wrapper.appendChild(this.sizeEl);
this.updateClientSizeDisplay();
this.bindSizeObserver();
this.registry.container = this.container;
this.registry.wrapper = this.wrapper;
this.engine = new EngineManager(this.wrapper, this.registry);
this.dialog = new DialogManager(this.wrapper, this.registry);
this.rightKey = new RightKeyManager(this.wrapper, this.registry);
this.bottomDock = new BottomDockManager(this.wrapper, this.registry);
this.registry.bottomDock = this.bottomDock;
this.registry.engine3d = this.engine;
this.registry.dialog = this.dialog;
this.registry.rightKey = this.rightKey;
this.measureDock = new MeasureDockManager(this.registry);
this.registry.measureDock = this.measureDock;
this.measureDock.init();
this.sectionDock = new SectionDockManager(this.registry);
this.registry.sectionDock = this.sectionDock;
this.sectionDock.init();
this.walkDock = new WalkDockManager(this.registry);
this.registry.walkDock = this.walkDock;
this.walkDock.init();
this.radialToolbar = new RadialToolbarManager(this.wrapper, this.registry);
this.measure = new MeasureDialogManager(this.registry);
this.sectionPlane = new SectionPlaneDialogManager(this.registry);
this.sectionAxis = new SectionAxisDialogManager(this.registry);
this.sectionBox = new SectionBoxDialogManager(this.registry);
this.walkControl = new WalkControlManager(this.registry);
this.walkControl.init();
this.engineInfo = new EngineInfoDialogManager(this.registry);
this.engineInfo.init();
this.registry.radialToolbar = this.radialToolbar;
this.registry.measure = this.measure;
this.registry.sectionPlane = this.sectionPlane;
this.registry.sectionAxis = this.sectionAxis;
this.registry.sectionBox = this.sectionBox;
this.registry.walkControl = this.walkControl;
this.registry.engineInfo = this.engineInfo;
this.componentDetail = new ComponentDetailManager(this.registry);
this.registry.componentDetail = this.componentDetail;
this.componentDetail.init();
this.aiChat = new AiChatManager(this.registry);
this.registry.aiChat = this.aiChat;
this.aiChat.init();
this.setting = new SettingDialogManager(this.registry);
this.registry.setting = this.setting;
this.setting.init();
this.updateTheme(themeManager.getTheme());
this.unsubscribeTheme = themeManager.subscribe((theme) => {
this.updateTheme(theme);
});
}
private updateTheme(theme: ThemeConfig) {
if (this.wrapper) {
this.wrapper.style.color = theme.textPrimary;
}
}
private updateClientSizeDisplay(): void {
const width = this.container.clientWidth;
const height = this.container.clientHeight;
if (this.sizeEl) {
this.sizeEl.textContent = `${width}px x ${height}px`;
}
this.syncEngineSize(width, height);
}
private syncEngineSize(width: number, height: number): void {
if (width <= 0 || height <= 0) {
return;
}
if (width === this.lastSyncedWidth && height === this.lastSyncedHeight) {
return;
}
this.lastSyncedWidth = width;
this.lastSyncedHeight = height;
this.engine?.getEngineComponent()?.resize(width, height);
}
private bindSizeObserver(): void {
if (typeof ResizeObserver !== 'undefined') {
this.resizeObserver = new ResizeObserver(() => {
this.updateClientSizeDisplay();
});
this.resizeObserver.observe(this.container);
return;
}
window.addEventListener('resize', this.handleWindowResize);
}
private unbindSizeObserver(): void {
if (this.resizeObserver) {
this.resizeObserver.disconnect();
this.resizeObserver = null;
return;
}
window.removeEventListener('resize', this.handleWindowResize);
}
public destroy() {
this.unbindSizeObserver();
if (this.unsubscribeTheme) {
this.unsubscribeTheme();
this.unsubscribeTheme = null;
}
this.radialToolbar?.destroy();
this.measureDock?.destroy();
this.sectionDock?.destroy();
this.walkDock?.destroy();
this.bottomDock?.destroy();
this.engine?.destroy();
this.dialog?.destroy();
this.rightKey?.destroy();
this.measure?.destroy();
this.sectionPlane?.destroy();
this.sectionAxis?.destroy();
this.sectionBox?.destroy();
this.walkControl?.destroy();
this.aiChat?.destroy();
this.setting?.destroy();
this.sizeEl = null;
this.lastSyncedWidth = -1;
this.lastSyncedHeight = -1;
this.container.innerHTML = '';
this.registry.reset();
}
}