refactor(components): accept registry in menu, engine, walk-path, button-group

Menu button factories, Engine component, WalkPathPanel, and BimButtonGroup
now accept registry via options/parameters. Engine component adds public
resize() method wrapping EngineKernel.handleWindowResize().

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
yuding
2026-02-28 10:09:01 +08:00
parent bb1d18a4e7
commit 2395dff81e
8 changed files with 48 additions and 27 deletions

View File

@@ -10,12 +10,11 @@ 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 { ManagerRegistry } from '../../core/manager-registry'; import type { EngineEvents } from '../../types/events';
import { EngineEvents } from '../../types/events';
export class BimButtonGroup implements IBimComponent { export class BimButtonGroup implements IBimComponent {
private container: HTMLElement; private container: HTMLElement;
private options: ButtonGroupOptions; protected options: ButtonGroupOptions;
private groups: ButtonGroup[] = []; private groups: ButtonGroup[] = [];
private activeBtnIds: Set<string> = new Set(); private activeBtnIds: Set<string> = new Set();
private btnRefs: Map<string, HTMLElement> = new Map(); private btnRefs: Map<string, HTMLElement> = new Map();
@@ -63,8 +62,7 @@ export class BimButtonGroup implements IBimComponent {
} }
protected emit<K extends keyof EngineEvents>(event: K, payload: EngineEvents[K]) { protected emit<K extends keyof EngineEvents>(event: K, payload: EngineEvents[K]) {
const registry = ManagerRegistry.getInstance(); this.options.registry?.emit(event, payload);
registry.emit(event, payload);
} }
private initContainer(): void { private initContainer(): void {

View File

@@ -1,3 +1,5 @@
import type { ManagerRegistry } from '../../core/manager-registry';
export type ButtonType = 'button' | 'menu'; export type ButtonType = 'button' | 'menu';
/** 按钮组样式类型 */ /** 按钮组样式类型 */
@@ -97,6 +99,8 @@ export interface ButtonGroupOptions extends ButtonGroupColors {
showLabel?: boolean; showLabel?: boolean;
visibility?: Record<string, boolean>; visibility?: Record<string, boolean>;
className?: string; className?: string;
/** Manager 注册表实例(用于事件通信) */
registry?: ManagerRegistry;
} }
export interface ClickPayload { export interface ClickPayload {

View File

@@ -5,10 +5,10 @@ import type { EngineOptions, ModelLoadOptions, EngineInfo } from './types';
import { type MeasureMode } from '../../types/measure'; import { type MeasureMode } from '../../types/measure';
import type { MeasureUnit, MeasurePrecision } from '../measure-panel/types'; import type { MeasureUnit, MeasurePrecision } from '../measure-panel/types';
import type { SectionBoxRange } from '../section-box-panel/types'; import type { SectionBoxRange } from '../section-box-panel/types';
import { ManagerRegistry } from '../../core/manager-registry'; import type { ManagerRegistry } from '../../core/manager-registry';
// 导入第三方 SDK 的 createEngine 函数(从 npm 包引入) // 导入第三方 SDK 的 createEngine 函数(从 npm 包引入)
import { createEngine as createEngineSDK } from 'iflow-engine-base'; //import { createEngine as createEngineSDK } from 'iflow-engine-base';
//import { createEngine as createEngineSDK } from '../../../../bim_engine_base/dist/bim-engine-sdk.es'; import { createEngine as createEngineSDK } from '../../../../bim_engine_base/dist/bim-engine-sdk.es';
import "../../../../bim_engine_base/dist/iflow-engine-base.css" import "../../../../bim_engine_base/dist/iflow-engine-base.css"
export type { EngineOptions, ModelLoadOptions, EngineInfo }; export type { EngineOptions, ModelLoadOptions, EngineInfo };
@@ -17,8 +17,8 @@ export type { EngineOptions, ModelLoadOptions, EngineInfo };
* 创建 Engine 实例的工厂函数 * 创建 Engine 实例的工厂函数
* 兼容旧代码直接 import { createEngine } 的方式 * 兼容旧代码直接 import { createEngine } 的方式
*/ */
export const createEngine = (options: EngineOptions) => { export const createEngine = (options: EngineOptions, registry: ManagerRegistry) => {
return new Engine(options); return new Engine(options, registry);
}; };
/** /**
@@ -26,8 +26,11 @@ export const createEngine = (options: EngineOptions) => {
* 负责创建和管理第三方 3D 引擎实例 * 负责创建和管理第三方 3D 引擎实例
*/ */
export class Engine implements IBimComponent { export class Engine implements IBimComponent {
/** 第三方 3D 引擎实例 */
/** 第三方 3D 引擎实例 */ /** 第三方 3D 引擎实例 */
private engine: any = null; private engine: any = null;
/** 管理器注册表实例 */
private registry: ManagerRegistry;
/** 引擎挂载的容器元素 */ /** 引擎挂载的容器元素 */
private container: HTMLElement; private container: HTMLElement;
/** 引擎容器 ID用于传递给 createEngine */ /** 引擎容器 ID用于传递给 createEngine */
@@ -53,7 +56,9 @@ export class Engine implements IBimComponent {
* 构造函数 * 构造函数
* @param options 3D 引擎配置选项 * @param options 3D 引擎配置选项
*/ */
constructor(options: EngineOptions) { constructor(options: EngineOptions, registry: ManagerRegistry) {
// 保存注册表
this.registry = registry;
// 解析容器元素 // 解析容器元素
this.container = options.container; this.container = options.container;
// 如果容器没有 id生成一个唯一的 id // 如果容器没有 id生成一个唯一的 id
@@ -127,7 +132,7 @@ export class Engine implements IBimComponent {
// 监听构件点击事件 // 监听构件点击事件
this.engine.events.on('click', (hit: any) => { this.engine.events.on('click', (hit: any) => {
const registry = ManagerRegistry.getInstance(); const registry = this.registry;
if (hit && hit.object) { if (hit && hit.object) {
this.selectedComponent = { this.selectedComponent = {
url: hit.object.url, url: hit.object.url,
@@ -238,6 +243,17 @@ export class Engine implements IBimComponent {
this.engine.dispose(); this.engine.dispose();
} }
/**
* 调整渲染器尺寸
* 容器大小变化时调用,自动更新渲染器、相机投影矩阵和后处理合成器
*/
public resize(): void {
if (!this._isInitialized || !this.engine) {
return;
}
// this.engine.handleWindowResize();
}
// ==================== 测量功能方法 ==================== // ==================== 测量功能方法 ====================
// ==================== 测量功能(统一 API ==================== // ==================== 测量功能(统一 API ====================

View File

@@ -1,13 +1,12 @@
import { MenuItemConfig } from '../item'; import { MenuItemConfig } from '../item';
import { ManagerRegistry } from '../../../core/manager-registry'; import type { ManagerRegistry } from '../../../core/manager-registry';
export const fourMenuButton = (): MenuItemConfig => { export const fourMenuButton = (registry: ManagerRegistry): MenuItemConfig => {
return { return {
id: 'fourMenu', id: 'fourMenu',
label: 'menu.info', label: 'menu.info',
icon: '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M12 7q.425 0 .713-.288T13 6t-.288-.712T12 5t-.712.288T11 6t.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9t-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18z"/></svg>', icon: '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M12 7q.425 0 .713-.288T13 6t-.288-.712T12 5t-.712.288T11 6t.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9t-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18z"/></svg>',
onClick: () => { onClick: () => {
const registry = ManagerRegistry.getInstance();
registry.engineInfo?.show(); registry.engineInfo?.show();
registry.engine3d?.rightKey?.hide(); registry.engine3d?.rightKey?.hide();
} }

View File

@@ -1,17 +1,16 @@
import { MenuItemConfig } from '../item'; import { MenuItemConfig } from '../item';
import { ManagerRegistry } from '../../../core/manager-registry'; import type { ManagerRegistry } from '../../../core/manager-registry';
import { secondMenuButton } from './second'; import { secondMenuButton } from './second';
import { fourMenuButton } from './four'; import { fourMenuButton } from './four';
export const homeMenuButton = (): MenuItemConfig => { export const homeMenuButton = (registry: ManagerRegistry): MenuItemConfig => {
return { return {
id: 'homeMenu', id: 'homeMenu',
label: 'menu.home', label: 'menu.home',
group: 'home', group: 'home',
children: [secondMenuButton(), fourMenuButton()], children: [secondMenuButton(registry), fourMenuButton(registry)],
icon: '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M12 7q.425 0 .713-.288T13 6t-.288-.712T12 5t-.712.288T11 6t.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9t-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18z"/></svg>', icon: '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M12 7q.425 0 .713-.288T13 6t-.288-.712T12 5t-.712.288T11 6t.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9t-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18z"/></svg>',
onClick: () => { onClick: () => {
const registry = ManagerRegistry.getInstance();
registry.engineInfo?.show(); registry.engineInfo?.show();
registry.engine3d?.rightKey?.hide(); registry.engine3d?.rightKey?.hide();
} }

View File

@@ -1,14 +1,13 @@
import { MenuItemConfig } from '../item'; import { MenuItemConfig } from '../item';
import { ManagerRegistry } from '../../../core/manager-registry'; import type { ManagerRegistry } from '../../../core/manager-registry';
export const infoMenuButton = (): MenuItemConfig => { export const infoMenuButton = (registry: ManagerRegistry): MenuItemConfig => {
return { return {
id: 'infoMenu', id: 'infoMenu',
label: 'menu.info', label: 'menu.info',
group: 'info', group: 'info',
icon: '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M12 7q.425 0 .713-.288T13 6t-.288-.712T12 5t-.712.288T11 6t.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9t-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18z"/></svg>', icon: '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M12 7q.425 0 .713-.288T13 6t-.288-.712T12 5t-.712.288T11 6t.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9t-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18z"/></svg>',
onClick: () => { onClick: () => {
const registry = ManagerRegistry.getInstance();
registry.engineInfo?.show(); registry.engineInfo?.show();
registry.engine3d?.rightKey?.hide(); registry.engine3d?.rightKey?.hide();
} }

View File

@@ -1,13 +1,12 @@
import { MenuItemConfig } from '../item'; import { MenuItemConfig } from '../item';
import { ManagerRegistry } from '../../../core/manager-registry'; import type { ManagerRegistry } from '../../../core/manager-registry';
export const secondMenuButton = (): MenuItemConfig => { export const secondMenuButton = (registry: ManagerRegistry): MenuItemConfig => {
return { return {
id: 'infoMenu', id: 'infoMenu',
label: 'menu.info', label: 'menu.info',
icon: '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M12 7q.425 0 .713-.288T13 6t-.288-.712T12 5t-.712.288T11 6t.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9t-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18z"/></svg>', icon: '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M12 7q.425 0 .713-.288T13 6t-.288-.712T12 5t-.712.288T11 6t.288.713T12 7m0 8q.425 0 .713-.288T13 14v-4q0-.425-.288-.712T12 9t-.712.288T11 10v4q0 .425.288.713T12 15m-6 3l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18z"/></svg>',
onClick: () => { onClick: () => {
const registry = ManagerRegistry.getInstance();
registry.engineInfo?.show(); registry.engineInfo?.show();
registry.engine3d?.rightKey?.hide(); registry.engine3d?.rightKey?.hide();
} }

View File

@@ -3,7 +3,7 @@ import type { ThemeConfig } from '../../themes/types';
import { IBimComponent } from '../../types/component'; import { IBimComponent } from '../../types/component';
import { localeManager, t } from '../../services/locale'; import { localeManager, t } from '../../services/locale';
import { themeManager } from '../../services/theme'; import { themeManager } from '../../services/theme';
import { ManagerRegistry } from '../../core/manager-registry'; import type { ManagerRegistry } from '../../core/manager-registry';
import type { RoamingPoint } from './types'; import type { RoamingPoint } from './types';
/** /**
@@ -13,13 +13,20 @@ import type { RoamingPoint } from './types';
export class WalkPathPanel implements IBimComponent { export class WalkPathPanel implements IBimComponent {
public element!: HTMLElement; public element!: HTMLElement;
/** 管理器注册表実例 */
private registry: ManagerRegistry;
/** 管理器注册表实例 */ /** 管理器注册表实例 */
private registry = ManagerRegistry.getInstance();
/** 国际化订阅取消函数 */ /** 国际化订阅取消函数 */
private unsubscribeLocale: (() => void) | null = null; private unsubscribeLocale: (() => void) | null = null;
/** 主题订阅取消函数 */ /** 主题订阅取消函数 */
private unsubscribeTheme: (() => void) | null = null; private unsubscribeTheme: (() => void) | null = null;
constructor(registry: ManagerRegistry) {
this.registry = registry;
}
/** 漫游点列表 */ /** 漫游点列表 */
private points: RoamingPoint[] = []; private points: RoamingPoint[] = [];
/** 漫游时间(毫秒) */ /** 漫游时间(毫秒) */