99 lines
3.3 KiB
TypeScript
99 lines
3.3 KiB
TypeScript
|
|
import { BimComponent } from '../core/component';
|
|||
|
|
import { BimEngine } from '../bim-engine';
|
|||
|
|
import { BimRightKey } from '../components/right-key';
|
|||
|
|
import { BimMenu } from '../components/menu';
|
|||
|
|
import { MenuItemConfig } from '../components/menu/item';
|
|||
|
|
import { infoMenuButton } from '../components/menu/buttons/info';
|
|||
|
|
import { homeMenuButton } from '../components/menu/buttons/home';
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 右键菜单管理器 (RightKeyManager)
|
|||
|
|
* 负责协调右键交互流程:
|
|||
|
|
* 1. 监听 Canvas/容器的 contextmenu 事件
|
|||
|
|
* 2. 通过注册的处理器 (Handler) 获取需要显示的菜单项
|
|||
|
|
* 3. 实例化 Menu 组件并装载到 RightKey 容器中显示
|
|||
|
|
*/
|
|||
|
|
export class RightKeyManager extends BimComponent {
|
|||
|
|
private container: HTMLElement;
|
|||
|
|
private rightKeyPanel: BimRightKey;
|
|||
|
|
|
|||
|
|
// 存储注册的上下文处理器
|
|||
|
|
// 每个处理<E5A484><E79086><EFBFBD>接收鼠标事件,返回一组菜单项(如果没有对应菜单则返回 null)
|
|||
|
|
private contextHandlers: Array<(e: MouseEvent) => MenuItemConfig[] | null> = [];
|
|||
|
|
|
|||
|
|
constructor(engine: BimEngine, container: HTMLElement) {
|
|||
|
|
super(engine);
|
|||
|
|
this.container = container;
|
|||
|
|
|
|||
|
|
// 初始化右键容器,设置极高的层级以覆盖所有 UI
|
|||
|
|
this.rightKeyPanel = new BimRightKey({ zIndex: 9000 });
|
|||
|
|
this.rightKeyPanel.init();
|
|||
|
|
|
|||
|
|
this.initEventListeners();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private initEventListeners(): void {
|
|||
|
|
this.container.addEventListener('contextmenu', this.handleContextMenu);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public destroy(): void {
|
|||
|
|
this.container.removeEventListener('contextmenu', this.handleContextMenu);
|
|||
|
|
this.rightKeyPanel.destroy();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 注册上下文菜单处理器
|
|||
|
|
* @param handler 处理函数,接收鼠标事件,返回菜单项数组
|
|||
|
|
*/
|
|||
|
|
public registerHandler(handler: (e: MouseEvent) => MenuItemConfig[] | null): void {
|
|||
|
|
this.contextHandlers.push(handler);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 手动显示菜单
|
|||
|
|
* 允许外部直接调用以显示特定的菜单,不一定依赖右键事件
|
|||
|
|
* @param x 屏幕 X 坐标
|
|||
|
|
* @param y 屏幕 Y 坐标
|
|||
|
|
* @param items 菜单项列表
|
|||
|
|
* @param groupOrder 可<EFBFBD><EFBFBD>的分组顺序
|
|||
|
|
*/
|
|||
|
|
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
|
|||
|
|
|
|||
|
|
// 2. 将菜单挂载到右键容器
|
|||
|
|
this.rightKeyPanel.mount(menu);
|
|||
|
|
|
|||
|
|
// 3. 显示容器
|
|||
|
|
this.rightKeyPanel.show(x, y);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 隐藏右键菜单
|
|||
|
|
*/
|
|||
|
|
public hide(): void {
|
|||
|
|
this.rightKeyPanel.hide();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 处理右键点击事件
|
|||
|
|
*/
|
|||
|
|
private handleContextMenu = (e: MouseEvent): void => {
|
|||
|
|
// 阻止浏览器默认的右键菜单
|
|||
|
|
e.preventDefault();
|
|||
|
|
let items: MenuItemConfig[] = [];
|
|||
|
|
items.push(infoMenuButton(this.engine))
|
|||
|
|
items.push(infoMenuButton(this.engine))
|
|||
|
|
items.push(infoMenuButton(this.engine))
|
|||
|
|
items.push(homeMenuButton(this.engine))
|
|||
|
|
if (items && items.length > 0) {
|
|||
|
|
this.showMenu(e.clientX, e.clientY, items);
|
|||
|
|
} else {
|
|||
|
|
// 如果没有任何内容,则关闭可能存在的菜单
|
|||
|
|
this.hide();
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
}
|