feat: 新增底部Dock测量面板与回调联动
This commit is contained in:
156
src/managers/bottom-dock-manager.ts
Normal file
156
src/managers/bottom-dock-manager.ts
Normal file
@@ -0,0 +1,156 @@
|
||||
import { BaseManager } from '../core/base-manager';
|
||||
import { ManagerRegistry } from '../core/manager-registry';
|
||||
import { BottomDockStack } from '../components/bottom-dock-stack';
|
||||
import { themeManager } from '../services/theme';
|
||||
|
||||
export interface BottomDockPanelDefinition {
|
||||
id: string;
|
||||
title: string;
|
||||
closable?: boolean;
|
||||
createContent?: () => HTMLElement;
|
||||
}
|
||||
|
||||
export interface BottomDockStateChange {
|
||||
id: string;
|
||||
open: boolean;
|
||||
}
|
||||
|
||||
type BottomDockStateListener = (state: BottomDockStateChange) => void;
|
||||
|
||||
export class BottomDockManager extends BaseManager {
|
||||
private stack: BottomDockStack;
|
||||
private definitions: Map<string, BottomDockPanelDefinition> = new Map();
|
||||
private openStates: Map<string, boolean> = new Map();
|
||||
private listeners: Set<BottomDockStateListener> = new Set();
|
||||
private unsubscribeTheme: (() => void) | null = null;
|
||||
|
||||
constructor(container: HTMLElement, registry: ManagerRegistry) {
|
||||
super(registry);
|
||||
this.stack = new BottomDockStack(container);
|
||||
this.stack.setTheme(themeManager.getTheme());
|
||||
this.unsubscribeTheme = themeManager.subscribe((theme) => {
|
||||
this.stack.setTheme(theme);
|
||||
});
|
||||
this.registerDefaultPanels();
|
||||
}
|
||||
|
||||
public register(definition: BottomDockPanelDefinition): void {
|
||||
this.definitions.set(definition.id, definition);
|
||||
if (!this.openStates.has(definition.id)) {
|
||||
this.openStates.set(definition.id, false);
|
||||
}
|
||||
}
|
||||
|
||||
public unregister(id: string): void {
|
||||
if (this.isOpen(id)) {
|
||||
this.close(id);
|
||||
}
|
||||
this.definitions.delete(id);
|
||||
this.openStates.delete(id);
|
||||
}
|
||||
|
||||
public toggle(id: string): void {
|
||||
if (this.isOpen(id)) {
|
||||
this.close(id);
|
||||
return;
|
||||
}
|
||||
this.open(id);
|
||||
}
|
||||
|
||||
public open(id: string): void {
|
||||
const definition = this.definitions.get(id);
|
||||
if (!definition) {
|
||||
console.warn(`[BottomDock] Unknown panel id: ${id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isOpen(id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const content = definition.createContent
|
||||
? definition.createContent()
|
||||
: this.stack.createPlaceholderContent(`${definition.title} 面板内容占位`);
|
||||
|
||||
this.stack.addPanel({
|
||||
id,
|
||||
content,
|
||||
closable: definition.closable !== false,
|
||||
onClose: () => {
|
||||
this.close(id);
|
||||
}
|
||||
});
|
||||
|
||||
this.openStates.set(id, true);
|
||||
this.emitState({ id, open: true });
|
||||
}
|
||||
|
||||
public close(id: string): void {
|
||||
if (!this.isOpen(id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.stack.removePanel(id);
|
||||
this.openStates.set(id, false);
|
||||
this.emitState({ id, open: false });
|
||||
}
|
||||
|
||||
public isOpen(id: string): boolean {
|
||||
return this.openStates.get(id) ?? false;
|
||||
}
|
||||
|
||||
public createPlaceholderContent(text: string): HTMLElement {
|
||||
return this.stack.createPlaceholderContent(text);
|
||||
}
|
||||
|
||||
public onStateChange(listener: BottomDockStateListener): () => void {
|
||||
this.listeners.add(listener);
|
||||
return () => {
|
||||
this.listeners.delete(listener);
|
||||
};
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
if (this.unsubscribeTheme) {
|
||||
this.unsubscribeTheme();
|
||||
this.unsubscribeTheme = null;
|
||||
}
|
||||
this.listeners.clear();
|
||||
this.definitions.clear();
|
||||
this.openStates.clear();
|
||||
this.stack.destroy();
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
private emitState(state: BottomDockStateChange): void {
|
||||
this.listeners.forEach((listener) => {
|
||||
listener(state);
|
||||
});
|
||||
}
|
||||
|
||||
private registerDefaultPanels(): void {
|
||||
this.register({
|
||||
id: 'measure',
|
||||
title: '测量',
|
||||
createContent: () => {
|
||||
const measurePanel = this.registry.measureDock?.getPanelElement();
|
||||
if (measurePanel) {
|
||||
return measurePanel;
|
||||
}
|
||||
return this.stack.createPlaceholderContent('测量面板占位');
|
||||
}
|
||||
});
|
||||
|
||||
this.register({
|
||||
id: 'section',
|
||||
title: '剖切',
|
||||
createContent: () => this.stack.createPlaceholderContent('剖切面板占位')
|
||||
});
|
||||
|
||||
this.register({
|
||||
id: 'walk',
|
||||
title: '漫游',
|
||||
createContent: () => this.stack.createPlaceholderContent('漫游面板占位')
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user