@preference-sl/pref-viewer 2.11.0-beta.3 → 2.11.0-beta.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.
- package/package.json +1 -2
- package/src/babylonjs-animation-controller.js +51 -392
- package/src/babylonjs-animation-opening-menu.js +360 -0
- package/src/babylonjs-animation-opening.js +496 -0
- package/src/babylonjs-controller.js +11 -10
- package/src/pref-viewer-3d.js +1 -1
- package/src/images/icon-pause.svg +0 -1
- package/src/images/icon-play-backwards.svg +0 -1
- package/src/images/icon-play.svg +0 -1
- package/src/images/icon-skip-backward.svg +0 -1
- package/src/images/icon-skip-forward.svg +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@preference-sl/pref-viewer",
|
|
3
|
-
"version": "2.11.0-beta.
|
|
3
|
+
"version": "2.11.0-beta.4",
|
|
4
4
|
"description": "Web Component to preview GLTF models with Babylon.js",
|
|
5
5
|
"author": "Alex Moreno Palacio <amoreno@preference.es>",
|
|
6
6
|
"scripts": {
|
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
"sideEffects": false,
|
|
31
31
|
"files": [
|
|
32
32
|
"src",
|
|
33
|
-
"src/images",
|
|
34
33
|
"index.d.ts"
|
|
35
34
|
],
|
|
36
35
|
"dependencies": {
|
|
@@ -1,382 +1,21 @@
|
|
|
1
|
-
import { Color3, PointerEventTypes,
|
|
2
|
-
import { AdvancedDynamicTexture
|
|
3
|
-
|
|
4
|
-
// https://doc.babylonjs.com/typedoc/classes/BABYLON.AnimationGroup
|
|
5
|
-
class OpeningAnimationController {
|
|
6
|
-
static states = {
|
|
7
|
-
paused: 0,
|
|
8
|
-
closed: 1,
|
|
9
|
-
opened: 2,
|
|
10
|
-
opening: 3,
|
|
11
|
-
closing: 4,
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
#openAnimation = null;
|
|
15
|
-
#closeAnimation = null;
|
|
16
|
-
|
|
17
|
-
#nodes = [];
|
|
18
|
-
#state = OpeningAnimationController.states.closed;
|
|
19
|
-
#currentFrame = 0;
|
|
20
|
-
#startFrame = 0;
|
|
21
|
-
#endFrame = 0;
|
|
22
|
-
#speedRatio = 1.0;
|
|
23
|
-
|
|
24
|
-
#advancedDynamicTexture = null;
|
|
25
|
-
#menu = null;
|
|
26
|
-
|
|
27
|
-
constructor(name, openAnimationGroup, closeAnimationGroup) {
|
|
28
|
-
this.name = name;
|
|
29
|
-
this.#openAnimation = openAnimationGroup;
|
|
30
|
-
this.#closeAnimation = closeAnimationGroup;
|
|
31
|
-
|
|
32
|
-
this.#openAnimation.stop();
|
|
33
|
-
this.#openAnimation._loopAnimation = false;
|
|
34
|
-
this.#closeAnimation.stop();
|
|
35
|
-
this.#closeAnimation._loopAnimation = false;
|
|
36
|
-
|
|
37
|
-
this.#startFrame = this.#openAnimation.from;
|
|
38
|
-
this.#endFrame = this.#openAnimation.to;
|
|
39
|
-
this.#speedRatio = this.#openAnimation.speedRatio || 1.0;
|
|
40
|
-
|
|
41
|
-
this.#getNodesFromAnimationGroups();
|
|
42
|
-
this.#openAnimation.onAnimationGroupEndObservable.add(this.#onOpened.bind(this));
|
|
43
|
-
this.#closeAnimation.onAnimationGroupEndObservable.add(this.#onClosed.bind(this));
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
#getNodesFromAnimationGroups() {
|
|
47
|
-
[this.#openAnimation, this.#closeAnimation].forEach((animationGroup) => {
|
|
48
|
-
animationGroup._targetedAnimations.forEach((targetedAnimation) => {
|
|
49
|
-
if (!this.#nodes.includes(targetedAnimation.target.id)) {
|
|
50
|
-
this.#nodes.push(targetedAnimation.target.id);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
#onOpened() {
|
|
57
|
-
this.goToOpened();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
#onClosed() {
|
|
61
|
-
this.goToClosed();
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* ---------------------------
|
|
66
|
-
* Public methods
|
|
67
|
-
* ---------------------------
|
|
68
|
-
*/
|
|
69
|
-
|
|
70
|
-
isAnimationForNode(node) {
|
|
71
|
-
return this.#nodes.includes(node);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
playOpen() {
|
|
75
|
-
if (this.#state === OpeningAnimationController.states.opening || this.#state === OpeningAnimationController.states.opened) {
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
if (this.#state === OpeningAnimationController.states.closing) {
|
|
79
|
-
this.#currentFrame = this.#endFrame - this.#closeAnimation.getCurrentFrame();
|
|
80
|
-
this.#closeAnimation.pause();
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (this.#openAnimation._isStarted && this.#openAnimation._isPaused) {
|
|
84
|
-
this.#openAnimation.goToFrame(this.#currentFrame);
|
|
85
|
-
this.#openAnimation.restart();
|
|
86
|
-
} else {
|
|
87
|
-
this.#openAnimation.start(false, this.#speedRatio, this.#currentFrame, this.#endFrame, undefined);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
this.#state = OpeningAnimationController.states.opening;
|
|
91
|
-
this.updateControls();
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
playClose() {
|
|
95
|
-
if (this.#state === OpeningAnimationController.states.closing || this.#state === OpeningAnimationController.states.closed) {
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
if (this.#state === OpeningAnimationController.states.opening) {
|
|
99
|
-
this.#currentFrame = this.#openAnimation.getCurrentFrame();
|
|
100
|
-
this.#openAnimation.pause();
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (this.#closeAnimation._isStarted && this.#closeAnimation._isPaused) {
|
|
104
|
-
this.#closeAnimation.goToFrame(this.#endFrame - this.#currentFrame);
|
|
105
|
-
this.#closeAnimation.restart();
|
|
106
|
-
} else {
|
|
107
|
-
this.#closeAnimation.start(false, this.#speedRatio, this.#endFrame - this.#currentFrame, this.#endFrame, undefined);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
this.#state = OpeningAnimationController.states.closing;
|
|
111
|
-
this.updateControls();
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
pause() {
|
|
115
|
-
if (this.#state === OpeningAnimationController.states.opening) {
|
|
116
|
-
this.#currentFrame = this.#openAnimation.getCurrentFrame();
|
|
117
|
-
this.#openAnimation.pause();
|
|
118
|
-
}
|
|
119
|
-
if (this.#state === OpeningAnimationController.states.closing) {
|
|
120
|
-
this.#currentFrame = this.#endFrame - this.#closeAnimation.getCurrentFrame();
|
|
121
|
-
this.#closeAnimation.pause();
|
|
122
|
-
}
|
|
123
|
-
this.#state = OpeningAnimationController.states.paused;
|
|
124
|
-
this.updateControls();
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
goToOpened() {
|
|
128
|
-
this.#currentFrame = this.#endFrame;
|
|
129
|
-
|
|
130
|
-
if (this.#openAnimation._isStarted) {
|
|
131
|
-
this.#openAnimation.start();
|
|
132
|
-
}
|
|
133
|
-
this.#openAnimation.pause();
|
|
134
|
-
this.#openAnimation.goToFrame(this.#endFrame);
|
|
135
|
-
|
|
136
|
-
if (!this.#closeAnimation._isStarted) {
|
|
137
|
-
this.#closeAnimation.start();
|
|
138
|
-
}
|
|
139
|
-
this.#closeAnimation.pause();
|
|
140
|
-
this.#closeAnimation.goToFrame(this.#startFrame);
|
|
141
|
-
|
|
142
|
-
this.#state = OpeningAnimationController.states.opened;
|
|
143
|
-
this.updateControls();
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
goToClosed() {
|
|
147
|
-
this.#currentFrame = this.#startFrame;
|
|
148
|
-
if (this.#openAnimation._isStarted) {
|
|
149
|
-
this.#openAnimation.start();
|
|
150
|
-
}
|
|
151
|
-
this.#openAnimation.pause();
|
|
152
|
-
this.#openAnimation.goToFrame(this.#startFrame);
|
|
153
|
-
|
|
154
|
-
if (this.#closeAnimation._isStarted) {
|
|
155
|
-
this.#closeAnimation.start();
|
|
156
|
-
}
|
|
157
|
-
this.#closeAnimation.pause();
|
|
158
|
-
this.#closeAnimation.goToFrame(this.#endFrame);
|
|
159
|
-
|
|
160
|
-
this.#state = OpeningAnimationController.states.closed;
|
|
161
|
-
this.updateControls();
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
showControls(advancedDynamicTexture, mesh) {
|
|
165
|
-
this.#advancedDynamicTexture = advancedDynamicTexture;
|
|
166
|
-
this.#advancedDynamicTexture.metadata = { name: this.name };
|
|
167
|
-
const controlCallbacks = {
|
|
168
|
-
onGoToOpened: () => {
|
|
169
|
-
if (this.#state === OpeningAnimationController.states.opened) {
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
this.goToOpened();
|
|
173
|
-
this.hideControls();
|
|
174
|
-
},
|
|
175
|
-
onOpen: () => {
|
|
176
|
-
if (this.#state === OpeningAnimationController.states.opened || this.#state === OpeningAnimationController.states.opening) {
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
this.playOpen();
|
|
180
|
-
this.hideControls();
|
|
181
|
-
},
|
|
182
|
-
onPause: () => {
|
|
183
|
-
if (this.#state === OpeningAnimationController.states.paused || this.#state === OpeningAnimationController.states.closed || this.#state === OpeningAnimationController.states.opened) {
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
this.pause();
|
|
187
|
-
this.hideControls();
|
|
188
|
-
},
|
|
189
|
-
onClose: () => {
|
|
190
|
-
if (this.#state === OpeningAnimationController.states.closed || this.#state === OpeningAnimationController.states.closing) {
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
this.playClose();
|
|
194
|
-
this.hideControls();
|
|
195
|
-
},
|
|
196
|
-
onGoToClosed: () => {
|
|
197
|
-
if (this.#state === OpeningAnimationController.states.closed) {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
this.goToClosed();
|
|
201
|
-
this.hideControls();
|
|
202
|
-
},
|
|
203
|
-
};
|
|
204
|
-
this.#menu = new AnimationMenu(this.#advancedDynamicTexture, mesh, this.#state, controlCallbacks);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
hideControls() {
|
|
208
|
-
if (!this.isControlsVisible()) {
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
this.#advancedDynamicTexture.dispose();
|
|
212
|
-
this.#advancedDynamicTexture = null;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
updateControls() {
|
|
216
|
-
if (!this.isControlsVisible()) {
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
if (!this.#menu) {
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
this.#menu.animationState = this.#state;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
isControlsVisible() {
|
|
226
|
-
return this.#advancedDynamicTexture !== null || this.#advancedDynamicTexture?.metadata?.name === this.name;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* ---------------------------
|
|
231
|
-
* Public properties
|
|
232
|
-
* ---------------------------
|
|
233
|
-
*/
|
|
234
|
-
|
|
235
|
-
get state() {
|
|
236
|
-
return this.#state;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* AnimationMenu - Models and renders a popup menu for controlling animation playback in a Babylon.js 3D scene.
|
|
242
|
-
*
|
|
243
|
-
* Responsibilities:
|
|
244
|
-
* - Creates a Babylon.js GUI panel with buttons for animation actions (open, close, pause, go to opened/closed).
|
|
245
|
-
* - Handles button states (enabled/disabled, active/inactive) based on animation state.
|
|
246
|
-
* - Attaches the menu to a mesh and disposes it when an action is taken.
|
|
247
|
-
* - Allows external callbacks for each action.
|
|
248
|
-
*
|
|
249
|
-
* Usage:
|
|
250
|
-
* const menu = new AnimationMenu(advancedDynamicTexture, mesh, animationState, {
|
|
251
|
-
* onOpen: () => { ... },
|
|
252
|
-
* onClose: () => { ... },
|
|
253
|
-
* onPause: () => { ... },
|
|
254
|
-
* onGoToOpened: () => { ... },
|
|
255
|
-
* onGoToClosed: () => { ... }
|
|
256
|
-
* });
|
|
257
|
-
* menu.show();
|
|
258
|
-
* menu.hide();
|
|
259
|
-
*/
|
|
260
|
-
|
|
261
|
-
class AnimationMenu {
|
|
262
|
-
#advancedDynamicTexture = null;
|
|
263
|
-
#animationState = OpeningAnimationController.states.closed;
|
|
264
|
-
#mesh = null;
|
|
265
|
-
#callbacks = null;
|
|
266
|
-
#panel = null;
|
|
267
|
-
#colorActive = "#6BA53A";
|
|
268
|
-
#colorEnabled = "#333333";
|
|
269
|
-
#colorDisabled = "#777777";
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* @param {AdvancedDynamicTexture} advancedDynamicTexture - Babylon.js GUI texture.
|
|
273
|
-
* @param {BABYLON.Mesh} mesh - Mesh to attach the menu to.
|
|
274
|
-
* @param {number} animationState - Current animation state (enum).
|
|
275
|
-
* @param {object} callbacks - Callback functions for menu actions.
|
|
276
|
-
*/
|
|
277
|
-
constructor(advancedDynamicTexture, mesh, animationState, callbacks) {
|
|
278
|
-
this.#advancedDynamicTexture = advancedDynamicTexture;
|
|
279
|
-
this.#mesh = mesh;
|
|
280
|
-
this.#animationState = animationState;
|
|
281
|
-
this.#callbacks = callbacks;
|
|
282
|
-
|
|
283
|
-
this.#createMenu(animationState);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Renders the menu and attaches it to the mesh.
|
|
288
|
-
*/
|
|
289
|
-
#createMenu() {
|
|
290
|
-
if (!this.#advancedDynamicTexture || !this.#mesh) {
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
this.#panel = new StackPanel();
|
|
294
|
-
this.#panel.isVertical = false;
|
|
295
|
-
this.#panel.verticalAlignment = Control.VERTICAL_ALIGNMENT_BOTTOM;
|
|
296
|
-
this.#panel.left = 0;
|
|
297
|
-
this.#panel.top = 0;
|
|
298
|
-
this.#advancedDynamicTexture.addControl(this.#panel);
|
|
299
|
-
this.#panel.linkWithMesh(this.#mesh);
|
|
300
|
-
|
|
301
|
-
this.#createButtons();
|
|
302
|
-
this.#setButtonsState();
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Internal helper to add a button to the menu.
|
|
307
|
-
* @private
|
|
308
|
-
*/
|
|
309
|
-
#addButton(name, imageURL, callback) {
|
|
310
|
-
const button = Button.CreateImageOnlyButton(`button_animation_${name}`, imageURL);
|
|
311
|
-
button.image.stretch = Image.STRETCH_UNIFORM;
|
|
312
|
-
button.color = "white";
|
|
313
|
-
button.hoverCursor = "pointer";
|
|
314
|
-
button.width = "28px";
|
|
315
|
-
button.height = "28px";
|
|
316
|
-
button.cornerRadius = 0;
|
|
317
|
-
button.background = this.#colorEnabled;
|
|
318
|
-
button.onPointerUpObservable.add(() => {
|
|
319
|
-
if (callback) {
|
|
320
|
-
callback();
|
|
321
|
-
}
|
|
322
|
-
});
|
|
323
|
-
this.#panel.addControl(button);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
#createButtons() {
|
|
327
|
-
this.#addButton("closed", "../src/images/icon-skip-backward.svg", this.#callbacks.onGoToClosed);
|
|
328
|
-
this.#addButton("close", "../src/images/icon-play-backwards.svg", this.#callbacks.onClose);
|
|
329
|
-
this.#addButton("pause", "../src/images/icon-pause.svg", this.#callbacks.onPause);
|
|
330
|
-
this.#addButton("open", "../src/images/icon-play.svg", this.#callbacks.onOpen);
|
|
331
|
-
this.#addButton("opened", "../src/images/icon-skip-forward.svg", this.#callbacks.onGoToOpened);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
#setButtonState(name, enabled, active) {
|
|
335
|
-
const button = this.#advancedDynamicTexture.getControlByName(`button_animation_${name}`);
|
|
336
|
-
if (!button) {
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
button.background = active ? this.#colorActive : enabled ? this.#colorEnabled : this.#colorDisabled;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
#setButtonsState() {
|
|
343
|
-
const goToOpenedButtonEnabled = this.#animationState !== OpeningAnimationController.states.opened;
|
|
344
|
-
const goToOpenedButtonActive = false;
|
|
345
|
-
const openButtonEnabled = this.#animationState !== OpeningAnimationController.states.opened && this.#animationState !== OpeningAnimationController.states.opening;
|
|
346
|
-
const openButtonActive = this.#animationState === OpeningAnimationController.states.opening;
|
|
347
|
-
const pauseButtonEnabled = this.#animationState !== OpeningAnimationController.states.paused && this.#animationState !== OpeningAnimationController.states.closed && this.#animationState !== OpeningAnimationController.states.opened;
|
|
348
|
-
const pauseButtonActive = this.#animationState === OpeningAnimationController.states.paused;
|
|
349
|
-
const closeButtonEnabled = this.#animationState !== OpeningAnimationController.states.closed && this.#animationState !== OpeningAnimationController.states.closing;
|
|
350
|
-
const closeButtonActive = this.#animationState === OpeningAnimationController.states.closing;
|
|
351
|
-
const goToClosedButtonEnabled = this.#animationState !== OpeningAnimationController.states.closed;
|
|
352
|
-
const goToClosedButtonActive = false;
|
|
353
|
-
|
|
354
|
-
this.#setButtonState("opened", goToOpenedButtonEnabled, goToOpenedButtonActive);
|
|
355
|
-
this.#setButtonState("open", openButtonEnabled, openButtonActive);
|
|
356
|
-
this.#setButtonState("pause", pauseButtonEnabled, pauseButtonActive);
|
|
357
|
-
this.#setButtonState("close", closeButtonEnabled, closeButtonActive);
|
|
358
|
-
this.#setButtonState("closed", goToClosedButtonEnabled, goToClosedButtonActive);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
set animationState(state) {
|
|
362
|
-
this.#animationState = state;
|
|
363
|
-
this.#setButtonsState();
|
|
364
|
-
}
|
|
365
|
-
}
|
|
1
|
+
import { Color3, HighlightLayer, Mesh, PickingInfo, PointerEventTypes, Scene } from "@babylonjs/core";
|
|
2
|
+
import { AdvancedDynamicTexture } from "@babylonjs/gui";
|
|
3
|
+
import { OpeningAnimation } from "./babylonjs-animation-opening.js";
|
|
366
4
|
|
|
367
5
|
/**
|
|
368
6
|
* BabylonJSAnimationController - Manages animation playback and interactive highlighting for model containers in Babylon.js scenes.
|
|
369
7
|
*
|
|
370
8
|
* Responsibilities:
|
|
371
|
-
* - Detects
|
|
372
|
-
* -
|
|
373
|
-
* -
|
|
374
|
-
* -
|
|
375
|
-
* - Provides API for
|
|
9
|
+
* - Detects and groups opening/closing animations in the scene.
|
|
10
|
+
* - Tracks animated transformation nodes and their relationships to meshes.
|
|
11
|
+
* - Highlights animated nodes and their child meshes when hovered.
|
|
12
|
+
* - Displays and disposes the animation control menu (GUI) for animated nodes.
|
|
13
|
+
* - Provides API for interaction and animation control.
|
|
14
|
+
*
|
|
15
|
+
* @class
|
|
376
16
|
*/
|
|
377
17
|
export default class BabylonJSAnimationController {
|
|
378
18
|
#scene = null;
|
|
379
|
-
#assetContainer = null;
|
|
380
19
|
#animatedNodes = [];
|
|
381
20
|
#highlightLayer = null;
|
|
382
21
|
#highlightColor = new Color3(0, 1, 0); // Color para resaltar los elementos animados (Verde)
|
|
@@ -384,31 +23,33 @@ export default class BabylonJSAnimationController {
|
|
|
384
23
|
#openingAnimations = [];
|
|
385
24
|
|
|
386
25
|
/**
|
|
387
|
-
*
|
|
388
|
-
* @param {
|
|
26
|
+
* Creates a new BabylonJSAnimationController for a Babylon.js scene.
|
|
27
|
+
* @param {Scene} scene - The Babylon.js scene instance.
|
|
389
28
|
*/
|
|
390
|
-
constructor(scene
|
|
29
|
+
constructor(scene) {
|
|
391
30
|
this.#scene = scene;
|
|
392
|
-
this.#assetContainer = assetContainer;
|
|
393
31
|
this.#initializeAnimations();
|
|
394
32
|
this.#setupPointerObservers();
|
|
395
33
|
}
|
|
396
34
|
|
|
397
35
|
/**
|
|
398
|
-
* Detects and stores animatable objects and animated nodes in the
|
|
36
|
+
* Detects and stores animatable objects and animated nodes in the scene.
|
|
399
37
|
* @private
|
|
400
38
|
*/
|
|
401
39
|
#initializeAnimations() {
|
|
402
|
-
if (!this.#
|
|
40
|
+
if (!this.#scene.animationGroups.length) {
|
|
403
41
|
return;
|
|
404
42
|
}
|
|
405
|
-
|
|
406
43
|
this.#getAnimatedNodes();
|
|
407
44
|
this.#getOpeneingAnimations();
|
|
408
45
|
}
|
|
409
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Collects the IDs of all nodes targeted by any animation group in the scene.
|
|
49
|
+
* @private
|
|
50
|
+
*/
|
|
410
51
|
#getAnimatedNodes() {
|
|
411
|
-
this.#
|
|
52
|
+
this.#scene.animationGroups.forEach((animationGroup) => {
|
|
412
53
|
if (!animationGroup._targetedAnimations.length) {
|
|
413
54
|
return;
|
|
414
55
|
}
|
|
@@ -420,9 +61,15 @@ export default class BabylonJSAnimationController {
|
|
|
420
61
|
});
|
|
421
62
|
}
|
|
422
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Groups opening and closing animations by node name and creates OpeningAnimation instances.
|
|
66
|
+
* @private
|
|
67
|
+
* @description
|
|
68
|
+
* Uses animation group names with the pattern "animation_open_<name>" and "animation_close_<name>".
|
|
69
|
+
*/
|
|
423
70
|
#getOpeneingAnimations() {
|
|
424
71
|
const openings = {};
|
|
425
|
-
this.#
|
|
72
|
+
this.#scene.animationGroups.forEach((animationGroup) => {
|
|
426
73
|
const match = animationGroup.name.match(/^animation_(open|close)_(.+)$/);
|
|
427
74
|
if (!match) {
|
|
428
75
|
return;
|
|
@@ -439,21 +86,25 @@ export default class BabylonJSAnimationController {
|
|
|
439
86
|
});
|
|
440
87
|
|
|
441
88
|
Object.values(openings).forEach((opening) => {
|
|
442
|
-
this.#openingAnimations.push(new
|
|
89
|
+
this.#openingAnimations.push(new OpeningAnimation(opening.name, opening.animationOpen, opening.animationClose));
|
|
443
90
|
});
|
|
444
91
|
}
|
|
445
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Finds the OpeningAnimation instance associated with a given node ID.
|
|
95
|
+
* @private
|
|
96
|
+
* @param {string} nodeId - The node identifier.
|
|
97
|
+
* @returns {OpeningAnimation|null} The matching OpeningAnimation instance or null.
|
|
98
|
+
*/
|
|
446
99
|
#getOpeningAnimationByNode(nodeId) {
|
|
447
100
|
return this.#openingAnimations.find((openingAnimation) => openingAnimation.isAnimationForNode(nodeId));
|
|
448
101
|
}
|
|
449
102
|
|
|
450
103
|
/**
|
|
451
|
-
*
|
|
452
|
-
* @
|
|
453
|
-
* @param {
|
|
454
|
-
* @returns {
|
|
455
|
-
* @description
|
|
456
|
-
* El segundo elemento del array devuelto es se necesita para poder resaltar esas mallas hijas cuando el puntero del ratón está sobre alguna de ellas
|
|
104
|
+
* Determines if a mesh belongs to a node targeted by an animation.
|
|
105
|
+
* @private
|
|
106
|
+
* @param {Mesh} mesh - The mesh to check.
|
|
107
|
+
* @returns {string|false} The animated node ID if found, otherwise false.
|
|
457
108
|
*/
|
|
458
109
|
#getNodeAnimatedByMesh = function (mesh) {
|
|
459
110
|
let nodeId = false;
|
|
@@ -468,8 +119,9 @@ export default class BabylonJSAnimationController {
|
|
|
468
119
|
};
|
|
469
120
|
|
|
470
121
|
/**
|
|
471
|
-
*
|
|
472
|
-
* @
|
|
122
|
+
* Highlights meshes that are children of an animated node when hovered.
|
|
123
|
+
* @private
|
|
124
|
+
* @param {PickingInfo} pickingInfo - Raycast info from pointer position.
|
|
473
125
|
*/
|
|
474
126
|
#hightlightMeshesForAnimation(pickingInfo) {
|
|
475
127
|
if (!this.#highlightLayer) {
|
|
@@ -494,7 +146,7 @@ export default class BabylonJSAnimationController {
|
|
|
494
146
|
}
|
|
495
147
|
|
|
496
148
|
/**
|
|
497
|
-
* Sets up pointer observers to highlight animated nodes on hover.
|
|
149
|
+
* Sets up pointer observers to highlight animated nodes on hover and show the animation menu on click.
|
|
498
150
|
* @private
|
|
499
151
|
*/
|
|
500
152
|
#setupPointerObservers() {
|
|
@@ -504,7 +156,7 @@ export default class BabylonJSAnimationController {
|
|
|
504
156
|
this.#hightlightMeshesForAnimation(pickingInfo);
|
|
505
157
|
}
|
|
506
158
|
if (pointerInfo.type === PointerEventTypes.POINTERUP) {
|
|
507
|
-
//
|
|
159
|
+
// Remove any previously created Babylon GUI
|
|
508
160
|
if (this.#advancedDynamicTexture) {
|
|
509
161
|
this.#advancedDynamicTexture.dispose();
|
|
510
162
|
this.#advancedDynamicTexture = null;
|
|
@@ -515,6 +167,13 @@ export default class BabylonJSAnimationController {
|
|
|
515
167
|
});
|
|
516
168
|
}
|
|
517
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Displays the animation control menu for the animated node under the pointer.
|
|
172
|
+
* @private
|
|
173
|
+
* @param {PickingInfo} pickingInfo - Raycast info from pointer position.
|
|
174
|
+
* @description
|
|
175
|
+
* Creates the GUI if needed and invokes OpeningAnimation.showControls.
|
|
176
|
+
*/
|
|
518
177
|
#showMenu(pickingInfo) {
|
|
519
178
|
if (!pickingInfo?.hit && !pickingInfo?.pickedMesh) {
|
|
520
179
|
return;
|
|
@@ -531,6 +190,6 @@ export default class BabylonJSAnimationController {
|
|
|
531
190
|
if (!this.#advancedDynamicTexture) {
|
|
532
191
|
this.#advancedDynamicTexture = AdvancedDynamicTexture.CreateFullscreenUI("UI_Animation");
|
|
533
192
|
}
|
|
534
|
-
openingAnimation.showControls(this.#advancedDynamicTexture
|
|
193
|
+
openingAnimation.showControls(this.#advancedDynamicTexture);
|
|
535
194
|
}
|
|
536
195
|
}
|