@ridp/threejs 1.4.2 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -352,9 +352,13 @@ threeJsIns.setView(model, ViewType.ISO, { scale: 1.0, animate: true });
352
352
 
353
353
  ### useGLTFLoader()
354
354
 
355
- GLTF 模型加载器,支持 IndexedDB 缓存。
355
+ GLTF 模型加载器,支持 IndexedDB 缓存、内存缓存、重试机制和调试模式。
356
356
 
357
357
  ```javascript
358
+ const loader = useGLTFLoader({
359
+ debug: false // 是否开启调试日志(默认: false)
360
+ });
361
+
358
362
  const {
359
363
  // 核心加载方法
360
364
  load, // 基础加载方法
@@ -366,30 +370,61 @@ const {
366
370
  loadBatch, // 批量加载模型
367
371
  loadBatchSequential, // 顺序批量加载
368
372
 
369
- // 缓存管理
370
- clearCache, // 清空缓存
373
+ // IndexedDB 缓存管理
374
+ clearCache, // 清空 IndexedDB 缓存
371
375
  invalidateCache, // 使缓存失效
372
376
  getCacheStats, // 获取缓存统计
373
377
  logCacheReport, // 输出缓存性能报告
378
+ getCache, // 获取 IDBCache 实例
379
+ resetCacheStats, // 重置缓存统计
380
+
381
+ // 内存缓存管理 (v1.4.2+)
382
+ clearMemoryCache, // 清空内存缓存
383
+ getMemoryCacheInfo, // 获取内存缓存统计
384
+ deleteMemoryCache, // 删除指定模型的内存缓存
374
385
 
375
386
  // 性能监控
376
387
  cacheMonitor // 缓存监控器实例
377
- } = useGLTFLoader();
388
+ } = loader;
389
+ ```
390
+
391
+ **新增功能 (v1.4.2):**
392
+
393
+ 1. **内存缓存机制**: 自动缓存已解析的 3D 模型对象,避免重复解析
394
+ 2. **调试模式控制**: 通过初始化参数统一控制所有日志输出
395
+
396
+ #### 初始化配置
397
+
398
+ ```javascript
399
+ // 生产环境 - 默认静默
400
+ const loader = useGLTFLoader();
401
+
402
+ // 开发环境 - 开启调试日志
403
+ const loader = useGLTFLoader({
404
+ debug: true
405
+ });
406
+
407
+ // 所有操作都会输出详细日志
408
+ const model = await loader.asyncFetch('/models/car.glb', '1.0.0');
409
+ // 输出: [ asyncFetch ] ====> 缓存未命中
410
+ // [ fetchArrayBuffer ] 加载模型耗时: 150ms
411
+ // [ 解析模型耗时 ]: 80ms
412
+ // [ 内存缓存 ] 存储模型 /models/car.glb (version: 1.0.0)
378
413
  ```
379
414
 
380
415
  **常用方法:**
381
416
 
382
417
  ##### asyncFetch()
383
418
 
384
- 推荐的模型加载方法,集成缓存、重试、性能监控和模型优化。
419
+ 推荐的模型加载方法,集成 IndexedDB 缓存、内存缓存、重试机制、性能监控和模型优化。
385
420
 
386
421
  ```javascript
387
- const [err, model] = await asyncFetch(
422
+ const model = await asyncFetch(
388
423
  url: string, // 模型 URL
389
424
  version?: string, // 模型版本(用于缓存失效)
425
+ onProgress?: (percent: number) => void, // 进度回调
390
426
  options?: {
391
- // 进度和重试
392
- onProgress?: (progress: ProgressEvent) => void,
427
+ // 重试配置
393
428
  maxRetries?: number, // 最大重试次数(默认: 3)
394
429
 
395
430
  // 模型优化选项
@@ -399,35 +434,40 @@ const [err, model] = await asyncFetch(
399
434
  simplifyOptions?: {
400
435
  minFaceCount?: number, // 最小面数阈值,低于此值不简化(默认: 100)
401
436
  preserveUVs?: boolean // 是否保留UV坐标(默认: true)
402
- }
437
+ },
438
+
439
+ // 缓存控制
440
+ useMemoryCache?: boolean // 是否使用内存缓存(默认: true, v1.4.2+)
403
441
  }
404
- ): Promise<[Error | null, THREE.Object3D | null]>
442
+ ): Promise<THREE.Object3D | null>
405
443
  ```
406
444
 
445
+ **缓存层级 (v1.4.2+):**
446
+
447
+ 1. **内存缓存** (最快) - 已解析的 3D 对象,仅需克隆(~2ms)
448
+ 2. **IndexedDB 缓存** (快) - ArrayBuffer 数据,需要解析(~200ms)
449
+ 3. **网络加载** (慢) - 完整下载 + 解析(~2s)
450
+
407
451
  **示例:**
408
452
  ```javascript
409
453
  // 基础用法
410
- const [err, model] = await asyncFetch('/models/car.glb', '1.0.0');
454
+ const model = await asyncFetch('/models/car.glb', '1.0.0');
411
455
  if (model) {
412
456
  scene.add(model);
413
457
  }
414
458
 
415
459
  // 带进度回调
416
- const [err, model] = await asyncFetch('/models/car.glb', '1.0.0', {
417
- onProgress: (progress) => {
418
- const percent = (progress.loaded / progress.total * 100).toFixed(2);
419
- console.log(`加载进度: ${percent}%`);
420
- },
421
- maxRetries: 5
460
+ const model = await asyncFetch('/models/car.glb', '1.0.0', (percent) => {
461
+ console.log(`加载进度: ${percent}%`);
422
462
  });
423
463
 
424
464
  // 启用材质优化
425
- const [err, model] = await asyncFetch('/models/car.glb', '1.0.0', {
465
+ const model = await asyncFetch('/models/car.glb', '1.0.0', null, {
426
466
  optimizeMaterials: true // 自动合并相同材质
427
467
  });
428
468
 
429
469
  // 启用几何体简化(适合大型模型)
430
- const [err, model] = await asyncFetch('/models/large-scene.glb', '1.0.0', {
470
+ const model = await asyncFetch('/models/large-scene.glb', '1.0.0', null, {
431
471
  simplifyGeometry: true, // 启用简化
432
472
  simplifyRatio: 0.5, // 保留 50% 的面
433
473
  simplifyOptions: {
@@ -436,18 +476,43 @@ const [err, model] = await asyncFetch('/models/large-scene.glb', '1.0.0', {
436
476
  }
437
477
  });
438
478
 
479
+ // 禁用内存缓存
480
+ const model = await asyncFetch('/models/car.glb', '1.0.0', null, {
481
+ useMemoryCache: false // 跳过内存缓存
482
+ });
483
+
439
484
  // 综合优化
440
- const [err, model] = await asyncFetch('/models/complex.glb', '1.0.0', {
441
- optimizeMaterials: true, // 优化材质
442
- simplifyGeometry: true, // 简化几何体
443
- simplifyRatio: 0.7, // 保留 70% 的面
444
- onProgress: (p) => console.log(`加载: ${(p.loaded/p.total*100).toFixed(1)}%`)
485
+ const model = await asyncFetch('/models/complex.glb', '1.0.0', (p) => {
486
+ console.log(`加载: ${p.toFixed(1)}%`);
487
+ }, {
488
+ maxRetries: 5, // 增加重试次数
489
+ optimizeMaterials: true, // 优化材质
490
+ simplifyGeometry: true, // 简化几何体
491
+ simplifyRatio: 0.7, // 保留 70% 的面
492
+ useMemoryCache: true // 使用内存缓存(默认)
445
493
  });
446
494
  ```
447
495
 
496
+ **性能对比:**
497
+
498
+ ```javascript
499
+ // 首次加载
500
+ await asyncFetch('/models/car.glb', '1.0.0');
501
+ // 耗时: ~2s (网络 + 解析 + 优化)
502
+
503
+ // 二次加载 (内存缓存命中)
504
+ await asyncFetch('/models/car.glb', '1.0.0');
505
+ // 耗时: ~2ms (仅克隆对象)
506
+
507
+ // 二次加载 (仅 IndexedDB 命中,内存缓存被清空)
508
+ loader.clearMemoryCache();
509
+ await asyncFetch('/models/car.glb', '1.0.0');
510
+ // 耗时: ~200ms (从 IndexedDB 读取 + 解析)
511
+ ```
512
+
448
513
  ##### logCacheReport()
449
514
 
450
- 输出缓存性能报告到控制台。
515
+ 输出 IndexedDB 缓存性能报告到控制台。
451
516
 
452
517
  ```javascript
453
518
  logCacheReport(): void
@@ -465,6 +530,89 @@ logCacheReport(): void
465
530
  - 缓存节省时间: ~1.5s
466
531
  ```
467
532
 
