refactor: 重构 Manager 架构,引入 ManagerRegistry 和 BaseManager 基类
- 新增 ManagerRegistry 单例注册表,统一管理所有 Manager 实例 - 新增 BaseManager 基类,自动管理事件订阅清理 - 新增 BaseDialogManager 基类,统一对话框生命周期管理 - 重构 15 个 Manager 使用新基类 - 重构 Toolbar 按钮和 Menu 按钮移除 engine 参数依赖 - 删除 BimComponent 基类(已不再使用) - 为所有 Manager 和核心模块添加中文 JSDoc 注释
This commit is contained in:
@@ -1,46 +1,65 @@
|
||||
/**
|
||||
* 按钮组管理器
|
||||
* 负责创建和管理按钮组实例
|
||||
*/
|
||||
import { BimButtonGroup } from '../components/button-group';
|
||||
import type { ButtonGroupOptions } from '../components/button-group/index.type';
|
||||
import type { ThemeConfig } from '../themes/types';
|
||||
import { BimComponent } from '../core/component';
|
||||
import type { BimEngine } from '../bim-engine';
|
||||
import { BaseManager } from '../core/base-manager';
|
||||
|
||||
/**
|
||||
* 通用按钮组管理器 (ButtonGroupManager)
|
||||
* 负责创建和管理通用的按钮组实例。
|
||||
* 按钮组管理器
|
||||
* 统一管理多个按钮组的创建、主题更新和销毁
|
||||
*/
|
||||
export class ButtonGroupManager extends BimComponent {
|
||||
export class ButtonGroupManager extends BaseManager {
|
||||
/** 按钮组映射表 */
|
||||
private groups: Map<string, BimButtonGroup> = new Map();
|
||||
/** 容器元素 */
|
||||
private container: HTMLElement;
|
||||
|
||||
constructor(engine: BimEngine, container: HTMLElement) {
|
||||
super(engine);
|
||||
constructor(container: HTMLElement) {
|
||||
super();
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建按钮组
|
||||
* @param id 按钮组 ID
|
||||
* @param options 按钮组配置
|
||||
* @returns 按钮组实例
|
||||
*/
|
||||
public create(id: string, options: Omit<ButtonGroupOptions, 'container'>): BimButtonGroup {
|
||||
const group = new BimButtonGroup({
|
||||
container: this.container,
|
||||
...options
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
group.setEngine(this.engine);
|
||||
|
||||
group.init();
|
||||
this.groups.set(id, group);
|
||||
return group;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取按钮组
|
||||
* @param id 按钮组 ID
|
||||
* @returns 按钮组实例
|
||||
*/
|
||||
public get(id: string): BimButtonGroup | undefined {
|
||||
return this.groups.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新所有按钮组的主题
|
||||
* @param theme 主题配置
|
||||
*/
|
||||
public updateTheme(theme: ThemeConfig) {
|
||||
this.groups.forEach(group => group.setTheme(theme));
|
||||
}
|
||||
|
||||
/** 销毁管理器和所有按钮组 */
|
||||
public destroy() {
|
||||
this.groups.forEach(group => group.destroy());
|
||||
this.groups.clear();
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import type {ButtonGroupColors, ButtonConfig} from '../components/button-group/index.type';
|
||||
import {Toolbar} from '../components/button-group/toolbar';
|
||||
import {BimComponent} from '../core/component';
|
||||
import type {BimEngine} from '../bim-engine';
|
||||
import {BimButtonGroup} from "../components/button-group";
|
||||
import {BimTree} from "../components/tree";
|
||||
import {TreeNodeConfig} from "../components/tree/types.ts";
|
||||
import {BimDialog} from "../components/dialog";
|
||||
import {BimTab} from "../components/tab";
|
||||
import {getIcon} from "../utils/icon-manager";
|
||||
/**
|
||||
* 构件树管理器
|
||||
* 负责管理构件树按钮和构件树对话框
|
||||
*/
|
||||
import type { ButtonGroupColors, ButtonConfig } from '../components/button-group/index.type';
|
||||
import { BaseManager } from '../core/base-manager';
|
||||
import { BimButtonGroup } from '../components/button-group';
|
||||
import { BimTree } from '../components/tree';
|
||||
import { TreeNodeConfig } from '../components/tree/types';
|
||||
import { BimDialog } from '../components/dialog';
|
||||
import { BimTab } from '../components/tab';
|
||||
import { getIcon } from '../utils/icon-manager';
|
||||
|
||||
const MOCK_STRUCT_DATA: TreeNodeConfig[] =[
|
||||
/** 模拟的构件树数据 */
|
||||
const MOCK_STRUCT_DATA: TreeNodeConfig[] = [
|
||||
{
|
||||
id: 'root',
|
||||
label: '全部构件',
|
||||
@@ -20,10 +23,10 @@ const MOCK_STRUCT_DATA: TreeNodeConfig[] =[
|
||||
id: 'level-1',
|
||||
label: '一层',
|
||||
expanded: false,
|
||||
icon:'<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M20.73 16.52V7.59a.7.7 0 0 0-.08-.33a.74.74 0 0 0-.36-.36l-8-3.58a.75.75 0 0 0-.62 0l-8 3.58a.8.8 0 0 0-.44.69v8.82a.83.83 0 0 0 .44.69l8 3.58a.72.72 0 0 0 .62 0l8-3.58a.77.77 0 0 0 .44-.58m-16-7.78l6.5 2.92v7.18l-6.5-2.91Zm8 2.92l6.5-2.92v7.19l-6.5 2.91ZM12 4.82l6.17 2.77L12 10.35L5.83 7.59Z"/></svg>',
|
||||
icon: '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M20.73 16.52V7.59a.7.7 0 0 0-.08-.33a.74.74 0 0 0-.36-.36l-8-3.58a.75.75 0 0 0-.62 0l-8 3.58a.8.8 0 0 0-.44.69v8.82a.83.83 0 0 0 .44.69l8 3.58a.72.72 0 0 0 .62 0l8-3.58a.77.77 0 0 0 .44-.58m-16-7.78l6.5 2.92v7.18l-6.5-2.91Zm8 2.92l6.5-2.92v7.19l-6.5 2.91ZM12 4.82l6.17 2.77L12 10.35L5.83 7.59Z"/></svg>',
|
||||
clickAction: 'expand',
|
||||
children: [
|
||||
{ id: 'l1-wall', label: '墙体(128)'},
|
||||
{ id: 'l1-wall', label: '墙体(128)' },
|
||||
{ id: 'l1-column', label: '柱(46)' },
|
||||
{ id: 'l1-beam', label: '梁(82)' },
|
||||
{ id: 'l1-slab', label: '楼板(12)' },
|
||||
@@ -75,23 +78,27 @@ const MOCK_STRUCT_DATA: TreeNodeConfig[] =[
|
||||
];
|
||||
|
||||
/**
|
||||
* 底部工具栏管理器 (ToolbarManager)
|
||||
* 仅负责管理底部工具栏实例。
|
||||
* 构件树管理器
|
||||
* 管理左上角的构件树按钮和对话框
|
||||
*/
|
||||
export class ConstructTreeManagerBtn extends BimComponent {
|
||||
private toolbar: Toolbar | null = null;
|
||||
export class ConstructTreeManagerBtn extends BaseManager {
|
||||
/** 按钮组实例 */
|
||||
private toolbar: BimButtonGroup | null = null;
|
||||
/** 按钮容器元素 */
|
||||
private toolbarContainer: HTMLElement | null = null;
|
||||
/** 主容器元素 */
|
||||
private container: HTMLElement;
|
||||
/** 构件树对话框实例 */
|
||||
private dialog: BimDialog | null = null;
|
||||
|
||||
constructor(engine: BimEngine, container: HTMLElement) {
|
||||
super(engine);
|
||||
constructor(container: HTMLElement) {
|
||||
super();
|
||||
this.container = container;
|
||||
this.init();
|
||||
}
|
||||
|
||||
/** 初始化按钮 */
|
||||
private init() {
|
||||
// 创建底部工具栏专用容器
|
||||
this.toolbarContainer = document.createElement('div');
|
||||
this.toolbarContainer.id = 'bim-construct-tree';
|
||||
this.container.appendChild(this.toolbarContainer);
|
||||
@@ -99,12 +106,11 @@ export class ConstructTreeManagerBtn extends BimComponent {
|
||||
container: this.toolbarContainer,
|
||||
showLabel: false,
|
||||
direction: 'column',
|
||||
position: 'top-left', // 底部居中
|
||||
align: 'vertical', // 图标在上
|
||||
expand: 'up' // 向上展开
|
||||
position: 'top-left',
|
||||
align: 'vertical',
|
||||
expand: 'up'
|
||||
});
|
||||
this.toolbar.init();
|
||||
this.toolbar.setEngine(this.engine);
|
||||
this.toolbar.addGroup('construct-tree');
|
||||
this.toolbar.addButton({
|
||||
id: 'construct-tree-btn',
|
||||
@@ -113,16 +119,16 @@ export class ConstructTreeManagerBtn extends BimComponent {
|
||||
label: 'construct-tree',
|
||||
icon: getIcon('目录树'),
|
||||
onClick: () => {
|
||||
this.openConstructTreeDialog()
|
||||
this.openConstructTreeDialog();
|
||||
}
|
||||
});
|
||||
this.toolbar.render();
|
||||
}
|
||||
|
||||
/** 打开构件树对话框 */
|
||||
public openConstructTreeDialog() {
|
||||
this.setVisible(false);
|
||||
|
||||
// 构件树实例(放在“构件”标签内)
|
||||
const tree = new BimTree({
|
||||
data: MOCK_STRUCT_DATA,
|
||||
checkable: true,
|
||||
@@ -146,18 +152,15 @@ export class ConstructTreeManagerBtn extends BimComponent {
|
||||
});
|
||||
tree.init();
|
||||
|
||||
// 系统/空间暂留空占位,可后续填充业务内容
|
||||
const systemPlaceholder = document.createElement('div');
|
||||
systemPlaceholder.className = 'construct-tab__panel-content';
|
||||
const spacePlaceholder = document.createElement('div');
|
||||
spacePlaceholder.className = 'construct-tab__panel-content';
|
||||
|
||||
// 构件面板容器,确保内部树区域可滚动
|
||||
const componentPanel = document.createElement('div');
|
||||
componentPanel.className = 'construct-tab__panel-content';
|
||||
componentPanel.appendChild(tree.element);
|
||||
|
||||
// 创建 Tab 容器(仅在本弹窗内使用,不额外挂 Manager)
|
||||
const tabMount = document.createElement('div');
|
||||
tabMount.className = 'construct-tab__container';
|
||||
tabMount.style.height = '100%';
|
||||
@@ -165,24 +168,23 @@ export class ConstructTreeManagerBtn extends BimComponent {
|
||||
const tab = new BimTab({
|
||||
container: tabMount,
|
||||
tabs: [
|
||||
{id: 'component', title: 'tab.component', content: componentPanel},
|
||||
{id: 'system', title: 'tab.system', content: systemPlaceholder},
|
||||
{id: 'space', title: 'tab.space', content: spacePlaceholder},
|
||||
{ id: 'component', title: 'tab.component', content: componentPanel },
|
||||
{ id: 'system', title: 'tab.system', content: systemPlaceholder },
|
||||
{ id: 'space', title: 'tab.space', content: spacePlaceholder },
|
||||
],
|
||||
activeId: 'component',
|
||||
onChange: () => {
|
||||
// 切换后根据内容宽度刷新弹窗
|
||||
this.dialog?.fitWidth();
|
||||
}
|
||||
});
|
||||
tab.init();
|
||||
|
||||
this.dialog = this.engine.dialog!.create({
|
||||
this.dialog = this.registry.dialog!.create({
|
||||
title: 'constructTree.title',
|
||||
minWidth: 320,
|
||||
height: 420,
|
||||
content: tabMount,
|
||||
position: {x: 20, y: 20},
|
||||
position: { x: 20, y: 20 },
|
||||
resizable: false,
|
||||
onClose: () => {
|
||||
tab.destroy();
|
||||
@@ -193,44 +195,76 @@ export class ConstructTreeManagerBtn extends BimComponent {
|
||||
this.dialog?.fitWidth();
|
||||
}
|
||||
|
||||
/** 刷新渲染 */
|
||||
public refresh() {
|
||||
this.toolbar?.render();
|
||||
}
|
||||
|
||||
/** 销毁管理器 */
|
||||
public destroy() {
|
||||
this.toolbar?.destroy();
|
||||
this.toolbar = null;
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
// --- 转发 API ---
|
||||
/**
|
||||
* 添加按钮组
|
||||
* @param groupId 组 ID
|
||||
* @param beforeGroupId 插入位置
|
||||
*/
|
||||
public addGroup(groupId: string, beforeGroupId?: string) {
|
||||
this.toolbar?.addGroup(groupId, beforeGroupId);
|
||||
this.toolbar?.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加按钮
|
||||
* @param config 按钮配置
|
||||
*/
|
||||
public addButton(config: ButtonConfig) {
|
||||
this.toolbar?.addButton(config);
|
||||
this.toolbar?.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置按钮可见性
|
||||
* @param id 按钮 ID
|
||||
* @param v 是否可见
|
||||
*/
|
||||
public setButtonVisibility(id: string, v: boolean) {
|
||||
this.toolbar?.updateButtonVisibility(id, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否显示标签
|
||||
* @param show 是否显示
|
||||
*/
|
||||
public setShowLabel(show: boolean) {
|
||||
this.toolbar?.setShowLabel(show);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置按钮组可见性
|
||||
* @param visible 是否可见
|
||||
*/
|
||||
public setVisible(visible: boolean) {
|
||||
if (this.toolbarContainer) {
|
||||
this.toolbarContainer.style.visibility = visible ? 'visible' : 'hidden';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置背景颜色
|
||||
* @param color 颜色值
|
||||
*/
|
||||
public setBackgroundColor(color: string) {
|
||||
this.toolbar?.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置按钮组颜色
|
||||
* @param colors 颜色配置
|
||||
*/
|
||||
public setColors(colors: ButtonGroupColors) {
|
||||
this.toolbar?.setColors(colors);
|
||||
}
|
||||
|
||||
@@ -1,35 +1,30 @@
|
||||
/**
|
||||
* 对话框管理器
|
||||
* 负责创建和管理所有对话框实例
|
||||
*/
|
||||
import { BimDialog } from '../components/dialog';
|
||||
import { BimInfoDialog } from '../components/dialog/bimInfoDialog';
|
||||
import type { DialogOptions } from '../components/dialog/index.type';
|
||||
import type { ThemeConfig } from '../themes/types';
|
||||
import { themeManager } from '../services/theme';
|
||||
import { BimComponent } from '../core/component';
|
||||
import type { BimEngine } from '../bim-engine';
|
||||
import { BaseManager } from '../core/base-manager';
|
||||
|
||||
/**
|
||||
* 弹窗管理器
|
||||
* 负责创建和管理应用中的各类弹窗。
|
||||
* 对话框管理器
|
||||
* 统一管理对话框的创建、主题更新和销毁
|
||||
*/
|
||||
export class DialogManager extends BimComponent {
|
||||
/** 弹窗挂载的父容器 */
|
||||
export class DialogManager extends BaseManager {
|
||||
/** 容器元素 */
|
||||
private container: HTMLElement;
|
||||
/** 活跃的弹窗实例列表 */
|
||||
/** 活跃的对话框列表 */
|
||||
private activeDialogs: BimDialog[] = [];
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param engine 引擎实例
|
||||
* @param container 弹窗挂载的目标容器
|
||||
*/
|
||||
constructor(engine: BimEngine, container: HTMLElement) {
|
||||
super(engine);
|
||||
constructor(container: HTMLElement) {
|
||||
super();
|
||||
this.container = container;
|
||||
|
||||
// 监听打开弹窗事件
|
||||
this.on('ui:open-dialog', (payload) => {
|
||||
// 这里可以根据 payload.id 做更复杂的逻辑,目前简单演示
|
||||
this.subscribe('ui:open-dialog', (payload) => {
|
||||
console.log('[DialogManager] Received open-dialog event:', payload);
|
||||
// 示例:如果 payload.id 是 'info',则打开 info dialog
|
||||
if (payload.id === 'info') {
|
||||
this.showInfoDialog();
|
||||
}
|
||||
@@ -37,41 +32,33 @@ export class DialogManager extends BimComponent {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个通用弹窗
|
||||
* @param options 弹窗配置选项(不需要传 container,自动使用管理器绑定的容器)
|
||||
* @returns BimDialog 实例
|
||||
* 创建对话框
|
||||
* @param options 对话框配置选项
|
||||
* @returns 对话框实例
|
||||
*/
|
||||
public create(options: Omit<DialogOptions, 'container'>): BimDialog {
|
||||
const dialog = new BimDialog({
|
||||
container: this.container,
|
||||
...options,
|
||||
onClose: () => {
|
||||
// 从活跃列表中移除
|
||||
this.activeDialogs = this.activeDialogs.filter(d => d !== dialog);
|
||||
if (options.onClose) options.onClose();
|
||||
}
|
||||
});
|
||||
|
||||
// 应用当前主题
|
||||
dialog.setTheme(themeManager.getTheme());
|
||||
|
||||
this.activeDialogs.push(dialog);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示二次封装的模型信息弹窗
|
||||
* 演示如何调用特定的业务弹窗组件
|
||||
*/
|
||||
/** 显示信息对话框 */
|
||||
public showInfoDialog() {
|
||||
// 最佳实践:所有弹窗应通过 create 统一管理,或者手动加入管理。
|
||||
new BimInfoDialog(this.container);
|
||||
// 暂时不做主题追踪,作为遗留逻辑保留
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应全局主题变更
|
||||
* @param theme 全局主题配置
|
||||
* 更新所有对话框的主题
|
||||
* @param theme 主题配置
|
||||
*/
|
||||
public updateTheme(theme: ThemeConfig) {
|
||||
this.activeDialogs.forEach(dialog => {
|
||||
@@ -81,8 +68,10 @@ export class DialogManager extends BimComponent {
|
||||
});
|
||||
}
|
||||
|
||||
/** 销毁管理器和所有对话框 */
|
||||
public destroy() {
|
||||
this.activeDialogs.forEach(d => d.destroy());
|
||||
this.activeDialogs = [];
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
/**
|
||||
* 3D 引擎管理器
|
||||
* 负责管理 3D 渲染引擎的初始化、模型加载和测量功能
|
||||
*/
|
||||
import { Engine, type EngineOptions, type ModelLoadOptions } from '../components/engine';
|
||||
import { BimComponent } from '../core/component';
|
||||
import type { BimEngine } from '../bim-engine';
|
||||
import { BaseManager } from '../core/base-manager';
|
||||
import { RightKeyManager } from './right-key-manager';
|
||||
import { infoMenuButton } from '../components/menu/buttons/info';
|
||||
import { homeMenuButton } from '../components/menu/buttons/home';
|
||||
@@ -8,34 +11,27 @@ import type { MeasureMode } from '../types/measure';
|
||||
|
||||
/**
|
||||
* 3D 引擎管理器
|
||||
* 负责连接 Engine 组件和 BimEngine,向外部暴露简化的 API
|
||||
* 采用延迟初始化模式,用户需主动调用 initialize() 方法
|
||||
* 封装底层 3D 引擎,提供模型加载、相机控制、测量等功能
|
||||
*/
|
||||
export class EngineManager extends BimComponent {
|
||||
/** 3D 引擎挂载的父容器 */
|
||||
export class EngineManager extends BaseManager {
|
||||
/** 容器元素 */
|
||||
private container: HTMLElement;
|
||||
/** 3D 引擎组件实例 */
|
||||
/** 引擎实例 */
|
||||
private engineInstance: Engine | null = null;
|
||||
/** 右键菜单管理器 */
|
||||
public rightKey: RightKeyManager | null = null;
|
||||
|
||||
public rightKey: RightKeyManager | null = null; // 右键菜单管理器
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param engine 引擎实例
|
||||
* @param container 3D 引擎挂载的目标容器
|
||||
*/
|
||||
constructor(engine: BimEngine, container: HTMLElement) {
|
||||
super(engine);
|
||||
constructor(container: HTMLElement) {
|
||||
super();
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化 3D 引擎
|
||||
* @param options 引擎配置选项(可选,如果不提供则使用默认配置)
|
||||
* @param options 引擎配置选项
|
||||
* @returns 是否初始化成功
|
||||
*/
|
||||
public initialize(options?: Omit<EngineOptions, 'container'>): boolean {
|
||||
// 如果已经初始化,先销毁旧的实例
|
||||
if (this.engineInstance && this.engineInstance.isInitialized()) {
|
||||
console.warn('[EngineManager] 3D Engine already initialized. Destroying old instance...');
|
||||
this.engineInstance.destroy();
|
||||
@@ -43,24 +39,19 @@ export class EngineManager extends BimComponent {
|
||||
}
|
||||
|
||||
try {
|
||||
// 创建 Engine 组件实例
|
||||
// options 中的配置会自动复制给 createEngine 使用
|
||||
this.engineInstance = new Engine({
|
||||
container: this.container,
|
||||
...options, // 合并配置选项
|
||||
...options,
|
||||
});
|
||||
|
||||
// 调用组件的 init 方法初始化引擎
|
||||
this.engineInstance.init();
|
||||
|
||||
// 初始化右键 (移到 return 之前)
|
||||
this.rightKey = new RightKeyManager(this.engine, this.container);
|
||||
this.rightKey = new RightKeyManager(this.container);
|
||||
|
||||
// 注册默认右键菜单
|
||||
this.rightKey.registerHandler((_e) => {
|
||||
return [
|
||||
infoMenuButton(this.engine),
|
||||
homeMenuButton(this.engine)
|
||||
infoMenuButton(),
|
||||
homeMenuButton()
|
||||
];
|
||||
});
|
||||
|
||||
@@ -71,16 +62,19 @@ export class EngineManager extends BimComponent {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检<EFBFBD><EFBFBD><EFBFBD> 3D 引擎是否已初始化
|
||||
* 检查引擎是否已初始化
|
||||
* @returns 是否已初始化
|
||||
*/
|
||||
public isInitialized(): boolean {
|
||||
return this.engineInstance !== null && this.engineInstance.isInitialized();
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载 3D 模型
|
||||
* @param url 模型文件 URL
|
||||
* @param options 加载选项(位置、旋转、缩放)
|
||||
* 加载模型
|
||||
* @param url 模型 URL
|
||||
* @param options 加载选项
|
||||
*/
|
||||
public loadModel(url: string, options?: ModelLoadOptions): void {
|
||||
if (!this.engineInstance) {
|
||||
@@ -90,10 +84,9 @@ export class EngineManager extends BimComponent {
|
||||
this.engineInstance.loadModel(url, options);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取原始 3D 引擎实例
|
||||
* 用于直接调用第三方引擎的其他 API
|
||||
* 获取底层引擎实例
|
||||
* @returns 引擎实例
|
||||
*/
|
||||
public getEngine(): any {
|
||||
if (!this.engineInstance) {
|
||||
@@ -103,9 +96,7 @@ export class EngineManager extends BimComponent {
|
||||
return this.engineInstance.getEngine();
|
||||
}
|
||||
|
||||
/**
|
||||
* 回到主视角
|
||||
*/
|
||||
/** 相机回到初始位置 */
|
||||
public CameraGoHome(): void {
|
||||
if (!this.engineInstance) {
|
||||
console.warn('[EngineManager] 3D Engine not initialized.');
|
||||
@@ -113,9 +104,10 @@ export class EngineManager extends BimComponent {
|
||||
}
|
||||
this.engineInstance.CameraGoHome();
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活测量功能
|
||||
* @param mode 测量类型
|
||||
* 激活测量模式
|
||||
* @param mode 测量模式
|
||||
*/
|
||||
public activateMeasure(mode: MeasureMode): void {
|
||||
if (!this.engineInstance) {
|
||||
@@ -125,9 +117,7 @@ export class EngineManager extends BimComponent {
|
||||
this.engineInstance.activateMeasure(mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停用测量功能
|
||||
*/
|
||||
/** 停用测量模式 */
|
||||
public deactivateMeasure(): void {
|
||||
if (!this.engineInstance) {
|
||||
return;
|
||||
@@ -136,7 +126,8 @@ export class EngineManager extends BimComponent {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前激活的测量类型
|
||||
* 获取当前测量类型
|
||||
* @returns 当前测量模式
|
||||
*/
|
||||
public getCurrentMeasureType(): MeasureMode | null {
|
||||
if (!this.engineInstance) {
|
||||
@@ -145,11 +136,7 @@ export class EngineManager extends BimComponent {
|
||||
return this.engineInstance.getCurrentMeasureType();
|
||||
}
|
||||
|
||||
// ==================== 结束:测量功能方法 ====================
|
||||
|
||||
/**
|
||||
* 销毁 3D 引擎实例
|
||||
*/
|
||||
/** 销毁引擎管理器 */
|
||||
public destroy(): void {
|
||||
if (this.engineInstance) {
|
||||
this.engineInstance.destroy();
|
||||
@@ -159,8 +146,6 @@ export class EngineManager extends BimComponent {
|
||||
this.rightKey.destroy();
|
||||
this.rightKey = null;
|
||||
}
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,107 +1,76 @@
|
||||
import { BimComponent } from '../core/component';
|
||||
import { BimEngine } from '../bim-engine';
|
||||
import { BimDialog } from '../components/dialog';
|
||||
/**
|
||||
* 地图对话框管理器
|
||||
* 负责管理地图/平面图对话框的显示和交互
|
||||
*/
|
||||
import { BaseDialogManager } from '../core/base-dialog-manager';
|
||||
import { MapPanel } from '../components/map-panel';
|
||||
|
||||
/**
|
||||
* 地图弹窗管理器(独立通用组件)
|
||||
* 地图对话框管理器
|
||||
* 继承自 BaseDialogManager,提供地图面板的对话框管理功能
|
||||
*/
|
||||
export class MapDialogManager extends BimComponent {
|
||||
private dialogId = 'map-dialog';
|
||||
private dialog: BimDialog | null = null;
|
||||
export class MapDialogManager extends BaseDialogManager {
|
||||
/** 地图面板实例 */
|
||||
private panel: MapPanel | null = null;
|
||||
|
||||
constructor(engine: BimEngine) {
|
||||
super(engine);
|
||||
}
|
||||
/** 对话框唯一标识 */
|
||||
protected get dialogId() { return 'map-dialog'; }
|
||||
/** 对话框标题(国际化 key) */
|
||||
protected get dialogTitle() { return 'map.dialogTitle'; }
|
||||
/** 对话框宽度 */
|
||||
protected get dialogWidth() { return 300; }
|
||||
/** 对话框高度 */
|
||||
protected get dialogHeight(): number { return 400; }
|
||||
|
||||
public init(): void {
|
||||
// 可以在这里监听事件
|
||||
}
|
||||
/** 初始化 */
|
||||
public init(): void {}
|
||||
|
||||
/**
|
||||
* 显示弹窗
|
||||
* 获取对话框位置
|
||||
* 定位在容器左下角
|
||||
*/
|
||||
public show(): void {
|
||||
if (!this.engine.dialog || !this.engine.container) {
|
||||
console.warn('Dialog manager or container is not initialized');
|
||||
return;
|
||||
}
|
||||
protected getDialogPosition() {
|
||||
const container = this.registry.container;
|
||||
if (!container) return { x: 20, y: 100 };
|
||||
|
||||
// 如果已打开,不重复打开
|
||||
if (this.isOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建面板
|
||||
this.panel = new MapPanel();
|
||||
this.panel.init();
|
||||
|
||||
const dialogWidth = 300;
|
||||
const dialogHeight = 400;
|
||||
const paddingLeft = 20;
|
||||
const paddingBottom = 20;
|
||||
const container = this.engine.container;
|
||||
const containerHeight = container.clientHeight;
|
||||
|
||||
// 左下角:left: 20px, bottom: 20px
|
||||
const x = paddingLeft;
|
||||
const y = containerHeight - dialogHeight - paddingBottom;
|
||||
return {
|
||||
x: paddingLeft,
|
||||
y: containerHeight - this.dialogHeight - paddingBottom
|
||||
};
|
||||
}
|
||||
|
||||
this.dialog = this.engine.dialog.create({
|
||||
id: this.dialogId,
|
||||
title: 'map.dialogTitle',
|
||||
width: dialogWidth,
|
||||
height: dialogHeight,
|
||||
position: { x, y },
|
||||
draggable: true,
|
||||
resizable: false,
|
||||
content: this.panel.element,
|
||||
onClose: () => {
|
||||
this.hide();
|
||||
}
|
||||
});
|
||||
this.dialog.init();
|
||||
/** 创建对话框内容 */
|
||||
protected createContent(): HTMLElement {
|
||||
this.panel = new MapPanel();
|
||||
this.panel.init();
|
||||
return this.panel.element;
|
||||
}
|
||||
|
||||
// 触发地图打开事件
|
||||
/** 对话框创建后的回调 */
|
||||
protected onDialogCreated(): void {
|
||||
this.emit('map:opened', {});
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏弹窗
|
||||
*/
|
||||
public hide(): void {
|
||||
this.destroy();
|
||||
// 触发地图关闭事件
|
||||
/** 对话框关闭时的回调 */
|
||||
protected onDialogClose(): void {
|
||||
this.emit('map:closed', {});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查地图是否打开
|
||||
*/
|
||||
public isOpen(): boolean {
|
||||
return this.dialog !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁弹窗和面板
|
||||
*/
|
||||
public destroy(): void {
|
||||
// 先保存 dialog 引用,避免在回调中重复调用
|
||||
const dialog = this.dialog;
|
||||
|
||||
// 立即清空引用,防止递归
|
||||
this.dialog = null;
|
||||
|
||||
// 关闭弹窗
|
||||
if (dialog) {
|
||||
dialog.destroy();
|
||||
}
|
||||
|
||||
// 销毁面板
|
||||
/** 销毁前的清理 */
|
||||
protected onBeforeDestroy(): void {
|
||||
if (this.panel) {
|
||||
this.panel.destroy();
|
||||
this.panel = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** 隐藏对话框 */
|
||||
public hide(): void {
|
||||
super.hide();
|
||||
this.emit('map:closed', {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,114 +1,100 @@
|
||||
import { BimComponent } from '../core/component';
|
||||
import { BimEngine } from '../bim-engine';
|
||||
import { BimDialog } from "../components/dialog";
|
||||
/**
|
||||
* 测量对话框管理器
|
||||
* 负责管理测量工具对话框的显示、隐藏和测量面板的交互
|
||||
*/
|
||||
import { BaseDialogManager } from '../core/base-dialog-manager';
|
||||
import { MeasurePanel } from '../components/measure-panel';
|
||||
import type { MeasureConfig, MeasureMode, MeasureResult } from '../components/measure-panel/types';
|
||||
|
||||
/**
|
||||
* 测量弹窗管理器
|
||||
* 测量对话框管理器
|
||||
* 继承自 BaseDialogManager,提供测量工具的对话框管理功能
|
||||
*/
|
||||
export class MeasureDialogManager extends BimComponent {
|
||||
private dialogId = 'measure-dialog';
|
||||
private dialog: BimDialog | null = null;
|
||||
export class MeasureDialogManager extends BaseDialogManager {
|
||||
/** 测量面板实例 */
|
||||
private panel: MeasurePanel | null = null;
|
||||
/**
|
||||
* 测量配置项(单位/精度)
|
||||
* 说明:MeasurePanel 会自行从缓存加载默认配置,Manager 这里只做“对外读取/设置”的镜像。
|
||||
*/
|
||||
/** 测量配置(单位、精度等) */
|
||||
private config: MeasureConfig | null = null;
|
||||
|
||||
constructor(engine: BimEngine) {
|
||||
super(engine);
|
||||
/** 对话框唯一标识 */
|
||||
protected get dialogId(): string {
|
||||
return 'measure-dialog';
|
||||
}
|
||||
|
||||
public init(): void {
|
||||
// 可以在这里监听事件
|
||||
/** 对话框标题(国际化 key) */
|
||||
protected get dialogTitle(): string {
|
||||
return 'measure.dialogTitle';
|
||||
}
|
||||
|
||||
/** 对话框宽度 */
|
||||
protected get dialogWidth(): number {
|
||||
return 250;
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示测量弹窗
|
||||
* 创建对话框内容
|
||||
* 初始化测量面板并设置回调
|
||||
*/
|
||||
public show() {
|
||||
if (!this.engine.dialog || !this.engine.container) {
|
||||
console.warn('Dialog manager or container is not initialized');
|
||||
return;
|
||||
}
|
||||
|
||||
const dialogWidth = 250;
|
||||
const dialogHeight = 300;
|
||||
const paddingRight = 20; // 你想要的右边距
|
||||
const container = this.engine.container;
|
||||
const containerWidth = container.clientWidth;
|
||||
const containerHeight = container.clientHeight;
|
||||
const x = containerWidth - dialogWidth - paddingRight;
|
||||
const y = (containerHeight - dialogHeight) / 2;
|
||||
|
||||
// 如果已打开过,先销毁旧实例,避免重复创建/重复订阅
|
||||
this.destroy();
|
||||
|
||||
// 创建测量面板(只做 UI,不实现真实测量)
|
||||
protected createContent(): HTMLElement {
|
||||
this.panel = new MeasurePanel({
|
||||
defaultMode: 'distance', // 默认展示前四个,且默认选中"距离"
|
||||
defaultMode: 'distance',
|
||||
defaultExpanded: false,
|
||||
onModeChange: (mode) => {
|
||||
console.log('[MeasureDialogManager] 当前测量方式已切换:', mode);
|
||||
this.engine.engine?.activateMeasure(mode);
|
||||
this.registry.engine3d?.activateMeasure(mode);
|
||||
},
|
||||
onClearAll: () => {
|
||||
// 预留:未来可清理引擎测量绘制/标注
|
||||
console.log('[MeasureDialogManager] 删除全部(仅 UI 清空,本次不清理引擎侧内容)');
|
||||
console.log('[MeasureDialogManager] 删除全部');
|
||||
},
|
||||
onSettings: () => {
|
||||
// 预留:未来可打开设置弹窗/面板
|
||||
console.log('[MeasureDialogManager] 打开设置(仅预留接口)');
|
||||
console.log('[MeasureDialogManager] 打开设置');
|
||||
},
|
||||
onExpandedChange: () => {
|
||||
// 展开/收起时,动态适配 Dialog 高度,避免遮挡底部操作按钮
|
||||
this.dialog?.fitHeight(false);
|
||||
}
|
||||
});
|
||||
this.panel.init();
|
||||
// 同步一次当前配置(由组件从缓存/默认加载)
|
||||
this.config = this.panel.getConfig();
|
||||
|
||||
// 注意:你要求“组件本身不加边距”,因此在 Manager 这里用 wrapper 增加左右内边距
|
||||
// 这样 MeasurePanel 可以保持通用性,避免在不同场景复用时产生多余 padding。
|
||||
const panelWrapper = document.createElement('div');
|
||||
panelWrapper.style.padding = '12px';
|
||||
panelWrapper.appendChild(this.panel.element);
|
||||
|
||||
this.dialog = this.engine.dialog.create({
|
||||
id: this.dialogId,
|
||||
title: 'measure.dialogTitle',
|
||||
content: panelWrapper,
|
||||
width: dialogWidth,
|
||||
// 高度交给 fitHeight 动态计算(避免内容展开后遮挡底部操作区)
|
||||
height: 'auto',
|
||||
position: {
|
||||
x: x,
|
||||
y: y
|
||||
},
|
||||
onClose: () => {
|
||||
this.engine.toolbar?.setBtnActive('measure', false)
|
||||
this.destroy()
|
||||
}
|
||||
});
|
||||
this.dialog.init();
|
||||
return panelWrapper;
|
||||
}
|
||||
|
||||
// 初次打开时也执行一次自适应高度(收起态)
|
||||
this.dialog.fitHeight(false);
|
||||
/** 对话框创建后的回调,自适应高度 */
|
||||
protected onDialogCreated(): void {
|
||||
this.dialog?.fitHeight(false);
|
||||
}
|
||||
|
||||
/** 对话框关闭时的回调,取消工具栏按钮激活状态 */
|
||||
protected onDialogClose(): void {
|
||||
this.registry.toolbar?.setBtnActive('measure', false);
|
||||
}
|
||||
|
||||
/** 销毁前的清理,停用测量功能并销毁面板 */
|
||||
protected onBeforeDestroy(): void {
|
||||
if (this.registry.engine3d) {
|
||||
this.registry.engine3d.deactivateMeasure();
|
||||
}
|
||||
if (this.panel) {
|
||||
this.panel.destroy();
|
||||
this.panel = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前测量方式
|
||||
* 说明:如果面板未创建,则返回 null
|
||||
* 获取当前激活的测量模式
|
||||
* @returns 当前测量模式,如 'distance'、'angle' 等
|
||||
*/
|
||||
public getActiveMode(): MeasureMode | null {
|
||||
return this.panel ? this.panel.getActiveMode() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换测量方式(你要求的“切换类型的方法”)
|
||||
* @param mode 测量方式
|
||||
* 切换测量模式
|
||||
* @param mode 目标测量模式
|
||||
*/
|
||||
public switchMode(mode: MeasureMode): void {
|
||||
if (!this.panel) return;
|
||||
@@ -116,22 +102,17 @@ export class MeasureDialogManager extends BimComponent {
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置测量结果(推荐使用的新方法名)
|
||||
* 说明:内部直接调用 MeasurePanel.setResult()
|
||||
* @param result 测量结果;传 null 表示清空
|
||||
* 设置测量结果
|
||||
* @param result 测量结果对象
|
||||
*/
|
||||
public setMeasureResult(result: MeasureResult | null): void {
|
||||
// 按你的要求:仅当 panel 存在时才调用,不做缓存
|
||||
if (!this.panel) {
|
||||
return;
|
||||
}
|
||||
if (!this.panel) return;
|
||||
this.panel.setResult(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取测量配置(单位/精度)
|
||||
* - 如果面板存在:返回面板当前配置
|
||||
* - 否则:返回 Manager 缓存的最后一次配置(可能为 null)
|
||||
* 获取测量配置
|
||||
* @returns 测量配置副本
|
||||
*/
|
||||
public getConfig(): MeasureConfig | null {
|
||||
if (this.panel) {
|
||||
@@ -141,63 +122,35 @@ export class MeasureDialogManager extends BimComponent {
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置测量配置(单位/精度)
|
||||
* @param partial 部分更新
|
||||
* @param persist 是否写入缓存(默认 true)
|
||||
* 设置测量配置
|
||||
* @param partial 部分配置
|
||||
* @param persist 是否持久化
|
||||
*/
|
||||
public setConfig(partial: Partial<MeasureConfig>, persist: boolean = true): void {
|
||||
// 面板存在则直接设置面板;否则仅更新 Manager 缓存
|
||||
if (this.panel) {
|
||||
this.panel.setConfig(partial, persist);
|
||||
this.config = this.panel.getConfig();
|
||||
// 配置变化可能影响高度(比如设置面板显示/隐藏),安全起见做一次 fit
|
||||
this.dialog?.fitHeight(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 面板未创建:只更新本地缓存
|
||||
const prev = this.config;
|
||||
const next: MeasureConfig = {
|
||||
unit: partial.unit ?? prev?.unit ?? 'mm',
|
||||
precision: partial.precision ?? prev?.precision ?? 2
|
||||
};
|
||||
this.config = next;
|
||||
// 注意:缓存写入由 MeasurePanel 负责(你要求默认维护在组件里)
|
||||
// 这里不写 localStorage,避免重复逻辑。
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除全部(仅清空 UI;真实测量清理逻辑后续再接)
|
||||
*/
|
||||
/** 清除所有测量结果 */
|
||||
public clearAll(): void {
|
||||
if (!this.panel) return;
|
||||
this.panel.clearAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开设置(仅预留方法/回调)
|
||||
*/
|
||||
/** 打开测量设置面板 */
|
||||
public openSettings(): void {
|
||||
if (!this.panel) return;
|
||||
this.panel.openSettings();
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
// 停用测量功能
|
||||
if (this.engine.engine) {
|
||||
this.engine.engine.deactivateMeasure();
|
||||
}
|
||||
|
||||
// 关闭弹窗
|
||||
if (this.dialog) {
|
||||
this.dialog.destroy();
|
||||
this.dialog = null;
|
||||
}
|
||||
|
||||
// 销毁测量面板(清理订阅与 DOM)
|
||||
if (this.panel) {
|
||||
this.panel.destroy();
|
||||
this.panel = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
import { BimComponent } from '../core/component';
|
||||
import { BimEngine } from '../bim-engine';
|
||||
/**
|
||||
* 属性面板管理器
|
||||
* 负责管理构件属性面板的显示和内容
|
||||
*/
|
||||
import { BaseManager } from '../core/base-manager';
|
||||
import { BimCollapse } from '../components/collapse/index';
|
||||
import { BimDescription } from '../components/description/index';
|
||||
import { BimTab } from '../components/tab/index';
|
||||
|
||||
/**
|
||||
* 属性面板管理器
|
||||
* 负责展示和管理属性面板弹窗 (演示 Tab + Collapse + Description 组件)
|
||||
* 显示选中构件的属性信息和材质信息
|
||||
*/
|
||||
export class PropertyPanelManager extends BimComponent {
|
||||
export class PropertyPanelManager extends BaseManager {
|
||||
/** 对话框 ID */
|
||||
private dialogId = 'property-panel-dialog';
|
||||
private dialog: any = null; // 保存 dialog 引用
|
||||
/** 对话框实例 */
|
||||
private dialog: any = null;
|
||||
|
||||
constructor(engine: BimEngine) {
|
||||
super(engine);
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
/** 初始化,监听打开事件 */
|
||||
public init(): void {
|
||||
// 监听来自 Demo 的打开属性面板事件
|
||||
document.addEventListener('bim-demo:open-property-panel', () => {
|
||||
this.show();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示属性面板
|
||||
*/
|
||||
/** 显示属性面板 */
|
||||
public show() {
|
||||
if (!this.engine.dialog) {
|
||||
if (!this.registry.dialog) {
|
||||
console.warn('Dialog manager is not initialized');
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果已打开,不重复打开
|
||||
if (this.isOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 创建弹窗
|
||||
const width = 360; // 稍微加宽一点以容纳 Tab
|
||||
const width = 360;
|
||||
const x = document.body.clientWidth - width - 40;
|
||||
console.log('x', x)
|
||||
|
||||
this.dialog = this.engine.dialog.create({
|
||||
this.dialog = this.registry.dialog.create({
|
||||
id: this.dialogId,
|
||||
title: 'panel.property.title', // '构件详情'
|
||||
title: 'panel.property.title',
|
||||
content: '',
|
||||
width: `${width}px`,
|
||||
height: '500px',
|
||||
@@ -56,7 +56,6 @@ export class PropertyPanelManager extends BimComponent {
|
||||
}
|
||||
} as any);
|
||||
|
||||
// 2. 创建内容容器
|
||||
const contentContainer = document.createElement('div');
|
||||
contentContainer.style.height = '100%';
|
||||
contentContainer.style.display = 'flex';
|
||||
@@ -64,33 +63,29 @@ export class PropertyPanelManager extends BimComponent {
|
||||
|
||||
this.dialog.setContent(contentContainer);
|
||||
|
||||
// 3. 创建标签页组件
|
||||
const tab = new BimTab({
|
||||
container: contentContainer,
|
||||
tabs: [
|
||||
{
|
||||
id: 'props',
|
||||
title: 'panel.property.tab.props', // '属性'
|
||||
title: 'panel.property.tab.props',
|
||||
content: this.createPropsTabContent()
|
||||
},
|
||||
{
|
||||
id: 'material',
|
||||
title: 'panel.property.tab.material', // '材质'
|
||||
title: 'panel.property.tab.material',
|
||||
content: this.createMaterialTabContent()
|
||||
}
|
||||
]
|
||||
});
|
||||
tab.init();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建"属性"标签页的内容 (包含 Collapse)
|
||||
*/
|
||||
/** 创建属性标签页内容 */
|
||||
private createPropsTabContent(): HTMLElement {
|
||||
const container = document.createElement('div');
|
||||
container.style.height = '100%';
|
||||
container.style.overflowY = 'auto'; // 内容区域滚动
|
||||
container.style.overflowY = 'auto';
|
||||
|
||||
new BimCollapse({
|
||||
container: container,
|
||||
@@ -99,13 +94,13 @@ export class PropertyPanelManager extends BimComponent {
|
||||
items: [
|
||||
{
|
||||
id: 'base',
|
||||
title: 'panel.property.base', // '基本属性'
|
||||
title: 'panel.property.base',
|
||||
content: this.createBaseInfoContent(),
|
||||
},
|
||||
{
|
||||
id: 'advanced',
|
||||
title: 'panel.property.advanced', // '高级设置'
|
||||
content: this.createAdvancedInfoContent(), // 新增一个内容
|
||||
title: 'panel.property.advanced',
|
||||
content: this.createAdvancedInfoContent(),
|
||||
disabled: false
|
||||
}
|
||||
]
|
||||
@@ -114,9 +109,7 @@ export class PropertyPanelManager extends BimComponent {
|
||||
return container;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建"材质"标签页的内容 (包含 Collapse)
|
||||
*/
|
||||
/** 创建材质标签页内容 */
|
||||
private createMaterialTabContent(): HTMLElement {
|
||||
const container = document.createElement('div');
|
||||
container.style.height = '100%';
|
||||
@@ -129,7 +122,7 @@ export class PropertyPanelManager extends BimComponent {
|
||||
items: [
|
||||
{
|
||||
id: 'material',
|
||||
title: 'panel.property.material', // '材质信息'
|
||||
title: 'panel.property.material',
|
||||
content: this.createMaterialContent(),
|
||||
}
|
||||
]
|
||||
@@ -138,6 +131,7 @@ export class PropertyPanelManager extends BimComponent {
|
||||
return container;
|
||||
}
|
||||
|
||||
/** 创建基本信息内容 */
|
||||
private createBaseInfoContent(): HTMLElement {
|
||||
const container = document.createElement('div');
|
||||
|
||||
@@ -156,6 +150,7 @@ export class PropertyPanelManager extends BimComponent {
|
||||
return container;
|
||||
}
|
||||
|
||||
/** 创建高级信息内容 */
|
||||
private createAdvancedInfoContent(): HTMLElement {
|
||||
const container = document.createElement('div');
|
||||
|
||||
@@ -174,10 +169,10 @@ export class PropertyPanelManager extends BimComponent {
|
||||
return container;
|
||||
}
|
||||
|
||||
/** 创建材质内容 */
|
||||
private createMaterialContent(): HTMLElement {
|
||||
const container = document.createElement('div');
|
||||
|
||||
// 材质预览块
|
||||
const preview = document.createElement('div');
|
||||
preview.style.display = 'flex';
|
||||
preview.style.alignItems = 'center';
|
||||
@@ -204,15 +199,14 @@ export class PropertyPanelManager extends BimComponent {
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查属性面板是否打开
|
||||
* 检查面板是否打开
|
||||
* @returns 是否打开
|
||||
*/
|
||||
public isOpen(): boolean {
|
||||
return this.dialog !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏属性面板
|
||||
*/
|
||||
/** 隐藏面板 */
|
||||
public hide(): void {
|
||||
if (this.dialog) {
|
||||
this.dialog.destroy();
|
||||
@@ -220,7 +214,9 @@ export class PropertyPanelManager extends BimComponent {
|
||||
}
|
||||
}
|
||||
|
||||
/** 销毁管理器 */
|
||||
public destroy(): void {
|
||||
this.hide();
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,28 @@
|
||||
import { BimComponent } from '../core/component';
|
||||
import { BimEngine } from '../bim-engine';
|
||||
/**
|
||||
* 右键菜单管理器
|
||||
* 负责管理右键上下文菜单的显示和交互
|
||||
*/
|
||||
import { BaseManager } from '../core/base-manager';
|
||||
import { BimRightKey } from '../components/right-key';
|
||||
import { BimMenu } from '../components/menu';
|
||||
import { MenuItemConfig } from '../components/menu/item';
|
||||
|
||||
/**
|
||||
* 右键菜单管理器 (RightKeyManager)
|
||||
* 负责协调右键交互流程:
|
||||
* 1. 监听 Canvas/容器的 contextmenu 事件
|
||||
* 2. 通过注册的处理器 (Handler) 获取需要显示的菜单项
|
||||
* 3. 实例化 Menu 组件并装载到 RightKey 容器中显示
|
||||
* 右键菜单管理器
|
||||
* 支持注册多个上下文处理器,动态生成右键菜单
|
||||
*/
|
||||
export class RightKeyManager extends BimComponent {
|
||||
export class RightKeyManager extends BaseManager {
|
||||
/** 容器元素 */
|
||||
private container: HTMLElement;
|
||||
/** 右键面板实例 */
|
||||
private rightKeyPanel: BimRightKey;
|
||||
|
||||
// 存储注册的上下文处理器
|
||||
// 每个处理器接收鼠标事件,返回一组菜单项(如果没有对应菜单则返回 null)
|
||||
/** 上下文处理器列表 */
|
||||
private contextHandlers: Array<(e: MouseEvent) => MenuItemConfig[] | null> = [];
|
||||
|
||||
constructor(engine: BimEngine, container: HTMLElement) {
|
||||
super(engine);
|
||||
constructor(container: HTMLElement) {
|
||||
super();
|
||||
this.container = container;
|
||||
|
||||
// 初始化右键容器,设置极高的层级以覆盖所有 UI
|
||||
// 将事件监听和触发逻辑下放给 BimRightKey 组件
|
||||
this.rightKeyPanel = new BimRightKey({
|
||||
zIndex: 9000,
|
||||
container: this.container,
|
||||
@@ -33,55 +31,44 @@ export class RightKeyManager extends BimComponent {
|
||||
this.rightKeyPanel.init();
|
||||
}
|
||||
|
||||
/** 销毁管理器 */
|
||||
public destroy(): void {
|
||||
this.rightKeyPanel.destroy();
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册上下文菜单处理器
|
||||
* @param handler 处理函数,接收鼠标事件,返回菜单项数组
|
||||
* 注册上下文处理器
|
||||
* @param handler 处理器函数,返回菜单项配置
|
||||
*/
|
||||
public registerHandler(handler: (e: MouseEvent) => MenuItemConfig[] | null): void {
|
||||
this.contextHandlers.push(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动显示菜单
|
||||
* 允许外部直接调用以显示特定的菜单,不一定依赖右键事件
|
||||
* @param x 屏幕 X 坐标
|
||||
* @param y 屏幕 Y 坐标
|
||||
* @param items 菜单项列表
|
||||
* @param groupOrder 可选的分组顺序
|
||||
* 显示菜单
|
||||
* @param x 横坐标
|
||||
* @param y 纵坐标
|
||||
* @param items 菜单项配置
|
||||
* @param groupOrder 分组顺序
|
||||
*/
|
||||
public showMenu(x: number, y: number, items: MenuItemConfig[], groupOrder?: string[]): void {
|
||||
if (!items || items.length === 0) return;
|
||||
|
||||
// 1. 创建菜单内容组件
|
||||
const menu = new BimMenu({ items, groupOrder });
|
||||
menu.init(); // 必须初始化以生成 DOM
|
||||
menu.init();
|
||||
|
||||
// 2. 将菜单挂载到右键容器
|
||||
this.rightKeyPanel.mount(menu);
|
||||
|
||||
// 3. 显示容器
|
||||
this.rightKeyPanel.show(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏右键菜单
|
||||
*/
|
||||
/** 隐藏菜单 */
|
||||
public hide(): void {
|
||||
this.rightKeyPanel.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理右键点击事件
|
||||
* 由 BimRightKey 组件在检测到有效右键点击时调用
|
||||
*/
|
||||
/** 处理右键点击事件 */
|
||||
private handleContextMenu = (e: MouseEvent): void => {
|
||||
// 1. 确定上下文项
|
||||
// 遍历所有注册的处理器,找到第一个返回非空结果的处理器
|
||||
// 这种责任链模式允许插件优先处理特定对象的右键
|
||||
let items: MenuItemConfig[] | null = null;
|
||||
for (const handler of this.contextHandlers) {
|
||||
const result = handler(e);
|
||||
@@ -91,11 +78,9 @@ export class RightKeyManager extends BimComponent {
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 如果有菜单项,则显示
|
||||
if (items && items.length > 0) {
|
||||
this.showMenu(e.clientX, e.clientY, items);
|
||||
} else {
|
||||
// 如果没有任何内容,则关闭可能存在的菜单
|
||||
this.hide();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,135 +1,122 @@
|
||||
import { BimComponent } from '../core/component';
|
||||
import { BimEngine } from '../bim-engine';
|
||||
import { BimDialog } from '../components/dialog';
|
||||
/**
|
||||
* 轴向剖切对话框管理器
|
||||
* 负责管理轴向剖切工具对话框的显示、隐藏和剖切面板的交互
|
||||
*/
|
||||
import { BaseDialogManager } from '../core/base-dialog-manager';
|
||||
import { SectionAxisPanel } from '../components/section-axis-panel';
|
||||
import type { SectionAxis } from '../components/section-axis-panel/types';
|
||||
|
||||
/**
|
||||
* 轴向剖切弹窗管理器
|
||||
* 轴向剖切对话框管理器
|
||||
* 继承自 BaseDialogManager,提供 X/Y/Z 轴向剖切的对话框管理功能
|
||||
*/
|
||||
export class SectionAxisDialogManager extends BimComponent {
|
||||
private dialogId = 'section-axis-dialog';
|
||||
private dialog: BimDialog | null = null;
|
||||
export class SectionAxisDialogManager extends BaseDialogManager {
|
||||
/** 轴向剖切面板实例 */
|
||||
private panel: SectionAxisPanel | null = null;
|
||||
|
||||
constructor(engine: BimEngine) {
|
||||
super(engine);
|
||||
/** 对话框唯一标识 */
|
||||
protected get dialogId(): string {
|
||||
return 'section-axis-dialog';
|
||||
}
|
||||
|
||||
public init(): void {
|
||||
// 可以在这里监听事件
|
||||
/** 对话框标题(国际化 key) */
|
||||
protected get dialogTitle(): string {
|
||||
return 'sectionAxis.dialogTitle';
|
||||
}
|
||||
|
||||
/** 对话框宽度 */
|
||||
protected get dialogWidth(): number {
|
||||
return 240;
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示弹窗
|
||||
* 获取对话框位置
|
||||
* 定位在容器右下角
|
||||
*/
|
||||
public show(): void {
|
||||
if (!this.engine.dialog || !this.engine.container) {
|
||||
console.warn('Dialog manager or container is not initialized');
|
||||
return;
|
||||
}
|
||||
protected getDialogPosition(): { x: number; y: number } {
|
||||
const container = this.registry.container;
|
||||
if (!container) return { x: 100, y: 100 };
|
||||
|
||||
// 如果已打开,先销毁
|
||||
this.destroy();
|
||||
const containerWidth = container.clientWidth;
|
||||
const containerHeight = container.clientHeight;
|
||||
const paddingRight = 20;
|
||||
const paddingBottom = 50;
|
||||
|
||||
// 创建面板
|
||||
return {
|
||||
x: containerWidth - this.dialogWidth - paddingRight,
|
||||
y: containerHeight - paddingBottom - 200
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建对话框内容
|
||||
* 初始化轴向剖切面板并设置回调
|
||||
*/
|
||||
protected createContent(): HTMLElement {
|
||||
this.panel = new SectionAxisPanel({
|
||||
defaultAxis: 'x',
|
||||
defaultHidden: false,
|
||||
onHideToggle: (isHidden) => {
|
||||
console.log('[SectionAxisDialogManager] 隐藏切换:', isHidden);
|
||||
// TODO: 实现隐藏/显示剖切面的逻辑
|
||||
},
|
||||
onReverse: () => {
|
||||
console.log('[SectionAxisDialogManager] 反向剖切');
|
||||
// TODO: 实现反向剖切的逻辑
|
||||
},
|
||||
onAxisChange: (axis) => {
|
||||
console.log('[SectionAxisDialogManager] 切换轴向:', axis);
|
||||
// TODO: 实现轴向切换的逻辑
|
||||
}
|
||||
});
|
||||
this.panel.init();
|
||||
return this.panel.element;
|
||||
}
|
||||
|
||||
// 创建弹窗
|
||||
const dialogWidth = 240;
|
||||
const paddingRight = 20;
|
||||
const paddingBottom = 50;
|
||||
const container = this.engine.container;
|
||||
const containerWidth = container.clientWidth;
|
||||
const containerHeight = container.clientHeight;
|
||||
const x = containerWidth - dialogWidth - paddingRight;
|
||||
const y = containerHeight - paddingBottom - 200; // 临时y值,会被fitHeight调整
|
||||
/** 对话框创建后的回调,自适应高度 */
|
||||
protected onDialogCreated(): void {
|
||||
this.dialog?.fitHeight(false);
|
||||
}
|
||||
|
||||
this.dialog = this.engine.dialog.create({
|
||||
id: this.dialogId,
|
||||
title: 'sectionAxis.dialogTitle',
|
||||
width: dialogWidth,
|
||||
height: 'auto', // 自动高度
|
||||
position: { x, y },
|
||||
draggable: true,
|
||||
resizable: false,
|
||||
content: this.panel.element,
|
||||
onClose: () => {
|
||||
this.engine.toolbar?.setBtnActive('section-axis', false);
|
||||
this.hide();
|
||||
}
|
||||
});
|
||||
this.dialog.init();
|
||||
/** 对话框关闭时的回调,取消工具栏按钮激活状态 */
|
||||
protected onDialogClose(): void {
|
||||
this.registry.toolbar?.setBtnActive('section-axis', false);
|
||||
}
|
||||
|
||||
// 自适应高度
|
||||
this.dialog.fitHeight(false);
|
||||
/** 销毁前的清理,销毁面板实例 */
|
||||
protected onBeforeDestroy(): void {
|
||||
if (this.panel) {
|
||||
this.panel.destroy();
|
||||
this.panel = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏弹窗
|
||||
*/
|
||||
public hide(): void {
|
||||
this.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取隐藏状态
|
||||
* 获取剖切面隐藏状态
|
||||
* @returns 是否隐藏
|
||||
*/
|
||||
public getHiddenState(): boolean {
|
||||
return this.panel?.getHiddenState() ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置隐藏状态
|
||||
* 设置剖切面隐藏状态
|
||||
* @param isHidden 是否隐藏
|
||||
*/
|
||||
public setHiddenState(isHidden: boolean): void {
|
||||
this.panel?.setHiddenState(isHidden);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前激活的轴向
|
||||
* 获取当前激活的剖切轴向
|
||||
* @returns 当前轴向 'x' | 'y' | 'z'
|
||||
*/
|
||||
public getActiveAxis(): SectionAxis {
|
||||
return this.panel?.getActiveAxis() ?? 'x';
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置激活的轴向
|
||||
* 设置剖切轴向
|
||||
* @param axis 目标轴向
|
||||
*/
|
||||
public setActiveAxis(axis: SectionAxis): void {
|
||||
this.panel?.setActiveAxis(axis);
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁弹窗和面板
|
||||
*/
|
||||
public destroy(): void {
|
||||
// 关闭弹窗
|
||||
if (this.dialog) {
|
||||
this.dialog.destroy();
|
||||
this.dialog = null;
|
||||
}
|
||||
|
||||
// 销毁面板
|
||||
if (this.panel) {
|
||||
this.panel.destroy();
|
||||
this.panel = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,159 +1,144 @@
|
||||
import { BimComponent } from '../core/component';
|
||||
import { BimEngine } from '../bim-engine';
|
||||
import { BimDialog } from '../components/dialog';
|
||||
/**
|
||||
* 剖切盒对话框管理器
|
||||
* 负责管理剖切盒工具对话框的显示、隐藏和剖切盒面板的交互
|
||||
*/
|
||||
import { BaseDialogManager } from '../core/base-dialog-manager';
|
||||
import { SectionBoxPanel } from '../components/section-box-panel';
|
||||
import type { SectionBoxRange } from '../components/section-box-panel/types';
|
||||
|
||||
/**
|
||||
* 剖切盒弹窗管理器
|
||||
* 剖切盒对话框管理器
|
||||
* 继承自 BaseDialogManager,提供六面体剖切盒的对话框管理功能
|
||||
*/
|
||||
export class SectionBoxDialogManager extends BimComponent {
|
||||
private dialogId = 'section-box-dialog';
|
||||
private dialog: BimDialog | null = null;
|
||||
export class SectionBoxDialogManager extends BaseDialogManager {
|
||||
/** 剖切盒面板实例 */
|
||||
private panel: SectionBoxPanel | null = null;
|
||||
|
||||
constructor(engine: BimEngine) {
|
||||
super(engine);
|
||||
/** 对话框唯一标识 */
|
||||
protected get dialogId(): string {
|
||||
return 'section-box-dialog';
|
||||
}
|
||||
|
||||
public init(): void {
|
||||
// 可以在这里监听事件
|
||||
/** 对话框标题(国际化 key) */
|
||||
protected get dialogTitle(): string {
|
||||
return 'sectionBox.dialogTitle';
|
||||
}
|
||||
|
||||
/** 对话框宽度 */
|
||||
protected get dialogWidth(): number {
|
||||
return 280;
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示弹窗
|
||||
* 获取对话框位置
|
||||
* 定位在容器右下角
|
||||
*/
|
||||
public show(): void {
|
||||
if (!this.engine.dialog || !this.engine.container) {
|
||||
console.warn('Dialog manager or container is not initialized');
|
||||
return;
|
||||
}
|
||||
protected getDialogPosition(): { x: number; y: number } {
|
||||
const container = this.registry.container;
|
||||
if (!container) return { x: 100, y: 100 };
|
||||
|
||||
// 如果已打开,先销毁
|
||||
this.destroy();
|
||||
const containerWidth = container.clientWidth;
|
||||
const containerHeight = container.clientHeight;
|
||||
const paddingRight = 20;
|
||||
const paddingBottom = 50;
|
||||
|
||||
// 创建面板
|
||||
return {
|
||||
x: containerWidth - this.dialogWidth - paddingRight,
|
||||
y: containerHeight - paddingBottom - 300
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建对话框内容
|
||||
* 初始化剖切盒面板并设置回调
|
||||
*/
|
||||
protected createContent(): HTMLElement {
|
||||
this.panel = new SectionBoxPanel({
|
||||
defaultHidden: false,
|
||||
defaultReversed: false,
|
||||
onHideToggle: (isHidden) => {
|
||||
console.log('[SectionBoxDialogManager] 隐藏切换:', isHidden);
|
||||
// TODO: 实现隐藏/显示剖切盒的逻辑
|
||||
},
|
||||
onReverseToggle: (isReversed) => {
|
||||
console.log('[SectionBoxDialogManager] 反向切换:', isReversed);
|
||||
// TODO: 实现反向剖切的逻辑
|
||||
},
|
||||
onFitToModel: () => {
|
||||
console.log('[SectionBoxDialogManager] 适应到模型');
|
||||
// TODO: 实现自动适应模型的逻辑
|
||||
},
|
||||
onReset: () => {
|
||||
console.log('[SectionBoxDialogManager] 重置');
|
||||
// 注意:不要在这里调用 panel.reset(),会造成无限递归
|
||||
// panel 的 reset 按钮已经在内部处理了状态重置
|
||||
// TODO: 这里只需要通知 3D 引擎重置剖切盒即可
|
||||
},
|
||||
onRangeChange: (range) => {
|
||||
console.log('[SectionBoxDialogManager] 范围变化:', range);
|
||||
// TODO: 实现范围变化的逻辑
|
||||
}
|
||||
});
|
||||
this.panel.init();
|
||||
return this.panel.element;
|
||||
}
|
||||
|
||||
// 创建弹窗
|
||||
const dialogWidth = 280;
|
||||
const paddingRight = 20;
|
||||
const paddingBottom = 50;
|
||||
const container = this.engine.container;
|
||||
const containerWidth = container.clientWidth;
|
||||
const containerHeight = container.clientHeight;
|
||||
const x = containerWidth - dialogWidth - paddingRight;
|
||||
const y = containerHeight - paddingBottom - 300; // 临时y值,会被fitHeight调整
|
||||
/** 对话框创建后的回调,自适应高度 */
|
||||
protected onDialogCreated(): void {
|
||||
this.dialog?.fitHeight(false);
|
||||
}
|
||||
|
||||
this.dialog = this.engine.dialog.create({
|
||||
id: this.dialogId,
|
||||
title: 'sectionBox.dialogTitle',
|
||||
width: dialogWidth,
|
||||
height: 'auto',
|
||||
position: { x, y },
|
||||
draggable: true,
|
||||
resizable: false,
|
||||
content: this.panel.element,
|
||||
onClose: () => {
|
||||
this.engine.toolbar?.setBtnActive('section-box', false);
|
||||
this.hide();
|
||||
}
|
||||
});
|
||||
this.dialog.init();
|
||||
/** 对话框关闭时的回调,取消工具栏按钮激活状态 */
|
||||
protected onDialogClose(): void {
|
||||
this.registry.toolbar?.setBtnActive('section-box', false);
|
||||
}
|
||||
|
||||
// 自适应高度
|
||||
this.dialog.fitHeight(false);
|
||||
/** 销毁前的清理,销毁面板实例 */
|
||||
protected onBeforeDestroy(): void {
|
||||
if (this.panel) {
|
||||
this.panel.destroy();
|
||||
this.panel = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏弹窗
|
||||
*/
|
||||
public hide(): void {
|
||||
this.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取隐藏状态
|
||||
* 获取剖切盒隐藏状态
|
||||
* @returns 是否隐藏
|
||||
*/
|
||||
public getHiddenState(): boolean {
|
||||
return this.panel?.getHiddenState() ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置隐藏状态
|
||||
* 设置剖切盒隐藏状态
|
||||
* @param isHidden 是否隐藏
|
||||
*/
|
||||
public setHiddenState(isHidden: boolean): void {
|
||||
this.panel?.setHiddenState(isHidden);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取反向状态
|
||||
* 获取剖切盒反向状态
|
||||
* @returns 是否反向(显示盒内/盒外)
|
||||
*/
|
||||
public getReversedState(): boolean {
|
||||
return this.panel?.getReversedState() ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置反向状态
|
||||
* 设置剖切盒反向状态
|
||||
* @param isReversed 是否反向
|
||||
*/
|
||||
public setReversedState(isReversed: boolean): void {
|
||||
this.panel?.setReversedState(isReversed);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取范围值
|
||||
* 获取剖切盒范围
|
||||
* @returns 六面体范围 { minX, maxX, minY, maxY, minZ, maxZ }
|
||||
*/
|
||||
public getRange(): SectionBoxRange | null {
|
||||
return this.panel?.getRange() ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置范围值
|
||||
* 设置剖切盒范围
|
||||
* @param range 部分或全部范围值
|
||||
*/
|
||||
public setRange(range: Partial<SectionBoxRange>): void {
|
||||
this.panel?.setRange(range);
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁弹窗和面板
|
||||
*/
|
||||
public destroy(): void {
|
||||
// 关闭弹窗
|
||||
if (this.dialog) {
|
||||
this.dialog.destroy();
|
||||
this.dialog = null;
|
||||
}
|
||||
|
||||
// 销毁面板
|
||||
if (this.panel) {
|
||||
this.panel.destroy();
|
||||
this.panel = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,95 +1,73 @@
|
||||
import { BimComponent } from '../core/component';
|
||||
import { BimEngine } from '../bim-engine';
|
||||
import { BimDialog } from '../components/dialog';
|
||||
/**
|
||||
* 拾取面剖切对话框管理器
|
||||
* 负责管理拾取面剖切工具对话框的显示和交互
|
||||
*/
|
||||
import { BaseDialogManager } from '../core/base-dialog-manager';
|
||||
import { SectionPlanePanel } from '../components/section-plane-panel';
|
||||
|
||||
/**
|
||||
* 拾取面剖切弹窗管理器
|
||||
* 拾取面剖切对话框管理器
|
||||
* 继承自 BaseDialogManager,提供拾取面剖切功能的对话框管理
|
||||
*/
|
||||
export class SectionPlaneDialogManager extends BimComponent {
|
||||
private dialogId = 'section-plane-dialog';
|
||||
private dialog: BimDialog | null = null;
|
||||
export class SectionPlaneDialogManager extends BaseDialogManager {
|
||||
/** 剖切面板实例 */
|
||||
private panel: SectionPlanePanel | null = null;
|
||||
|
||||
constructor(engine: BimEngine) {
|
||||
super(engine);
|
||||
}
|
||||
/** 对话框唯一标识 */
|
||||
protected get dialogId() { return 'section-plane-dialog'; }
|
||||
/** 对话框标题(国际化 key) */
|
||||
protected get dialogTitle() { return 'sectionPlane.dialogTitle'; }
|
||||
/** 对话框宽度 */
|
||||
protected get dialogWidth() { return 240; }
|
||||
/** 对话框高度 */
|
||||
protected get dialogHeight(): number { return 120; }
|
||||
|
||||
public init(): void {
|
||||
// 可以在这里监听事件
|
||||
}
|
||||
/** 初始化 */
|
||||
public init(): void {}
|
||||
|
||||
/**
|
||||
* 显示拾取面剖切弹窗
|
||||
* 获取对话框位置
|
||||
* 定位在容器右下角
|
||||
*/
|
||||
public show(): void {
|
||||
if (!this.engine.dialog || !this.engine.container) {
|
||||
console.warn('Dialog manager or container is not initialized');
|
||||
return;
|
||||
}
|
||||
protected getDialogPosition() {
|
||||
const container = this.registry.container;
|
||||
if (!container) return { x: 100, y: 100 };
|
||||
|
||||
// 如果已打开过,先销毁旧实例
|
||||
this.destroy();
|
||||
const paddingRight = 20;
|
||||
const paddingBottom = 50;
|
||||
const containerWidth = container.clientWidth;
|
||||
const containerHeight = container.clientHeight;
|
||||
|
||||
// 创建面板
|
||||
return {
|
||||
x: containerWidth - this.dialogWidth - paddingRight,
|
||||
y: containerHeight - this.dialogHeight - paddingBottom
|
||||
};
|
||||
}
|
||||
|
||||
/** 创建对话框内容 */
|
||||
protected createContent(): HTMLElement {
|
||||
this.panel = new SectionPlanePanel({
|
||||
onHide: () => {
|
||||
console.log('[SectionPlaneDialogManager] 隐藏');
|
||||
// TODO: 调用引擎的隐藏功能
|
||||
},
|
||||
onReverse: () => {
|
||||
console.log('[SectionPlaneDialogManager] 反向');
|
||||
// TODO: 调用引擎的反向功能
|
||||
},
|
||||
onReset: () => {
|
||||
console.log('[SectionPlaneDialogManager] 重置');
|
||||
// TODO: 调用引擎的重置功能
|
||||
}
|
||||
});
|
||||
this.panel.init();
|
||||
|
||||
// 创建弹窗
|
||||
const dialogWidth = 240;
|
||||
const dialogHeight = 120;
|
||||
const paddingRight = 20;
|
||||
const paddingBottom = 50;
|
||||
const container = this.engine.container;
|
||||
const containerWidth = container.clientWidth;
|
||||
const containerHeight = container.clientHeight;
|
||||
const x = containerWidth - dialogWidth - paddingRight;
|
||||
const y = containerHeight - dialogHeight - paddingBottom;
|
||||
|
||||
this.dialog = this.engine.dialog.create({
|
||||
id: this.dialogId,
|
||||
title: 'sectionPlane.dialogTitle',
|
||||
width: dialogWidth,
|
||||
height: dialogHeight,
|
||||
position: { x, y },
|
||||
draggable: true,
|
||||
resizable: false,
|
||||
content: this.panel.element,
|
||||
onClose: () => {
|
||||
this.engine.toolbar?.setBtnActive('section-plane', false);
|
||||
this.hide();
|
||||
}
|
||||
});
|
||||
return this.panel.element;
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏弹窗
|
||||
*/
|
||||
public hide(): void {
|
||||
this.destroy();
|
||||
/** 对话框关闭时的回调 */
|
||||
protected onDialogClose(): void {
|
||||
this.registry.toolbar?.setBtnActive('section-plane', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁弹窗
|
||||
*/
|
||||
public destroy(): void {
|
||||
if (this.dialog) {
|
||||
this.dialog.destroy();
|
||||
this.dialog = null;
|
||||
}
|
||||
/** 销毁前的清理 */
|
||||
protected onBeforeDestroy(): void {
|
||||
if (this.panel) {
|
||||
this.panel.destroy();
|
||||
this.panel = null;
|
||||
|
||||
@@ -1,26 +1,32 @@
|
||||
/**
|
||||
* 工具栏管理器
|
||||
* 负责管理底部工具栏的创建、按钮配置和显示控制
|
||||
*/
|
||||
import type { ButtonGroupColors, ButtonConfig } from '../components/button-group/index.type';
|
||||
import { Toolbar } from '../components/button-group/toolbar';
|
||||
import type { ThemeConfig } from '../themes/types';
|
||||
import { BimComponent } from '../core/component';
|
||||
import type { BimEngine } from '../bim-engine';
|
||||
import { BaseManager } from '../core/base-manager';
|
||||
|
||||
/**
|
||||
* 底部工具栏管理器 (ToolbarManager)
|
||||
* 仅负责管理底部工具栏实例。
|
||||
* 工具栏管理器
|
||||
* 提供工具栏按钮的添加、显示/隐藏、主题更新等功能
|
||||
*/
|
||||
export class ToolbarManager extends BimComponent {
|
||||
export class ToolbarManager extends BaseManager {
|
||||
/** 工具栏实例 */
|
||||
private toolbar: Toolbar | null = null;
|
||||
/** 工具栏容器元素 */
|
||||
private toolbarContainer: HTMLElement | null = null;
|
||||
/** 主容器元素 */
|
||||
private container: HTMLElement;
|
||||
|
||||
constructor(engine: BimEngine, container: HTMLElement) {
|
||||
super(engine);
|
||||
constructor(container: HTMLElement) {
|
||||
super();
|
||||
this.container = container;
|
||||
this.init();
|
||||
}
|
||||
|
||||
/** 初始化工具栏 */
|
||||
private init() {
|
||||
// 创建底部工具栏专用容器
|
||||
this.toolbarContainer = document.createElement('div');
|
||||
this.toolbarContainer.id = 'opt-btn-groups';
|
||||
this.toolbarContainer.className = 'bim-engine-opt-btn-container is-bottom-toolbar';
|
||||
@@ -36,52 +42,108 @@ export class ToolbarManager extends BimComponent {
|
||||
expand: 'up'
|
||||
});
|
||||
|
||||
// 注入 engine 到 Toolbar
|
||||
// @ts-ignore - Toolbar 还没更新类型,暂时忽略
|
||||
this.toolbar.setEngine(this.engine);
|
||||
|
||||
this.toolbar.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新工具栏主题
|
||||
* @param theme 主题配置
|
||||
*/
|
||||
public updateTheme(theme: ThemeConfig) {
|
||||
this.toolbar?.setTheme(theme);
|
||||
}
|
||||
|
||||
/** 刷新工具栏渲染 */
|
||||
public refresh() {
|
||||
this.toolbar?.render();
|
||||
}
|
||||
|
||||
/** 销毁工具栏 */
|
||||
public destroy() {
|
||||
this.toolbar?.destroy();
|
||||
this.toolbar = null;
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
// --- 转发 API ---
|
||||
public addGroup(groupId: string, beforeGroupId?: string) { this.toolbar?.addGroup(groupId, beforeGroupId); this.toolbar?.render(); }
|
||||
public addButton(config: ButtonConfig) { this.toolbar?.addButton(config); this.toolbar?.render(); }
|
||||
public setButtonVisibility(id: string, v: boolean) { this.toolbar?.updateButtonVisibility(id, v); }
|
||||
public setShowLabel(show: boolean) { this.toolbar?.setShowLabel(show); }
|
||||
public setBtnActive(id: string, active?: boolean) { this.toolbar?.setBtnActive(id, active); }
|
||||
/**
|
||||
* 添加按钮组
|
||||
* @param groupId 组 ID
|
||||
* @param beforeGroupId 插入到指定组之前
|
||||
*/
|
||||
public addGroup(groupId: string, beforeGroupId?: string) {
|
||||
this.toolbar?.addGroup(groupId, beforeGroupId);
|
||||
this.toolbar?.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加按钮
|
||||
* @param config 按钮配置
|
||||
*/
|
||||
public addButton(config: ButtonConfig) {
|
||||
this.toolbar?.addButton(config);
|
||||
this.toolbar?.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置按钮可见性
|
||||
* @param id 按钮 ID
|
||||
* @param v 是否可见
|
||||
*/
|
||||
public setButtonVisibility(id: string, v: boolean) {
|
||||
this.toolbar?.updateButtonVisibility(id, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否显示标签
|
||||
* @param show 是否显示
|
||||
*/
|
||||
public setShowLabel(show: boolean) {
|
||||
this.toolbar?.setShowLabel(show);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置按钮激活状态
|
||||
* @param id 按钮 ID
|
||||
* @param active 是否激活
|
||||
*/
|
||||
public setBtnActive(id: string, active?: boolean) {
|
||||
this.toolbar?.setBtnActive(id, active);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置工具栏可见性
|
||||
* @param visible 是否可见
|
||||
*/
|
||||
public setVisible(visible: boolean) {
|
||||
if (this.toolbarContainer) {
|
||||
this.toolbarContainer.style.visibility = visible ? 'visible' : 'hidden';
|
||||
}
|
||||
}
|
||||
public setBackgroundColor(color: string) { this.toolbar?.setBackgroundColor(color); }
|
||||
public setColors(colors: ButtonGroupColors) { this.toolbar?.setColors(colors); }
|
||||
|
||||
/**
|
||||
* 隐藏工具栏
|
||||
* 设置背景颜色
|
||||
* @param color 颜色值
|
||||
*/
|
||||
public setBackgroundColor(color: string) {
|
||||
this.toolbar?.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置按钮组颜色
|
||||
* @param colors 颜色配置
|
||||
*/
|
||||
public setColors(colors: ButtonGroupColors) {
|
||||
this.toolbar?.setColors(colors);
|
||||
}
|
||||
|
||||
/** 隐藏工具栏 */
|
||||
public hide(): void {
|
||||
if (this.toolbarContainer) {
|
||||
this.toolbarContainer.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示工具栏
|
||||
*/
|
||||
/** 显示工具栏 */
|
||||
public show(): void {
|
||||
if (this.toolbarContainer) {
|
||||
this.toolbarContainer.style.display = '';
|
||||
@@ -90,6 +152,7 @@ export class ToolbarManager extends BimComponent {
|
||||
|
||||
/**
|
||||
* 获取工具栏容器
|
||||
* @returns 容器元素
|
||||
*/
|
||||
public getContainer(): HTMLElement | null {
|
||||
return this.toolbarContainer;
|
||||
|
||||
@@ -1,47 +1,48 @@
|
||||
import { BimComponent } from '../core/component';
|
||||
import { BimEngine } from '../bim-engine';
|
||||
/**
|
||||
* 漫游控制管理器
|
||||
* 负责管理漫游模式的控制面板和相关交互
|
||||
*/
|
||||
import { BaseManager } from '../core/base-manager';
|
||||
import { WalkControlPanel } from '../components/walk-control-panel';
|
||||
import { WalkPathDialogManager } from './walk-path-dialog-manager';
|
||||
|
||||
/**
|
||||
* 漫游控制管理器
|
||||
* 提供第一人称漫游、路径漫游等功能的控制界面
|
||||
*/
|
||||
export class WalkControlManager extends BimComponent {
|
||||
export class WalkControlManager extends BaseManager {
|
||||
/** 漫游控制面板实例 */
|
||||
public panel: WalkControlPanel | null = null;
|
||||
/** 路径漫游对话框管理器 */
|
||||
private pathManager: WalkPathDialogManager | null = null;
|
||||
|
||||
constructor(engine: BimEngine) {
|
||||
super(engine);
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
/** 初始化管理器 */
|
||||
public init(): void {
|
||||
// 初始化子 manager
|
||||
this.pathManager = new WalkPathDialogManager(this.engine);
|
||||
this.pathManager = new WalkPathDialogManager();
|
||||
this.pathManager.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示漫游控制面板
|
||||
*/
|
||||
/** 显示漫游控制面板 */
|
||||
public show(): void {
|
||||
if (!this.engine.toolbar) {
|
||||
if (!this.registry.toolbar) {
|
||||
console.warn('Toolbar not initialized');
|
||||
return;
|
||||
}
|
||||
|
||||
// 隐藏 toolbar
|
||||
this.engine.toolbar.hide();
|
||||
this.registry.toolbar.hide();
|
||||
|
||||
// 创建漫游控制面板
|
||||
this.panel = new WalkControlPanel({
|
||||
onPlanViewToggle: (isActive) => {
|
||||
console.log('[WalkControl] 地图:', isActive);
|
||||
if (isActive) {
|
||||
this.engine.map?.show();
|
||||
this.registry.map?.show();
|
||||
} else {
|
||||
this.engine.map?.hide();
|
||||
this.registry.map?.hide();
|
||||
}
|
||||
// 触发事件
|
||||
this.emit('walk:plan-view-toggle', { isActive });
|
||||
},
|
||||
onPathModeToggle: (isActive) => {
|
||||
@@ -51,40 +52,32 @@ export class WalkControlManager extends BimComponent {
|
||||
} else {
|
||||
this.pathManager?.hide();
|
||||
}
|
||||
// 触发事件
|
||||
this.emit('walk:path-mode-toggle', { isActive });
|
||||
},
|
||||
onWalkModeToggle: (isActive) => {
|
||||
console.log('[WalkControl] 漫游模式:', isActive);
|
||||
// 切换到漫游模式时,关闭路径漫游弹窗
|
||||
if (isActive) {
|
||||
this.pathManager?.hide();
|
||||
}
|
||||
// 触发事件
|
||||
this.emit('walk:walk-mode-toggle', { isActive });
|
||||
},
|
||||
onSpeedChange: (speed) => {
|
||||
console.log('[WalkControl] 速度变化:', speed);
|
||||
// 触发事件
|
||||
this.emit('walk:speed-change', { speed });
|
||||
},
|
||||
onGravityToggle: (enabled) => {
|
||||
console.log('[WalkControl] 重力:', enabled);
|
||||
// 触发事件
|
||||
this.emit('walk:gravity-toggle', { enabled });
|
||||
},
|
||||
onCollisionToggle: (enabled) => {
|
||||
console.log('[WalkControl] 碰撞:', enabled);
|
||||
// 触发事件
|
||||
this.emit('walk:collision-toggle', { enabled });
|
||||
},
|
||||
onCharacterModelChange: (model) => {
|
||||
console.log('[WalkControl] 角色模型:', model);
|
||||
// TODO: 实现角色模型变化逻辑
|
||||
},
|
||||
onWalkModeChange: (mode) => {
|
||||
console.log('[WalkControl] 行走模式:', mode);
|
||||
// TODO: 实现行走模式变化逻辑
|
||||
},
|
||||
onExit: () => {
|
||||
this.hide();
|
||||
@@ -92,60 +85,50 @@ export class WalkControlManager extends BimComponent {
|
||||
});
|
||||
this.panel.init();
|
||||
|
||||
// 如果地图已经打开,同步按钮状态
|
||||
if (this.engine.map?.isOpen()) {
|
||||
if (this.registry.map?.isOpen()) {
|
||||
this.panel.setPlanViewActive(true);
|
||||
}
|
||||
|
||||
// 监听地图事件,同步漫游面板中的地图按钮状态
|
||||
this.engine.on('map:opened', () => {
|
||||
this.subscribe('map:opened', () => {
|
||||
this.panel?.setPlanViewActive(true);
|
||||
});
|
||||
|
||||
this.engine.on('map:closed', () => {
|
||||
this.subscribe('map:closed', () => {
|
||||
this.panel?.setPlanViewActive(false);
|
||||
});
|
||||
|
||||
// 将面板添加到主容器中,定位在底部中间(类似toolbar的位置)
|
||||
if (this.engine.container) {
|
||||
// 添加定位样式
|
||||
if (this.registry.container) {
|
||||
this.panel.element.style.position = 'absolute';
|
||||
this.panel.element.style.bottom = '20px';
|
||||
this.panel.element.style.left = '50%';
|
||||
this.panel.element.style.transform = 'translateX(-50%)';
|
||||
this.panel.element.style.zIndex = '1000';
|
||||
|
||||
this.engine.container.appendChild(this.panel.element);
|
||||
this.registry.container.appendChild(this.panel.element);
|
||||
} else {
|
||||
console.warn('[WalkControlManager] Container not found');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏漫游控制面板
|
||||
*/
|
||||
/** 隐藏漫游控制面板 */
|
||||
public hide(): void {
|
||||
// 关闭路径漫游弹窗(但不关闭地图,因为地图可能是用户单独打开的)
|
||||
this.pathManager?.hide();
|
||||
|
||||
// 销毁面板
|
||||
if (this.panel) {
|
||||
this.panel.destroy();
|
||||
this.panel = null;
|
||||
}
|
||||
|
||||
// 显示 toolbar
|
||||
if (this.engine.toolbar) {
|
||||
this.engine.toolbar.show();
|
||||
if (this.registry.toolbar) {
|
||||
this.registry.toolbar.show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁管理器
|
||||
*/
|
||||
/** 销毁管理器 */
|
||||
public destroy(): void {
|
||||
this.hide();
|
||||
this.pathManager?.destroy();
|
||||
this.pathManager = null;
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,94 +1,64 @@
|
||||
import { BimComponent } from '../core/component';
|
||||
import { BimEngine } from '../bim-engine';
|
||||
import { BimDialog } from '../components/dialog';
|
||||
/**
|
||||
* 漫游路径对话框管理器
|
||||
* 负责管理漫游路径设置对话框的显示和交互
|
||||
*/
|
||||
import { BaseDialogManager } from '../core/base-dialog-manager';
|
||||
import { WalkPathPanel } from '../components/walk-path-panel';
|
||||
|
||||
/**
|
||||
* 路径漫游弹窗管理器
|
||||
* 漫游路径对话框管理器
|
||||
* 继承自 BaseDialogManager,提供漫游路径配置的对话框管理功能
|
||||
*/
|
||||
export class WalkPathDialogManager extends BimComponent {
|
||||
private dialogId = 'walk-path-dialog';
|
||||
private dialog: BimDialog | null = null;
|
||||
export class WalkPathDialogManager extends BaseDialogManager {
|
||||
/** 漫游路径面板实例 */
|
||||
private panel: WalkPathPanel | null = null;
|
||||
|
||||
constructor(engine: BimEngine) {
|
||||
super(engine);
|
||||
}
|
||||
/** 对话框唯一标识 */
|
||||
protected get dialogId() { return 'walk-path-dialog'; }
|
||||
/** 对话框标题(国际化 key) */
|
||||
protected get dialogTitle() { return 'walkControl.path.dialogTitle'; }
|
||||
/** 对话框宽度 */
|
||||
protected get dialogWidth() { return 300; }
|
||||
/** 对话框高度 */
|
||||
protected get dialogHeight(): number { return 400; }
|
||||
|
||||
public init(): void {
|
||||
// 可以在这里监听事件
|
||||
}
|
||||
/** 初始化 */
|
||||
public init(): void {}
|
||||
|
||||
/**
|
||||
* 显示弹窗
|
||||
* 获取对话框位置
|
||||
* 定位在容器右侧居中
|
||||
*/
|
||||
public show(): void {
|
||||
if (!this.engine.dialog || !this.engine.container) {
|
||||
console.warn('Dialog manager or container is not initialized');
|
||||
return;
|
||||
}
|
||||
protected getDialogPosition() {
|
||||
const container = this.registry.container;
|
||||
if (!container) return { x: 100, y: 100 };
|
||||
|
||||
// 如果已打开,先销毁
|
||||
this.destroy();
|
||||
const paddingRight = 20;
|
||||
const containerWidth = container.clientWidth;
|
||||
const containerHeight = container.clientHeight;
|
||||
|
||||
// 创建面板(暂时空内容)
|
||||
return {
|
||||
x: containerWidth - this.dialogWidth - paddingRight,
|
||||
y: (containerHeight - this.dialogHeight) / 2
|
||||
};
|
||||
}
|
||||
|
||||
/** 创建对话框内容 */
|
||||
protected createContent(): HTMLElement {
|
||||
this.panel = new WalkPathPanel();
|
||||
this.panel.init();
|
||||
|
||||
const dialogWidth = 300;
|
||||
const dialogHeight = 400;
|
||||
const paddingRight = 20;
|
||||
const container = this.engine.container;
|
||||
const containerHeight = container.clientHeight;
|
||||
const containerWidth = container.clientWidth;
|
||||
|
||||
// 右边中间:right: 20px, 垂直居中
|
||||
const x = containerWidth - dialogWidth - paddingRight;
|
||||
const y = (containerHeight - dialogHeight) / 2;
|
||||
|
||||
this.dialog = this.engine.dialog.create({
|
||||
id: this.dialogId,
|
||||
title: 'walkControl.path.dialogTitle',
|
||||
width: dialogWidth,
|
||||
height: dialogHeight,
|
||||
position: { x, y },
|
||||
draggable: true,
|
||||
resizable: false,
|
||||
content: this.panel.element,
|
||||
onClose: () => {
|
||||
// 通知主控制面板更新状态
|
||||
if (this.engine.walkControl && this.engine.walkControl.panel) {
|
||||
this.engine.walkControl.panel.setPathModeActive(false);
|
||||
}
|
||||
this.hide();
|
||||
}
|
||||
});
|
||||
this.dialog.init();
|
||||
return this.panel.element;
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏弹窗
|
||||
*/
|
||||
public hide(): void {
|
||||
this.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁弹窗和面板
|
||||
*/
|
||||
public destroy(): void {
|
||||
// 先保存 dialog 引用,避免在回调中重复调用
|
||||
const dialog = this.dialog;
|
||||
|
||||
// 立即清空引用,防止递归
|
||||
this.dialog = null;
|
||||
|
||||
// 关闭弹窗
|
||||
if (dialog) {
|
||||
dialog.destroy();
|
||||
/** 对话框关闭时的回调 */
|
||||
protected onDialogClose(): void {
|
||||
if (this.registry.walkControl && this.registry.walkControl.panel) {
|
||||
this.registry.walkControl.panel.setPathModeActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
// 销毁面板
|
||||
/** 销毁前的清理 */
|
||||
protected onBeforeDestroy(): void {
|
||||
if (this.panel) {
|
||||
this.panel.destroy();
|
||||
this.panel = null;
|
||||
|
||||
@@ -1,94 +1,64 @@
|
||||
import { BimComponent } from '../core/component';
|
||||
import { BimEngine } from '../bim-engine';
|
||||
import { BimDialog } from '../components/dialog';
|
||||
/**
|
||||
* 漫游平面图对话框管理器
|
||||
* 负责管理漫游平面图对话框的显示和交互
|
||||
*/
|
||||
import { BaseDialogManager } from '../core/base-dialog-manager';
|
||||
import { WalkPlanViewPanel } from '../components/walk-plan-view-panel';
|
||||
|
||||
/**
|
||||
* 平面图弹窗管理器
|
||||
* 漫游平面图对话框管理器
|
||||
* 继承自 BaseDialogManager,提供漫游平面图的对话框管理功能
|
||||
*/
|
||||
export class WalkPlanViewDialogManager extends BimComponent {
|
||||
private dialogId = 'walk-plan-view-dialog';
|
||||
private dialog: BimDialog | null = null;
|
||||
export class WalkPlanViewDialogManager extends BaseDialogManager {
|
||||
/** 漫游平面图面板实例 */
|
||||
private panel: WalkPlanViewPanel | null = null;
|
||||
|
||||
constructor(engine: BimEngine) {
|
||||
super(engine);
|
||||
}
|
||||
/** 对话框唯一标识 */
|
||||
protected get dialogId() { return 'walk-plan-view-dialog'; }
|
||||
/** 对话框标题(国际化 key) */
|
||||
protected get dialogTitle() { return 'walkControl.planView.dialogTitle'; }
|
||||
/** 对话框宽度 */
|
||||
protected get dialogWidth() { return 300; }
|
||||
/** 对话框高度 */
|
||||
protected get dialogHeight(): number { return 400; }
|
||||
|
||||
public init(): void {
|
||||
// 可以在这里监听事件
|
||||
}
|
||||
/** 初始化 */
|
||||
public init(): void {}
|
||||
|
||||
/**
|
||||
* 显示弹窗
|
||||
* 获取对话框位置
|
||||
* 定位在容器左下角
|
||||
*/
|
||||
public show(): void {
|
||||
if (!this.engine.dialog || !this.engine.container) {
|
||||
console.warn('Dialog manager or container is not initialized');
|
||||
return;
|
||||
}
|
||||
protected getDialogPosition() {
|
||||
const container = this.registry.container;
|
||||
if (!container) return { x: 20, y: 100 };
|
||||
|
||||
// 如果已打开,先销毁
|
||||
this.destroy();
|
||||
|
||||
// 创建面板(暂时空内容)
|
||||
this.panel = new WalkPlanViewPanel();
|
||||
this.panel.init();
|
||||
|
||||
const dialogWidth = 300;
|
||||
const dialogHeight = 400;
|
||||
const paddingLeft = 20;
|
||||
const paddingBottom = 20;
|
||||
const container = this.engine.container;
|
||||
const containerHeight = container.clientHeight;
|
||||
|
||||
// 左下角:left: 20px, bottom: 20px
|
||||
const x = paddingLeft;
|
||||
const y = containerHeight - dialogHeight - paddingBottom;
|
||||
|
||||
this.dialog = this.engine.dialog.create({
|
||||
id: this.dialogId,
|
||||
title: 'walkControl.planView.dialogTitle',
|
||||
width: dialogWidth,
|
||||
height: dialogHeight,
|
||||
position: { x, y },
|
||||
draggable: true,
|
||||
resizable: false,
|
||||
content: this.panel.element,
|
||||
onClose: () => {
|
||||
// 通知主控制面板更新状态
|
||||
if (this.engine.walkControl && this.engine.walkControl.panel) {
|
||||
this.engine.walkControl.panel.setPlanViewActive(false);
|
||||
}
|
||||
this.hide();
|
||||
}
|
||||
});
|
||||
this.dialog.init();
|
||||
return {
|
||||
x: paddingLeft,
|
||||
y: containerHeight - this.dialogHeight - paddingBottom
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏弹窗
|
||||
*/
|
||||
public hide(): void {
|
||||
this.destroy();
|
||||
/** 创建对话框内容 */
|
||||
protected createContent(): HTMLElement {
|
||||
this.panel = new WalkPlanViewPanel();
|
||||
this.panel.init();
|
||||
return this.panel.element;
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁弹窗和面板
|
||||
*/
|
||||
public destroy(): void {
|
||||
// 先保存 dialog 引用,避免在回调中重复调用
|
||||
const dialog = this.dialog;
|
||||
|
||||
// 立即清空引用,防止递归
|
||||
this.dialog = null;
|
||||
|
||||
// 关闭弹窗
|
||||
if (dialog) {
|
||||
dialog.destroy();
|
||||
/** 对话框关闭时的回调 */
|
||||
protected onDialogClose(): void {
|
||||
if (this.registry.walkControl && this.registry.walkControl.panel) {
|
||||
this.registry.walkControl.panel.setPlanViewActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
// 销毁面板
|
||||
/** 销毁前的清理 */
|
||||
protected onBeforeDestroy(): void {
|
||||
if (this.panel) {
|
||||
this.panel.destroy();
|
||||
this.panel = null;
|
||||
|
||||
Reference in New Issue
Block a user