import './index.css'; import type { ThemeConfig } from '../../themes/types'; import { IBimComponent } from '../../types/component'; import { localeManager, t } from '../../services/locale'; import { themeManager } from '../../services/theme'; import type { SectionAxisPanelOptions, SectionAxis } from './types'; /** * 轴向剖切面板组件 * 第一行:隐藏(toggle)、反向 * 第二行:X、Y、Z(互斥按钮组) */ export class SectionAxisPanel implements IBimComponent { public element: HTMLElement; private options: SectionAxisPanelOptions; // 状态 private isHidden: boolean = false; private activeAxis: SectionAxis = 'x'; // DOM 引用 - 第一行 private hideBtn!: HTMLButtonElement; private reverseBtn!: HTMLButtonElement; private hideLabelEl!: HTMLElement; private reverseLabelEl!: HTMLElement; // DOM 引用 - 第二行 private axisXBtn!: HTMLButtonElement; private axisYBtn!: HTMLButtonElement; private axisZBtn!: HTMLButtonElement; // 订阅清理 private unsubscribeLocale: (() => void) | null = null; private unsubscribeTheme: (() => void) | null = null; constructor(options: SectionAxisPanelOptions = {}) { this.options = options; this.isHidden = options.defaultHidden ?? false; this.activeAxis = options.defaultAxis ?? 'x'; this.element = this.createDom(); } /** * 初始化组件 */ public init(): void { // 订阅语言变更 this.unsubscribeLocale = localeManager.subscribe(() => { this.setLocales(); }); // 订阅主题变更 this.unsubscribeTheme = themeManager.subscribe((theme) => { this.setTheme(theme); }); // 初始应用 this.setLocales(); this.setTheme(themeManager.getTheme()); // 初始化按钮状态 this.updateHideButtonState(); this.updateAxisButtonsState(); } /** * 设置主题 */ public setTheme(theme: ThemeConfig): void { const style = this.element.style; style.setProperty('--bim-section-axis-btn-bg', theme.componentBackground ?? 'rgba(255, 255, 255, 0.06)'); style.setProperty('--bim-section-axis-btn-hover', theme.componentHover ?? 'rgba(255, 255, 255, 0.10)'); style.setProperty('--bim-section-axis-btn-active', theme.componentActive ?? 'rgba(255, 255, 255, 0.14)'); style.setProperty('--bim-primary-color', theme.primary ?? '#1890ff'); style.setProperty('--bim-icon-color', theme.icon ?? '#ccc'); style.setProperty('--bim-text-color', theme.textSecondary ?? 'rgba(255, 255, 255, 0.90)'); style.setProperty('--bim-text-active-color', theme.textPrimary ?? '#fff'); } /** * 设置语言 */ public setLocales(): void { this.hideLabelEl.textContent = t('sectionAxis.actions.hide'); this.reverseLabelEl.textContent = t('sectionAxis.actions.reverse'); // XYZ按钮的文字不需要国际化,保持为单个字母 this.hideBtn.title = t('sectionAxis.actions.hide'); this.reverseBtn.title = t('sectionAxis.actions.reverse'); this.axisXBtn.title = t('sectionAxis.actions.axisX'); this.axisYBtn.title = t('sectionAxis.actions.axisY'); this.axisZBtn.title = t('sectionAxis.actions.axisZ'); } /** * 设置隐藏状态 */ public setHiddenState(isHidden: boolean): void { this.isHidden = isHidden; this.updateHideButtonState(); } /** * 获取隐藏状态 */ public getHiddenState(): boolean { return this.isHidden; } /** * 设置激活的轴向 */ public setActiveAxis(axis: SectionAxis): void { this.activeAxis = axis; this.updateAxisButtonsState(); } /** * 获取激活的轴向 */ public getActiveAxis(): SectionAxis { return this.activeAxis; } /** * 销毁组件 */ public destroy(): void { if (this.unsubscribeLocale) { this.unsubscribeLocale(); this.unsubscribeLocale = null; } if (this.unsubscribeTheme) { this.unsubscribeTheme(); this.unsubscribeTheme = null; } this.element.remove(); } /** * 创建 DOM */ private createDom(): HTMLElement { const root = document.createElement('div'); root.className = 'section-axis-panel'; // 第一行:隐藏、反向 const row1 = document.createElement('div'); row1.className = 'section-axis-row-1'; this.hideBtn = this.createButton( 'hide', '', () => this.handleHideToggle() ); this.reverseBtn = this.createButton( 'reverse', '', () => this.handleReverse() ); row1.appendChild(this.hideBtn); row1.appendChild(this.reverseBtn); // 第二行:X、Y、Z const row2 = document.createElement('div'); row2.className = 'section-axis-row-2'; this.axisXBtn = this.createAxisButton('axisX', 'X', () => this.handleAxisChange('x')); this.axisYBtn = this.createAxisButton('axisY', 'Y', () => this.handleAxisChange('y')); this.axisZBtn = this.createAxisButton('axisZ', 'Z', () => this.handleAxisChange('z')); row2.appendChild(this.axisXBtn); row2.appendChild(this.axisYBtn); row2.appendChild(this.axisZBtn); root.appendChild(row1); root.appendChild(row2); return root; } /** * 创建按钮(带图标) */ private createButton( type: 'hide' | 'reverse', iconSvg: string, onClick: () => void ): HTMLButtonElement { const btn = document.createElement('button'); btn.type = 'button'; btn.className = 'section-axis-btn'; // 图标 const icon = document.createElement('div'); icon.className = 'section-axis-btn-icon'; icon.innerHTML = iconSvg; btn.appendChild(icon); // 标签 const label = document.createElement('div'); label.className = 'section-axis-btn-label'; btn.appendChild(label); // 保存 label 引用 if (type === 'hide') { this.hideLabelEl = label; } else if (type === 'reverse') { this.reverseLabelEl = label; } // 点击事件 btn.addEventListener('click', onClick); return btn; } /** * 创建轴向按钮(仅文字) */ private createAxisButton( _type: 'axisX' | 'axisY' | 'axisZ', text: string, onClick: () => void ): HTMLButtonElement { const btn = document.createElement('button'); btn.type = 'button'; btn.className = 'section-axis-btn section-axis-btn-text'; // 文字标签(既是图标也是标签) const label = document.createElement('div'); label.className = 'section-axis-btn-label'; label.textContent = text; btn.appendChild(label); // 点击事件 btn.addEventListener('click', onClick); return btn; } /** * 处理隐藏按钮切换 */ private handleHideToggle(): void { this.isHidden = !this.isHidden; this.updateHideButtonState(); if (this.options.onHideToggle) { this.options.onHideToggle(this.isHidden); } } /** * 处理反向按钮点击 */ private handleReverse(): void { if (this.options.onReverse) { this.options.onReverse(); } } /** * 处理轴向切换 */ private handleAxisChange(axis: SectionAxis): void { if (this.activeAxis === axis) { return; // 已经是激活状态,不重复触发 } this.activeAxis = axis; this.updateAxisButtonsState(); if (this.options.onAxisChange) { this.options.onAxisChange(axis); } } /** * 更新隐藏按钮状态 */ private updateHideButtonState(): void { if (this.isHidden) { this.hideBtn.classList.add('active'); } else { this.hideBtn.classList.remove('active'); } } /** * 更新轴向按钮状态 */ private updateAxisButtonsState(): void { this.axisXBtn.classList.toggle('active', this.activeAxis === 'x'); this.axisYBtn.classList.toggle('active', this.activeAxis === 'y'); this.axisZBtn.classList.toggle('active', this.activeAxis === 'z'); } }