533
+ ##### 内存缓存管理 API (v1.4.2+)
534
+
535
+ **getMemoryCacheInfo()**
536
+
537
+ 获取内存缓存统计信息。
538
+
539
+ ```javascript
540
+ const info = loader.getMemoryCacheInfo();
541
+
542
+ // 返回值:
543
+ {
544
+ totalPaths: 2, // 缓存的不同模型路径数量
545
+ totalModels: 3, // 缓存的总模型数量
546
+ details: [
547
+ {
548
+ path: '/models/car.glb',
549
+ versions: ['1.0.0', '1.1.0'],
550
+ count: 2
551
+ },
552
+ {
553
+ path: '/models/truck.glb',
554
+ versions: ['1.0.0'],
555
+ count: 1
556
+ }
557
+ ]
558
+ }
559
+ ```
560
+
561
+ **clearMemoryCache()**
562
+
563
+ 清空所有内存缓存,释放已缓存的 3D 模型对象内存。
564
+
565
+ ```javascript
566
+ const count = loader.clearMemoryCache();
567
+ console.log(`释放了 ${count} 个模型`);
568
+
569
+ // 使用场景: 内存不足时主动释放
570
+ if (info.totalModels > 100) {
571
+ loader.clearMemoryCache();
572
+ }
573
+ ```
574
+
575
+ **deleteMemoryCache(path, version?)**
576
+
577
+ 删除指定模型的内存缓存。
578
+
579
+ ```javascript
580
+ // 删除特定版本
581
+ loader.deleteMemoryCache('/models/car.glb', '1.0.0');
582
+
583
+ // 删除所有版本
584
+ loader.deleteMemoryCache('/models/car.glb');
585
+ ```
586
+
587
+ **使用示例:**
588
+
589
+ ```javascript
590
+ import { useGLTFLoader } from '@ridp/threejs/hooks';
591
+
592
+ const loader = useGLTFLoader({ debug: true });
593
+
594
+ // 首次加载 - 从网络加载并缓存
595
+ const model1 = await loader.asyncFetch('/models/car.glb', '1.0.0');
596
+ // [ asyncFetch ] ====> 缓存未命中
597
+ // [ 内存缓存 ] 存储模型 /models/car.glb (version: 1.0.0)
598
+
599
+ // 二次加载 - 从内存缓存获取(极快)
600
+ const model2 = await loader.asyncFetch('/models/car.glb', '1.0.0');
601
+ // [ 内存缓存命中 ] /models/car.glb (version: 1.0.0)
602
+ // [ 内存缓存克隆耗时 ]: 2ms
603
+
604
+ // 查看内存缓存信息
605
+ const info = loader.getMemoryCacheInfo();
606
+ console.log(`缓存了 ${info.totalModels} 个模型`);
607
+
608
+ // 清空内存缓存
609
+ loader.clearMemoryCache();
610
+
611
+ // 再次加载 - 从 IndexedDB 缓存获取
612
+ const model3 = await loader.asyncFetch('/models/car.glb', '1.0.0');
613
+ // [ asyncFetch ] ====> IndexedDB 缓存命中
614
+ ```
615
+
468
616
  ### useRaycaster()
469
617
 
470
618
  射线拾取工具,用于鼠标交互和物体选择。
