@ridp/threejs 1.4.3 → 1.4.5
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.
- package/dist/ImageLoader-6mmE7g5P.cjs +24 -0
- package/dist/ImageLoader-CnBqJLru.js +1444 -0
- package/dist/PredictiveLoader-DTN7SDRI.js +3842 -0
- package/dist/PredictiveLoader-KOCZXzGy.cjs +2 -0
- package/dist/assets/{gltfParser.worker-Bqz8BBJx.js → gltfParser.worker-D2lwod50.js} +2 -2
- package/dist/assets/{gltfParserOptimized.worker-DfipxPjm.js → gltfParserOptimized.worker-yo8WMPFM.js} +2 -2
- package/dist/hooks.cjs +1 -1
- package/dist/hooks.js +9 -12
- package/dist/{packages/threejs/src/utils/modelOptimizer.js → modelOptimizer-D6fRg-DF.js} +1 -1
- package/dist/threejs.cjs +3 -1
- package/dist/threejs.js +428 -58
- package/dist/useBatchGLTFLoader-19GZ1dxv.cjs +5 -0
- package/dist/useBatchGLTFLoader-DPT0_95u.js +493 -0
- package/dist/utils.cjs +1 -1
- package/dist/utils.js +32 -40
- package/package.json +1 -1
- package/dist/packages/threejs/package.json.cjs +0 -1
- package/dist/packages/threejs/package.json.js +0 -4
- package/dist/packages/threejs/src/hooks/useBatchGLTFLoader.cjs +0 -1
- package/dist/packages/threejs/src/hooks/useBatchGLTFLoader.js +0 -83
- package/dist/packages/threejs/src/hooks/useGLTFLoader.cjs +0 -1
- package/dist/packages/threejs/src/hooks/useGLTFLoader.js +0 -292
- package/dist/packages/threejs/src/hooks/useObb.cjs +0 -1
- package/dist/packages/threejs/src/hooks/useObb.js +0 -41
- package/dist/packages/threejs/src/hooks/useRaycaster.cjs +0 -1
- package/dist/packages/threejs/src/hooks/useRaycaster.js +0 -35
- package/dist/packages/threejs/src/hooks/useThreeJs.cjs +0 -5
- package/dist/packages/threejs/src/hooks/useThreeJs.js +0 -153
- package/dist/packages/threejs/src/instance/IDBCache.cjs +0 -1
- package/dist/packages/threejs/src/instance/IDBCache.js +0 -142
- package/dist/packages/threejs/src/instance/threeIns.cjs +0 -3
- package/dist/packages/threejs/src/instance/threeIns.js +0 -393
- package/dist/packages/threejs/src/utils/CacheMonitor.cjs +0 -1
- package/dist/packages/threejs/src/utils/CacheMonitor.js +0 -125
- package/dist/packages/threejs/src/utils/ImageLoader.cjs +0 -1
- package/dist/packages/threejs/src/utils/ImageLoader.js +0 -33
- package/dist/packages/threejs/src/utils/PredictiveLoader.cjs +0 -1
- package/dist/packages/threejs/src/utils/PredictiveLoader.js +0 -155
- package/dist/packages/threejs/src/utils/RetryHelper.cjs +0 -1
- package/dist/packages/threejs/src/utils/RetryHelper.js +0 -108
- package/dist/packages/threejs/src/utils/common.cjs +0 -1
- package/dist/packages/threejs/src/utils/common.js +0 -15
- package/dist/packages/threejs/src/utils/css3dHelper.cjs +0 -15
- package/dist/packages/threejs/src/utils/css3dHelper.js +0 -42
- package/dist/packages/threejs/src/utils/disposeObject.cjs +0 -1
- package/dist/packages/threejs/src/utils/disposeObject.js +0 -13
- package/dist/packages/threejs/src/utils/helper.cjs +0 -1
- package/dist/packages/threejs/src/utils/helper.js +0 -47
- package/dist/packages/threejs/src/utils/modelSerialize.cjs +0 -1
- package/dist/packages/threejs/src/utils/modelSerialize.js +0 -225
- package/dist/packages/threejs/src/utils/sceneRebuilder.cjs +0 -1
- package/dist/packages/threejs/src/utils/sceneRebuilder.js +0 -138
- package/dist/packages/threejs/src/workers/gltfParser.worker.cjs +0 -1
- package/dist/packages/threejs/src/workers/gltfParser.worker.js +0 -11
- package/dist/packages/threejs/src/workers/gltfParserOptimized.worker.cjs +0 -1
- package/dist/packages/threejs/src/workers/gltfParserOptimized.worker.js +0 -11
- /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 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
|
-
旧用法: threeIns.frameArea(model, scale)
|
|
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,393 +0,0 @@
|
|
|
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
|
-
import "../utils/PredictiveLoader.js";
|
|
10
|
-
import { version as W } from "../../package.json.js";
|
|
11
|
-
const k = 50, G = 20, U = 20, y = {
|
|
12
|
-
TOP: "top",
|
|
13
|
-
// 俯视(从上往下)
|
|
14
|
-
RIGHT: "right",
|
|
15
|
-
// 侧视(从右往左)
|
|
16
|
-
LEFT: "left",
|
|
17
|
-
// 左侧视
|
|
18
|
-
ISO: "iso"
|
|
19
|
-
// 正斜视(等轴测视角)
|
|
20
|
-
}, $ = {
|
|
21
|
-
enableDamping: !0,
|
|
22
|
-
dampingFactor: 0.25,
|
|
23
|
-
screenSpacePanning: !1,
|
|
24
|
-
minDistance: 0.1,
|
|
25
|
-
maxDistance: 1e3,
|
|
26
|
-
maxPolarAngle: F.degToRad(60)
|
|
27
|
-
};
|
|
28
|
-
class J {
|
|
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
|
-
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
|
-
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
|
-
o(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, 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
|
-
const s = Object.assign(
|
|
83
|
-
$,
|
|
84
|
-
this.initOpt.control.options || {}
|
|
85
|
-
);
|
|
86
|
-
Object.keys(s).forEach((p) => {
|
|
87
|
-
this.control[p] = s[p];
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
setTimeout(() => {
|
|
91
|
-
this.isReady = !0;
|
|
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
|
-
"change",
|
|
94
|
-
this.requestRenderIfNotRequested
|
|
95
|
-
), this.initListener();
|
|
96
|
-
});
|
|
97
|
-
/**
|
|
98
|
-
* WebGL 上下文丢失处理
|
|
99
|
-
* @param {Event} e - 事件对象
|
|
100
|
-
*/
|
|
101
|
-
o(this, "onContextLost", (e) => {
|
|
102
|
-
e.preventDefault(), this.animationFrameId && cancelAnimationFrame(this.animationFrameId);
|
|
103
|
-
});
|
|
104
|
-
/**
|
|
105
|
-
* WebGL 上下文恢复处理
|
|
106
|
-
* @param {Event} e - 事件对象
|
|
107
|
-
*/
|
|
108
|
-
o(this, "onContextRestored", (e) => {
|
|
109
|
-
e.preventDefault(), this.dispose(), setTimeout(() => {
|
|
110
|
-
this.setup(this.selector);
|
|
111
|
-
}, U);
|
|
112
|
-
});
|
|
113
|
-
/**
|
|
114
|
-
* 初始化事件监听器
|
|
115
|
-
*/
|
|
116
|
-
o(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
|
-
o(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
|
-
o(this, "animate", () => {
|
|
145
|
-
this.isDispose || (this.initOpt.renderType === "loop" && this.onRender(), this.animationFrameId = requestAnimationFrame(this.animate));
|
|
146
|
-
});
|
|
147
|
-
/**
|
|
148
|
-
* 执行渲染
|
|
149
|
-
*/
|
|
150
|
-
o(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
|
-
o(this, "requestRenderIfNotRequested", () => {
|
|
157
|
-
this.renderRequested || (this.renderRequested = !0, requestAnimationFrame(() => {
|
|
158
|
-
this.onRender();
|
|
159
|
-
}));
|
|
160
|
-
});
|
|
161
|
-
/**
|
|
162
|
-
* 处理窗口大小变化(带防抖)
|
|
163
|
-
*/
|
|
164
|
-
o(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
|
-
}, k);
|
|
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
|
-
o(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, y.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 {string|Vector3} [options.position='center'] - 模型在画布中的位置
|
|
203
|
-
* - 字符串选项:'center'(中心), 'top-left'(左上), 'top-right'(右上), 'bottom-left'(左下), 'bottom-right'(右下)
|
|
204
|
-
* - Vector3:自定义偏移向量
|
|
205
|
-
* @param {Vector3} [options.offset] - 额外的手动偏移量,在 position 基础上再次调整
|
|
206
|
-
* @param {boolean} [options.showBox=false] - 是否显示包围盒辅助线
|
|
207
|
-
* @param {number} [options.boxColor=0xffff00] - 包围盒颜色
|
|
208
|
-
* @param {boolean} [options.animate=true] - 是否使用动画过渡
|
|
209
|
-
* @param {number} [options.duration=1000] - 动画持续时间(毫秒)
|
|
210
|
-
* @returns {Object} 返回相机位置和模型信息
|
|
211
|
-
* @returns {Vector3} return.position - 相机位置
|
|
212
|
-
* @returns {Vector3} return.target - 相机观察目标点
|
|
213
|
-
* @returns {number} return.distance - 相机到模型的距离
|
|
214
|
-
*
|
|
215
|
-
* @example
|
|
216
|
-
* // 导入 ViewType 枚举
|
|
217
|
-
* import { ThreeIns, ViewType } from 'threejs';
|
|
218
|
-
*
|
|
219
|
-
* // 切换到俯视,模型占满画布,居中显示
|
|
220
|
-
* threeIns.setView(model, ViewType.TOP);
|
|
221
|
-
*
|
|
222
|
-
* // 切换到等轴测,模型占画布的 80%,左上角显示
|
|
223
|
-
* threeIns.setView(model, ViewType.ISO, {
|
|
224
|
-
* scale: 0.8,
|
|
225
|
-
* position: 'top-left'
|
|
226
|
-
* });
|
|
227
|
-
*
|
|
228
|
-
* // 切换到斜视,显示包围盒,右上角显示
|
|
229
|
-
* threeIns.setView(model, ViewType.ISO, {
|
|
230
|
-
* position: 'top-right',
|
|
231
|
-
* showBox: true,
|
|
232
|
-
* animate: false
|
|
233
|
-
* });
|
|
234
|
-
*
|
|
235
|
-
* // 切换到侧视,自定义观察点
|
|
236
|
-
* threeIns.setView(model, ViewType.RIGHT, {
|
|
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
|
|
245
|
-
* scale: 0.8
|
|
246
|
-
* });
|
|
247
|
-
*
|
|
248
|
-
* // 或者使用类静态属性(向后兼容)
|
|
249
|
-
* threeIns.setView(model, ThreeIns.ViewType.TOP);
|
|
250
|
-
*/
|
|
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),
|
|
268
|
-
// 从上往下:Y 轴正方向
|
|
269
|
-
right: new a(2, 1, 1).normalize(),
|
|
270
|
-
// 从右往左:X 轴正方向
|
|
271
|
-
left: new a(-2, 1, 1).normalize(),
|
|
272
|
-
// 从左往右:X 轴负方向
|
|
273
|
-
iso: new a(0, 1, 1).normalize()
|
|
274
|
-
// 等轴测:从对角线上方俯视
|
|
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;
|
|
277
|
-
if (t === "top") {
|
|
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);
|
|
280
|
-
} else if (t === "right" || t === "left") {
|
|
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);
|
|
283
|
-
} else {
|
|
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);
|
|
286
|
-
}
|
|
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);
|
|
294
|
-
} else
|
|
295
|
-
this.camera.lookAt(h);
|
|
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());
|
|
297
|
-
};
|
|
298
|
-
T();
|
|
299
|
-
} else
|
|
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));
|
|
305
|
-
} else if (t === "right" || t === "left") {
|
|
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));
|
|
308
|
-
} else {
|
|
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));
|
|
311
|
-
}
|
|
312
|
-
console.log(" - 最终距离:", f.toFixed(2)), console.log(" - 缩放比例:", s), console.log(" - 动画:", M ? "是 (" + b + "ms)" : "否");
|
|
313
|
-
}
|
|
314
|
-
return {
|
|
315
|
-
position: u,
|
|
316
|
-
target: h,
|
|
317
|
-
distance: f,
|
|
318
|
-
viewType: t
|
|
319
|
-
};
|
|
320
|
-
});
|
|
321
|
-
/**
|
|
322
|
-
* 注册事件监听器
|
|
323
|
-
* @param {string} event - 事件名称
|
|
324
|
-
* @param {Function} callback - 回调函数
|
|
325
|
-
* @returns {Function} 返回取消监听的函数
|
|
326
|
-
*/
|
|
327
|
-
o(this, "on", (e, t) => !e || !t || typeof t != "function" ? (console.warn("ThreeIns.on: 无效的参数"), () => {
|
|
328
|
-
}) : (this.eventsListener[e] || (this.eventsListener[e] = []), this.eventsListener[e].push(t), () => this.off(e, t)));
|
|
329
|
-
this.isReady = !1, this.scene = new P({}), this.camera = new q(50, 1, 0.1, 2e3), this.renderer = new X({
|
|
330
|
-
antialias: !0,
|
|
331
|
-
alpha: !0,
|
|
332
|
-
precision: "mediump",
|
|
333
|
-
logarithmicDepthBuffer: !0
|
|
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);
|
|
335
|
-
}
|
|
336
|
-
/**
|
|
337
|
-
* 更新相机 FOV 以适应容器尺寸
|
|
338
|
-
* @private
|
|
339
|
-
* @param {number} domW - 容器宽度
|
|
340
|
-
* @param {number} domH - 容器高度
|
|
341
|
-
*/
|
|
342
|
-
updateCameraFOV(e, t) {
|
|
343
|
-
const c = this.initOpt.initialFov || 50, s = Math.tan(Math.PI / 180 * c / 2);
|
|
344
|
-
this.camera.aspect = e / t, this.camera.fov = 360 / Math.PI * Math.atan(s * (t / e)), this.camera.updateProjectionMatrix();
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* 初始化性能统计
|
|
348
|
-
*/
|
|
349
|
-
initStats() {
|
|
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);
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
* 初始化 CSS3D 渲染器
|
|
354
|
-
*/
|
|
355
|
-
initCss3dRenderer() {
|
|
356
|
-
this.css3dRenderer = new j();
|
|
357
|
-
const [e, t] = this.getTargetSize();
|
|
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);
|
|
359
|
-
}
|
|
360
|
-
/**
|
|
361
|
-
* 获取目标容器尺寸
|
|
362
|
-
* 使用智能缓存策略:全屏时使用窗口尺寸,非全屏时使用元素尺寸
|
|
363
|
-
* @returns {[number, number]} [width, height]
|
|
364
|
-
*/
|
|
365
|
-
getTargetSize() {
|
|
366
|
-
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];
|
|
367
|
-
}
|
|
368
|
-
/**
|
|
369
|
-
* 移除事件监听器
|
|
370
|
-
* @param {string} event - 事件名称
|
|
371
|
-
* @param {Function} [callback] - 可选的回调函数,如果不提供则移除该事件的所有监听器
|
|
372
|
-
*/
|
|
373
|
-
off(e, t) {
|
|
374
|
-
if (!e) {
|
|
375
|
-
this.eventsListener = {};
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
this.eventsListener[e] && (t ? this.eventsListener[e] = this.eventsListener[e].filter((c) => c !== t) : this.eventsListener[e] = []);
|
|
379
|
-
}
|
|
380
|
-
/**
|
|
381
|
-
* 清理所有资源
|
|
382
|
-
*/
|
|
383
|
-
dispose() {
|
|
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: 资源已清理完成"));
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
// 存储包围盒辅助器
|
|
388
|
-
// 视角类型枚举(作为类静态属性引用,保持向后兼容)
|
|
389
|
-
o(J, "ViewType", y);
|
|
390
|
-
export {
|
|
391
|
-
J as ThreeIns,
|
|
392
|
-
y as ViewType
|
|
393
|
-
};
|
|
@@ -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;
|