@ridp/threejs 1.4.2 → 1.4.4

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.
Files changed (58) hide show
  1. package/{readme.md → README.md} +228 -26
  2. package/dist/ImageLoader-CMAmH-92.js +1444 -0
  3. package/dist/ImageLoader-y6-Adf1b.cjs +24 -0
  4. package/dist/PredictiveLoader-BXCwkdSX.cjs +2 -0
  5. package/dist/PredictiveLoader-eiPgVdsJ.js +3832 -0
  6. package/dist/assets/{gltfParser.worker-Bqz8BBJx.js → gltfParser.worker-D2lwod50.js} +2 -2
  7. package/dist/assets/{gltfParserOptimized.worker-DfipxPjm.js → gltfParserOptimized.worker-FT73rIOj.js} +2 -2
  8. package/dist/hooks.cjs +1 -1
  9. package/dist/hooks.js +9 -12
  10. package/dist/{packages/threejs/src/utils/modelOptimizer.js → modelOptimizer-D6fRg-DF.js} +1 -1
  11. package/dist/threejs.cjs +3 -1
  12. package/dist/threejs.js +428 -58
  13. package/dist/useBatchGLTFLoader-D3gPYO-K.cjs +5 -0
  14. package/dist/useBatchGLTFLoader-DP_NdYhC.js +493 -0
  15. package/dist/utils.cjs +1 -1
  16. package/dist/utils.js +32 -40
  17. package/package.json +1 -1
  18. package/dist/packages/threejs/package.json.cjs +0 -1
  19. package/dist/packages/threejs/package.json.js +0 -4
  20. package/dist/packages/threejs/src/hooks/useBatchGLTFLoader.cjs +0 -1
  21. package/dist/packages/threejs/src/hooks/useBatchGLTFLoader.js +0 -83
  22. package/dist/packages/threejs/src/hooks/useGLTFLoader.cjs +0 -1
  23. package/dist/packages/threejs/src/hooks/useGLTFLoader.js +0 -292
  24. package/dist/packages/threejs/src/hooks/useObb.cjs +0 -1
  25. package/dist/packages/threejs/src/hooks/useObb.js +0 -41
  26. package/dist/packages/threejs/src/hooks/useRaycaster.cjs +0 -1
  27. package/dist/packages/threejs/src/hooks/useRaycaster.js +0 -35
  28. package/dist/packages/threejs/src/hooks/useThreeJs.cjs +0 -5
  29. package/dist/packages/threejs/src/hooks/useThreeJs.js +0 -153
  30. package/dist/packages/threejs/src/instance/IDBCache.cjs +0 -1
  31. package/dist/packages/threejs/src/instance/IDBCache.js +0 -142
  32. package/dist/packages/threejs/src/instance/threeIns.cjs +0 -3
  33. package/dist/packages/threejs/src/instance/threeIns.js +0 -369
  34. package/dist/packages/threejs/src/utils/CacheMonitor.cjs +0 -1
  35. package/dist/packages/threejs/src/utils/CacheMonitor.js +0 -125
  36. package/dist/packages/threejs/src/utils/ImageLoader.cjs +0 -1
  37. package/dist/packages/threejs/src/utils/ImageLoader.js +0 -33
  38. package/dist/packages/threejs/src/utils/PredictiveLoader.cjs +0 -1
  39. package/dist/packages/threejs/src/utils/PredictiveLoader.js +0 -155
  40. package/dist/packages/threejs/src/utils/RetryHelper.cjs +0 -1
  41. package/dist/packages/threejs/src/utils/RetryHelper.js +0 -108
  42. package/dist/packages/threejs/src/utils/common.cjs +0 -1
  43. package/dist/packages/threejs/src/utils/common.js +0 -15
  44. package/dist/packages/threejs/src/utils/css3dHelper.cjs +0 -15
  45. package/dist/packages/threejs/src/utils/css3dHelper.js +0 -42
  46. package/dist/packages/threejs/src/utils/disposeObject.cjs +0 -1
  47. package/dist/packages/threejs/src/utils/disposeObject.js +0 -13
  48. package/dist/packages/threejs/src/utils/helper.cjs +0 -1
  49. package/dist/packages/threejs/src/utils/helper.js +0 -47
  50. package/dist/packages/threejs/src/utils/modelSerialize.cjs +0 -1
  51. package/dist/packages/threejs/src/utils/modelSerialize.js +0 -225
  52. package/dist/packages/threejs/src/utils/sceneRebuilder.cjs +0 -1
  53. package/dist/packages/threejs/src/utils/sceneRebuilder.js +0 -138
  54. package/dist/packages/threejs/src/workers/gltfParser.worker.cjs +0 -1
  55. package/dist/packages/threejs/src/workers/gltfParser.worker.js +0 -11
  56. package/dist/packages/threejs/src/workers/gltfParserOptimized.worker.cjs +0 -1
  57. package/dist/packages/threejs/src/workers/gltfParserOptimized.worker.js +0 -11
  58. /package/dist/{packages/threejs/src/utils/modelOptimizer.cjs → modelOptimizer-A0Cs6f9e.cjs} +0 -0
