three-base 2.0.27 → 2.0.30
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/MeshBase.d.ts +15 -6
- package/MeshBase.js +64 -38
- package/MeshBase.ts +73 -42
- package/ThreeBase.js +6 -1
- package/ThreeBase.ts +7 -1
- package/package.json +1 -1
- package/threeLoader.js +7 -2
- package/threeLoader.ts +6 -2
package/MeshBase.d.ts
CHANGED
|
@@ -1,19 +1,28 @@
|
|
|
1
|
-
import { Group, Mesh, Object3D, Vector3 } from "three";
|
|
1
|
+
import { AnimationAction, AnimationMixer, Clock, Group, Mesh, Object3D, Vector3 } from "three";
|
|
2
2
|
export default class MeshBase extends Group {
|
|
3
3
|
constructor(url?: string);
|
|
4
4
|
static models: Map<string, Object3D>;
|
|
5
5
|
static loadModeling: Map<string, boolean>;
|
|
6
6
|
loaded: boolean;
|
|
7
|
+
hasAnimation: boolean;
|
|
8
|
+
mixer?: AnimationMixer;
|
|
9
|
+
animationActions: {
|
|
10
|
+
[key: string]: AnimationAction;
|
|
11
|
+
};
|
|
7
12
|
loadModel(url: string): Promise<void>;
|
|
8
13
|
frustumCulled: boolean;
|
|
9
14
|
castShadow: boolean;
|
|
10
15
|
receiveShadow: boolean;
|
|
16
|
+
awaitLoaded(callback?: Function): Promise<void>;
|
|
11
17
|
traverseMesh(callback: (mesh: Mesh) => void): Promise<void>;
|
|
18
|
+
clock: Clock;
|
|
19
|
+
setClipActionWeight(weights?: {
|
|
20
|
+
[key: string]: number;
|
|
21
|
+
}): Promise<void>;
|
|
12
22
|
updateMatrix(): void;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
scaleTo(size?: number, key?: Array<"x" | "y" | "z">): void;
|
|
23
|
+
getSize(): Promise<Vector3>;
|
|
24
|
+
center(): Promise<void>;
|
|
25
|
+
alignBottom(y?: number): Promise<void>;
|
|
26
|
+
scaleTo(size?: number, key?: Array<"x" | "y" | "z">): Promise<void>;
|
|
18
27
|
expandBynormal(length: number): void;
|
|
19
28
|
}
|
package/MeshBase.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AnimationMixer, Clock, Group, Mesh, Object3D, Vector3 } from "three";
|
|
2
2
|
import threeUtils from "./threeUtils";
|
|
3
3
|
import threeLoader from "./threeLoader";
|
|
4
|
+
import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils';
|
|
4
5
|
// 模型基类
|
|
5
6
|
export default class MeshBase extends Group {
|
|
6
7
|
constructor(url) {
|
|
@@ -13,6 +14,12 @@ export default class MeshBase extends Group {
|
|
|
13
14
|
static loadModeling = new Map();
|
|
14
15
|
// 加载完成
|
|
15
16
|
loaded = false;
|
|
17
|
+
// 是否有动画
|
|
18
|
+
hasAnimation = false;
|
|
19
|
+
//动画混合器
|
|
20
|
+
mixer;
|
|
21
|
+
//动画剪辑对象数组
|
|
22
|
+
animationActions = {};
|
|
16
23
|
async loadModel(url) {
|
|
17
24
|
if (!url) {
|
|
18
25
|
this.clear();
|
|
@@ -33,6 +40,14 @@ export default class MeshBase extends Group {
|
|
|
33
40
|
else if (/\.(gltf|glb)$/i.test(url)) {
|
|
34
41
|
await threeLoader.gltfLoader.loadAsync(url).then(res => {
|
|
35
42
|
modal = res.scene;
|
|
43
|
+
modal.animations = res.animations;
|
|
44
|
+
}).catch(() => {
|
|
45
|
+
console.error(`${url},加载失败`);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
else if (/\.stl$/i.test(url)) {
|
|
49
|
+
await threeLoader.stlLoader.loadAsync(url).then(stlGeo => {
|
|
50
|
+
modal = new Mesh(stlGeo);
|
|
36
51
|
}).catch(() => {
|
|
37
52
|
console.error(`${url},加载失败`);
|
|
38
53
|
});
|
|
@@ -43,29 +58,32 @@ export default class MeshBase extends Group {
|
|
|
43
58
|
threeUtils.center(modal);
|
|
44
59
|
threeUtils.alignBottom(modal);
|
|
45
60
|
modal.updateMatrixWorld(true);
|
|
46
|
-
// 应用全部变换
|
|
47
|
-
modal.traverse(obj => {
|
|
48
|
-
const mesh = obj;
|
|
49
|
-
mesh.position.set(0, 0, 0);
|
|
50
|
-
mesh.rotation.set(0, 0, 0);
|
|
51
|
-
mesh.scale.set(1, 1, 1);
|
|
52
|
-
if (mesh.isMesh) {
|
|
53
|
-
mesh.geometry.applyMatrix4(mesh.matrixWorld);
|
|
54
|
-
mesh.material.side = DoubleSide;
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
61
|
MeshBase.models.set(url, modal);
|
|
58
62
|
MeshBase.loadModeling.set(url, false);
|
|
59
63
|
}
|
|
60
64
|
// 如果模型还在加载中, 就等待模型加载完成
|
|
61
65
|
do {
|
|
62
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
66
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
63
67
|
} while (MeshBase.loadModeling.get(url));
|
|
64
68
|
if (MeshBase.models.get(url)) {
|
|
65
|
-
const mesh = MeshBase.models.get(url).clone();
|
|
66
69
|
this.clear();
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
const mesh = MeshBase.models.get(url);
|
|
71
|
+
// 判断是否有动画
|
|
72
|
+
this.hasAnimation = mesh.animations.length > 0;
|
|
73
|
+
if (this.hasAnimation) {
|
|
74
|
+
const model = SkeletonUtils.clone(mesh);
|
|
75
|
+
this.mixer = new AnimationMixer(model);
|
|
76
|
+
this.animationActions = {};
|
|
77
|
+
mesh.animations.map(animation => {
|
|
78
|
+
const animationAction = this.mixer.clipAction(animation).play();
|
|
79
|
+
animationAction.weight = 0;
|
|
80
|
+
this.animationActions[animation.name] = animationAction;
|
|
81
|
+
});
|
|
82
|
+
this.add(model);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
this.add(mesh.clone());
|
|
86
|
+
}
|
|
69
87
|
}
|
|
70
88
|
await new Promise(resolve => requestAnimationFrame(resolve));
|
|
71
89
|
// 加载完成事件
|
|
@@ -78,11 +96,17 @@ export default class MeshBase extends Group {
|
|
|
78
96
|
castShadow = false;
|
|
79
97
|
// 接受阴影
|
|
80
98
|
receiveShadow = false;
|
|
81
|
-
|
|
82
|
-
async
|
|
99
|
+
// 等待加载加载完成
|
|
100
|
+
async awaitLoaded(callback) {
|
|
83
101
|
while (!this.loaded) {
|
|
84
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
102
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
85
103
|
}
|
|
104
|
+
callback && callback();
|
|
105
|
+
}
|
|
106
|
+
//遍历模型
|
|
107
|
+
async traverseMesh(callback) {
|
|
108
|
+
// 等待加载完成
|
|
109
|
+
await this.awaitLoaded();
|
|
86
110
|
this.traverse(obj => {
|
|
87
111
|
const mesh = obj;
|
|
88
112
|
if (mesh.isMesh) {
|
|
@@ -90,7 +114,20 @@ export default class MeshBase extends Group {
|
|
|
90
114
|
}
|
|
91
115
|
});
|
|
92
116
|
}
|
|
117
|
+
clock = new Clock();
|
|
118
|
+
//设置动画的权重
|
|
119
|
+
async setClipActionWeight(weights = {}) {
|
|
120
|
+
// 等待加载完成
|
|
121
|
+
await this.awaitLoaded();
|
|
122
|
+
for (let key in this.animationActions) {
|
|
123
|
+
this.animationActions[key].weight = weights[key] || 0;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
93
126
|
updateMatrix() {
|
|
127
|
+
//播放动画
|
|
128
|
+
if (this.mixer) {
|
|
129
|
+
this.mixer.update(this.clock.getDelta());
|
|
130
|
+
}
|
|
94
131
|
// 深度应用属性
|
|
95
132
|
this.traverse(obj => {
|
|
96
133
|
const mesh = obj;
|
|
@@ -102,35 +139,24 @@ export default class MeshBase extends Group {
|
|
|
102
139
|
});
|
|
103
140
|
super.updateMatrix();
|
|
104
141
|
}
|
|
105
|
-
// 应用全部变化
|
|
106
|
-
applyAllTranstion() {
|
|
107
|
-
this.updateMatrixWorld(true);
|
|
108
|
-
// 应用全部变换
|
|
109
|
-
this.traverse(obj => {
|
|
110
|
-
const mesh = obj;
|
|
111
|
-
mesh.position.set(0, 0, 0);
|
|
112
|
-
mesh.rotation.set(0, 0, 0);
|
|
113
|
-
mesh.scale.set(1, 1, 1);
|
|
114
|
-
if (mesh.isMesh) {
|
|
115
|
-
mesh.geometry.applyMatrix4(mesh.matrixWorld);
|
|
116
|
-
mesh.material.side = DoubleSide;
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
142
|
// 获取模型的尺寸
|
|
121
|
-
getSize() {
|
|
143
|
+
async getSize() {
|
|
144
|
+
await this.awaitLoaded();
|
|
122
145
|
return threeUtils.getSize(this);
|
|
123
146
|
}
|
|
124
147
|
// 居中
|
|
125
|
-
center() {
|
|
148
|
+
async center() {
|
|
149
|
+
await this.awaitLoaded();
|
|
126
150
|
threeUtils.center(this);
|
|
127
151
|
}
|
|
128
152
|
//底对齐
|
|
129
|
-
alignBottom(y = 0) {
|
|
153
|
+
async alignBottom(y = 0) {
|
|
154
|
+
await this.awaitLoaded();
|
|
130
155
|
threeUtils.alignBottom(this, y);
|
|
131
156
|
}
|
|
132
157
|
// 放大到指定尺寸
|
|
133
|
-
scaleTo(size = 1, key = ["x", "y", "z"]) {
|
|
158
|
+
async scaleTo(size = 1, key = ["x", "y", "z"]) {
|
|
159
|
+
await this.awaitLoaded();
|
|
134
160
|
threeUtils.scaleTo(this, size, key);
|
|
135
161
|
}
|
|
136
162
|
//按照法线拓展
|
package/MeshBase.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
import { DoubleSide, Group, Mesh, MeshStandardMaterial, Object3D, Vector3 } from "three";
|
|
2
|
+
import { AnimationAction, AnimationMixer, Clock, DoubleSide, Group, Mesh, MeshStandardMaterial, Object3D, Vector3 } from "three";
|
|
3
3
|
import threeUtils from "./threeUtils";
|
|
4
4
|
import threeLoader from "./threeLoader";
|
|
5
|
+
import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils';
|
|
5
6
|
|
|
6
7
|
// 模型基类
|
|
7
8
|
export default class MeshBase extends Group {
|
|
@@ -19,6 +20,15 @@ export default class MeshBase extends Group {
|
|
|
19
20
|
// 加载完成
|
|
20
21
|
loaded = false;
|
|
21
22
|
|
|
23
|
+
// 是否有动画
|
|
24
|
+
hasAnimation = false;
|
|
25
|
+
|
|
26
|
+
//动画混合器
|
|
27
|
+
mixer?: AnimationMixer;
|
|
28
|
+
|
|
29
|
+
//动画剪辑对象数组
|
|
30
|
+
animationActions: { [key: string]: AnimationAction } = {};
|
|
31
|
+
|
|
22
32
|
async loadModel(url: string) {
|
|
23
33
|
if (!url) {
|
|
24
34
|
this.clear();
|
|
@@ -42,6 +52,13 @@ export default class MeshBase extends Group {
|
|
|
42
52
|
} else if (/\.(gltf|glb)$/i.test(url)) {
|
|
43
53
|
await threeLoader.gltfLoader.loadAsync(url).then(res => {
|
|
44
54
|
modal = res.scene;
|
|
55
|
+
modal.animations = res.animations;
|
|
56
|
+
}).catch(() => {
|
|
57
|
+
console.error(`${url},加载失败`);
|
|
58
|
+
})
|
|
59
|
+
} else if (/\.stl$/i.test(url)) {
|
|
60
|
+
await threeLoader.stlLoader.loadAsync(url).then(stlGeo => {
|
|
61
|
+
modal = new Mesh(stlGeo);
|
|
45
62
|
}).catch(() => {
|
|
46
63
|
console.error(`${url},加载失败`);
|
|
47
64
|
})
|
|
@@ -53,32 +70,38 @@ export default class MeshBase extends Group {
|
|
|
53
70
|
threeUtils.alignBottom(modal);
|
|
54
71
|
modal.updateMatrixWorld(true);
|
|
55
72
|
|
|
56
|
-
// 应用全部变换
|
|
57
|
-
modal.traverse(obj => {
|
|
58
|
-
const mesh = obj as Mesh;
|
|
59
|
-
mesh.position.set(0, 0, 0);
|
|
60
|
-
mesh.rotation.set(0, 0, 0);
|
|
61
|
-
mesh.scale.set(1, 1, 1);
|
|
62
|
-
if (mesh.isMesh) {
|
|
63
|
-
mesh.geometry.applyMatrix4(mesh.matrixWorld);
|
|
64
|
-
(mesh.material as MeshStandardMaterial).side = DoubleSide;
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
|
|
68
73
|
MeshBase.models.set(url, modal);
|
|
69
74
|
MeshBase.loadModeling.set(url, false);
|
|
70
75
|
}
|
|
71
76
|
|
|
72
77
|
// 如果模型还在加载中, 就等待模型加载完成
|
|
73
78
|
do {
|
|
74
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
79
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
75
80
|
} while (MeshBase.loadModeling.get(url));
|
|
76
81
|
|
|
77
82
|
if (MeshBase.models.get(url)) {
|
|
78
|
-
|
|
83
|
+
|
|
79
84
|
this.clear();
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
const mesh = MeshBase.models.get(url);
|
|
86
|
+
// 判断是否有动画
|
|
87
|
+
this.hasAnimation = mesh.animations.length > 0;
|
|
88
|
+
|
|
89
|
+
if (this.hasAnimation) {
|
|
90
|
+
const model = SkeletonUtils.clone(mesh);
|
|
91
|
+
this.mixer = new AnimationMixer(model);
|
|
92
|
+
|
|
93
|
+
this.animationActions = {};
|
|
94
|
+
mesh.animations.map(animation => {
|
|
95
|
+
const animationAction = this.mixer.clipAction(animation).play();
|
|
96
|
+
animationAction.weight = 0;
|
|
97
|
+
this.animationActions[animation.name] = animationAction;
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
this.add(model);
|
|
101
|
+
} else {
|
|
102
|
+
this.add(mesh.clone());
|
|
103
|
+
}
|
|
104
|
+
|
|
82
105
|
}
|
|
83
106
|
|
|
84
107
|
await new Promise(resolve => requestAnimationFrame(resolve));
|
|
@@ -98,12 +121,18 @@ export default class MeshBase extends Group {
|
|
|
98
121
|
// 接受阴影
|
|
99
122
|
receiveShadow: boolean = false;
|
|
100
123
|
|
|
101
|
-
|
|
102
|
-
async
|
|
103
|
-
|
|
124
|
+
// 等待加载加载完成
|
|
125
|
+
async awaitLoaded(callback?: Function) {
|
|
104
126
|
while (!this.loaded) {
|
|
105
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
127
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
106
128
|
}
|
|
129
|
+
callback && callback();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
//遍历模型
|
|
133
|
+
async traverseMesh(callback: (mesh: Mesh) => void) {
|
|
134
|
+
// 等待加载完成
|
|
135
|
+
await this.awaitLoaded();
|
|
107
136
|
|
|
108
137
|
this.traverse(obj => {
|
|
109
138
|
const mesh = obj as Mesh;
|
|
@@ -113,8 +142,22 @@ export default class MeshBase extends Group {
|
|
|
113
142
|
});
|
|
114
143
|
}
|
|
115
144
|
|
|
116
|
-
|
|
145
|
+
clock = new Clock();
|
|
146
|
+
|
|
147
|
+
//设置动画的权重
|
|
148
|
+
async setClipActionWeight(weights: { [key: string]: number } = {}) {
|
|
149
|
+
// 等待加载完成
|
|
150
|
+
await this.awaitLoaded();
|
|
151
|
+
for (let key in this.animationActions) {
|
|
152
|
+
this.animationActions[key].weight = weights[key] || 0;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
117
155
|
|
|
156
|
+
updateMatrix(): void {
|
|
157
|
+
//播放动画
|
|
158
|
+
if (this.mixer) {
|
|
159
|
+
this.mixer.update(this.clock.getDelta());
|
|
160
|
+
}
|
|
118
161
|
// 深度应用属性
|
|
119
162
|
this.traverse(obj => {
|
|
120
163
|
const mesh = obj as Mesh;
|
|
@@ -128,39 +171,27 @@ export default class MeshBase extends Group {
|
|
|
128
171
|
super.updateMatrix();
|
|
129
172
|
}
|
|
130
173
|
|
|
131
|
-
// 应用全部变化
|
|
132
|
-
applyAllTranstion() {
|
|
133
|
-
this.updateMatrixWorld(true);
|
|
134
|
-
// 应用全部变换
|
|
135
|
-
this.traverse(obj => {
|
|
136
|
-
const mesh = obj as Mesh;
|
|
137
|
-
mesh.position.set(0, 0, 0);
|
|
138
|
-
mesh.rotation.set(0, 0, 0);
|
|
139
|
-
mesh.scale.set(1, 1, 1);
|
|
140
|
-
if (mesh.isMesh) {
|
|
141
|
-
mesh.geometry.applyMatrix4(mesh.matrixWorld);
|
|
142
|
-
(mesh.material as MeshStandardMaterial).side = DoubleSide;
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
|
|
147
174
|
// 获取模型的尺寸
|
|
148
|
-
getSize() {
|
|
175
|
+
async getSize() {
|
|
176
|
+
await this.awaitLoaded();
|
|
149
177
|
return threeUtils.getSize(this);
|
|
150
178
|
}
|
|
151
179
|
|
|
152
180
|
// 居中
|
|
153
|
-
center() {
|
|
181
|
+
async center() {
|
|
182
|
+
await this.awaitLoaded();
|
|
154
183
|
threeUtils.center(this);
|
|
155
184
|
}
|
|
156
185
|
|
|
157
186
|
//底对齐
|
|
158
|
-
alignBottom(y: number = 0) {
|
|
187
|
+
async alignBottom(y: number = 0) {
|
|
188
|
+
await this.awaitLoaded();
|
|
159
189
|
threeUtils.alignBottom(this, y);
|
|
160
190
|
}
|
|
161
191
|
|
|
162
192
|
// 放大到指定尺寸
|
|
163
|
-
scaleTo(size: number = 1, key: Array<"x" | "y" | "z"> = ["x", "y", "z"]) {
|
|
193
|
+
async scaleTo(size: number = 1, key: Array<"x" | "y" | "z"> = ["x", "y", "z"]) {
|
|
194
|
+
await this.awaitLoaded();
|
|
164
195
|
threeUtils.scaleTo(this, size, key);
|
|
165
196
|
}
|
|
166
197
|
|
package/ThreeBase.js
CHANGED
|
@@ -187,7 +187,12 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
187
187
|
frame = 50;
|
|
188
188
|
init() {
|
|
189
189
|
// 资源加载进度有更新时, 需要渲染
|
|
190
|
-
threeLoader.addEventListener("
|
|
190
|
+
threeLoader.addEventListener("loadding", () => {
|
|
191
|
+
this.dispatchEvent({ type: "loadding" });
|
|
192
|
+
this.needRender = true;
|
|
193
|
+
});
|
|
194
|
+
threeLoader.addEventListener("onLoad", () => {
|
|
195
|
+
this.dispatchEvent({ type: "onLoad" });
|
|
191
196
|
this.needRender = true;
|
|
192
197
|
});
|
|
193
198
|
}
|
package/ThreeBase.ts
CHANGED
|
@@ -227,7 +227,13 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
227
227
|
|
|
228
228
|
init() {
|
|
229
229
|
// 资源加载进度有更新时, 需要渲染
|
|
230
|
-
threeLoader.addEventListener("
|
|
230
|
+
threeLoader.addEventListener("loadding", () => {
|
|
231
|
+
this.dispatchEvent({ type: "loadding" } as never);
|
|
232
|
+
this.needRender = true;
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
threeLoader.addEventListener("onLoad", () => {
|
|
236
|
+
this.dispatchEvent({ type: "onLoad" } as never);
|
|
231
237
|
this.needRender = true;
|
|
232
238
|
});
|
|
233
239
|
|
package/package.json
CHANGED
package/threeLoader.js
CHANGED
|
@@ -26,8 +26,13 @@ class ThreeLoader extends EventDispatcher {
|
|
|
26
26
|
this.onload = false;
|
|
27
27
|
};
|
|
28
28
|
// 有资源加载完成时通知渲染器
|
|
29
|
-
DefaultLoadingManager.onProgress = () => {
|
|
30
|
-
|
|
29
|
+
DefaultLoadingManager.onProgress = (url, loaded, total) => {
|
|
30
|
+
if (loaded < total) {
|
|
31
|
+
this.dispatchEvent({ type: "loadding" });
|
|
32
|
+
}
|
|
33
|
+
else if (loaded === total) {
|
|
34
|
+
this.dispatchEvent({ type: "onLoad" });
|
|
35
|
+
}
|
|
31
36
|
};
|
|
32
37
|
DefaultLoadingManager.onLoad = () => {
|
|
33
38
|
this.onload = true;
|
package/threeLoader.ts
CHANGED
|
@@ -32,8 +32,12 @@ class ThreeLoader extends EventDispatcher {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
// 有资源加载完成时通知渲染器
|
|
35
|
-
DefaultLoadingManager.onProgress = () => {
|
|
36
|
-
|
|
35
|
+
DefaultLoadingManager.onProgress = (url: string, loaded: number, total: number) => {
|
|
36
|
+
if (loaded < total) {
|
|
37
|
+
this.dispatchEvent({ type: "loadding" } as never);
|
|
38
|
+
} else if (loaded === total) {
|
|
39
|
+
this.dispatchEvent({ type: "onLoad" } as never);
|
|
40
|
+
}
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
DefaultLoadingManager.onLoad = () => {
|