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');
}
}