@@ -1,142 +0,0 @@
1
- import "three";
2
- import d from "dexie";
3
- const c = 4;
4
- class m {
5
- /**
6
- * 构造函数
7
- * @param {string} dbName - 数据库名称
8
- * @param {CacheOptions} options - 缓存配置选项
9
- */
10
- constructor(e = "threeJsIDBCache", t = {}) {
11
- this.version = c, this.dbName = e, this.options = {
12
- maxSize: t.maxSize || 500 * 1024 * 1024,
13
- // 默认 500MB
14
- maxEntries: t.maxEntries || 50,
15
- // 默认最多 50 个模型
16
- evictRatio: t.evictRatio || 0.2
17
- // 淘汰 20%
18
- }, this.dbInit();
19
- }
20
- dbInit() {
21
- this.db = new d(this.dbName), this.db.version(this.version).stores({
22
- models: "&path, version, timestamp, accessCount, size"
23
- }).upgrade(async (e) => {
24
- console.log("[ IDBCache 版本更新 ] ====> version", c);
25
- const t = e.table("models"), s = await t.toArray();
26
- for (const o of s)
27
- o.data instanceof ArrayBuffer || await t.delete(o.path);
28
- });
29
- }
30
- /**
31
- * 获取 Dexie 数据库实例
32
- * @returns {Dexie} Dexie 实例
33
- */
34
- getDatabase() {
35
- return this.db;
36
- }
37
- async saveModel(e, t, s) {
38
- await this.ensureCapacity(s.byteLength), await this.db.table("models").put({
39
- path: e,
40
- version: t,
41
- data: s,
42
- size: s.byteLength,
43
- timestamp: Date.now(),
44
- accessCount: 0
45
- });
46
- }
47
- /**
48
- * 确保缓存容量足够,不足时执行 LRU 淘汰
49
- * @param {number} requiredSize - 需要的额外空间(字节)
50
- */
51
- async ensureCapacity(e) {
52
- const t = await this.db.table("models").toArray(), s = t.reduce((a, i) => a + (i.size || 0), 0), o = t.length, n = s + e > this.options.maxSize, l = o >= this.options.maxEntries;
53
- (n || l) && (console.log(`[ IDBCache ] ====> 容量不足,开始 LRU 淘汰. 总大小: ${(s / 1024 / 1024).toFixed(2)}MB, 条目数: ${o}`), await this.evictLRU(t));
54
- }
55
- /**
56
- * 执行 LRU 淘汰策略
57
- * @param {Array} models - 所有缓存记录
58
- */
59
- async evictLRU(e) {
60
- const t = e.sort((a, i) => (a.accessCount || 0) !== (i.accessCount || 0) ? (a.accessCount || 0) - (i.accessCount || 0) : (a.timestamp || 0) - (i.timestamp || 0)), s = Math.max(1, Math.floor(t.length * this.options.evictRatio)), o = t.slice(0, s), n = o.map((a) => a.path);
61
- await this.db.table("models").bulkDelete(n);
62
- const l = o.reduce((a, i) => a + (i.size || 0), 0);
63
- console.log(`[ IDBCache ] ====> LRU 淘汰完成. 删除 ${s} 个条目,释放 ${(l / 1024 / 1024).toFixed(2)}MB`);
64
- }
65
- async getModel(e, t) {
66
- const s = await this.db.table("models").get(e);
67
- return s ? s.version !== t ? (console.log("模型版本不一致, 清除当前记录"), await this.db.table("models").delete(e), null) : (await this.db.table("models").update(e, {
68
- accessCount: (s.accessCount || 0) + 1,
69
- timestamp: Date.now()
70
- }), s.data) : (console.warn(`Model "${e}" not found in table models`), null);
71
- }
72
- // ---------------------------- ---------------------------------
73
- /**
74
- * 缓存模型到 IndexedDB
75
- * @param {string} path - 主键值
76
- * @param {THREE.Object3D} model - 要缓存的模型
77
- * @param {string} [version] - 缓存模型版本
78
- */
79
- async cacheModel(e, t, s) {
80
- console.log("[ ] ====> path, modelData, version", e, t, s);
81
- try {
82
- this.db.table("models").put({ version: s, path: e, data: t }).then(() => {
83
- console.log(`Model "${e}" cached successfully in table models`);
84
- });
85
- } catch {
86
- console.log(" 缓存模型失败 =====> ");
87
- }
88
- return t;
89
- }
90
- /**
91
- * 从 IndexedDB 加载缓存的模型
92
- * @param {string} path - 主键值
93
- * @returns {THREE.Object3D | null} 加载的模型
94
- */
95
- async loadCachedModel(e, t) {
96
- let s = null;
97
- try {
98
- if (s = await this.db.table("models").get(e), !s)
99
- return console.warn(`Model "${t}" not found in table models`), null;
100
- if (s.version !== t)
101
- return console.log(" =====> 模型版本不一致, 清除当前记录"), await this.db.table("models").delete(e), null;
102
- } catch {
103
- return console.log(" =====> 查询表中模型失败"), this.db.delete().then(() => {
104
- this.init();
105
- }), null;
106
- }
107
- return s.data;
108
- }
109
- /**
110
- * 获取缓存统计信息
111
- * @returns {Promise<Object>} 缓存统计数据
112
- */
113
- async getStats() {
114
- const e = await this.db.table("models").toArray(), t = e.reduce((o, n) => o + (n.size || 0), 0), s = e.reduce((o, n) => o + (n.accessCount || 0), 0);
115
- return {
116
- count: e.length,
117
- totalSize: t,
118
- totalSizeMB: (t / 1024 / 1024).toFixed(2),
119
- maxEntries: this.options.maxEntries,
120
- maxSizeMB: (this.options.maxSize / 1024 / 1024).toFixed(2),
121
- usagePercentage: (t / this.options.maxSize * 100).toFixed(2),
122
- totalAccessCount: s,
123
- avgAccessCount: e.length > 0 ? (s / e.length).toFixed(2) : 0
124
- };
125
- }
126
- /**
127
- * 清空所有缓存
128
- */
129
- async clear() {
130
- await this.db.table("models").clear(), console.log("[ IDBCache ] ====> 缓存已清空");
131
- }
132
- /**
133
- * 删除指定模型缓存
134
- * @param {string} path - 模型路径
135
- */
136
- async deleteModel(e) {
137
- await this.db.table("models").delete(e);
138
- }
139
- }
140
- export {
141
- m as IDBCache
142
- };
@@ -1,3 +0,0 @@
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() 方法。
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;
@@ -1,369 +0,0 @@
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";
9
- import "../utils/PredictiveLoader.js";
10
- import { version as N } from "../../package.json.js";
11
- const W = 50, k = 20, G = 20, C = {
12
- TOP: "top",
13
- // 俯视(从上往下)
14
- RIGHT: "right",
15
- // 侧视(从右往左)
16
- LEFT: "left",
17
- // 左侧视
18
- ISO: "iso"
19
- // 正斜视(等轴测视角)
20
- }, U = {
21
- enableDamping: !0,
22
- dampingFactor: 0.25,
23
- screenSpacePanning: !1,
24
- minDistance: 0.1,
25
- maxDistance: 1e3,
26
- maxPolarAngle: g.degToRad(60)
27
- };
28
- class $ {
29
- /**
30
- * 构造函数
31
- * @param {string} selector - DOM 容器选择器
32
- * @param {Object} option - 配置选项
33
- * @param {boolean} [option.css3d=false] - 是否启用 CSS3D 渲染器
34
- * @param {boolean} [option.stats=false] - 是否显示性能统计
35
- * @param {string} [option.renderType='change'] - 渲染类型: 'loop' 或 'change'
36
- * @param {boolean} [option.initListener=true] - 是否初始化事件监听器
37
- * @param {number} [option.initialFov=50] - 初始相机 FOV 值
38
- * @param {Object} [option.control] - 控制器配置
39
- * @param {boolean} [option.control.init=true] - 是否初始化控制器
40
- * @param {Object} [option.control.options={}] - 控制器选项
41
- */
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", {
58
- css3d: !1,
59
- stats: !1,
60
- renderType: "change",
61
- initListener: !0,
62
- // 使用布尔值代替字符串
63
- initialFov: 50,
64
- // 初始 FOV 值,用于避免全屏切换时的累积误差
65
- control: {
66
- init: !0,
67
- options: {}
68
- }
69
- });
70
- /**
71
- * 初始化场景
72
- * @param {string} selector - DOM 容器选择器
73
- */
74
- i(this, "setup", (e) => {
75
- if (this.isDispose = !1, this.selector = e, this.el = document.querySelector(e), !this.el) {
76
- console.error(`ThreeIns: 找不到元素 ${e}`);
77
- return;
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);
82
- const s = Object.assign(
83
- U,
84
- this.initOpt.control.options || {}
85
- );
86
- Object.keys(s).forEach((x) => {
87
- this.control[x] = s[x];
88
- });
89
- }
90
- setTimeout(() => {
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(
93
- "change",
94
- this.requestRenderIfNotRequested
95
- ), this.initListener();
96
- });
97
- /**
98
- * WebGL 上下文丢失处理
99
- * @param {Event} e - 事件对象
100
- */
101
- i(this, "onContextLost", (e) => {
102
- e.preventDefault(), this.animationFrameId && cancelAnimationFrame(this.animationFrameId);
103
- });
104
- /**
105
- * WebGL 上下文恢复处理
106
- * @param {Event} e - 事件对象
107
- */
108
- i(this, "onContextRestored", (e) => {
109
- e.preventDefault(), this.dispose(), setTimeout(() => {
110
- this.setup(this.selector);
111
- }, G);
112
- });
113
- /**
114
- * 初始化事件监听器
115
- */
116
- i(this, "initListener", () => {
117
- this.initOpt.initListener && window && window.addEventListener("resize", this.onResize, !1), this.renderer.domElement.addEventListener(
118
- "webglcontextlost",
119
- this.onContextLost,
120
- !1
121
- ), this.renderer.domElement.addEventListener(
122
- "webglcontextrestored",
123
- this.onContextRestored,
124
- !1
125
- );
126
- });
127
- /**
128
- * 移除事件监听器
129
- */
130
- i(this, "removeListener", () => {
131
- window && window.removeEventListener("resize", this.onResize, !1), this.renderer && this.renderer.domElement && (this.renderer.domElement.removeEventListener(
132
- "webglcontextlost",
133
- this.onContextLost,
134
- !1
135
- ), this.renderer.domElement.removeEventListener(
136
- "webglcontextrestored",
137
- this.onContextRestored,
138
- !1
139
- ));
140
- });
141
- /**
142
- * 渲染循环(loop 模式)
143
- */
144
- i(this, "animate", () => {
145
- this.isDispose || (this.initOpt.renderType === "loop" && this.onRender(), this.animationFrameId = requestAnimationFrame(this.animate));
146
- });
147
- /**
148
- * 执行渲染
149
- */
150
- i(this, "onRender", () => {
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
- });
153
- /**
154
- * 请求渲染(如果尚未请求)
155
- */
156
- i(this, "requestRenderIfNotRequested", () => {
157
- this.renderRequested || (this.renderRequested = !0, requestAnimationFrame(() => {
158
- this.onRender();
159
- }));
160
- });
161
- /**
162
- * 处理窗口大小变化(带防抖)
163
- */
164
- i(this, "onResize", () => {
165
- this.resizeTimer && clearTimeout(this.resizeTimer), this.resizeTimer = setTimeout(() => {
166
- const [e, t] = this.getTargetSize();
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);
169
- });
170
- /**
171
- * @deprecated 此方法已弃用,请使用 setView() 方法代替
172
- *
173
- * frameArea 仅为兼容旧版本保留,功能已被 setView() 完全覆盖
174
- *
175
- * 旧用法:
176
- * threeIns.frameArea(model, 1.0)
177
- *
178
- * 推荐用法:
179
- * threeIns.setView(model, ViewType.ISO, { scale: 1.0 })
180
- *
181
- * @param {Object3D} model - 要调整视角的 3D 模型对象
182
- * @param {number} [scale=0.8] - 缩放比例,1=占满画布,0.5=50%,2.0=200%
183
- * @returns {Object} 返回 setView 的结果
184
- */
185
- i(this, "frameArea", (e, t) => (console.warn(
186
- `[ThreeIns] frameArea() 已弃用,建议使用 setView() 方法。
187
- 旧用法: threeIns.frameArea(model, scale)
188
- 新用法: threeIns.setView(model, ViewType.ISO, { scale })`
189
- ), this.setView(e, C.ISO, { scale: t, animate: !1, showBox: !1 })));
190
- /**
191
- * 切换到指定视角
192
- * 根据视角类型自动调整相机位置和朝向,支持缩放比例控制
193
- *
194
- * @param {Object3D} model - 3D 物体对象
195
- * @param {string} viewType - 视角类型,使用 ViewType 枚举
196
- * - 'top': 俯视(从上往下看 Y 轴正方向)
197
- * - 'right': 侧视(从右往左看 X 轴正方向)
198
- * - 'left': 左侧视(从左往右看 X 轴负方向)
199
- * - 'iso': 正斜视(等轴测视角,45°角)
200
- * @param {Object} [options] - 可选配置
201
- * @param {number} [options.scale=1] - 缩放比例,控制模型在画布中的占比
202
- * @param {Vector3} [options.offset] - 偏移量,调整观察中心点
203
- * @param {boolean} [options.showBox=false] - 是否显示包围盒辅助线
204
- * @param {number} [options.boxColor=0xffff00] - 包围盒颜色
205
- * @param {boolean} [options.animate=true] - 是否使用动画过渡
206
- * @param {number} [options.duration=1000] - 动画持续时间(毫秒)
207
- * @returns {Object} 返回相机位置和模型信息
208
- * @returns {Vector3} return.position - 相机位置
209
- * @returns {Vector3} return.target - 相机观察目标点
210
- * @returns {number} return.distance - 相机到模型的距离
211
- *
212
- * @example
213
- * // 导入 ViewType 枚举
214
- * import { ThreeIns, ViewType } from 'threejs';
215
- *
216
- * // 切换到俯视,模型占满画布
217
- * threeIns.setView(model, ViewType.TOP);
218
- *
219
- * // 切换到等轴测,模型占画布的 80%
220
- * threeIns.setView(model, ViewType.ISO, { scale: 0.8 });
221
- *
222
- * // 切换到斜视,显示包围盒,无动画
223
- * threeIns.setView(model, ViewType.ISO, {
224
- * showBox: true,
225
- * animate: false
226
- * });
227
- *
228
- * // 切换到侧视,自定义观察点
229
- * threeIns.setView(model, ViewType.RIGHT, {
230
- * offset: new THREE.Vector3(0, 10, 0),
231
- * scale: 0.8
232
- * });
233
- *
234
- * // 或者使用类静态属性(向后兼容)
235
- * threeIns.setView(model, ThreeIns.ViewType.TOP);
236
- */
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),
244
- // 从上往下:Y 轴正方向
245
- right: new d(2, 1, 1).normalize(),
246
- // 从右往左:X 轴正方向
247
- left: new d(-2, 1, 1).normalize(),
248
- // 从左往右:X 轴负方向
249
- iso: new d(0, 1, 1).normalize()
250
- // 等轴测:从对角线上方俯视
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;
253
- 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);
256
- } 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);
259
- } 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);
262
- }
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);
270
- } else
271
- 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());
273
- };
274
- v();
275
- } 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));
281
- } 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));
284
- } 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));
287
- }
288
- console.log(" - 最终距离:", m.toFixed(2)), console.log(" - 缩放比例:", s), console.log(" - 动画:", z ? "是 (" + M + "ms)" : "否");
289
- }
290
- return {
291
- position: f,
292
- target: h,
293
- distance: m,
294
- viewType: t
295
- };
296
- });
297
- /**
298
- * 注册事件监听器
299
- * @param {string} event - 事件名称
300
- * @param {Function} callback - 回调函数
301
- * @returns {Function} 返回取消监听的函数
302
- */
303
- i(this, "on", (e, t) => !e || !t || typeof t != "function" ? (console.warn("ThreeIns.on: 无效的参数"), () => {
304
- }) : (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({
306
- antialias: !0,
307
- alpha: !0,
308
- precision: "mediump",
309
- 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);
311
- }
312
- /**
313
- * 更新相机 FOV 以适应容器尺寸
314
- * @private
315
- * @param {number} domW - 容器宽度
316
- * @param {number} domH - 容器高度
317
- */
318
- updateCameraFOV(e, t) {
319
- const l = this.initOpt.initialFov || 50, s = Math.tan(Math.PI / 180 * l / 2);
320
- this.camera.aspect = e / t, this.camera.fov = 360 / Math.PI * Math.atan(s * (t / e)), this.camera.updateProjectionMatrix();
321
- }
322
- /**
323
- * 初始化性能统计
324
- */
325
- 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);
327
- }
328
- /**
329
- * 初始化 CSS3D 渲染器
330
- */
331
- initCss3dRenderer() {
332
- this.css3dRenderer = new Z();
333
- const [e, t] = this.getTargetSize();
334
- 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
- }
336
- /**
337
- * 获取目标容器尺寸
338
- * 使用智能缓存策略:全屏时使用窗口尺寸,非全屏时使用元素尺寸
339
- * @returns {[number, number]} [width, height]
340
- */
341
- getTargetSize() {
342
- 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];
343
- }
344
- /**
345
- * 移除事件监听器
346
- * @param {string} event - 事件名称
347
- * @param {Function} [callback] - 可选的回调函数,如果不提供则移除该事件的所有监听器
348
- */
349
- off(e, t) {
350
- if (!e) {
351
- this.eventsListener = {};
352
- return;
353
- }
354
- this.eventsListener[e] && (t ? this.eventsListener[e] = this.eventsListener[e].filter((l) => l !== t) : this.eventsListener[e] = []);
355
- }
356
- /**
357
- * 清理所有资源
358
- */
359
- 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: 资源已清理完成"));
361
- }
362
- }
363
- // 存储包围盒辅助器
364
- // 视角类型枚举(作为类静态属性引用,保持向后兼容)
365
- i($, "ViewType", C);
366
- export {
367
- $ as ThreeIns,
368
- C as ViewType
369
- };
@@ -1 +0,0 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class e{constructor(){this.stats={hits:0,misses:0,totalLoadTime:0,cacheSaveTime:0,errors:0},this.loadHistory=[]}recordHit(t){this.stats.hits++,this.stats.totalLoadTime+=t,this._recordHistory("hit",t)}recordMiss(t){this.stats.misses++,this.stats.totalLoadTime+=t,this._recordHistory("miss",t)}recordCacheSave(t){this.stats.cacheSaveTime+=t}recordError(t,s){this.stats.errors++,this._recordHistory("error",0,{path:t,error:s.message})}getHitRate(){const t=this.stats.hits+this.stats.misses;return t>0?(this.stats.hits/t*100).toFixed(2)+"%":"0%"}getAvgLoadTime(){const t=this.stats.hits+this.stats.misses;return t>0?(this.stats.totalLoadTime/t).toFixed(2)+"ms":"0ms"}getStats(){const t=this.stats.hits+this.stats.misses;return{命中率:this.getHitRate(),平均加载时间:this.getAvgLoadTime(),缓存命中数:this.stats.hits,缓存未命中数:this.stats.misses,总加载次数:t,总加载时间:this.stats.totalLoadTime.toFixed(2)+"ms",缓存保存时间:this.stats.cacheSaveTime.toFixed(2)+"ms",错误次数:this.stats.errors}}getHistory(t=10){return this.loadHistory.slice(-t)}reset(){this.stats={hits:0,misses:0,totalLoadTime:0,cacheSaveTime:0,errors:0},this.loadHistory=[]}_recordHistory(t,s,i={}){this.loadHistory.push({type:t,duration:s,timestamp:Date.now(),...i}),this.loadHistory.length>100&&this.loadHistory.shift()}logReport(){console.group("📊 缓存性能报告");const t=this.getStats();Object.entries(t).forEach(([s,i])=>{console.log(`${s}: ${i}`)}),console.groupEnd()}}const o=new e;exports.CacheMonitor=e;exports.cacheMonitor=o;