@@ -1152,7 +1300,61 @@ function captureScreenshot() {
1152
1300
 
1153
1301
  ## 更新日志
1154
1302
 
1155
- ### v1.3.3 (2025-01-06)
1303
+ ### v1.4.2 (2026-01-07)
1304
+
1305
+ **🎉 重大更新:**
1306
+
1307
+ - ✨ **新增内存缓存机制**: 自动缓存已解析的 3D 模型对象,避免重复解析
1308
+ - 首次加载后,二次加载仅需 ~2ms(对象克隆)
1309
+ - 相比完整加载流程,速度提升可达 **100倍以上**
1310
+ - 新增 `clearMemoryCache()` - 清空内存缓存
1311
+ - 新增 `getMemoryCacheInfo()` - 获取内存缓存统计
1312
+ - 新增 `deleteMemoryCache(path, version?)` - 删除指定缓存
1313
+ - 支持 `useMemoryCache` 选项控制是否使用内存缓存
1314
+
1315
+ - ✨ **新增调试模式控制**:
1316
+ - `useGLTFLoader` 现在支持初始化配置 `{ debug: boolean }`
1317
+ - 统一控制所有内部函数的日志输出
1318
+ - 生产环境默认静默,开发环境可开启详细日志
1319
+ - 错误日志始终输出,不受 debug 配置影响
1320
+
1321
+ - 🐛 **修复 Web Worker 在 npm 包中无法加载的问题**:
1322
+ - 使用 `?worker` 语法正确导入 Worker
1323
+ - 配置 `base: './'` 使用相对路径解析
1324
+ - Worker 文件正确打包到 `dist/assets/` 目录
1325
+ - 修复了之前 404 错误和 MIME 类型错误的问题
1326
+
1327
+ **API 变更:**
1328
+
1329
+ ```javascript
1330
+ // 旧 API (v1.4.1 及之前)
1331
+ const loader = useGLTFLoader();
1332
+ const model = await loader.asyncFetch(url, version, null, { debug: true });
1333
+
1334
+ // 新 API (v1.4.2+)
1335
+ const loader = useGLTFLoader({ debug: true });
1336
+ const model = await loader.asyncFetch(url, version);
1337
+
1338
+ // 新增内存缓存管理
1339
+ const info = loader.getMemoryCacheInfo();
1340
+ loader.clearMemoryCache();
1341
+ loader.deleteMemoryCache(url, version);
1342
+ ```
1343
+
1344
+ **性能提升:**
1345
+
1346
+ ```
1347
+ 加载场景 (v1.4.1):
1348
+ - 首次: ~2s (网络 + 解析)
1349
+ - 二次: ~200ms (IndexedDB 读取 + 解析)
1350
+
1351
+ 加载场景 (v1.4.2+):
1352
+ - 首次: ~2s (网络 + 解析)
1353
+ - 二次: ~2ms (内存缓存克隆)
1354
+ - 提升: 100倍
1355
+ ```
1356
+
1357
+ ### v1.4.1 (2025-XX-XX)
1156
1358
 
1157
1359
  - 🎯 优化 `setView` 方法的 scale 参数计算逻辑
1158
1360
  - 🔧 修复水平 FOV 超过 180° 导致的负数距离问题
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="1.4.2";exports.version=e;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="1.4.3";exports.version=e;
@@ -1,4 +1,4 @@
1
- const o = "1.4.2";
1
+ const o = "1.4.3";
2
2
  export {
3
3
  o as version
4
4
  };
@@ -1,3 +1,3 @@
1
- "use strict";var I=Object.defineProperty;var q=(x,e,t)=>e in x?I(x,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):x[e]=t;var i=(x,e,t)=>q(x,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("three"),A=require("../../../../node_modules/.pnpm/three@0.178.0/node_modules/three/examples/jsm/renderers/CSS3DRenderer.cjs"),H=require("../../../../node_modules/.pnpm/three@0.178.0/node_modules/three/examples/jsm/libs/stats.module.cjs"),P=require("../utils/helper.cjs"),X=require("../utils/disposeObject.cjs");require("../utils/PredictiveLoader.cjs");const Y=require("../../package.json.cjs"),j=50,Z=20,_=20,E={TOP:"top",RIGHT:"right",LEFT:"left",ISO:"iso"},B={enableDamping:!0,dampingFactor:.25,screenSpacePanning:!1,minDistance:.1,maxDistance:1e3,maxPolarAngle:n.MathUtils.degToRad(60)};class C{constructor(e,t){i(this,"isReady",!1);i(this,"scene",null);i(this,"camera",null);i(this,"renderer",null);i(this,"control",null);i(this,"css3dRenderer",null);i(this,"el",null);i(this,"renderRequested",!1);i(this,"selector",null);i(this,"eventsListener",{});i(this,"stats",null);i(this,"isDispose",!1);i(this,"version","0.0.0");i(this,"boxHelper",null);i(this,"initOpt",{css3d:!1,stats:!1,renderType:"change",initListener:!0,initialFov:50,control:{init:!0,options:{}}});i(this,"setup",e=>{if(this.isDispose=!1,this.selector=e,this.el=document.querySelector(e),!this.el){console.error(`ThreeIns: 找不到元素 ${e}`);return}const[t,h]=this.getTargetSize();if(this.updateCameraFOV(t,h),this.camera.position.set(0,0,0),this.camera.lookAt(0,0,0),this.camera.updateProjectionMatrix(),this.renderer.setPixelRatio(window.devicePixelRatio),this.renderer.setSize(t,h),this.el.appendChild(this.renderer.domElement),this.initOpt.control&&this.initOpt.control.init){this.control=P.createOrbitControl(this.camera,this.renderer.domElement);const s=Object.assign(B,this.initOpt.control.options||{});Object.keys(s).forEach(p=>{this.control[p]=s[p]})}setTimeout(()=>{this.isReady=!0},Z),this.initOpt.stats&&this.initStats(),this.initOpt.css3d&&this.initCss3dRenderer(),this.initOpt.renderType==="loop"?this.animate():this.initOpt.renderType==="change"&&this.control&&this.control.addEventListener("change",this.requestRenderIfNotRequested),this.initListener()});i(this,"onContextLost",e=>{e.preventDefault(),this.animationFrameId&&cancelAnimationFrame(this.animationFrameId)});i(this,"onContextRestored",e=>{e.preventDefault(),this.dispose(),setTimeout(()=>{this.setup(this.selector)},_)});i(this,"initListener",()=>{this.initOpt.initListener&&window&&window.addEventListener("resize",this.onResize,!1),this.renderer.domElement.addEventListener("webglcontextlost",this.onContextLost,!1),this.renderer.domElement.addEventListener("webglcontextrestored",this.onContextRestored,!1)});i(this,"removeListener",()=>{window&&window.removeEventListener("resize",this.onResize,!1),this.renderer&&this.renderer.domElement&&(this.renderer.domElement.removeEventListener("webglcontextlost",this.onContextLost,!1),this.renderer.domElement.removeEventListener("webglcontextrestored",this.onContextRestored,!1))});i(this,"animate",()=>{this.isDispose||(this.initOpt.renderType==="loop"&&this.onRender(),this.animationFrameId=requestAnimationFrame(this.animate))});i(this,"onRender",()=>{this.isDispose||(this.renderRequested=!1,this.stats&&this.stats.update(),this.control&&this.control.update(),this.renderer.render(this.scene,this.camera),this.css3dRenderer&&this.css3dRenderer.render(this.scene,this.camera),this.eventsListener.onRender&&this.eventsListener.onRender.length&&this.eventsListener.onRender.forEach(e=>e()))});i(this,"requestRenderIfNotRequested",()=>{this.renderRequested||(this.renderRequested=!0,requestAnimationFrame(()=>{this.onRender()}))});i(this,"onResize",()=>{this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=setTimeout(()=>{const[e,t]=this.getTargetSize();this.updateCameraFOV(e,t),this.camera.lookAt(this.scene.position),this.renderer.setSize(e,t),this.css3dRenderer&&this.css3dRenderer.setSize(e,t),this.onRender()},j)});i(this,"frameArea",(e,t)=>(console.warn(`[ThreeIns] frameArea() 已弃用,建议使用 setView() 方法。
1
+ "use strict";var q=Object.defineProperty;var A=(x,e,t)=>e in x?q(x,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):x[e]=t;var i=(x,e,t)=>A(x,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("three"),H=require("../../../../node_modules/.pnpm/three@0.178.0/node_modules/three/examples/jsm/renderers/CSS3DRenderer.cjs"),P=require("../../../../node_modules/.pnpm/three@0.178.0/node_modules/three/examples/jsm/libs/stats.module.cjs"),X=require("../utils/helper.cjs"),Y=require("../utils/disposeObject.cjs");require("../utils/PredictiveLoader.cjs");const j=require("../../package.json.cjs"),Z=50,_=20,B=20,M={TOP:"top",RIGHT:"right",LEFT:"left",ISO:"iso"},U={enableDamping:!0,dampingFactor:.25,screenSpacePanning:!1,minDistance:.1,maxDistance:1e3,maxPolarAngle:r.MathUtils.degToRad(60)};class y{constructor(e,t){i(this,"isReady",!1);i(this,"scene",null);i(this,"camera",null);i(this,"renderer",null);i(this,"control",null);i(this,"css3dRenderer",null);i(this,"el",null);i(this,"renderRequested",!1);i(this,"selector",null);i(this,"eventsListener",{});i(this,"stats",null);i(this,"isDispose",!1);i(this,"version","0.0.0");i(this,"boxHelper",null);i(this,"initOpt",{css3d:!1,stats:!1,renderType:"change",initListener:!0,initialFov:50,control:{init:!0,options:{}}});i(this,"setup",e=>{if(this.isDispose=!1,this.selector=e,this.el=document.querySelector(e),!this.el){console.error(`ThreeIns: 找不到元素 ${e}`);return}const[t,h]=this.getTargetSize();if(this.updateCameraFOV(t,h),this.camera.position.set(0,0,0),this.camera.lookAt(0,0,0),this.camera.updateProjectionMatrix(),this.renderer.setPixelRatio(window.devicePixelRatio),this.renderer.setSize(t,h),this.el.appendChild(this.renderer.domElement),this.initOpt.control&&this.initOpt.control.init){this.control=X.createOrbitControl(this.camera,this.renderer.domElement);const s=Object.assign(U,this.initOpt.control.options||{});Object.keys(s).forEach(p=>{this.control[p]=s[p]})}setTimeout(()=>{this.isReady=!0},_),this.initOpt.stats&&this.initStats(),this.initOpt.css3d&&this.initCss3dRenderer(),this.initOpt.renderType==="loop"?this.animate():this.initOpt.renderType==="change"&&this.control&&this.control.addEventListener("change",this.requestRenderIfNotRequested),this.initListener()});i(this,"onContextLost",e=>{e.preventDefault(),this.animationFrameId&&cancelAnimationFrame(this.animationFrameId)});i(this,"onContextRestored",e=>{e.preventDefault(),this.dispose(),setTimeout(()=>{this.setup(this.selector)},B)});i(this,"initListener",()=>{this.initOpt.initListener&&window&&window.addEventListener("resize",this.onResize,!1),this.renderer.domElement.addEventListener("webglcontextlost",this.onContextLost,!1),this.renderer.domElement.addEventListener("webglcontextrestored",this.onContextRestored,!1)});i(this,"removeListener",()=>{window&&window.removeEventListener("resize",this.onResize,!1),this.renderer&&this.renderer.domElement&&(this.renderer.domElement.removeEventListener("webglcontextlost",this.onContextLost,!1),this.renderer.domElement.removeEventListener("webglcontextrestored",this.onContextRestored,!1))});i(this,"animate",()=>{this.isDispose||(this.initOpt.renderType==="loop"&&this.onRender(),this.animationFrameId=requestAnimationFrame(this.animate))});i(this,"onRender",()=>{this.isDispose||(this.renderRequested=!1,this.stats&&this.stats.update(),this.control&&this.control.update(),this.renderer.render(this.scene,this.camera),this.css3dRenderer&&this.css3dRenderer.render(this.scene,this.camera),this.eventsListener.onRender&&this.eventsListener.onRender.length&&this.eventsListener.onRender.forEach(e=>e()))});i(this,"requestRenderIfNotRequested",()=>{this.renderRequested||(this.renderRequested=!0,requestAnimationFrame(()=>{this.onRender()}))});i(this,"onResize",()=>{this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=setTimeout(()=>{const[e,t]=this.getTargetSize();this.updateCameraFOV(e,t),this.camera.lookAt(this.scene.position),this.renderer.setSize(e,t),this.css3dRenderer&&this.css3dRenderer.setSize(e,t),this.onRender()},Z)});i(this,"frameArea",(e,t)=>(console.warn(`[ThreeIns] frameArea() 已弃用,建议使用 setView() 方法。
2
2
  旧用法: threeIns.frameArea(model, scale)
3
- 新用法: threeIns.setView(model, ViewType.ISO, { scale })`),this.setView(e,E.ISO,{scale:t,animate:!1,showBox:!1})));i(this,"setView",(e,t,h={})=>{let s=h.scale||.8,p=h.offset||null,F=h.showBox||!1,y=h.boxColor||16776960,w=h.animate!==void 0?h.animate:!0,z=h.duration||1e3;const g=new n.Box3().setFromObject(e);let c=g.getCenter(new n.Vector3);p&&c.add(p);const T={top:new n.Vector3(0,1,0),right:new n.Vector3(2,1,1).normalize(),left:new n.Vector3(-2,1,1).normalize(),iso:new n.Vector3(0,1,1).normalize()},R=T[t]||T.iso,o=g.getSize(new n.Vector3),b=this.camera.aspect,r=n.MathUtils.degToRad(this.camera.fov*.5),S=n.MathUtils.degToRad(80),d=Math.min(Math.atan(Math.tan(r)*b),S);let m;if(t==="top"){const a=o.x*.5/(Math.tan(d)*s),l=o.z*.5/(Math.tan(r)*s);m=Math.max(a,l)}else if(t==="right"||t==="left"){const a=o.y*.5/(Math.tan(r)*s),l=o.z*.5/(Math.tan(r)*s);m=Math.max(a,l)}else{const a=o.x*.5/(Math.tan(d)*s),l=o.y*.5/(Math.tan(r)*s),f=o.z*.5/(Math.tan(r)*s);m=Math.max(a,l,f)}const u=R.clone().multiplyScalar(m).add(c);if(F&&(console.log("📍 相机位置验证:"),console.log(" - 方向向量:",R),console.log(" - 距离:",m.toFixed(2)),console.log(" - 包围盒中心:",c),console.log(" - 计算公式: direction * distance + boxCenter"),console.log(" - 目标位置:",u),console.log(" - 实际相机与中心的距离:",u.clone().sub(c).length().toFixed(2))),F?(this.boxHelper&&(this.scene.remove(this.boxHelper),this.boxHelper=null),this.boxHelper=new n.Box3Helper(g,y),this.scene.add(this.boxHelper)):this.boxHelper&&(this.scene.remove(this.boxHelper),this.boxHelper=null),w){const a=this.camera.position.clone(),l=this.control?this.control.target.clone():new n.Vector3(0,0,0),f=c,V=Date.now(),v=()=>{const D=Date.now()-V,L=Math.min(D/z,1),O=1-Math.pow(1-L,3);if(this.camera.position.lerpVectors(a,u,O),this.control){const M=new n.Vector3;M.lerpVectors(l,f,O),this.control.target.copy(M),this.camera.lookAt(M)}else this.camera.lookAt(c);this.camera.updateProjectionMatrix(),L<1?requestAnimationFrame(v):(this.camera.position.copy(u),this.camera.lookAt(c),this.camera.updateProjectionMatrix(),this.control&&(this.control.target.copy(c),this.control.update()),this.onRender())};v()}else this.camera.position.copy(u),this.camera.lookAt(c),this.camera.updateProjectionMatrix(),this.control&&(this.control.target.copy(c),this.control.update()),this.onRender();if(F){if(console.log("🎥 视角切换信息:"),console.log(" - 视角类型:",t),console.log(" - 相机位置:",u),console.log(" - 观察目标:",c),console.log(" - 方向向量:",R),console.log(" - 包围盒尺寸:",o),console.log(" - 包围盒中心:",g.getCenter(new n.Vector3)),console.log(" - 水平 FOV:",n.MathUtils.radToDeg(d*2).toFixed(2)+"°"),console.log(" - 垂直 FOV:",n.MathUtils.radToDeg(r*2).toFixed(2)+"°"),console.log(" - 宽高比:",b.toFixed(4)),console.log(" - 模型宽度:",o.x.toFixed(2)),console.log(" - 模型高度:",o.y.toFixed(2)),console.log(" - 模型深度:",o.z.toFixed(2)),console.log(" - 传入的 scale 参数:",s),t==="top"){const a=o.x*.5/(Math.tan(d)*s),l=o.z*.5/(Math.tan(r)*s);console.log(" - 模型 X 尺寸 (宽度):",o.x.toFixed(2)),console.log(" - 模型 Z 尺寸 (深度):",o.z.toFixed(2)),console.log(" - tan(halfFovX):",Math.tan(d).toFixed(4)),console.log(" - tan(halfFovY):",Math.tan(r).toFixed(4)),console.log(" - X方向距离计算: (",(o.x*.5).toFixed(2),") / (",Math.tan(d).toFixed(4)," *",s,") =",a.toFixed(2)),console.log(" - Z方向距离计算: (",(o.z*.5).toFixed(2),") / (",Math.tan(r).toFixed(4)," *",s,") =",l.toFixed(2)),console.log(" - X方向距离 (scale="+s+"):",a.toFixed(2)),console.log(" - Z方向距离 (scale="+s+"):",l.toFixed(2))}else if(t==="right"||t==="left"){const a=o.y*.5/(Math.tan(r)*s),l=o.z*.5/(Math.tan(r)*s);console.log(" - Y方向距离 (scale="+s+"):",a.toFixed(2)),console.log(" - Z方向距离 (scale="+s+"):",l.toFixed(2))}else{const a=o.x*.5/(Math.tan(d)*s),l=o.y*.5/(Math.tan(r)*s),f=o.z*.5/(Math.tan(r)*s);console.log(" - 模型 X 尺寸 (宽度):",o.x.toFixed(2)),console.log(" - 模型 Y 尺寸 (高度):",o.y.toFixed(2)),console.log(" - 模型 Z 尺寸 (深度):",o.z.toFixed(2)),console.log(" - tan(halfFovX):",Math.tan(d).toFixed(4)),console.log(" - tan(halfFovY):",Math.tan(r).toFixed(4)),console.log(" - X方向距离计算: (",(o.x*.5).toFixed(2),") / (",Math.tan(d).toFixed(4)," *",s,") =",a.toFixed(2)),console.log(" - Y方向距离计算: (",(o.y*.5).toFixed(2),") / (",Math.tan(r).toFixed(4)," *",s,") =",l.toFixed(2)),console.log(" - Z方向距离计算: (",(o.z*.5).toFixed(2),") / (",Math.tan(r).toFixed(4)," *",s,") =",f.toFixed(2)),console.log(" - X方向距离 (scale="+s+"):",a.toFixed(2)),console.log(" - Y方向距离 (scale="+s+"):",l.toFixed(2)),console.log(" - Z方向距离 (scale="+s+"):",f.toFixed(2)),console.log(" - 最大距离 (Max):",Math.max(a,l,f).toFixed(2))}console.log(" - 最终距离:",m.toFixed(2)),console.log(" - 缩放比例:",s),console.log(" - 动画:",w?"是 ("+z+"ms)":"否")}return{position:u,target:c,distance:m,viewType:t}});i(this,"on",(e,t)=>!e||!t||typeof t!="function"?(console.warn("ThreeIns.on: 无效的参数"),()=>{}):(this.eventsListener[e]||(this.eventsListener[e]=[]),this.eventsListener[e].push(t),()=>this.off(e,t)));this.isReady=!1,this.scene=new n.Scene({}),this.camera=new n.PerspectiveCamera(50,1,.1,2e3),this.renderer=new n.WebGLRenderer({antialias:!0,alpha:!0,precision:"mediump",logarithmicDepthBuffer:!0}),this.version=Y.version,this.onContextLost=this.onContextLost.bind(this),this.onContextRestored=this.onContextRestored.bind(this),this.onResize=this.onResize.bind(this),this.animate=this.animate.bind(this),this.resizeTimer=null,this.animationFrameId=null,t&&(this.initOpt=Object.assign(this.initOpt,t)),e&&this.setup(e)}updateCameraFOV(e,t){const h=this.initOpt.initialFov||50,s=Math.tan(Math.PI/180*h/2);this.camera.aspect=e/t,this.camera.fov=360/Math.PI*Math.atan(s*(t/e)),this.camera.updateProjectionMatrix()}initStats(){this.stats=new H,this.stats.dom.style.cssText="position:absolute;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000",this.el.appendChild(this.stats.dom)}initCss3dRenderer(){this.css3dRenderer=new A.CSS3DRenderer;const[e,t]=this.getTargetSize();this.css3dRenderer.setSize(e,t),this.css3dRenderer.domElement.style.position="absolute",this.css3dRenderer.domElement.style.pointerEvents="none",this.css3dRenderer.domElement.style.top=0,this.css3dRenderer.domElement.style.left=0,this.el.appendChild(this.css3dRenderer.domElement)}getTargetSize(){return document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement?[window.innerWidth,window.innerHeight]:this.el?!document.body.contains(this.el)&&(console.warn(`ThreeIns: 缓存的元素已失效,重新查询 ${this.selector}`),this.el=document.querySelector(this.selector),!this.el)?[0,0]:[this.el.clientWidth,this.el.clientHeight]:[0,0]}off(e,t){if(!e){this.eventsListener={};return}this.eventsListener[e]&&(t?this.eventsListener[e]=this.eventsListener[e].filter(h=>h!==t):this.eventsListener[e]=[])}dispose(){this.isDispose||(this.isDispose=!0,this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.resizeTimer&&(clearTimeout(this.resizeTimer),this.resizeTimer=null),this.removeListener(),this.eventsListener={},this.stats&&this.stats.dom&&(this.stats.dom.remove(),this.stats=null),this.css3dRenderer&&(this.css3dRenderer.domElement.remove(),this.css3dRenderer=null),this.boxHelper&&(this.scene.remove(this.boxHelper),this.boxHelper=null),this.scene&&(X.disposeThreeObject(this.scene),this.scene=null),this.renderer&&(this.renderer.dispose(),this.renderer.domElement&&this.renderer.domElement.remove(),this.renderer=null),this.control&&(this.control.dispose(),this.control=null),this.camera=null,this.el=null,this.selector=null,console.log("ThreeIns: 资源已清理完成"))}}i(C,"ViewType",E);exports.ThreeIns=C;exports.ViewType=E;
3
+ 新用法: threeIns.setView(model, ViewType.ISO, { scale })`),this.setView(e,M.ISO,{scale:t,animate:!1,showBox:!1})));i(this,"setView",(e,t,h={})=>{let s=h.scale||.8,p=h.offset||null,F=h.position||"center",R=h.showBox||!1,C=h.boxColor||16776960,E=h.animate!==void 0?h.animate:!0,b=h.duration||1e3;const g=new r.Box3().setFromObject(e);let c=g.getCenter(new r.Vector3);if(typeof F=="string"){const o=g.getSize(new r.Vector3),l={center:new r.Vector3(0,0,0),"top-left":new r.Vector3(-o.x*.3,o.y*.3,o.z*.3),"top-right":new r.Vector3(o.x*.3,o.y*.3,o.z*.3),"bottom-left":new r.Vector3(-o.x*.3,-o.y*.3,o.z*.3),"bottom-right":new r.Vector3(o.x*.3,-o.y*.3,o.z*.3)},d=l[F]||l.center;t==="top"?c.add(new r.Vector3(d.x,0,d.z)):t==="right"||t==="left"?c.add(new r.Vector3(0,d.y,d.z)):c.add(d)}else F instanceof r.Vector3&&c.add(F);p&&c.add(p);const T={top:new r.Vector3(0,1,0),right:new r.Vector3(2,1,1).normalize(),left:new r.Vector3(-2,1,1).normalize(),iso:new r.Vector3(0,1,1).normalize()},z=T[t]||T.iso,n=g.getSize(new r.Vector3),O=this.camera.aspect,a=r.MathUtils.degToRad(this.camera.fov*.5),S=r.MathUtils.degToRad(80),m=Math.min(Math.atan(Math.tan(a)*O),S);let f;if(t==="top"){const o=n.x*.5/(Math.tan(m)*s),l=n.z*.5/(Math.tan(a)*s);f=Math.max(o,l)}else if(t==="right"||t==="left"){const o=n.y*.5/(Math.tan(a)*s),l=n.z*.5/(Math.tan(a)*s);f=Math.max(o,l)}else{const o=n.x*.5/(Math.tan(m)*s),l=n.y*.5/(Math.tan(a)*s),d=n.z*.5/(Math.tan(a)*s);f=Math.max(o,l,d)}const u=z.clone().multiplyScalar(f).add(c);if(R&&(console.log("📍 相机位置验证:"),console.log(" - 方向向量:",z),console.log(" - 距离:",f.toFixed(2)),console.log(" - 包围盒中心:",c),console.log(" - 计算公式: direction * distance + boxCenter"),console.log(" - 目标位置:",u),console.log(" - 实际相机与中心的距离:",u.clone().sub(c).length().toFixed(2))),R?(this.boxHelper&&(this.scene.remove(this.boxHelper),this.boxHelper=null),this.boxHelper=new r.Box3Helper(g,C),this.scene.add(this.boxHelper)):this.boxHelper&&(this.scene.remove(this.boxHelper),this.boxHelper=null),E){const o=this.camera.position.clone(),l=this.control?this.control.target.clone():new r.Vector3(0,0,0),d=c,D=Date.now(),L=()=>{const I=Date.now()-D,V=Math.min(I/b,1),v=1-Math.pow(1-V,3);if(this.camera.position.lerpVectors(o,u,v),this.control){const w=new r.Vector3;w.lerpVectors(l,d,v),this.control.target.copy(w),this.camera.lookAt(w)}else this.camera.lookAt(c);this.camera.updateProjectionMatrix(),V<1?requestAnimationFrame(L):(this.camera.position.copy(u),this.camera.lookAt(c),this.camera.updateProjectionMatrix(),this.control&&(this.control.target.copy(c),this.control.update()),this.onRender())};L()}else this.camera.position.copy(u),this.camera.lookAt(c),this.camera.updateProjectionMatrix(),this.control&&(this.control.target.copy(c),this.control.update()),this.onRender();if(R){if(console.log("🎥 视角切换信息:"),console.log(" - 视角类型:",t),console.log(" - 相机位置:",u),console.log(" - 观察目标:",c),console.log(" - 方向向量:",z),console.log(" - 包围盒尺寸:",n),console.log(" - 包围盒中心:",g.getCenter(new r.Vector3)),console.log(" - 水平 FOV:",r.MathUtils.radToDeg(m*2).toFixed(2)+"°"),console.log(" - 垂直 FOV:",r.MathUtils.radToDeg(a*2).toFixed(2)+"°"),console.log(" - 宽高比:",O.toFixed(4)),console.log(" - 模型宽度:",n.x.toFixed(2)),console.log(" - 模型高度:",n.y.toFixed(2)),console.log(" - 模型深度:",n.z.toFixed(2)),console.log(" - 传入的 scale 参数:",s),t==="top"){const o=n.x*.5/(Math.tan(m)*s),l=n.z*.5/(Math.tan(a)*s);console.log(" - 模型 X 尺寸 (宽度):",n.x.toFixed(2)),console.log(" - 模型 Z 尺寸 (深度):",n.z.toFixed(2)),console.log(" - tan(halfFovX):",Math.tan(m).toFixed(4)),console.log(" - tan(halfFovY):",Math.tan(a).toFixed(4)),console.log(" - X方向距离计算: (",(n.x*.5).toFixed(2),") / (",Math.tan(m).toFixed(4)," *",s,") =",o.toFixed(2)),console.log(" - Z方向距离计算: (",(n.z*.5).toFixed(2),") / (",Math.tan(a).toFixed(4)," *",s,") =",l.toFixed(2)),console.log(" - X方向距离 (scale="+s+"):",o.toFixed(2)),console.log(" - Z方向距离 (scale="+s+"):",l.toFixed(2))}else if(t==="right"||t==="left"){const o=n.y*.5/(Math.tan(a)*s),l=n.z*.5/(Math.tan(a)*s);console.log(" - Y方向距离 (scale="+s+"):",o.toFixed(2)),console.log(" - Z方向距离 (scale="+s+"):",l.toFixed(2))}else{const o=n.x*.5/(Math.tan(m)*s),l=n.y*.5/(Math.tan(a)*s),d=n.z*.5/(Math.tan(a)*s);console.log(" - 模型 X 尺寸 (宽度):",n.x.toFixed(2)),console.log(" - 模型 Y 尺寸 (高度):",n.y.toFixed(2)),console.log(" - 模型 Z 尺寸 (深度):",n.z.toFixed(2)),console.log(" - tan(halfFovX):",Math.tan(m).toFixed(4)),console.log(" - tan(halfFovY):",Math.tan(a).toFixed(4)),console.log(" - X方向距离计算: (",(n.x*.5).toFixed(2),") / (",Math.tan(m).toFixed(4)," *",s,") =",o.toFixed(2)),console.log(" - Y方向距离计算: (",(n.y*.5).toFixed(2),") / (",Math.tan(a).toFixed(4)," *",s,") =",l.toFixed(2)),console.log(" - Z方向距离计算: (",(n.z*.5).toFixed(2),") / (",Math.tan(a).toFixed(4)," *",s,") =",d.toFixed(2)),console.log(" - X方向距离 (scale="+s+"):",o.toFixed(2)),console.log(" - Y方向距离 (scale="+s+"):",l.toFixed(2)),console.log(" - Z方向距离 (scale="+s+"):",d.toFixed(2)),console.log(" - 最大距离 (Max):",Math.max(o,l,d).toFixed(2))}console.log(" - 最终距离:",f.toFixed(2)),console.log(" - 缩放比例:",s),console.log(" - 动画:",E?"是 ("+b+"ms)":"否")}return{position:u,target:c,distance:f,viewType:t}});i(this,"on",(e,t)=>!e||!t||typeof t!="function"?(console.warn("ThreeIns.on: 无效的参数"),()=>{}):(this.eventsListener[e]||(this.eventsListener[e]=[]),this.eventsListener[e].push(t),()=>this.off(e,t)));this.isReady=!1,this.scene=new r.Scene({}),this.camera=new r.PerspectiveCamera(50,1,.1,2e3),this.renderer=new r.WebGLRenderer({antialias:!0,alpha:!0,precision:"mediump",logarithmicDepthBuffer:!0}),this.version=j.version,this.onContextLost=this.onContextLost.bind(this),this.onContextRestored=this.onContextRestored.bind(this),this.onResize=this.onResize.bind(this),this.animate=this.animate.bind(this),this.resizeTimer=null,this.animationFrameId=null,t&&(this.initOpt=Object.assign(this.initOpt,t)),e&&this.setup(e)}updateCameraFOV(e,t){const h=this.initOpt.initialFov||50,s=Math.tan(Math.PI/180*h/2);this.camera.aspect=e/t,this.camera.fov=360/Math.PI*Math.atan(s*(t/e)),this.camera.updateProjectionMatrix()}initStats(){this.stats=new P,this.stats.dom.style.cssText="position:absolute;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000",this.el.appendChild(this.stats.dom)}initCss3dRenderer(){this.css3dRenderer=new H.CSS3DRenderer;const[e,t]=this.getTargetSize();this.css3dRenderer.setSize(e,t),this.css3dRenderer.domElement.style.position="absolute",this.css3dRenderer.domElement.style.pointerEvents="none",this.css3dRenderer.domElement.style.top=0,this.css3dRenderer.domElement.style.left=0,this.el.appendChild(this.css3dRenderer.domElement)}getTargetSize(){return document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement?[window.innerWidth,window.innerHeight]:this.el?!document.body.contains(this.el)&&(console.warn(`ThreeIns: 缓存的元素已失效,重新查询 ${this.selector}`),this.el=document.querySelector(this.selector),!this.el)?[0,0]:[this.el.clientWidth,this.el.clientHeight]:[0,0]}off(e,t){if(!e){this.eventsListener={};return}this.eventsListener[e]&&(t?this.eventsListener[e]=this.eventsListener[e].filter(h=>h!==t):this.eventsListener[e]=[])}dispose(){this.isDispose||(this.isDispose=!0,this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.resizeTimer&&(clearTimeout(this.resizeTimer),this.resizeTimer=null),this.removeListener(),this.eventsListener={},this.stats&&this.stats.dom&&(this.stats.dom.remove(),this.stats=null),this.css3dRenderer&&(this.css3dRenderer.domElement.remove(),this.css3dRenderer=null),this.boxHelper&&(this.scene.remove(this.boxHelper),this.boxHelper=null),this.scene&&(Y.disposeThreeObject(this.scene),this.scene=null),this.renderer&&(this.renderer.dispose(),this.renderer.domElement&&this.renderer.domElement.remove(),this.renderer=null),this.control&&(this.control.dispose(),this.control=null),this.camera=null,this.el=null,this.selector=null,console.log("ThreeIns: 资源已清理完成"))}}i(y,"ViewType",M);exports.ThreeIns=y;exports.ViewType=M;
@@ -1,14 +1,14 @@
1
- var A = Object.defineProperty;
2
- var H = (p, e, t) => e in p ? A(p, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : p[e] = t;
3
- var i = (p, e, t) => H(p, typeof e != "symbol" ? e + "" : e, t);
4
- import { MathUtils as g, Scene as V, PerspectiveCamera as P, WebGLRenderer as q, Box3 as X, Vector3 as d, Box3Helper as Y } from "three";
5
- import { CSS3DRenderer as Z } from "../../../../node_modules/.pnpm/three@0.178.0/node_modules/three/examples/jsm/renderers/CSS3DRenderer.js";
6
- import j from "../../../../node_modules/.pnpm/three@0.178.0/node_modules/three/examples/jsm/libs/stats.module.js";
7
- import { createOrbitControl as B } from "../utils/helper.js";
8
- import { disposeThreeObject as _ } from "../utils/disposeObject.js";
1
+ var H = Object.defineProperty;
2
+ var V = (x, e, t) => e in x ? H(x, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : x[e] = t;
3
+ var o = (x, e, t) => V(x, typeof e != "symbol" ? e + "" : e, t);
4
+ import { MathUtils as F, Scene as P, PerspectiveCamera as q, WebGLRenderer as X, Box3 as Y, Vector3 as a, Box3Helper as Z } from "three";
5
+ import { CSS3DRenderer as j } from "../../../../node_modules/.pnpm/three@0.178.0/node_modules/three/examples/jsm/renderers/CSS3DRenderer.js";
6
+ import B from "../../../../node_modules/.pnpm/three@0.178.0/node_modules/three/examples/jsm/libs/stats.module.js";
7
+ import { createOrbitControl as _ } from "../utils/helper.js";
8
+ import { disposeThreeObject as N } from "../utils/disposeObject.js";
9
9
  import "../utils/PredictiveLoader.js";
10
- import { version as N } from "../../package.json.js";
11
- const W = 50, k = 20, G = 20, C = {
10
+ import { version as W } from "../../package.json.js";
11
+ const k = 50, G = 20, U = 20, y = {
12
12
  TOP: "top",
13
13
  // 俯视(从上往下)
14
14
  RIGHT: "right",
@@ -17,15 +17,15 @@ const W = 50, k = 20, G = 20, C = {
17
17
  // 左侧视
18
18
  ISO: "iso"
19
19
  // 正斜视(等轴测视角)
20
- }, U = {
20
+ }, $ = {
21
21
  enableDamping: !0,
22
22
  dampingFactor: 0.25,
23
23
  screenSpacePanning: !1,
24
24
  minDistance: 0.1,
25
25
  maxDistance: 1e3,
26
- maxPolarAngle: g.degToRad(60)
26
+ maxPolarAngle: F.degToRad(60)
27
27
  };
28
- class $ {
28
+ class J {
29
29
  /**
30
30
  * 构造函数
31
31
  * @param {string} selector - DOM 容器选择器
@@ -40,21 +40,21 @@ class $ {
40
40
  * @param {Object} [option.control.options={}] - 控制器选项
41
41
  */
42
42
  constructor(e, t) {
43
- i(this, "isReady", !1);
44
- i(this, "scene", null);
45
- i(this, "camera", null);
46
- i(this, "renderer", null);
47
- i(this, "control", null);
48
- i(this, "css3dRenderer", null);
49
- i(this, "el", null);
50
- i(this, "renderRequested", !1);
51
- i(this, "selector", null);
52
- i(this, "eventsListener", {});
53
- i(this, "stats", null);
54
- i(this, "isDispose", !1);
55
- i(this, "version", "0.0.0");
56
- i(this, "boxHelper", null);
57
- i(this, "initOpt", {
43
+ o(this, "isReady", !1);
44
+ o(this, "scene", null);
45
+ o(this, "camera", null);
46
+ o(this, "renderer", null);
47
+ o(this, "control", null);
48
+ o(this, "css3dRenderer", null);
49
+ o(this, "el", null);
50
+ o(this, "renderRequested", !1);
51
+ o(this, "selector", null);
52
+ o(this, "eventsListener", {});
53
+ o(this, "stats", null);
54
+ o(this, "isDispose", !1);
55
+ o(this, "version", "0.0.0");
56
+ o(this, "boxHelper", null);
57
+ o(this, "initOpt", {
58
58
  css3d: !1,
59
59
  stats: !1,
60
60
  renderType: "change",
@@ -71,25 +71,25 @@ class $ {
71
71
  * 初始化场景
72
72
  * @param {string} selector - DOM 容器选择器
73
73
  */
74
- i(this, "setup", (e) => {
74
+ o(this, "setup", (e) => {
75
75
  if (this.isDispose = !1, this.selector = e, this.el = document.querySelector(e), !this.el) {
76
76
  console.error(`ThreeIns: 找不到元素 ${e}`);
77
77
  return;
78
78
  }
79
- const [t, l] = this.getTargetSize();
80
- if (this.updateCameraFOV(t, l), this.camera.position.set(0, 0, 0), this.camera.lookAt(0, 0, 0), this.camera.updateProjectionMatrix(), this.renderer.setPixelRatio(window.devicePixelRatio), this.renderer.setSize(t, l), this.el.appendChild(this.renderer.domElement), this.initOpt.control && this.initOpt.control.init) {
81
- this.control = B(this.camera, this.renderer.domElement);
79
+ const [t, c] = this.getTargetSize();
80
+ if (this.updateCameraFOV(t, c), this.camera.position.set(0, 0, 0), this.camera.lookAt(0, 0, 0), this.camera.updateProjectionMatrix(), this.renderer.setPixelRatio(window.devicePixelRatio), this.renderer.setSize(t, c), this.el.appendChild(this.renderer.domElement), this.initOpt.control && this.initOpt.control.init) {
81
+ this.control = _(this.camera, this.renderer.domElement);
82
82
  const s = Object.assign(
83
- U,
83
+ $,
84
84
  this.initOpt.control.options || {}
85
85
  );
86
- Object.keys(s).forEach((x) => {
87
- this.control[x] = s[x];
86
+ Object.keys(s).forEach((p) => {
87
+ this.control[p] = s[p];
88
88
  });
89
89
  }
90
90
  setTimeout(() => {
91
91
  this.isReady = !0;
92
- }, k), this.initOpt.stats && this.initStats(), this.initOpt.css3d && this.initCss3dRenderer(), this.initOpt.renderType === "loop" ? this.animate() : this.initOpt.renderType === "change" && this.control && this.control.addEventListener(
92
+ }, G), this.initOpt.stats && this.initStats(), this.initOpt.css3d && this.initCss3dRenderer(), this.initOpt.renderType === "loop" ? this.animate() : this.initOpt.renderType === "change" && this.control && this.control.addEventListener(
93
93
  "change",
94
94
  this.requestRenderIfNotRequested
95
95
  ), this.initListener();
@@ -98,22 +98,22 @@ class $ {
98
98
  * WebGL 上下文丢失处理
99
99
  * @param {Event} e - 事件对象
100
100
  */
101
- i(this, "onContextLost", (e) => {
101
+ o(this, "onContextLost", (e) => {
102
102
  e.preventDefault(), this.animationFrameId && cancelAnimationFrame(this.animationFrameId);
103
103
  });
104
104
  /**
105
105
  * WebGL 上下文恢复处理
106
106
  * @param {Event} e - 事件对象
107
107
  */
108
- i(this, "onContextRestored", (e) => {
108
+ o(this, "onContextRestored", (e) => {
109
109
  e.preventDefault(), this.dispose(), setTimeout(() => {
110
110
  this.setup(this.selector);
111
- }, G);
111
+ }, U);
112
112
  });
113
113
  /**
114
114
  * 初始化事件监听器
115
115
  */
116
- i(this, "initListener", () => {
116
+ o(this, "initListener", () => {
117
117
  this.initOpt.initListener && window && window.addEventListener("resize", this.onResize, !1), this.renderer.domElement.addEventListener(
118
118
  "webglcontextlost",
119
119
  this.onContextLost,
@@ -127,7 +127,7 @@ class $ {
127
127
  /**
128
128
  * 移除事件监听器
129
129
  */
130
- i(this, "removeListener", () => {
130
+ o(this, "removeListener", () => {
131
131
  window && window.removeEventListener("resize", this.onResize, !1), this.renderer && this.renderer.domElement && (this.renderer.domElement.removeEventListener(
132
132
  "webglcontextlost",
133
133
  this.onContextLost,
@@ -141,19 +141,19 @@ class $ {
141
141
  /**
142
142
  * 渲染循环(loop 模式)
143
143
  */
144
- i(this, "animate", () => {
144
+ o(this, "animate", () => {
145
145
  this.isDispose || (this.initOpt.renderType === "loop" && this.onRender(), this.animationFrameId = requestAnimationFrame(this.animate));
146
146
  });
147
147
  /**
148
148
  * 执行渲染
149
149
  */
150
- i(this, "onRender", () => {
150
+ o(this, "onRender", () => {
151
151
  this.isDispose || (this.renderRequested = !1, this.stats && this.stats.update(), this.control && this.control.update(), this.renderer.render(this.scene, this.camera), this.css3dRenderer && this.css3dRenderer.render(this.scene, this.camera), this.eventsListener.onRender && this.eventsListener.onRender.length && this.eventsListener.onRender.forEach((e) => e()));
152
152
  });
153
153
  /**
154
154
  * 请求渲染(如果尚未请求)
155
155
  */
156
- i(this, "requestRenderIfNotRequested", () => {
156
+ o(this, "requestRenderIfNotRequested", () => {
157
157
  this.renderRequested || (this.renderRequested = !0, requestAnimationFrame(() => {
158
158
  this.onRender();
159
159
  }));
@@ -161,11 +161,11 @@ class $ {
161
161
  /**
162
162
  * 处理窗口大小变化(带防抖)
163
163
  */
164
- i(this, "onResize", () => {
164
+ o(this, "onResize", () => {
165
165
  this.resizeTimer && clearTimeout(this.resizeTimer), this.resizeTimer = setTimeout(() => {
166
166
  const [e, t] = this.getTargetSize();
167
167
  this.updateCameraFOV(e, t), this.camera.lookAt(this.scene.position), this.renderer.setSize(e, t), this.css3dRenderer && this.css3dRenderer.setSize(e, t), this.onRender();
168
- }, W);
168
+ }, k);
169
169
  });
170
170
  /**
171
171
  * @deprecated 此方法已弃用,请使用 setView() 方法代替
@@ -182,11 +182,11 @@ class $ {
182
182
  * @param {number} [scale=0.8] - 缩放比例,1=占满画布,0.5=50%,2.0=200%
183
183
  * @returns {Object} 返回 setView 的结果
184
184
  */
185
- i(this, "frameArea", (e, t) => (console.warn(
185
+ o(this, "frameArea", (e, t) => (console.warn(
186
186
  `[ThreeIns] frameArea() 已弃用,建议使用 setView() 方法。
187
187
  旧用法: threeIns.frameArea(model, scale)
188
188
  新用法: threeIns.setView(model, ViewType.ISO, { scale })`
189
- ), this.setView(e, C.ISO, { scale: t, animate: !1, showBox: !1 })));
189
+ ), this.setView(e, y.ISO, { scale: t, animate: !1, showBox: !1 })));
190
190
  /**
191
191
  * 切换到指定视角
192
192
  * 根据视角类型自动调整相机位置和朝向,支持缩放比例控制
@@ -199,7 +199,10 @@ class $ {
199
199
  * - 'iso': 正斜视(等轴测视角,45°角)
200
200
  * @param {Object} [options] - 可选配置
201
201
  * @param {number} [options.scale=1] - 缩放比例,控制模型在画布中的占比
202
- * @param {Vector3} [options.offset] - 偏移量,调整观察中心点
202
+ * @param {string|Vector3} [options.position='center'] - 模型在画布中的位置
203
+ * - 字符串选项:'center'(中心), 'top-left'(左上), 'top-right'(右上), 'bottom-left'(左下), 'bottom-right'(右下)
204
+ * - Vector3:自定义偏移向量
205
+ * @param {Vector3} [options.offset] - 额外的手动偏移量,在 position 基础上再次调整
203
206
  * @param {boolean} [options.showBox=false] - 是否显示包围盒辅助线
204
207
  * @param {number} [options.boxColor=0xffff00] - 包围盒颜色
205
208
  * @param {boolean} [options.animate=true] - 是否使用动画过渡
@@ -213,84 +216,105 @@ class $ {
213
216
  * // 导入 ViewType 枚举
214
217
  * import { ThreeIns, ViewType } from 'threejs';
215
218
  *
216
- * // 切换到俯视,模型占满画布
219
+ * // 切换到俯视,模型占满画布,居中显示
217
220
  * threeIns.setView(model, ViewType.TOP);
218
221
  *
219
- * // 切换到等轴测,模型占画布的 80%
220
- * threeIns.setView(model, ViewType.ISO, { scale: 0.8 });
222
+ * // 切换到等轴测,模型占画布的 80%,左上角显示
223
+ * threeIns.setView(model, ViewType.ISO, {
224
+ * scale: 0.8,
225
+ * position: 'top-left'
226
+ * });
221
227
  *
222
- * // 切换到斜视,显示包围盒,无动画
228
+ * // 切换到斜视,显示包围盒,右上角显示
223
229
  * threeIns.setView(model, ViewType.ISO, {
230
+ * position: 'top-right',
224
231
  * showBox: true,
225
232
  * animate: false
226
233
  * });
227
234
  *
228
235
  * // 切换到侧视,自定义观察点
229
236
  * threeIns.setView(model, ViewType.RIGHT, {
230
- * offset: new THREE.Vector3(0, 10, 0),
237
+ * position: new THREE.Vector3(100, 0, 0),
238
+ * scale: 0.8
239
+ * });
240
+ *
241
+ * // 组合使用 position 和 offset
242
+ * threeIns.setView(model, ViewType.TOP, {
243
+ * position: 'top-left', // 先自动定位到左上
244
+ * offset: new THREE.Vector3(50, 0, 0), // 再额外向右偏移 50
231
245
  * scale: 0.8
232
246
  * });
233
247
  *
234
248
  * // 或者使用类静态属性(向后兼容)
235
249
  * threeIns.setView(model, ThreeIns.ViewType.TOP);
236
250
  */
237
- i(this, "setView", (e, t, l = {}) => {
238
- let s = l.scale || 0.8, x = l.offset || null, R = l.showBox || !1, y = l.boxColor || 16776960, z = l.animate !== void 0 ? l.animate : !0, M = l.duration || 1e3;
239
- const F = new X().setFromObject(e);
240
- let h = F.getCenter(new d());
241
- x && h.add(x);
242
- const T = {
243
- top: new d(0, 1, 0),
251
+ o(this, "setView", (e, t, c = {}) => {
252
+ let s = c.scale || 0.8, p = c.offset || null, R = c.position || "center", z = c.showBox || !1, S = c.boxColor || 16776960, M = c.animate !== void 0 ? c.animate : !0, b = c.duration || 1e3;
253
+ const g = new Y().setFromObject(e);
254
+ let h = g.getCenter(new a());
255
+ if (typeof R == "string") {
256
+ const i = g.getSize(new a()), r = {
257
+ center: new a(0, 0, 0),
258
+ "top-left": new a(-i.x * 0.3, i.y * 0.3, i.z * 0.3),
259
+ "top-right": new a(i.x * 0.3, i.y * 0.3, i.z * 0.3),
260
+ "bottom-left": new a(-i.x * 0.3, -i.y * 0.3, i.z * 0.3),
261
+ "bottom-right": new a(i.x * 0.3, -i.y * 0.3, i.z * 0.3)
262
+ }, d = r[R] || r.center;
263
+ t === "top" ? h.add(new a(d.x, 0, d.z)) : t === "right" || t === "left" ? h.add(new a(0, d.y, d.z)) : h.add(d);
264
+ } else R instanceof a && h.add(R);
265
+ p && h.add(p);
266
+ const L = {
267
+ top: new a(0, 1, 0),
244
268
  // 从上往下:Y 轴正方向
245
- right: new d(2, 1, 1).normalize(),
269
+ right: new a(2, 1, 1).normalize(),
246
270
  // 从右往左:X 轴正方向
247
- left: new d(-2, 1, 1).normalize(),
271
+ left: new a(-2, 1, 1).normalize(),
248
272
  // 从左往右:X 轴负方向
249
- iso: new d(0, 1, 1).normalize()
273
+ iso: new a(0, 1, 1).normalize()
250
274
  // 等轴测:从对角线上方俯视
251
- }, E = T[t] || T.iso, o = F.getSize(new d()), L = this.camera.aspect, n = g.degToRad(this.camera.fov * 0.5), S = g.degToRad(80), c = Math.min(Math.atan(Math.tan(n) * L), S);
252
- let m;
275
+ }, w = L[t] || L.iso, n = g.getSize(new a()), O = this.camera.aspect, l = F.degToRad(this.camera.fov * 0.5), D = F.degToRad(80), m = Math.min(Math.atan(Math.tan(l) * O), D);
276
+ let f;
253
277
  if (t === "top") {
254
- const r = o.x * 0.5 / (Math.tan(c) * s), a = o.z * 0.5 / (Math.tan(n) * s);
255
- m = Math.max(r, a);
278
+ const i = n.x * 0.5 / (Math.tan(m) * s), r = n.z * 0.5 / (Math.tan(l) * s);
279
+ f = Math.max(i, r);
256
280
  } else if (t === "right" || t === "left") {
257
- const r = o.y * 0.5 / (Math.tan(n) * s), a = o.z * 0.5 / (Math.tan(n) * s);
258
- m = Math.max(r, a);
281
+ const i = n.y * 0.5 / (Math.tan(l) * s), r = n.z * 0.5 / (Math.tan(l) * s);
282
+ f = Math.max(i, r);
259
283
  } else {
260
- const r = o.x * 0.5 / (Math.tan(c) * s), a = o.y * 0.5 / (Math.tan(n) * s), u = o.z * 0.5 / (Math.tan(n) * s);
261
- m = Math.max(r, a, u);
284
+ const i = n.x * 0.5 / (Math.tan(m) * s), r = n.y * 0.5 / (Math.tan(l) * s), d = n.z * 0.5 / (Math.tan(l) * s);
285
+ f = Math.max(i, r, d);
262
286
  }
263
- const f = E.clone().multiplyScalar(m).add(h);
264
- if (R && (console.log("📍 相机位置验证:"), console.log(" - 方向向量:", E), console.log(" - 距离:", m.toFixed(2)), console.log(" - 包围盒中心:", h), console.log(" - 计算公式: direction * distance + boxCenter"), console.log(" - 目标位置:", f), console.log(" - 实际相机与中心的距离:", f.clone().sub(h).length().toFixed(2))), R ? (this.boxHelper && (this.scene.remove(this.boxHelper), this.boxHelper = null), this.boxHelper = new Y(F, y), this.scene.add(this.boxHelper)) : this.boxHelper && (this.scene.remove(this.boxHelper), this.boxHelper = null), z) {
265
- const r = this.camera.position.clone(), a = this.control ? this.control.target.clone() : new d(0, 0, 0), u = h, D = Date.now(), v = () => {
266
- const I = Date.now() - D, b = Math.min(I / M, 1), O = 1 - Math.pow(1 - b, 3);
267
- if (this.camera.position.lerpVectors(r, f, O), this.control) {
268
- const w = new d();
269
- w.lerpVectors(a, u, O), this.control.target.copy(w), this.camera.lookAt(w);
287
+ const u = w.clone().multiplyScalar(f).add(h);
288
+ if (z && (console.log("📍 相机位置验证:"), console.log(" - 方向向量:", w), console.log(" - 距离:", f.toFixed(2)), console.log(" - 包围盒中心:", h), console.log(" - 计算公式: direction * distance + boxCenter"), console.log(" - 目标位置:", u), console.log(" - 实际相机与中心的距离:", u.clone().sub(h).length().toFixed(2))), z ? (this.boxHelper && (this.scene.remove(this.boxHelper), this.boxHelper = null), this.boxHelper = new Z(g, S), this.scene.add(this.boxHelper)) : this.boxHelper && (this.scene.remove(this.boxHelper), this.boxHelper = null), M) {
289
+ const i = this.camera.position.clone(), r = this.control ? this.control.target.clone() : new a(0, 0, 0), d = h, I = Date.now(), T = () => {
290
+ const A = Date.now() - I, v = Math.min(A / b, 1), C = 1 - Math.pow(1 - v, 3);
291
+ if (this.camera.position.lerpVectors(i, u, C), this.control) {
292
+ const E = new a();
293
+ E.lerpVectors(r, d, C), this.control.target.copy(E), this.camera.lookAt(E);
270
294
  } else
271
295
  this.camera.lookAt(h);
272
- this.camera.updateProjectionMatrix(), b < 1 ? requestAnimationFrame(v) : (this.camera.position.copy(f), this.camera.lookAt(h), this.camera.updateProjectionMatrix(), this.control && (this.control.target.copy(h), this.control.update()), this.onRender());
296
+ this.camera.updateProjectionMatrix(), v < 1 ? requestAnimationFrame(T) : (this.camera.position.copy(u), this.camera.lookAt(h), this.camera.updateProjectionMatrix(), this.control && (this.control.target.copy(h), this.control.update()), this.onRender());
273
297
  };
274
- v();
298
+ T();
275
299
  } else
276
- this.camera.position.copy(f), this.camera.lookAt(h), this.camera.updateProjectionMatrix(), this.control && (this.control.target.copy(h), this.control.update()), this.onRender();
277
- if (R) {
278
- if (console.log("🎥 视角切换信息:"), console.log(" - 视角类型:", t), console.log(" - 相机位置:", f), console.log(" - 观察目标:", h), console.log(" - 方向向量:", E), console.log(" - 包围盒尺寸:", o), console.log(" - 包围盒中心:", F.getCenter(new d())), console.log(" - 水平 FOV:", g.radToDeg(c * 2).toFixed(2) + "°"), console.log(" - 垂直 FOV:", g.radToDeg(n * 2).toFixed(2) + "°"), console.log(" - 宽高比:", L.toFixed(4)), console.log(" - 模型宽度:", o.x.toFixed(2)), console.log(" - 模型高度:", o.y.toFixed(2)), console.log(" - 模型深度:", o.z.toFixed(2)), console.log(" - 传入的 scale 参数:", s), t === "top") {
279
- const r = o.x * 0.5 / (Math.tan(c) * s), a = o.z * 0.5 / (Math.tan(n) * s);
280
- console.log(" - 模型 X 尺寸 (宽度):", o.x.toFixed(2)), console.log(" - 模型 Z 尺寸 (深度):", o.z.toFixed(2)), console.log(" - tan(halfFovX):", Math.tan(c).toFixed(4)), console.log(" - tan(halfFovY):", Math.tan(n).toFixed(4)), console.log(" - X方向距离计算: (", (o.x * 0.5).toFixed(2), ") / (", Math.tan(c).toFixed(4), " *", s, ") =", r.toFixed(2)), console.log(" - Z方向距离计算: (", (o.z * 0.5).toFixed(2), ") / (", Math.tan(n).toFixed(4), " *", s, ") =", a.toFixed(2)), console.log(" - X方向距离 (scale=" + s + "):", r.toFixed(2)), console.log(" - Z方向距离 (scale=" + s + "):", a.toFixed(2));
300
+ this.camera.position.copy(u), this.camera.lookAt(h), this.camera.updateProjectionMatrix(), this.control && (this.control.target.copy(h), this.control.update()), this.onRender();
301
+ if (z) {
302
+ if (console.log("🎥 视角切换信息:"), console.log(" - 视角类型:", t), console.log(" - 相机位置:", u), console.log(" - 观察目标:", h), console.log(" - 方向向量:", w), console.log(" - 包围盒尺寸:", n), console.log(" - 包围盒中心:", g.getCenter(new a())), console.log(" - 水平 FOV:", F.radToDeg(m * 2).toFixed(2) + "°"), console.log(" - 垂直 FOV:", F.radToDeg(l * 2).toFixed(2) + "°"), console.log(" - 宽高比:", O.toFixed(4)), console.log(" - 模型宽度:", n.x.toFixed(2)), console.log(" - 模型高度:", n.y.toFixed(2)), console.log(" - 模型深度:", n.z.toFixed(2)), console.log(" - 传入的 scale 参数:", s), t === "top") {
303
+ const i = n.x * 0.5 / (Math.tan(m) * s), r = n.z * 0.5 / (Math.tan(l) * s);
304
+ console.log(" - 模型 X 尺寸 (宽度):", n.x.toFixed(2)), console.log(" - 模型 Z 尺寸 (深度):", n.z.toFixed(2)), console.log(" - tan(halfFovX):", Math.tan(m).toFixed(4)), console.log(" - tan(halfFovY):", Math.tan(l).toFixed(4)), console.log(" - X方向距离计算: (", (n.x * 0.5).toFixed(2), ") / (", Math.tan(m).toFixed(4), " *", s, ") =", i.toFixed(2)), console.log(" - Z方向距离计算: (", (n.z * 0.5).toFixed(2), ") / (", Math.tan(l).toFixed(4), " *", s, ") =", r.toFixed(2)), console.log(" - X方向距离 (scale=" + s + "):", i.toFixed(2)), console.log(" - Z方向距离 (scale=" + s + "):", r.toFixed(2));
281
305
  } else if (t === "right" || t === "left") {
282
- const r = o.y * 0.5 / (Math.tan(n) * s), a = o.z * 0.5 / (Math.tan(n) * s);
283
- console.log(" - Y方向距离 (scale=" + s + "):", r.toFixed(2)), console.log(" - Z方向距离 (scale=" + s + "):", a.toFixed(2));
306
+ const i = n.y * 0.5 / (Math.tan(l) * s), r = n.z * 0.5 / (Math.tan(l) * s);
307
+ console.log(" - Y方向距离 (scale=" + s + "):", i.toFixed(2)), console.log(" - Z方向距离 (scale=" + s + "):", r.toFixed(2));
284
308
  } else {
285
- const r = o.x * 0.5 / (Math.tan(c) * s), a = o.y * 0.5 / (Math.tan(n) * s), u = o.z * 0.5 / (Math.tan(n) * s);
286
- console.log(" - 模型 X 尺寸 (宽度):", o.x.toFixed(2)), console.log(" - 模型 Y 尺寸 (高度):", o.y.toFixed(2)), console.log(" - 模型 Z 尺寸 (深度):", o.z.toFixed(2)), console.log(" - tan(halfFovX):", Math.tan(c).toFixed(4)), console.log(" - tan(halfFovY):", Math.tan(n).toFixed(4)), console.log(" - X方向距离计算: (", (o.x * 0.5).toFixed(2), ") / (", Math.tan(c).toFixed(4), " *", s, ") =", r.toFixed(2)), console.log(" - Y方向距离计算: (", (o.y * 0.5).toFixed(2), ") / (", Math.tan(n).toFixed(4), " *", s, ") =", a.toFixed(2)), console.log(" - Z方向距离计算: (", (o.z * 0.5).toFixed(2), ") / (", Math.tan(n).toFixed(4), " *", s, ") =", u.toFixed(2)), console.log(" - X方向距离 (scale=" + s + "):", r.toFixed(2)), console.log(" - Y方向距离 (scale=" + s + "):", a.toFixed(2)), console.log(" - Z方向距离 (scale=" + s + "):", u.toFixed(2)), console.log(" - 最大距离 (Max):", Math.max(r, a, u).toFixed(2));
309
+ const i = n.x * 0.5 / (Math.tan(m) * s), r = n.y * 0.5 / (Math.tan(l) * s), d = n.z * 0.5 / (Math.tan(l) * s);
310
+ console.log(" - 模型 X 尺寸 (宽度):", n.x.toFixed(2)), console.log(" - 模型 Y 尺寸 (高度):", n.y.toFixed(2)), console.log(" - 模型 Z 尺寸 (深度):", n.z.toFixed(2)), console.log(" - tan(halfFovX):", Math.tan(m).toFixed(4)), console.log(" - tan(halfFovY):", Math.tan(l).toFixed(4)), console.log(" - X方向距离计算: (", (n.x * 0.5).toFixed(2), ") / (", Math.tan(m).toFixed(4), " *", s, ") =", i.toFixed(2)), console.log(" - Y方向距离计算: (", (n.y * 0.5).toFixed(2), ") / (", Math.tan(l).toFixed(4), " *", s, ") =", r.toFixed(2)), console.log(" - Z方向距离计算: (", (n.z * 0.5).toFixed(2), ") / (", Math.tan(l).toFixed(4), " *", s, ") =", d.toFixed(2)), console.log(" - X方向距离 (scale=" + s + "):", i.toFixed(2)), console.log(" - Y方向距离 (scale=" + s + "):", r.toFixed(2)), console.log(" - Z方向距离 (scale=" + s + "):", d.toFixed(2)), console.log(" - 最大距离 (Max):", Math.max(i, r, d).toFixed(2));
287
311
  }
288
- console.log(" - 最终距离:", m.toFixed(2)), console.log(" - 缩放比例:", s), console.log(" - 动画:", z ? "是 (" + M + "ms)" : "否");
312
+ console.log(" - 最终距离:", f.toFixed(2)), console.log(" - 缩放比例:", s), console.log(" - 动画:", M ? "是 (" + b + "ms)" : "否");
289
313
  }
290
314
  return {
291
- position: f,
315
+ position: u,
292
316
  target: h,
293
- distance: m,
317
+ distance: f,
294
318
  viewType: t
295
319
  };
296
320
  });
@@ -300,14 +324,14 @@ class $ {
300
324
  * @param {Function} callback - 回调函数
301
325
  * @returns {Function} 返回取消监听的函数
302
326
  */
303
- i(this, "on", (e, t) => !e || !t || typeof t != "function" ? (console.warn("ThreeIns.on: 无效的参数"), () => {
327
+ o(this, "on", (e, t) => !e || !t || typeof t != "function" ? (console.warn("ThreeIns.on: 无效的参数"), () => {
304
328
  }) : (this.eventsListener[e] || (this.eventsListener[e] = []), this.eventsListener[e].push(t), () => this.off(e, t)));
305
- this.isReady = !1, this.scene = new V({}), this.camera = new P(50, 1, 0.1, 2e3), this.renderer = new q({
329
+ this.isReady = !1, this.scene = new P({}), this.camera = new q(50, 1, 0.1, 2e3), this.renderer = new X({
306
330
  antialias: !0,
307
331
  alpha: !0,
308
332
  precision: "mediump",
309
333
  logarithmicDepthBuffer: !0
310
- }), this.version = N, this.onContextLost = this.onContextLost.bind(this), this.onContextRestored = this.onContextRestored.bind(this), this.onResize = this.onResize.bind(this), this.animate = this.animate.bind(this), this.resizeTimer = null, this.animationFrameId = null, t && (this.initOpt = Object.assign(this.initOpt, t)), e && this.setup(e);
334
+ }), this.version = W, this.onContextLost = this.onContextLost.bind(this), this.onContextRestored = this.onContextRestored.bind(this), this.onResize = this.onResize.bind(this), this.animate = this.animate.bind(this), this.resizeTimer = null, this.animationFrameId = null, t && (this.initOpt = Object.assign(this.initOpt, t)), e && this.setup(e);
311
335
  }
312
336
  /**
313
337
  * 更新相机 FOV 以适应容器尺寸
@@ -316,20 +340,20 @@ class $ {
316
340
  * @param {number} domH - 容器高度
317
341
  */
318
342
  updateCameraFOV(e, t) {
319
- const l = this.initOpt.initialFov || 50, s = Math.tan(Math.PI / 180 * l / 2);
343
+ const c = this.initOpt.initialFov || 50, s = Math.tan(Math.PI / 180 * c / 2);
320
344
  this.camera.aspect = e / t, this.camera.fov = 360 / Math.PI * Math.atan(s * (t / e)), this.camera.updateProjectionMatrix();
321
345
  }
322
346
  /**
323
347
  * 初始化性能统计
324
348
  */
325
349
  initStats() {
326
- this.stats = new j(), this.stats.dom.style.cssText = "position:absolute;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000", this.el.appendChild(this.stats.dom);
350
+ this.stats = new B(), this.stats.dom.style.cssText = "position:absolute;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000", this.el.appendChild(this.stats.dom);
327
351
  }
328
352
  /**
329
353
  * 初始化 CSS3D 渲染器
330
354
  */
331
355
  initCss3dRenderer() {
332
- this.css3dRenderer = new Z();
356
+ this.css3dRenderer = new j();
333
357
  const [e, t] = this.getTargetSize();
334
358
  this.css3dRenderer.setSize(e, t), this.css3dRenderer.domElement.style.position = "absolute", this.css3dRenderer.domElement.style.pointerEvents = "none", this.css3dRenderer.domElement.style.top = 0, this.css3dRenderer.domElement.style.left = 0, this.el.appendChild(this.css3dRenderer.domElement);
335
359
  }
@@ -351,19 +375,19 @@ class $ {
351
375
  this.eventsListener = {};
352
376
  return;
353
377
  }
354
- this.eventsListener[e] && (t ? this.eventsListener[e] = this.eventsListener[e].filter((l) => l !== t) : this.eventsListener[e] = []);
378
+ this.eventsListener[e] && (t ? this.eventsListener[e] = this.eventsListener[e].filter((c) => c !== t) : this.eventsListener[e] = []);
355
379
  }
356
380
  /**
357
381
  * 清理所有资源
358
382
  */
359
383
  dispose() {
360
- this.isDispose || (this.isDispose = !0, this.animationFrameId && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null), this.resizeTimer && (clearTimeout(this.resizeTimer), this.resizeTimer = null), this.removeListener(), this.eventsListener = {}, this.stats && this.stats.dom && (this.stats.dom.remove(), this.stats = null), this.css3dRenderer && (this.css3dRenderer.domElement.remove(), this.css3dRenderer = null), this.boxHelper && (this.scene.remove(this.boxHelper), this.boxHelper = null), this.scene && (_(this.scene), this.scene = null), this.renderer && (this.renderer.dispose(), this.renderer.domElement && this.renderer.domElement.remove(), this.renderer = null), this.control && (this.control.dispose(), this.control = null), this.camera = null, this.el = null, this.selector = null, console.log("ThreeIns: 资源已清理完成"));
384
+ this.isDispose || (this.isDispose = !0, this.animationFrameId && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null), this.resizeTimer && (clearTimeout(this.resizeTimer), this.resizeTimer = null), this.removeListener(), this.eventsListener = {}, this.stats && this.stats.dom && (this.stats.dom.remove(), this.stats = null), this.css3dRenderer && (this.css3dRenderer.domElement.remove(), this.css3dRenderer = null), this.boxHelper && (this.scene.remove(this.boxHelper), this.boxHelper = null), this.scene && (N(this.scene), this.scene = null), this.renderer && (this.renderer.dispose(), this.renderer.domElement && this.renderer.domElement.remove(), this.renderer = null), this.control && (this.control.dispose(), this.control = null), this.camera = null, this.el = null, this.selector = null, console.log("ThreeIns: 资源已清理完成"));
361
385
  }
362
386
  }
363
387
  // 存储包围盒辅助器
364
388
  // 视角类型枚举(作为类静态属性引用,保持向后兼容)
365
- i($, "ViewType", C);
389
+ o(J, "ViewType", y);
366
390
  export {
367
- $ as ThreeIns,
368
- C as ViewType
391
+ J as ThreeIns,
392
+ y as ViewType
369
393
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ridp/threejs",
3
3
  "private": false,
4
- "version": "1.4.2",
4
+ "version": "1.4.3",
5
5
  "type": "module",
6
6
  "main": "dist/threejs.js",
7
7
  "exports": {