添加测试信息
This commit is contained in:
104
demo/index.html
104
demo/index.html
@@ -5,7 +5,8 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>BIM Engine SDK Demo</title>
|
||||
<script src="../dist/bim-engine-sdk.umd.js"></script>
|
||||
<!-- 从本地 lib 目录加载 SDK 文件 -->
|
||||
<script src="./lib/bim-engine-sdk.umd.js"></script>
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
@@ -157,6 +158,18 @@
|
||||
<button onclick="setCustomTheme()">自定义 (Red)</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 5. 3D 引擎 -->
|
||||
<div class="control-group">
|
||||
<h2>🎮 3D 引擎 (Engine3D)</h2>
|
||||
<div class="btn-container">
|
||||
<button class="primary" onclick="initEngine3D()">初始化引擎</button>
|
||||
<button class="primary" onclick="loadModel()">加载模型</button>
|
||||
</div>
|
||||
<div style="margin-top: 10px; font-size: 0.85rem; color: #666;">
|
||||
<div>状态: <span id="engine-status">未初始化</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- 右侧主区域 -->
|
||||
@@ -170,6 +183,7 @@
|
||||
let isLabelVisible = true;
|
||||
let isLocationVisible = true;
|
||||
let customGroupAdded = false;
|
||||
let engine3DInitialized = false;
|
||||
|
||||
// 初始化引擎
|
||||
window.onload = () => {
|
||||
@@ -177,6 +191,7 @@
|
||||
const Engine = window.LyzBimEngineSDK.BimEngine;
|
||||
try {
|
||||
engine = new Engine('app', { locale: 'zh-CN' });
|
||||
// initEngine3D();
|
||||
console.log('Engine initialized:', engine);
|
||||
} catch (err) {
|
||||
console.error('Init failed:', err);
|
||||
@@ -301,6 +316,93 @@
|
||||
componentActive: '#e57373'
|
||||
});
|
||||
}
|
||||
|
||||
// --- 3D 引擎操作 ---
|
||||
/**
|
||||
* 初始化 3D 引擎
|
||||
*/
|
||||
function initEngine3D() {
|
||||
if (!engine || !engine.engine) {
|
||||
alert('引擎未创建,请先等待页面加载完成');
|
||||
return;
|
||||
}
|
||||
|
||||
if (engine.engine.isInitialized()) {
|
||||
alert('3D 引擎已经初始化过了');
|
||||
updateEngineStatus('已初始化');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 初始化引擎,使用默认配置
|
||||
const success = engine.initEngine({
|
||||
backgroundColor: 0x333333, // 深色背景
|
||||
version: 'v1', // WebGL 版本
|
||||
showStats: true, // 显示性能统计
|
||||
showViewCube: true // 显示视图立方体
|
||||
});
|
||||
|
||||
if (success) {
|
||||
engine3DInitialized = true;
|
||||
updateEngineStatus('已初始化');
|
||||
console.log('✅ 3D 引擎初始化成功');
|
||||
} else {
|
||||
updateEngineStatus('初始化失败');
|
||||
console.error('❌ 3D 引擎初始化失败');
|
||||
}
|
||||
} catch (error) {
|
||||
updateEngineStatus('初始化错误');
|
||||
console.error('❌ 3D 引擎初始化错误:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载 3D 模型
|
||||
*/
|
||||
function loadModel() {
|
||||
if (!engine || !engine.engine) {
|
||||
alert('引擎未创建,请先等待页面加载完成');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!engine.engine.isInitialized()) {
|
||||
alert('请先初始化 3D 引擎!');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 加载模型文件(从 model 目录)
|
||||
const modelUrl = './model/gujianzhu.glb';
|
||||
|
||||
engine.engine.loadModel(modelUrl, {
|
||||
position: [0, 0, 0], // 初始位置
|
||||
rotation: [0, 0, 0], // 初始旋转
|
||||
scale: [1, 1, 1] // 初始缩放
|
||||
});
|
||||
|
||||
console.log('✅ 模型加载请求已发送:', modelUrl);
|
||||
} catch (error) {
|
||||
console.error('❌ 模型加载错误:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新引擎状态显示
|
||||
*/
|
||||
function updateEngineStatus(status) {
|
||||
const statusEl = document.getElementById('engine-status');
|
||||
if (statusEl) {
|
||||
statusEl.textContent = status;
|
||||
// 根据状态设置颜色
|
||||
if (status === '已初始化') {
|
||||
statusEl.style.color = '#28a745';
|
||||
} else if (status === '初始化失败' || status === '初始化错误') {
|
||||
statusEl.style.color = '#dc3545';
|
||||
} else {
|
||||
statusEl.style.color = '#666';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
||||
33259
dist/bim-engine-sdk.es.js
vendored
33259
dist/bim-engine-sdk.es.js
vendored
File diff suppressed because one or more lines are too long
2
dist/bim-engine-sdk.es.js.map
vendored
2
dist/bim-engine-sdk.es.js.map
vendored
File diff suppressed because one or more lines are too long
4892
dist/bim-engine-sdk.umd.js
vendored
4892
dist/bim-engine-sdk.umd.js
vendored
File diff suppressed because one or more lines are too long
2
dist/bim-engine-sdk.umd.js.map
vendored
2
dist/bim-engine-sdk.umd.js.map
vendored
File diff suppressed because one or more lines are too long
99
dist/index.d.ts
vendored
99
dist/index.d.ts
vendored
@@ -69,6 +69,7 @@ declare class BimDialog implements IBimComponent {
|
||||
private _isInitialized;
|
||||
private unsubscribeTheme;
|
||||
private unsubscribeLocale;
|
||||
private rafId;
|
||||
/**
|
||||
* 构造函数
|
||||
* @param options 弹窗配置选项
|
||||
@@ -97,11 +98,11 @@ declare class BimDialog implements IBimComponent {
|
||||
*/
|
||||
private initPosition;
|
||||
/**
|
||||
* 初始化拖拽功能
|
||||
* 初始化拖拽功能 (性能优化 + 解决粘手)
|
||||
*/
|
||||
private initDrag;
|
||||
/**
|
||||
* 初始化缩放功能
|
||||
* 初始化缩放功能 (性能优化 + 解决粘手)
|
||||
*/
|
||||
private initResize;
|
||||
/**
|
||||
@@ -126,6 +127,7 @@ export declare class BimEngine {
|
||||
toolbar: ToolbarManager | null;
|
||||
buttonGroup: ButtonGroupManager | null;
|
||||
dialog: DialogManager | null;
|
||||
engine: EngineManager | null;
|
||||
get localeManager(): LocaleManager;
|
||||
get themeManager(): ThemeManager;
|
||||
constructor(container: HTMLElement | string, options?: {
|
||||
@@ -137,7 +139,12 @@ export declare class BimEngine {
|
||||
setTheme(theme: 'dark' | 'light'): void;
|
||||
setCustomTheme(theme: ThemeConfig): void;
|
||||
private init;
|
||||
private createTopLeftGroup;
|
||||
/**
|
||||
* 初始化 3D 引擎组件
|
||||
* 注意:只初始化引擎,不加载模型。模型加载在使用层(如 demo.html)进行
|
||||
* @param options 引擎配置选项(可选)
|
||||
*/
|
||||
initEngine(options?: Omit<EngineOptions, 'container'>): boolean;
|
||||
private updateTheme;
|
||||
destroy(): void;
|
||||
}
|
||||
@@ -221,6 +228,18 @@ export declare interface ClickPayload {
|
||||
isActive?: boolean;
|
||||
}
|
||||
|
||||
export declare function createEngine(r) {
|
||||
const e = r.version || "v1";
|
||||
switch (e) {
|
||||
case "v2":
|
||||
return new Uc(r);
|
||||
case "v1":
|
||||
return new L_(r);
|
||||
:
|
||||
return console.warn(`Version '${e}' not found. Falling back to v2.`), new Uc(r);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 弹窗颜色配置
|
||||
*/
|
||||
@@ -311,6 +330,65 @@ declare type DialogPosition = 'center' | 'top-left' | 'top-center' | 'top-right'
|
||||
y: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* 3D 引擎管理器
|
||||
* 负责连接 Engine 组件和 BimEngine,向外部暴露简化的 API
|
||||
* 采用延迟初始化模式,用户需主动调用 initialize() 方法
|
||||
*/
|
||||
declare class EngineManager {
|
||||
/** 3D 引擎挂载的父容器 */
|
||||
private container;
|
||||
/** 3D 引擎组件实例 */
|
||||
private engine;
|
||||
/**
|
||||
* 构造函数
|
||||
* @param container 3D 引擎挂载的目标容器
|
||||
*/
|
||||
constructor(container: HTMLElement);
|
||||
/**
|
||||
* 初始化 3D 引擎
|
||||
* @param options 引擎配置选项(可选,如果不提供则使用默认配置)
|
||||
* @returns 是否初始化成功
|
||||
*/
|
||||
initialize(options?: Omit<EngineOptions, 'container'>): boolean;
|
||||
/**
|
||||
* 检查 3D 引擎是否已初始化
|
||||
*/
|
||||
isInitialized(): boolean;
|
||||
/**
|
||||
* 加载 3D 模型
|
||||
* @param url 模型文件 URL
|
||||
* @param options 加载选项(位置、旋转、缩放)
|
||||
*/
|
||||
loadModel(url: string, options?: ModelLoadOptions): void;
|
||||
/**
|
||||
* 获取原始 3D 引擎实例
|
||||
* 用于直接调用第三方引擎的其他 API
|
||||
*/
|
||||
getEngine(): any;
|
||||
/**
|
||||
* 销毁 3D 引擎实例
|
||||
*/
|
||||
destroy(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 引擎配置选项
|
||||
* 用于 Engine 组件的初始化
|
||||
*/
|
||||
export declare interface EngineOptions {
|
||||
/** 容器元素 */
|
||||
container: HTMLElement;
|
||||
/** 背景颜色(十六进制数字,如 0x333333) */
|
||||
backgroundColor?: number;
|
||||
/** WebGL 版本 */
|
||||
version?: 'v1' | 'v2';
|
||||
/** 是否显示性能统计 */
|
||||
showStats?: boolean;
|
||||
/** 是否显示视图立方体 */
|
||||
showViewCube?: boolean;
|
||||
}
|
||||
|
||||
/** 二级菜单展开方向 */
|
||||
declare type ExpandDirection = 'up' | 'down' | 'left' | 'right';
|
||||
|
||||
@@ -384,6 +462,21 @@ declare class LocaleManager {
|
||||
*/
|
||||
declare type LocaleType = 'zh-CN' | 'en-US';
|
||||
|
||||
/**
|
||||
* 模型加载选项
|
||||
* 用于配置模型的位置、旋转和缩放
|
||||
*/
|
||||
export declare interface ModelLoadOptions {
|
||||
/** 模型初始位置 [x, y, z] */
|
||||
position?: [number, number, number];
|
||||
/** 模型初始旋转 [x, y, z](弧度) */
|
||||
rotation?: [number, number, number];
|
||||
/** 模型初始缩放 [x, y, z] */
|
||||
scale?: [number, number, number];
|
||||
/** 模型 ID(可选,如果不提供则自动生成) */
|
||||
id?: string;
|
||||
}
|
||||
|
||||
export declare interface OptButton extends ButtonConfig {
|
||||
children?: OptButton[];
|
||||
}
|
||||
|
||||
@@ -17,7 +17,10 @@
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build"
|
||||
"build": "tsc && vite build",
|
||||
"dev:all": "./dev.sh",
|
||||
"dev:demo": "cd demo && npm run copy-sdk && npm run dev",
|
||||
"dev:demo-vue": "cd demo-vue && npm run copy-sdk && npm run dev"
|
||||
},
|
||||
"keywords": [
|
||||
"bim",
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
.bim-engine-wrapper {
|
||||
position: relative;
|
||||
/* 添加相对定位作为参照物 */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-family: sans-serif;
|
||||
color: #333;
|
||||
padding: 20px;
|
||||
background-color: #e16969;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e0e0e0;
|
||||
color: #bf1d1d;
|
||||
box-sizing: border-box;
|
||||
/* 确保 padding 不会撑大容器 */
|
||||
overflow: hidden;
|
||||
/* 防止内容溢出 */
|
||||
}
|
||||
|
||||
|
||||
/* ... (中间代码不变) ... */
|
||||
|
||||
/* 操作按钮组容器 */
|
||||
|
||||
@@ -2,11 +2,17 @@ import './bim-engine.css';
|
||||
import { ToolbarManager } from './managers/toolbar-manager';
|
||||
import { ButtonGroupManager } from './managers/button-group-manager';
|
||||
import { DialogManager } from './managers/dialog-manager';
|
||||
import { EngineManager } from './managers/engine-manager';
|
||||
import type { EngineOptions, ModelLoadOptions } from './components/engine';
|
||||
import { localeManager } from './services/locale';
|
||||
import { themeManager } from './services/theme';
|
||||
import type { LocaleType } from './locales/types';
|
||||
import type { ThemeType, ThemeConfig } from './themes/types';
|
||||
|
||||
export type { EngineOptions, ModelLoadOptions };
|
||||
|
||||
|
||||
|
||||
export class BimEngine {
|
||||
private container: HTMLElement;
|
||||
private wrapper: HTMLElement | null = null;
|
||||
@@ -15,11 +21,18 @@ export class BimEngine {
|
||||
public toolbar: ToolbarManager | null = null; // 底部专用
|
||||
public buttonGroup: ButtonGroupManager | null = null; // 通用
|
||||
public dialog: DialogManager | null = null;
|
||||
public engine: EngineManager | null = null; // 3D 引擎管理器
|
||||
|
||||
public get localeManager() { return localeManager; }
|
||||
public get themeManager() { return themeManager; }
|
||||
|
||||
constructor(container: HTMLElement | string, options?: { locale?: LocaleType; theme?: ThemeType }) {
|
||||
constructor(
|
||||
container: HTMLElement | string,
|
||||
options?: {
|
||||
locale?: LocaleType;
|
||||
theme?: ThemeType;
|
||||
}
|
||||
) {
|
||||
const el = typeof container === 'string' ? document.getElementById(container) : container;
|
||||
if (!el) throw new Error('Container not found');
|
||||
this.container = el;
|
||||
@@ -47,13 +60,14 @@ export class BimEngine {
|
||||
this.wrapper.className = 'bim-engine-wrapper';
|
||||
this.container.appendChild(this.wrapper);
|
||||
|
||||
// 初始化管理器
|
||||
// 创建 3D 引擎管理器
|
||||
this.engine = new EngineManager(this.wrapper);
|
||||
|
||||
// 初始化其他管理器
|
||||
this.dialog = new DialogManager(this.wrapper);
|
||||
this.toolbar = new ToolbarManager(this.wrapper);
|
||||
this.buttonGroup = new ButtonGroupManager(this.wrapper);
|
||||
|
||||
// --- 创建左上角按钮组 (需求 1 & 2) ---
|
||||
this.createTopLeftGroup();
|
||||
|
||||
// 初始主题
|
||||
this.updateTheme(themeManager.getTheme());
|
||||
@@ -69,34 +83,23 @@ export class BimEngine {
|
||||
});
|
||||
}
|
||||
|
||||
private createTopLeftGroup() {
|
||||
if (!this.buttonGroup) return;
|
||||
|
||||
this.topLeftGroup = this.buttonGroup.create({
|
||||
position: 'top-left',
|
||||
direction: 'column',
|
||||
align: 'vertical',
|
||||
backgroundColor: '#ff00ff', // 自定义背景色,不会被主题覆盖
|
||||
showLabel: false
|
||||
});
|
||||
|
||||
this.topLeftGroup.addGroup('main');
|
||||
this.topLeftGroup.addButton({
|
||||
id: 'menu-btn',
|
||||
groupId: 'main',
|
||||
type: 'button',
|
||||
label: 'Menu', // 应该用 translation key
|
||||
icon: '<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg>',
|
||||
onClick: () => {
|
||||
alert("点击按钮")
|
||||
/**
|
||||
* 初始化 3D 引擎组件
|
||||
* 注意:只初始化引擎,不加载模型。模型加载在使用层(如 demo.html)进行
|
||||
* @param options 引擎配置选项(可选)
|
||||
*/
|
||||
public initEngine(options?: Omit<EngineOptions, 'container'>): boolean {
|
||||
if (!this.engine) {
|
||||
console.error('[BimEngine] Engine manager not available.');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// 手动 render 一次以显示
|
||||
this.topLeftGroup.render();
|
||||
// 调用 manager 的 initialize 方法初始化引擎
|
||||
return this.engine.initialize(options);
|
||||
}
|
||||
|
||||
private updateTheme(theme: ThemeConfig) {
|
||||
|
||||
if (this.wrapper) {
|
||||
this.wrapper.style.backgroundColor = theme.background;
|
||||
this.wrapper.style.color = theme.textPrimary;
|
||||
@@ -106,6 +109,7 @@ export class BimEngine {
|
||||
public destroy() {
|
||||
this.toolbar?.destroy();
|
||||
this.buttonGroup?.destroy();
|
||||
this.engine?.destroy();
|
||||
this.dialog = null;
|
||||
this.container.innerHTML = '';
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
background-color: var(--bim-btn-group-section-bg, rgba(17, 17, 17, 0.88));
|
||||
border-radius: 6px;
|
||||
padding: 4px;
|
||||
/* 添加阴影效果,增强视觉层次感 */
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3), 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.bim-btn-group-root.dir-row .bim-btn-group-section {
|
||||
|
||||
@@ -14,11 +14,12 @@
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 1000;
|
||||
z-index: 10001; /* 提高 z-index,确保在第三方 SDK (10000) 之上 */
|
||||
color: var(--bim-dialog-title-color);
|
||||
overflow: hidden;
|
||||
min-width: 200px;
|
||||
min-height: 100px;
|
||||
pointer-events: auto; /* 确保弹窗可以接收事件 */
|
||||
}
|
||||
|
||||
.bim-dialog-header {
|
||||
|
||||
@@ -20,6 +20,9 @@ export class BimDialog implements IBimComponent {
|
||||
private unsubscribeTheme: (() => void) | null = null;
|
||||
private unsubscribeLocale: (() => void) | null = null;
|
||||
|
||||
// 性能优化:用于存储 requestAnimationFrame 的 ID
|
||||
private rafId: number | null = null;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param options 弹窗配置选项
|
||||
@@ -116,7 +119,7 @@ export class BimDialog implements IBimComponent {
|
||||
|
||||
if (this.options.id) el.id = this.options.id;
|
||||
|
||||
// 应用颜色配置到 CSS 变量 (局部作用域)
|
||||
// 应用颜色配置到 CSS 变量
|
||||
const style = el.style;
|
||||
if (this.options.backgroundColor) style.setProperty('--bim-dialog-bg', this.options.backgroundColor);
|
||||
if (this.options.headerBackgroundColor) style.setProperty('--bim-dialog-header-bg', this.options.headerBackgroundColor);
|
||||
@@ -139,7 +142,10 @@ export class BimDialog implements IBimComponent {
|
||||
const closeBtn = document.createElement('span');
|
||||
closeBtn.className = 'bim-dialog-close';
|
||||
closeBtn.innerHTML = '×';
|
||||
closeBtn.onclick = () => this.close();
|
||||
// 修复 TS 报错:去掉未使用的参数 e
|
||||
closeBtn.onclick = () => {
|
||||
this.close();
|
||||
};
|
||||
|
||||
header.appendChild(title);
|
||||
header.appendChild(closeBtn);
|
||||
@@ -163,6 +169,26 @@ export class BimDialog implements IBimComponent {
|
||||
el.appendChild(resizeHandle);
|
||||
}
|
||||
|
||||
// ==================== 事件拦截核心逻辑 ====================
|
||||
// 定义阻断逻辑:只阻止冒泡,不阻止捕获,也不阻止默认行为(除非显式阻止)
|
||||
const stopPropagation = (e: Event) => {
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
// 现代浏览器和 3D 引擎 (Three.js/Cesium) 交互事件
|
||||
const events = [
|
||||
'click', 'dblclick', 'contextmenu', 'wheel',
|
||||
'mousedown', 'mouseup', 'mousemove',
|
||||
'touchstart', 'touchend', 'touchmove',
|
||||
'pointerdown', 'pointerup', 'pointermove', 'pointerenter', 'pointerleave', 'pointerover', 'pointerout'
|
||||
];
|
||||
|
||||
// 绑定监听器 (默认冒泡阶段)
|
||||
// 这样内部元素(如关闭按钮)先触发,然后冒泡到这里被拦截,不再传给地图
|
||||
events.forEach(eventType => {
|
||||
el.addEventListener(eventType, stopPropagation, { passive: false });
|
||||
});
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
@@ -183,7 +209,6 @@ export class BimDialog implements IBimComponent {
|
||||
*/
|
||||
private initPosition() {
|
||||
const pos = this.options.position;
|
||||
|
||||
const elRect = this.element.getBoundingClientRect();
|
||||
|
||||
// 计算相对父容器的定位
|
||||
@@ -218,7 +243,6 @@ export class BimDialog implements IBimComponent {
|
||||
}
|
||||
}
|
||||
|
||||
// 简单的边界检查,防止初始位置溢出
|
||||
left = Math.max(0, Math.min(left, pW - elW));
|
||||
top = Math.max(0, Math.min(top, pH - elH));
|
||||
|
||||
@@ -227,53 +251,81 @@ export class BimDialog implements IBimComponent {
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化拖拽功能
|
||||
* 初始化拖拽功能 (性能优化 + 解决粘手)
|
||||
*/
|
||||
private initDrag() {
|
||||
let startX = 0;
|
||||
let startY = 0;
|
||||
let startLeft = 0;
|
||||
let startTop = 0;
|
||||
let containerW = 0;
|
||||
let containerH = 0;
|
||||
let elW = 0;
|
||||
let elH = 0;
|
||||
|
||||
const onMouseDown = (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.preventDefault(); // 阻止默认行为(如选中文本),非常重要,防止卡顿
|
||||
e.stopPropagation(); // 阻止传递给 Three.js
|
||||
|
||||
startX = e.clientX;
|
||||
startY = e.clientY;
|
||||
startLeft = this.element.offsetLeft;
|
||||
startTop = this.element.offsetTop;
|
||||
|
||||
document.addEventListener('mousemove', onMouseMove);
|
||||
document.addEventListener('mouseup', onMouseUp);
|
||||
// 缓存尺寸,减少 reflow
|
||||
containerW = this.container.clientWidth;
|
||||
containerH = this.container.clientHeight;
|
||||
elW = this.element.offsetWidth;
|
||||
elH = this.element.offsetHeight;
|
||||
|
||||
// 关键:使用 capture: true
|
||||
// 确保即使 createDom 阻止了冒泡,document 也能在捕获阶段收到事件
|
||||
document.addEventListener('mousemove', onMouseMove, { capture: true });
|
||||
document.addEventListener('mouseup', onMouseUp, { capture: true });
|
||||
};
|
||||
|
||||
const onMouseMove = (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
// 节流优化:使用 requestAnimationFrame
|
||||
if (this.rafId) return;
|
||||
|
||||
this.rafId = requestAnimationFrame(() => {
|
||||
const dx = e.clientX - startX;
|
||||
const dy = e.clientY - startY;
|
||||
|
||||
let newLeft = startLeft + dx;
|
||||
let newTop = startTop + dy;
|
||||
|
||||
// 边界限制,防止拖出容器
|
||||
const maxLeft = this.container.clientWidth - this.element.offsetWidth;
|
||||
const maxTop = this.container.clientHeight - this.element.offsetHeight;
|
||||
const maxLeft = containerW - elW;
|
||||
const maxTop = containerH - elH;
|
||||
|
||||
newLeft = Math.max(0, Math.min(newLeft, maxLeft));
|
||||
newTop = Math.max(0, Math.min(newTop, maxTop));
|
||||
|
||||
this.element.style.left = `${newLeft}px`;
|
||||
this.element.style.top = `${newTop}px`;
|
||||
|
||||
this.rafId = null;
|
||||
});
|
||||
};
|
||||
|
||||
const onMouseUp = () => {
|
||||
document.removeEventListener('mousemove', onMouseMove);
|
||||
document.removeEventListener('mouseup', onMouseUp);
|
||||
if (this.rafId) {
|
||||
cancelAnimationFrame(this.rafId);
|
||||
this.rafId = null;
|
||||
}
|
||||
// 移除监听
|
||||
document.removeEventListener('mousemove', onMouseMove, { capture: true });
|
||||
document.removeEventListener('mouseup', onMouseUp, { capture: true });
|
||||
};
|
||||
|
||||
this.header.addEventListener('mousedown', onMouseDown);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化缩放功能
|
||||
* 初始化缩放功能 (性能优化 + 解决粘手)
|
||||
*/
|
||||
private initResize() {
|
||||
const handle = this.element.querySelector('.bim-dialog-resize-handle') as HTMLElement;
|
||||
@@ -292,11 +344,18 @@ export class BimDialog implements IBimComponent {
|
||||
startW = this.element.offsetWidth;
|
||||
startH = this.element.offsetHeight;
|
||||
|
||||
document.addEventListener('mousemove', onMouseMove);
|
||||
document.addEventListener('mouseup', onMouseUp);
|
||||
// 关键:使用 capture: true
|
||||
document.addEventListener('mousemove', onMouseMove, { capture: true });
|
||||
document.addEventListener('mouseup', onMouseUp, { capture: true });
|
||||
};
|
||||
|
||||
const onMouseMove = (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
if (this.rafId) return;
|
||||
|
||||
this.rafId = requestAnimationFrame(() => {
|
||||
const dx = e.clientX - startX;
|
||||
const dy = e.clientY - startY;
|
||||
|
||||
@@ -305,11 +364,18 @@ export class BimDialog implements IBimComponent {
|
||||
|
||||
this.element.style.width = `${newW}px`;
|
||||
this.element.style.height = `${newH}px`;
|
||||
|
||||
this.rafId = null;
|
||||
});
|
||||
};
|
||||
|
||||
const onMouseUp = () => {
|
||||
document.removeEventListener('mousemove', onMouseMove);
|
||||
document.removeEventListener('mouseup', onMouseUp);
|
||||
if (this.rafId) {
|
||||
cancelAnimationFrame(this.rafId);
|
||||
this.rafId = null;
|
||||
}
|
||||
document.removeEventListener('mousemove', onMouseMove, { capture: true });
|
||||
document.removeEventListener('mouseup', onMouseUp, { capture: true });
|
||||
};
|
||||
|
||||
handle.addEventListener('mousedown', onMouseDown);
|
||||
@@ -333,6 +399,13 @@ export class BimDialog implements IBimComponent {
|
||||
*/
|
||||
public close() {
|
||||
if (this._isDestroyed) return;
|
||||
|
||||
// 清理可能存在的动画帧,防止报错
|
||||
if (this.rafId) {
|
||||
cancelAnimationFrame(this.rafId);
|
||||
this.rafId = null;
|
||||
}
|
||||
|
||||
if (this.unsubscribeTheme) {
|
||||
this.unsubscribeTheme();
|
||||
this.unsubscribeTheme = null;
|
||||
|
||||
34
src/index.ts
34
src/index.ts
@@ -9,3 +9,37 @@ export type { OptButton, ButtonGroup, ButtonGroupOptions, ClickPayload } from '.
|
||||
|
||||
// 导出主引擎类
|
||||
export { BimEngine };
|
||||
|
||||
// 导出 3D 引擎相关类型
|
||||
export type { EngineOptions, ModelLoadOptions } from './components/engine';
|
||||
|
||||
// 导出 createEngine 函数(从第三方 SDK 重新导出)
|
||||
// 注意:createEngine 的实际实现来自 bim-engine-sdk.es.js
|
||||
//
|
||||
// 使用方式:
|
||||
// 1. 直接从 SDK 文件导入(推荐,如 Vue 示例):
|
||||
// import { createEngine } from '/engine/bim-engine-sdk.es.js';
|
||||
//
|
||||
// 2. 从主入口导入(如果构建配置支持):
|
||||
// import { createEngine } from 'bim-engine-sdk';
|
||||
//
|
||||
// 示例:
|
||||
// ```javascript
|
||||
// const engine = createEngine({
|
||||
// containerId: 'vue2-container',
|
||||
// backgroundColor: 0x333333,
|
||||
// version: 'v1',
|
||||
// showStats: true,
|
||||
// showViewCube: true
|
||||
// });
|
||||
//
|
||||
// engine.loader.loadModel(url, {
|
||||
// position: [10, -5, 0],
|
||||
// rotation: [0, 0, 0],
|
||||
// scale: [1, 1, 1]
|
||||
// });
|
||||
// ```
|
||||
|
||||
// 重新导出 createEngine(从 SDK 文件)
|
||||
// 注意:如果直接导入失败,用户应该直接从 bim-engine-sdk.es.js 文件导入
|
||||
export { createEngine } from './bim-engine-sdk.es.js';
|
||||
@@ -3,25 +3,30 @@
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"lib": [
|
||||
"ES2020",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
|
||||
"allowJs": true,
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
|
||||
/* Library specifics */
|
||||
"declaration": true,
|
||||
"emitDeclarationOnly": true
|
||||
},
|
||||
"include": ["src", "playground"]
|
||||
"include": [
|
||||
"src",
|
||||
"playground"
|
||||
]
|
||||
}
|
||||
@@ -9,10 +9,21 @@ export default defineConfig(({ command }) => {
|
||||
// 移除 Vue 插件
|
||||
dts({
|
||||
include: ['src'],
|
||||
rollupTypes: true
|
||||
exclude: [
|
||||
'src/**/*.es.js',
|
||||
'src/bim-engine-sdk.es.js',
|
||||
'**/*.es.js'
|
||||
], // 排除第三方 SDK 文件,避免类型分析错误
|
||||
rollupTypes: true,
|
||||
logLevel: 'warn', // 只显示警告和错误
|
||||
}),
|
||||
cssInjectedByJs()
|
||||
],
|
||||
// 开发服务器配置
|
||||
server: {
|
||||
port: 3000,
|
||||
open: '/demo/index.html', // 自动打开 demo 页面
|
||||
},
|
||||
build: {
|
||||
lib: {
|
||||
entry: resolve(__dirname, 'src/index.ts'),
|
||||
|
||||
Reference in New Issue
Block a user