refactor: sync managers and section box actions
Wire section box scale/reverse/reset to clipping APIs and sync demo artifacts.
This commit is contained in:
@@ -4,7 +4,7 @@ import { IBimComponent } from '../../types/component';
|
||||
import { localeManager, t } from '../../services/locale';
|
||||
import { themeManager } from '../../services/theme';
|
||||
import type { MeasureConfig, MeasurePanelOptions, MeasurePrecision, MeasureResult, MeasureUnit } from './types';
|
||||
import { MEASURE_TYPES, MEASURE_MODES_ORDERED, type MeasureMode } from '../../types/measure';
|
||||
import { MEASURE_TYPES, MEASURE_MODES_ORDERED, getValueType, type MeasureMode, type MeasureValueType } from '../../types/measure';
|
||||
|
||||
/**
|
||||
* 测量面板组件(只做 UI,不实现真实测量)
|
||||
@@ -55,6 +55,7 @@ export class MeasurePanel implements IBimComponent {
|
||||
private toolButtons: Map<MeasureMode, HTMLButtonElement> = new Map();
|
||||
private toggleBtn!: HTMLButtonElement;
|
||||
private toggleTextEl!: HTMLElement;
|
||||
private mainValueRowEl!: HTMLElement;
|
||||
private mainValueValueEl!: HTMLElement;
|
||||
private mainValueLabelEl!: HTMLElement;
|
||||
private mainNumberEl!: HTMLElement;
|
||||
@@ -428,6 +429,7 @@ export class MeasurePanel implements IBimComponent {
|
||||
// 主结果值(随模式变化)
|
||||
const mainValueRow = document.createElement('div');
|
||||
mainValueRow.className = 'bim-measure-row';
|
||||
this.mainValueRowEl = mainValueRow;
|
||||
const mainValueLabel = document.createElement('span');
|
||||
mainValueLabel.className = 'label';
|
||||
this.mainValueLabelEl = mainValueLabel;
|
||||
@@ -764,7 +766,7 @@ export class MeasurePanel implements IBimComponent {
|
||||
private renderResult(): void {
|
||||
// 1) 根据模式决定结果区显示规则
|
||||
// 你给的规则:
|
||||
// - 距离:显示数值 + xyz
|
||||
// - 距离:只显示数值
|
||||
// - 最小距离:只显示数值
|
||||
// - 角度:--°
|
||||
// - 标高:--m(固定 m)
|
||||
@@ -773,14 +775,10 @@ export class MeasurePanel implements IBimComponent {
|
||||
// - 坡度:--%
|
||||
// - 空间体积:--mm³(单位随设置变动,即 unit³)
|
||||
|
||||
this.mainValueLabelEl.style.display = '';
|
||||
this.mainValueLabelEl.textContent = t(this.getModeValueLabelI18nKey(this.activeMode));
|
||||
const parts = this.formatMainValueParts(this.activeMode, this.result);
|
||||
this.mainNumberEl.textContent = parts.numberText;
|
||||
this.mainUnitEl.textContent = parts.unitText;
|
||||
|
||||
const showXyz = this.activeMode === 'distance' || this.activeMode === 'point';
|
||||
if (showXyz) {
|
||||
const isPointMode = this.activeMode === 'point';
|
||||
|
||||
if (isPointMode) {
|
||||
this.mainValueRowEl.style.display = 'none';
|
||||
this.xyzBoxEl.style.display = '';
|
||||
const xyz = this.result?.xyz;
|
||||
if (!xyz) {
|
||||
@@ -789,12 +787,24 @@ export class MeasurePanel implements IBimComponent {
|
||||
this.xyzZEl.textContent = '--';
|
||||
return;
|
||||
}
|
||||
this.xyzXEl.textContent = this.formatNumberWithPrecision(xyz.x, this.config.precision);
|
||||
this.xyzYEl.textContent = this.formatNumberWithPrecision(xyz.y, this.config.precision);
|
||||
this.xyzZEl.textContent = this.formatNumberWithPrecision(xyz.z, this.config.precision);
|
||||
this.xyzXEl.textContent = this.convertValue('length', xyz.x) + ' ' + this.getUnitText('length');
|
||||
this.xyzYEl.textContent = this.convertValue('length', xyz.y) + ' ' + this.getUnitText('length');
|
||||
this.xyzZEl.textContent = this.convertValue('length', xyz.z) + ' ' + this.getUnitText('length');
|
||||
return;
|
||||
}
|
||||
|
||||
this.mainValueRowEl.style.display = '';
|
||||
this.mainValueLabelEl.textContent = t(this.getModeValueLabelI18nKey(this.activeMode));
|
||||
const value = this.result ? (this.result as any)[MEASURE_TYPES[this.activeMode].callBackType] : undefined;
|
||||
|
||||
if (this.activeMode === 'slope'||this.activeMode === 'angle') {
|
||||
this.mainNumberEl.textContent = value ?? '--';
|
||||
this.mainUnitEl.textContent = '';
|
||||
} else {
|
||||
const valueType = getValueType(this.activeMode);
|
||||
this.mainNumberEl.textContent = this.convertValue(valueType, value);
|
||||
this.mainUnitEl.textContent = this.getUnitText(valueType);
|
||||
}
|
||||
this.xyzBoxEl.style.display = 'none';
|
||||
}
|
||||
|
||||
@@ -809,99 +819,69 @@ export class MeasurePanel implements IBimComponent {
|
||||
return `measure.labels.value.${mode}`;
|
||||
}
|
||||
|
||||
// 注意:旧的 formatMainValue/formatWithFixedUnit 已被 formatMainValueParts 替代,
|
||||
// 以支持“数值与单位分色显示”和“无数据时仍展示单位”。
|
||||
/**
|
||||
* 统一的数值转换方法
|
||||
* @param type 测量值类型:length(长度)、area(面积)、angle(角度)、percent(百分比)、point(坐标)
|
||||
* @param value 原始数值(单位:长度为米,面积为平方米)
|
||||
* @returns 转换后的格式化字符串,无效值返回 '--'
|
||||
*/
|
||||
private convertValue(type: MeasureValueType, value: number | undefined | null): string {
|
||||
if (value === null || value === undefined || Number.isNaN(value)) {
|
||||
return '--';
|
||||
}
|
||||
|
||||
const unit = this.config.unit;
|
||||
const precision = this.config.precision;
|
||||
let converted: number;
|
||||
|
||||
switch (type) {
|
||||
case 'length':
|
||||
switch (unit) {
|
||||
case 'mm': converted = value * 1000; break;
|
||||
case 'cm': converted = value * 100; break;
|
||||
case 'km': converted = value / 1000; break;
|
||||
default: converted = value;
|
||||
}
|
||||
break;
|
||||
case 'area':
|
||||
switch (unit) {
|
||||
case 'mm': converted = value * 1000 * 1000; break;
|
||||
case 'cm': converted = value * 100 * 100; break;
|
||||
case 'km': converted = value / 1000 / 1000; break;
|
||||
default: converted = value;
|
||||
}
|
||||
break;
|
||||
case 'angle':
|
||||
case 'percent':
|
||||
case 'point':
|
||||
default:
|
||||
converted = value;
|
||||
}
|
||||
|
||||
return converted.toFixed(precision);
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础数字格式化(按精度显示)
|
||||
* 获取单位文本
|
||||
* @param type 测量值类型
|
||||
* @returns 对应的单位文本(如 mm、m²、°)
|
||||
*/
|
||||
private formatNumberWithPrecision(value: number, precision: MeasurePrecision): string {
|
||||
// 你要求精度可选:0 / 0.0 / 0.00 / 0.000,因此这里不做 trim,严格按 toFixed 输出
|
||||
return value.toFixed(precision);
|
||||
}
|
||||
|
||||
// 注意:旧的 formatLengthWithConfig 已被 formatLengthParts 替代。
|
||||
|
||||
private getUnitI18nKey(unit: MeasureUnit): string {
|
||||
return `measure.units.${unit}`;
|
||||
}
|
||||
|
||||
private formatMainValueParts(mode: MeasureMode, result: MeasureResult | null): { numberText: string; unitText: string } {
|
||||
if (!result) {
|
||||
return this.getEmptyValuePartsByMode(mode);
|
||||
}
|
||||
|
||||
const config = MEASURE_TYPES[mode];
|
||||
const value = (result as any)[config.resultField];
|
||||
|
||||
switch (config.valueType) {
|
||||
case 'length':
|
||||
case 'area':
|
||||
return this.formatMeasureValue(value, config.valueType);
|
||||
case 'angle':
|
||||
return this.formatFixedUnitParts(value, t('measure.units.deg'));
|
||||
case 'percent':
|
||||
return this.formatFixedUnitParts(value, t('measure.units.percent'));
|
||||
case 'point':
|
||||
return { numberText: '--', unitText: '' };
|
||||
default:
|
||||
return { numberText: '--', unitText: '' };
|
||||
}
|
||||
}
|
||||
|
||||
private getEmptyValuePartsByMode(mode: MeasureMode): { numberText: string; unitText: string } {
|
||||
const config = MEASURE_TYPES[mode];
|
||||
|
||||
switch (config.valueType) {
|
||||
case 'length':
|
||||
return { numberText: '--', unitText: t(this.getUnitI18nKey(this.config.unit)) };
|
||||
case 'area':
|
||||
return { numberText: '--', unitText: `${this.config.unit}²` };
|
||||
case 'angle':
|
||||
return { numberText: '--', unitText: t('measure.units.deg') };
|
||||
case 'percent':
|
||||
return { numberText: '--', unitText: t('measure.units.percent') };
|
||||
case 'point':
|
||||
return { numberText: '--', unitText: '' };
|
||||
default:
|
||||
return { numberText: '--', unitText: '' };
|
||||
}
|
||||
}
|
||||
|
||||
private formatFixedUnitParts(value: number | undefined, unitText: string): { numberText: string; unitText: string } {
|
||||
if (value === null || value === undefined || Number.isNaN(value)) {
|
||||
return { numberText: '--', unitText };
|
||||
}
|
||||
return { numberText: this.formatNumberWithPrecision(value, this.config.precision), unitText };
|
||||
}
|
||||
|
||||
private formatMeasureValue(value: number | undefined, type: 'length' | 'area'): { numberText: string; unitText: string } {
|
||||
private getUnitText(type: MeasureValueType): string {
|
||||
const unit = this.config.unit;
|
||||
const unitText = type === 'area' ? `${unit}²` : t(this.getUnitI18nKey(unit));
|
||||
|
||||
if (value === null || value === undefined || Number.isNaN(value)) {
|
||||
return { numberText: '--', unitText };
|
||||
switch (type) {
|
||||
case 'length':
|
||||
case 'point':
|
||||
return unit;
|
||||
case 'area':
|
||||
return `${unit}²`;
|
||||
case 'angle':
|
||||
case 'percent':
|
||||
return '°';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
|
||||
let converted: number;
|
||||
if (type === 'length') {
|
||||
switch (unit) {
|
||||
case 'mm': converted = value * 1000; break;
|
||||
case 'cm': converted = value * 100; break;
|
||||
case 'km': converted = value / 1000; break;
|
||||
default: converted = value;
|
||||
}
|
||||
} else {
|
||||
switch (unit) {
|
||||
case 'mm': converted = value * 1000 * 1000; break;
|
||||
case 'cm': converted = value * 100 * 100; break;
|
||||
case 'km': converted = value / 1000 / 1000; break;
|
||||
default: converted = value;
|
||||
}
|
||||
}
|
||||
|
||||
return { numberText: converted.toFixed(this.config.precision), unitText };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user