增加测量窗口

This commit is contained in:
yuding
2025-12-22 18:48:38 +08:00
parent e1bb5558ff
commit 7d522afb70
25 changed files with 4625 additions and 2403 deletions

View File

@@ -94,13 +94,13 @@ export class BimButtonGroup implements IBimComponent {
}
this.updatePosition();
// 添加事件拦截,防止点击穿透到 3D 引擎
this.setupEventInterception(this.container);
}
/**
* 设置事件拦截,防止事件<EFBFBD><EFBFBD>泡到下层元素(如 3D 引擎)
* 设置事件拦截,防止事件泡到下层元素(如 3D 引擎)
*/
private setupEventInterception(el: HTMLElement): void {
const stopPropagation = (e: Event) => {
@@ -319,6 +319,11 @@ export class BimButtonGroup implements IBimComponent {
const btnEl = document.createElement('div');
btnEl.className = 'opt-btn';
// 初始化时根据 button 自身的属性同步 active 状态
if (button.isActive) {
this.activeBtnIds.add(button.id);
}
// 按钮优先使用自己的 align否则使用全局配置默认为 vertical
const align = button.align || this.options.align || 'vertical';
if (align === 'horizontal') {
@@ -380,14 +385,34 @@ export class BimButtonGroup implements IBimComponent {
return wrapper;
}
/**
* 设置按钮的激活状态
* @param id 按钮 ID
* @param active 可选,如果不传则切换(toggle)当前状态
*/
public setBtnActive(id: string, active?: boolean): void {
const button = this.findButtonById(id);
if (!button) return;
// 确定最终状态
const newState = active !== undefined ? active : !this.activeBtnIds.has(id);
if (newState) {
this.activeBtnIds.add(id);
} else {
this.activeBtnIds.delete(id);
}
// 同步对象状态并更新 DOM
button.isActive = newState;
this.updateButtonState(id);
}
private handleClick(button: OptButton): void {
if (button.disabled) return;
if (!button.children || button.children.length === 0) {
if (button.keepActive) {
const wasActive = this.activeBtnIds.has(button.id);
if (wasActive) this.activeBtnIds.delete(button.id);
else this.activeBtnIds.add(button.id);
this.updateButtonState(button.id);
this.setBtnActive(button.id);
}
this.closeDropdown();
if (button.onClick) button.onClick(button);
@@ -428,7 +453,7 @@ export class BimButtonGroup implements IBimComponent {
// 先添加到 DOM 以便计算尺寸
document.body.appendChild(dropdown);
// 添加事件拦截
this.setupEventInterception(dropdown);
@@ -518,16 +543,22 @@ export class BimButtonGroup implements IBimComponent {
private updateButtonState(buttonId: string): void {
const btnEl = this.btnRefs.get(buttonId);
if (btnEl) {
this.activeBtnIds.has(buttonId) ? btnEl.classList.add('active') : btnEl.classList.remove('active');
if (this.activeBtnIds.has(buttonId)) {
btnEl.classList.add('active');
} else {
btnEl.classList.remove('active');
}
}
}
private getIcon(icon?: string): string { return icon || this.DEFAULT_ICON; }
public updateButtonVisibility(id: string, visible: boolean): void {
if (!this.options.visibility) this.options.visibility = {};
this.options.visibility[id] = visible;
this.render();
}
public setShowLabel(show: boolean): void {
this.options.showLabel = show;
this.updateLabelsVisibility();
@@ -557,8 +588,10 @@ export class BimButtonGroup implements IBimComponent {
}
return undefined;
}
public setBackgroundColor(color: string): void { this.setColors({ backgroundColor: color }); }
private isVisible(id: string): boolean { return this.options.visibility?.[id] !== false; }
public destroy(): void {
if (this.unsubscribeLocale) {
this.unsubscribeLocale();

View File

@@ -7,6 +7,7 @@ export interface ButtonConfig {
label: string;
icon?: string;
keepActive?: boolean;
isActive?:boolean;
disabled?: boolean;
onClick?: (button: OptButton) => void;
children?: ButtonConfig[];
@@ -43,10 +44,10 @@ export interface ButtonGroupColors {
// --- 新增布局类型 ---
/** 弹窗/按钮组位置 */
export type GroupPosition =
| 'center'
| 'top-left' | 'top-center' | 'top-right'
| 'left-center' | 'right-center'
export type GroupPosition =
| 'center'
| 'top-left' | 'top-center' | 'top-right'
| 'left-center' | 'right-center'
| 'bottom-left' | 'bottom-center' | 'bottom-right'
| { x: number; y: number }
| 'static'; // static 表示不绝对定位,随文档流
@@ -62,16 +63,16 @@ export type ExpandDirection = 'up' | 'down' | 'left' | 'right';
export interface ButtonGroupOptions extends ButtonGroupColors {
container: HTMLElement | string;
/** 屏幕位置 (如 top-left) */
position?: GroupPosition;
/** 按钮组排列方向 (默认 row) */
direction?: GroupDirection;
/** 按钮内部图标文字排列 (默认 vertical) */
align?: ButtonAlign;
/** 菜单展开方向 */
expand?: ExpandDirection;
@@ -84,4 +85,4 @@ export interface ClickPayload {
button: OptButton;
action: 'activate' | 'deactivate' | 'trigger';
isActive?: boolean;
}
}

View File

@@ -0,0 +1,24 @@
import type {ButtonConfig} from '../../../index.type';
import type {BimEngine} from '../../../../../bim-engine';
/**
* 测量按钮配置
* 使用工厂函数模式,注入 engine 实例
*/
export const createMeasureButton = (engine: BimEngine): ButtonConfig => {
return {
id: 'measure',
groupId: 'group-1',
type: 'button',
label: 'toolbar.measure',
icon: '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" d="M3 6a3 3 0 0 0-3 3v7a3 3 0 0 0 3 3h18a3 3 0 0 0 3-3V9a3 3 0 0 0-3-3zm6 2H7v5a1 1 0 1 1-2 0V8H3a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h18a1 1 0 0 0 1-1V9a1 1 0 0 0-1-1h-2v3a1 1 0 1 1-2 0V8h-2v5a1 1 0 1 1-2 0V8h-2v3a1 1 0 1 1-2 0z" clip-rule="evenodd"/></svg>',
keepActive: true,
onClick: (button) => {
if (button.isActive) {
engine.measure?.show()
} else {
engine.measure?.destroy()
}
}
};
};

View File

@@ -19,12 +19,14 @@ export class Toolbar extends BimButtonGroup {
const { walkBirdButton } = await import('./buttons/walk/walk-bird');
const { settingButton } = await import('./buttons/setting');
const { infoButton } = await import('./buttons/info');
const { createMeasureButton } = await import('./buttons/measure');
this.addGroup('group-1');
// 使用工厂函数创建按钮,并注入 engine
if (this.engine) {
this.addButton(createHomeButton(this.engine));
this.addButton(createMeasureButton(this.engine));
} else {
console.warn('[Toolbar] Engine not available when creating buttons.');
}