feat: upgrade to v1.3.2 with settings panel overhaul, clear height enhancements and bug fixes
- Overhaul settings dialog: add edge line toggle, contrast/saturation/light intensity sliders, environment and ground type selectors - Add clear height measurement options: direction (up/down) and select type (point/element) with radio button UI - Fix right-click context menu triggering during model drag rotation (add move threshold) - Fix measure dialog event listener leak (on → off for cleanup) - Update mini map API to use engine.minMap.toggle() - Replace text-based measure icons with proper SVG assets (净高/净距/坐标/面积) - Add i18n keys for all new settings and clear height options (zh-CN / en-US) - Bump iflow-engine-base dependency to ^2.0.5 - Rebuild dist and sync demo libs
This commit is contained in:
@@ -2,13 +2,13 @@ import type { ThemeConfig } from '../../themes/types';
|
||||
import { IBimComponent } from '../../types/component';
|
||||
import { themeManager } from '../../services/theme';
|
||||
import type { EngineOptions, ModelLoadOptions, EngineInfo } from './types';
|
||||
import { type MeasureMode } from '../../types/measure';
|
||||
import { type MeasureMode, type ClearHeightDirection, type ClearHeightSelectType } from '../../types/measure';
|
||||
import type { MeasureUnit, MeasurePrecision } from '../measure-panel/types';
|
||||
import type { SectionBoxRange } from '../section-box-panel/types';
|
||||
import type { ManagerRegistry } from '../../core/manager-registry';
|
||||
// 导入第三方 SDK 的 createEngine 函数(从 npm 包引入)
|
||||
import { createEngine as createEngineSDK } from 'iflow-engine-base';
|
||||
//import { createEngine as createEngineSDK } from '../../../../bim_engine_base/dist/bim-engine-sdk.es';
|
||||
//import { createEngine as createEngineSDK } from 'iflow-engine-base';
|
||||
import { createEngine as createEngineSDK } from '../../../../bim_engine_base/dist/bim-engine-sdk.es';
|
||||
import "../../../../bim_engine_base/dist/iflow-engine-base.css"
|
||||
|
||||
export type { EngineOptions, ModelLoadOptions, EngineInfo };
|
||||
@@ -369,6 +369,30 @@ export class Engine implements IBimComponent {
|
||||
this.engine.measure.saveSetting?.(setting);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置净高测量朝向
|
||||
* @param direction 0=朝下,1=朝上
|
||||
*/
|
||||
public setClearHeightDirection(direction: ClearHeightDirection): void {
|
||||
if (!this._isInitialized || !this.engine?.measure) {
|
||||
return;
|
||||
}
|
||||
console.log(`[Engine] Setting clearHeight direction: ${direction}`);
|
||||
this.engine.measure.clearHeightMeasure.setDirection(direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置净高测量选择对象类型
|
||||
* @param selectType 'point'=选择点,'element'=选择构件
|
||||
*/
|
||||
public setClearHeightSelectType(selectType: ClearHeightSelectType): void {
|
||||
if (!this._isInitialized || !this.engine?.measure) {
|
||||
return;
|
||||
}
|
||||
console.log(`[Engine] Setting clearHeight selectType: ${selectType}`);
|
||||
this.engine.measure.clearHeightMeasure.setSelectType(selectType);
|
||||
}
|
||||
|
||||
// ==================== 结束:测量功能 ====================
|
||||
|
||||
// ==================== 剖切功能(统一 API) ====================
|
||||
@@ -696,11 +720,22 @@ export class Engine implements IBimComponent {
|
||||
* 切换小地图显示状态
|
||||
*/
|
||||
public toggleMiniMap(): void {
|
||||
if (!this._isInitialized || !this.engine?.controlModule) {
|
||||
if (!this._isInitialized || !this.engine) {
|
||||
console.error('[Engine] Cannot toggle mini map: engine not initialized.');
|
||||
return;
|
||||
}
|
||||
this.engine.controlModule.toggleMinMap();
|
||||
this.engine.minMap?.toggle();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取小地图显示状态
|
||||
* @returns true=显示,false=隐藏
|
||||
*/
|
||||
public getMiniMapState(): boolean {
|
||||
if (!this._isInitialized || !this.engine) {
|
||||
return false;
|
||||
}
|
||||
return this.engine.minMap?.getState() ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1004,7 +1039,7 @@ export class Engine implements IBimComponent {
|
||||
const normalizeUrl = (url: string): string => url.replace(/\/+$/, '');
|
||||
|
||||
const loadedModels = Array.isArray((this.engine as any)?.models)
|
||||
? ((this.engine as any).models as Array<{ url?: string; nodesMap?: Map<number, { indexes?: unknown[] }> }> )
|
||||
? ((this.engine as any).models as Array<{ url?: string; nodesMap?: Map<number, { indexes?: unknown[] }> }>)
|
||||
: [];
|
||||
const modelMap = new Map<string, { nodesMap?: Map<number, { indexes?: unknown[] }> }>();
|
||||
for (const loadedModel of loadedModels) {
|
||||
|
||||
@@ -208,6 +208,66 @@
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* ========== 模式选项区(净高朝向/选择对象) ========== */
|
||||
.bim-measure-mode-options {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin-top: 12px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid var(--bim-divider);
|
||||
}
|
||||
|
||||
.bim-measure-mode-options.is-visible {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.bim-measure-radio-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.bim-measure-radio-group .bim-measure-radio-label {
|
||||
color: var(--bim-text-secondary);
|
||||
min-width: 58px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.bim-measure-radio-group .bim-measure-radio-items {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.bim-measure-radio-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 26px;
|
||||
padding: 0 10px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--bim-border-default);
|
||||
background: var(--bim-bg-inset);
|
||||
color: var(--bim-text-secondary);
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.bim-measure-radio-item:hover {
|
||||
border-color: var(--bim-border-strong);
|
||||
color: var(--bim-text-primary);
|
||||
}
|
||||
|
||||
.bim-measure-radio-item.is-active {
|
||||
background: var(--bim-primary-subtle);
|
||||
border-color: var(--bim-primary);
|
||||
color: var(--bim-primary);
|
||||
}
|
||||
|
||||
.bim-measure-result {
|
||||
margin-top: 12px;
|
||||
padding-top: 12px;
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { ThemeConfig } from '../../themes/types';
|
||||
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 type { MeasureConfig, MeasurePanelOptions, MeasurePrecision, MeasureResult, MeasureUnit, ClearHeightDirection, ClearHeightSelectType } from './types';
|
||||
import { MEASURE_TYPES, MEASURE_MODES_ORDERED, getValueType, type MeasureMode, type MeasureValueType } from '../../types/measure';
|
||||
|
||||
/**
|
||||
@@ -27,6 +27,10 @@ export class MeasurePanel implements IBimComponent {
|
||||
private isExpanded: boolean;
|
||||
private result: MeasureResult | null = null;
|
||||
|
||||
// 净高模式专属状态
|
||||
private clearHeightDirection: ClearHeightDirection = 0; // 默认朝下
|
||||
private clearHeightSelectType: ClearHeightSelectType = 'point'; // 默认选择点
|
||||
|
||||
/**
|
||||
* 测量配置(单位/精度)
|
||||
* 说明:
|
||||
@@ -67,6 +71,11 @@ export class MeasurePanel implements IBimComponent {
|
||||
private clearBtn!: HTMLButtonElement;
|
||||
private settingsBtn!: HTMLButtonElement;
|
||||
|
||||
// 净高模式选项 DOM
|
||||
private modeOptionsEl!: HTMLElement;
|
||||
private directionBtns: Map<ClearHeightDirection, HTMLButtonElement> = new Map();
|
||||
private selectTypeBtns: Map<ClearHeightSelectType, HTMLButtonElement> = new Map();
|
||||
|
||||
// Settings DOM
|
||||
private mainViewEl!: HTMLElement;
|
||||
private settingsViewEl!: HTMLElement;
|
||||
@@ -115,6 +124,7 @@ export class MeasurePanel implements IBimComponent {
|
||||
// 初始渲染状态(按钮显隐、选中态、结果区)
|
||||
this.applyExpandedState();
|
||||
this.applyActiveModeState();
|
||||
this.applyClearHeightOptionsState();
|
||||
this.applyViewState();
|
||||
this.renderResult();
|
||||
|
||||
@@ -233,6 +243,7 @@ export class MeasurePanel implements IBimComponent {
|
||||
if (this.activeMode === mode) return;
|
||||
this.activeMode = mode;
|
||||
this.applyActiveModeState();
|
||||
this.applyClearHeightOptionsState();
|
||||
|
||||
this.mainValueLabelEl.textContent = t(this.getModeValueLabelI18nKey(this.activeMode));
|
||||
|
||||
@@ -422,6 +433,10 @@ export class MeasurePanel implements IBimComponent {
|
||||
toolsBox.appendChild(toggleBox);
|
||||
this.mainViewEl.appendChild(toolsBox);
|
||||
|
||||
// 净高模式选项区(朝向 + 选择对象)
|
||||
this.modeOptionsEl = this.createModeOptionsDom();
|
||||
this.mainViewEl.appendChild(this.modeOptionsEl);
|
||||
|
||||
// 中部:结果区
|
||||
const resultBox = document.createElement('div');
|
||||
resultBox.className = 'bim-measure-result';
|
||||
@@ -593,6 +608,118 @@ export class MeasurePanel implements IBimComponent {
|
||||
return box;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建净高模式选项区 DOM(朝向 + 选择对象)
|
||||
*/
|
||||
private createModeOptionsDom(): HTMLElement {
|
||||
const box = document.createElement('div');
|
||||
box.className = 'bim-measure-mode-options';
|
||||
|
||||
// 朝向单选组
|
||||
const dirGroup = document.createElement('div');
|
||||
dirGroup.className = 'bim-measure-radio-group';
|
||||
const dirLabel = document.createElement('span');
|
||||
dirLabel.className = 'bim-measure-radio-label';
|
||||
dirLabel.dataset.i18nKey = 'measure.clearHeight.direction';
|
||||
const dirItems = document.createElement('div');
|
||||
dirItems.className = 'bim-measure-radio-items';
|
||||
|
||||
const dirDown = this.createRadioItem('measure.clearHeight.directionDown', () => {
|
||||
this.setClearHeightDirection(0);
|
||||
});
|
||||
const dirUp = this.createRadioItem('measure.clearHeight.directionUp', () => {
|
||||
this.setClearHeightDirection(1);
|
||||
});
|
||||
this.directionBtns.set(0, dirDown);
|
||||
this.directionBtns.set(1, dirUp);
|
||||
|
||||
dirItems.appendChild(dirDown);
|
||||
dirItems.appendChild(dirUp);
|
||||
dirGroup.appendChild(dirLabel);
|
||||
dirGroup.appendChild(dirItems);
|
||||
box.appendChild(dirGroup);
|
||||
|
||||
// 选择对象单选组
|
||||
const selGroup = document.createElement('div');
|
||||
selGroup.className = 'bim-measure-radio-group';
|
||||
const selLabel = document.createElement('span');
|
||||
selLabel.className = 'bim-measure-radio-label';
|
||||
selLabel.dataset.i18nKey = 'measure.clearHeight.selectType';
|
||||
const selItems = document.createElement('div');
|
||||
selItems.className = 'bim-measure-radio-items';
|
||||
|
||||
const selPoint = this.createRadioItem('measure.clearHeight.selectPoint', () => {
|
||||
this.setClearHeightSelectType('point');
|
||||
});
|
||||
const selElement = this.createRadioItem('measure.clearHeight.selectElement', () => {
|
||||
this.setClearHeightSelectType('element');
|
||||
});
|
||||
this.selectTypeBtns.set('point', selPoint);
|
||||
this.selectTypeBtns.set('element', selElement);
|
||||
|
||||
selItems.appendChild(selPoint);
|
||||
selItems.appendChild(selElement);
|
||||
selGroup.appendChild(selLabel);
|
||||
selGroup.appendChild(selItems);
|
||||
box.appendChild(selGroup);
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
private createRadioItem(i18nKey: string, onClick: () => void): HTMLButtonElement {
|
||||
const btn = document.createElement('button');
|
||||
btn.type = 'button';
|
||||
btn.className = 'bim-measure-radio-item';
|
||||
btn.dataset.i18nKey = i18nKey;
|
||||
btn.textContent = t(i18nKey);
|
||||
btn.addEventListener('click', onClick);
|
||||
return btn;
|
||||
}
|
||||
|
||||
private setClearHeightDirection(direction: ClearHeightDirection): void {
|
||||
if (this.clearHeightDirection === direction) return;
|
||||
this.clearHeightDirection = direction;
|
||||
this.applyClearHeightOptionsState();
|
||||
this.options.onClearHeightDirectionChange?.(direction);
|
||||
}
|
||||
|
||||
private setClearHeightSelectType(selectType: ClearHeightSelectType): void {
|
||||
if (this.clearHeightSelectType === selectType) return;
|
||||
this.clearHeightSelectType = selectType;
|
||||
this.applyClearHeightOptionsState();
|
||||
this.options.onClearHeightSelectTypeChange?.(selectType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用净高选项状态(显隐 + 选中态)
|
||||
*/
|
||||
private applyClearHeightOptionsState(): void {
|
||||
// 显隐
|
||||
if (this.activeMode === 'clearHeight') {
|
||||
this.modeOptionsEl.classList.add('is-visible');
|
||||
} else {
|
||||
this.modeOptionsEl.classList.remove('is-visible');
|
||||
}
|
||||
|
||||
// 朝向按钮选中态
|
||||
for (const [dir, btn] of this.directionBtns.entries()) {
|
||||
if (dir === this.clearHeightDirection) {
|
||||
btn.classList.add('is-active');
|
||||
} else {
|
||||
btn.classList.remove('is-active');
|
||||
}
|
||||
}
|
||||
|
||||
// 选择对象按钮选中态
|
||||
for (const [type, btn] of this.selectTypeBtns.entries()) {
|
||||
if (type === this.clearHeightSelectType) {
|
||||
btn.classList.add('is-active');
|
||||
} else {
|
||||
btn.classList.remove('is-active');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private makeOption(unit: MeasureUnit): HTMLOptionElement {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = unit;
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
*/
|
||||
|
||||
// 从通用 types 目录导入 MeasureMode,避免组件间耦合
|
||||
import type { MeasureMode } from '../../types/measure';
|
||||
import type { MeasureMode, ClearHeightDirection, ClearHeightSelectType } from '../../types/measure';
|
||||
// 同时重新导出,保持向后兼容
|
||||
export type { MeasureMode };
|
||||
export type { MeasureMode, ClearHeightDirection, ClearHeightSelectType };
|
||||
|
||||
/**
|
||||
* 距离/标高等“长度类”单位
|
||||
@@ -105,6 +105,18 @@ export interface MeasurePanelOptions {
|
||||
* 说明:用户点击"保存设置"时触发,用于同步到引擎
|
||||
*/
|
||||
onConfigSave?: (config: MeasureConfig) => void;
|
||||
|
||||
/**
|
||||
* 净高朝向变更回调
|
||||
* @param direction 0=朝下,1=朝上
|
||||
*/
|
||||
onClearHeightDirectionChange?: (direction: ClearHeightDirection) => void;
|
||||
|
||||
/**
|
||||
* 净高选择对象变更回调
|
||||
* @param selectType 'point'=选择点,'element'=选择构件
|
||||
*/
|
||||
onClearHeightSelectTypeChange?: (selectType: ClearHeightSelectType) => void;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,10 @@ export class BimRightKey implements IBimComponent {
|
||||
private options?: RightKeyOptions;
|
||||
|
||||
private mouseDownTime: number = 0;
|
||||
private mouseDownX: number = 0;
|
||||
private mouseDownY: number = 0;
|
||||
private readonly CLICK_THRESHOLD: number = 200; // ms
|
||||
private readonly MOVE_THRESHOLD: number = 5; // px
|
||||
|
||||
constructor(options?: RightKeyOptions) {
|
||||
this.options = options;
|
||||
@@ -75,9 +78,11 @@ export class BimRightKey implements IBimComponent {
|
||||
}
|
||||
|
||||
private handleContainerMouseDown = (e: MouseEvent): void => {
|
||||
// 记录右键按下时间 (button 2 是右键)
|
||||
// 记录右键按下时间和位置 (button 2 是右键)
|
||||
if (e.button === 2) {
|
||||
this.mouseDownTime = Date.now();
|
||||
this.mouseDownX = e.clientX;
|
||||
this.mouseDownY = e.clientY;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -91,6 +96,13 @@ export class BimRightKey implements IBimComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查移动距离,如果鼠标移动超过阈值(用户在拖拽旋转模型),则不触发回调
|
||||
const dx = e.clientX - this.mouseDownX;
|
||||
const dy = e.clientY - this.mouseDownY;
|
||||
if (dx * dx + dy * dy > this.MOVE_THRESHOLD * this.MOVE_THRESHOLD) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 触发有效右键回调
|
||||
if (this.options?.onContext) {
|
||||
this.options.onContext(e);
|
||||
|
||||
Reference in New Issue
Block a user