@preference-sl/pref-viewer 2.11.0-beta.9 → 2.12.0-beta.1
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 +61 -50
- package/src/babylonjs-animation-controller.js +95 -95
- package/src/babylonjs-animation-opening-menu.js +255 -156
- package/src/babylonjs-animation-opening.js +74 -36
- package/src/babylonjs-controller.js +189 -60
- package/src/file-storage.js +11 -2
- package/src/index.js +18 -912
- package/src/panzoom-controller.js +92 -55
- package/src/pref-viewer-2d.js +15 -3
- package/src/pref-viewer-3d-data.js +3 -2
- package/src/pref-viewer-3d.js +11 -4
- package/src/pref-viewer-dialog.js +16 -9
- package/src/pref-viewer-task.js +1 -1
- package/src/pref-viewer.js +934 -0
- package/src/styles.js +381 -0
- package/src/svg-resolver.js +23 -0
- package/src/css/pref-viewer-2d.css +0 -39
- package/src/css/pref-viewer-3d.css +0 -28
- package/src/css/pref-viewer-dialog.css +0 -105
- package/src/css/pref-viewer.css +0 -11
package/package.json
CHANGED
|
@@ -1,53 +1,64 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
2
|
+
"name": "@preference-sl/pref-viewer",
|
|
3
|
+
"version": "2.12.0-beta.1",
|
|
4
|
+
"description": "Web Component to preview GLTF models with Babylon.js",
|
|
5
|
+
"author": "Alex Moreno Palacio <amoreno@preference.es>",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build:prefweb": "webpack --config webpack.config.cjs --mode production",
|
|
8
|
+
"build:prefweb:dev": "webpack --config webpack.config.cjs --mode development",
|
|
9
|
+
"release": "standard-version --releaseCommitMessageFormat \"chore(release): {{currentTag}} [skip ci]\"",
|
|
10
|
+
"release:beta": "standard-version --prerelease beta --releaseCommitMessageFormat \"chore(release): {{currentTag}} [skip ci]\"",
|
|
11
|
+
"build": "esbuild src/index.js --bundle --platform=node --format=esm --outfile=dist/bundle.js --sourcemap",
|
|
12
|
+
"start": "npm run build && http-server -c-1 . -p 8080",
|
|
13
|
+
"test": "vitest"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://bitbucket.org/preferencesl/pref-viewer.git"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"type": "module",
|
|
24
|
+
"main": "src/index.js",
|
|
25
|
+
"types": "index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"import": "./src/index.js",
|
|
29
|
+
"require": "./src/index.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"sideEffects": false,
|
|
33
|
+
"files": [
|
|
34
|
+
"src",
|
|
35
|
+
"index.d.ts"
|
|
36
|
+
],
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@babylonjs/core": "^8.39.2",
|
|
39
|
+
"@babylonjs/loaders": "^8.39.2",
|
|
40
|
+
"@babylonjs/serializers": "^8.39.2",
|
|
41
|
+
"@panzoom/panzoom": "^4.6.0",
|
|
42
|
+
"babylonjs-gltf2interface": "^8.39.2",
|
|
43
|
+
"buffer": "^6.0.3",
|
|
44
|
+
"idb": "^8.0.3",
|
|
45
|
+
"is-svg": "^6.1.0",
|
|
46
|
+
"jszip": "^3.10.1",
|
|
47
|
+
"stream": "^0.0.3",
|
|
48
|
+
"string_decoder": "^1.3.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@babel/core": "^7.22.0",
|
|
52
|
+
"@babel/preset-env": "^7.22.0",
|
|
53
|
+
"babel-loader": "^9.2.1",
|
|
54
|
+
"clean-webpack-plugin": "^4.0.0",
|
|
55
|
+
"esbuild": "^0.25.10",
|
|
56
|
+
"http-server": "^14.1.1",
|
|
57
|
+
"jsdom": "^26.1.0",
|
|
58
|
+
"standard-version": "^9.5.0",
|
|
59
|
+
"terser-webpack-plugin": "^5.3.6",
|
|
60
|
+
"vitest": "^3.2.3",
|
|
61
|
+
"webpack": "^5.88.2",
|
|
62
|
+
"webpack-cli": "^5.1.4"
|
|
28
63
|
}
|
|
29
|
-
},
|
|
30
|
-
"sideEffects": false,
|
|
31
|
-
"files": [
|
|
32
|
-
"src",
|
|
33
|
-
"index.d.ts"
|
|
34
|
-
],
|
|
35
|
-
"dependencies": {
|
|
36
|
-
"@babylonjs/core": "^8.36.1",
|
|
37
|
-
"@babylonjs/gui": "^8.36.1",
|
|
38
|
-
"@babylonjs/loaders": "^8.36.1",
|
|
39
|
-
"@babylonjs/serializers": "^8.36.1",
|
|
40
|
-
"@panzoom/panzoom": "^4.6.0",
|
|
41
|
-
"babylonjs-gltf2interface": "^8.36.1",
|
|
42
|
-
"idb": "^8.0.3",
|
|
43
|
-
"is-svg": "^6.1.0",
|
|
44
|
-
"jszip": "^3.10.1"
|
|
45
|
-
},
|
|
46
|
-
"devDependencies": {
|
|
47
|
-
"esbuild": "^0.25.10",
|
|
48
|
-
"http-server": "^14.1.1",
|
|
49
|
-
"jsdom": "^26.1.0",
|
|
50
|
-
"standard-version": "^9.5.0",
|
|
51
|
-
"vitest": "^3.2.3"
|
|
52
|
-
}
|
|
53
64
|
}
|
|
@@ -1,28 +1,35 @@
|
|
|
1
|
-
import { Color3, HighlightLayer, Mesh, PickingInfo,
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import { Color3, HighlightLayer, Mesh, PickingInfo, Scene } from "@babylonjs/core";
|
|
2
|
+
import { PrefViewerColors } from "./styles.js";
|
|
3
|
+
import OpeningAnimation from "./babylonjs-animation-opening.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* BabylonJSAnimationController - Manages animation playback and interactive
|
|
6
|
+
* BabylonJSAnimationController - Manages animation playback, highlighting, and interactive controls for animated nodes in Babylon.js scenes.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* Summary:
|
|
9
|
+
* This class detects, groups, and manages opening/closing animations for scene nodes, provides interactive highlighting of animated nodes and their meshes, and displays a menu for animation control. It is designed for integration with product configurators and interactive 3D applications using Babylon.js.
|
|
10
|
+
*
|
|
11
|
+
* Key features:
|
|
9
12
|
* - Detects and groups opening/closing animations in the scene.
|
|
10
13
|
* - Tracks animated transformation nodes and their relationships to meshes.
|
|
11
|
-
* - Highlights animated nodes and their child meshes
|
|
12
|
-
* - Displays and disposes the animation control menu
|
|
13
|
-
* - Provides API for
|
|
14
|
+
* - Highlights animated nodes and their child meshes on pointer hover.
|
|
15
|
+
* - Displays and disposes the animation control menu for animated nodes.
|
|
16
|
+
* - Provides public API for highlighting, showing the animation menu, and disposing resources.
|
|
17
|
+
* - Cleans up all resources and observers to prevent memory leaks.
|
|
14
18
|
*
|
|
15
19
|
* Public Methods:
|
|
16
20
|
* - dispose(): Disposes all resources managed by the animation controller.
|
|
21
|
+
* - hightlightMeshes(pickingInfo): Highlights meshes that are children of an animated node when hovered.
|
|
22
|
+
* - hideMenu(): Hides and disposes the animation control menu if it exists.
|
|
23
|
+
* - showMenu(pickingInfo): Displays the animation control menu for the animated node under the pointer.
|
|
17
24
|
*
|
|
18
25
|
* @class
|
|
19
26
|
*/
|
|
20
27
|
export default class BabylonJSAnimationController {
|
|
21
28
|
#scene = null;
|
|
29
|
+
#canvas = null;
|
|
22
30
|
#animatedNodes = [];
|
|
23
31
|
#highlightLayer = null;
|
|
24
|
-
#highlightColor =
|
|
25
|
-
#advancedDynamicTexture = null;
|
|
32
|
+
#highlightColor = Color3.FromHexString(PrefViewerColors.primary);
|
|
26
33
|
#openingAnimations = [];
|
|
27
34
|
|
|
28
35
|
/**
|
|
@@ -31,8 +38,8 @@ export default class BabylonJSAnimationController {
|
|
|
31
38
|
*/
|
|
32
39
|
constructor(scene) {
|
|
33
40
|
this.#scene = scene;
|
|
41
|
+
this.#canvas = this.#scene._engine._renderingCanvas;
|
|
34
42
|
this.#initializeAnimations();
|
|
35
|
-
this.#setupPointerObservers();
|
|
36
43
|
}
|
|
37
44
|
|
|
38
45
|
/**
|
|
@@ -40,11 +47,12 @@ export default class BabylonJSAnimationController {
|
|
|
40
47
|
* @private
|
|
41
48
|
*/
|
|
42
49
|
#initializeAnimations() {
|
|
50
|
+
this.hideMenu(); // Clean up any existing menus
|
|
43
51
|
if (!this.#scene.animationGroups.length) {
|
|
44
52
|
return;
|
|
45
53
|
}
|
|
46
54
|
this.#getAnimatedNodes();
|
|
47
|
-
this.#
|
|
55
|
+
this.#getOpeningAnimations();
|
|
48
56
|
}
|
|
49
57
|
|
|
50
58
|
/**
|
|
@@ -71,7 +79,7 @@ export default class BabylonJSAnimationController {
|
|
|
71
79
|
* @description
|
|
72
80
|
* Uses animation group names with the pattern "animation_open_<name>" and "animation_close_<name>".
|
|
73
81
|
*/
|
|
74
|
-
#
|
|
82
|
+
#getOpeningAnimations() {
|
|
75
83
|
const openings = {};
|
|
76
84
|
this.#scene.animationGroups.forEach((animationGroup) => {
|
|
77
85
|
const match = animationGroup.name.match(/^animation_(open|close)_(.+)$/);
|
|
@@ -105,29 +113,53 @@ export default class BabylonJSAnimationController {
|
|
|
105
113
|
}
|
|
106
114
|
|
|
107
115
|
/**
|
|
108
|
-
*
|
|
116
|
+
* Finds all animated node IDs associated with a given mesh by traversing its parent hierarchy.
|
|
109
117
|
* @private
|
|
110
118
|
* @param {Mesh} mesh - The mesh to check.
|
|
111
|
-
* @returns {string
|
|
119
|
+
* @returns {Array<string>} Array of animated node IDs associated with the mesh.
|
|
112
120
|
*/
|
|
113
|
-
#
|
|
114
|
-
let nodeId =
|
|
121
|
+
#getNodesAnimatedByMesh = function (mesh) {
|
|
122
|
+
let nodeId = [];
|
|
115
123
|
let node = mesh;
|
|
116
|
-
while (node.parent !== null
|
|
124
|
+
while (node.parent !== null) {
|
|
117
125
|
node = node.parent;
|
|
118
|
-
if (this.#animatedNodes.includes(node.id)) {
|
|
119
|
-
nodeId
|
|
126
|
+
if (this.#animatedNodes.includes(node.id) && !nodeId.includes(node.id)) {
|
|
127
|
+
nodeId.push(node.id);
|
|
120
128
|
}
|
|
121
129
|
}
|
|
122
130
|
return nodeId;
|
|
123
131
|
};
|
|
124
132
|
|
|
133
|
+
/**
|
|
134
|
+
* ---------------------------
|
|
135
|
+
* Public methods
|
|
136
|
+
* ---------------------------
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Disposes all resources managed by the animation controller.
|
|
141
|
+
* Cleans up the highlight layer, animation menu, and internal animation/node lists.
|
|
142
|
+
* Should be called when the controller is no longer needed to prevent memory leaks.
|
|
143
|
+
* @public
|
|
144
|
+
*/
|
|
145
|
+
dispose() {
|
|
146
|
+
if (this.#highlightLayer) {
|
|
147
|
+
this.#highlightLayer.removeAllMeshes();
|
|
148
|
+
this.#highlightLayer.dispose();
|
|
149
|
+
this.#highlightLayer = null;
|
|
150
|
+
}
|
|
151
|
+
this.hideMenu();
|
|
152
|
+
this.#animatedNodes = [];
|
|
153
|
+
this.#openingAnimations.forEach((openingAnimation) => openingAnimation.dispose());
|
|
154
|
+
this.#openingAnimations = [];
|
|
155
|
+
}
|
|
156
|
+
|
|
125
157
|
/**
|
|
126
158
|
* Highlights meshes that are children of an animated node when hovered.
|
|
127
|
-
* @
|
|
159
|
+
* @public
|
|
128
160
|
* @param {PickingInfo} pickingInfo - Raycast info from pointer position.
|
|
129
161
|
*/
|
|
130
|
-
|
|
162
|
+
hightlightMeshes(pickingInfo) {
|
|
131
163
|
if (!this.#highlightLayer) {
|
|
132
164
|
this.#highlightLayer = new HighlightLayer("hl_animations", this.#scene);
|
|
133
165
|
}
|
|
@@ -137,99 +169,67 @@ export default class BabylonJSAnimationController {
|
|
|
137
169
|
return;
|
|
138
170
|
}
|
|
139
171
|
|
|
140
|
-
const
|
|
141
|
-
if (!
|
|
172
|
+
const nodeIds = this.#getNodesAnimatedByMesh(pickingInfo.pickedMesh);
|
|
173
|
+
if (!nodeIds.length) {
|
|
142
174
|
return;
|
|
143
175
|
}
|
|
144
176
|
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
177
|
+
const transformNodes = [];
|
|
178
|
+
nodeIds.forEach((nodeId) => {
|
|
179
|
+
const transformNode = this.#scene.getTransformNodeByID(nodeId);
|
|
180
|
+
if (transformNode) {
|
|
181
|
+
transformNodes.push(transformNode);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
151
184
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
185
|
+
transformNodes.forEach((transformNode) => {
|
|
186
|
+
const nodeMeshes = transformNode.getChildMeshes();
|
|
187
|
+
if (nodeMeshes.length) {
|
|
188
|
+
nodeMeshes.forEach((mesh) => {
|
|
189
|
+
if (!this.#highlightLayer.hasMesh(mesh)) {
|
|
190
|
+
this.#highlightLayer.addMesh(mesh, this.#highlightColor);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
});
|
|
161
195
|
}
|
|
162
196
|
|
|
163
197
|
/**
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
* @private
|
|
169
|
-
* @param {PointerInfo} pointerInfo - The pointer event information from Babylon.js.
|
|
198
|
+
* Hides and disposes the animation control menu if it exists.
|
|
199
|
+
* @public
|
|
200
|
+
* @returns {void}
|
|
170
201
|
*/
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
this.#hightlightMeshesForAnimation(pickingInfo);
|
|
175
|
-
}
|
|
176
|
-
if (pointerInfo.type === PointerEventTypes.POINTERUP) {
|
|
177
|
-
// Remove any previously created Babylon GUI
|
|
178
|
-
if (this.#advancedDynamicTexture) {
|
|
179
|
-
this.#advancedDynamicTexture.dispose();
|
|
180
|
-
this.#advancedDynamicTexture = null;
|
|
181
|
-
}
|
|
182
|
-
const pickingInfo = this.#scene.pick(pointerInfo.event.clientX, pointerInfo.event.clientY);
|
|
183
|
-
this.#showMenu(pickingInfo);
|
|
184
|
-
}
|
|
202
|
+
hideMenu() {
|
|
203
|
+
this.#openingAnimations.forEach((openingAnimation) => openingAnimation.hideControls());
|
|
204
|
+
this.#canvas.parentElement.querySelectorAll("div.pref-viewer-3d.animation-menu").forEach((menu) => menu.remove());
|
|
185
205
|
}
|
|
186
206
|
|
|
187
207
|
/**
|
|
188
208
|
* Displays the animation control menu for the animated node under the pointer.
|
|
189
|
-
* @
|
|
209
|
+
* @public
|
|
190
210
|
* @param {PickingInfo} pickingInfo - Raycast info from pointer position.
|
|
191
|
-
* @description
|
|
192
|
-
* Creates the GUI if needed and invokes OpeningAnimation.showControls.
|
|
193
211
|
*/
|
|
194
|
-
|
|
212
|
+
showMenu(pickingInfo) {
|
|
195
213
|
if (!pickingInfo?.hit && !pickingInfo?.pickedMesh) {
|
|
196
214
|
return;
|
|
197
215
|
}
|
|
198
216
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const openingAnimation = this.#getOpeningAnimationByNode(nodeId);
|
|
204
|
-
if (!openingAnimation) {
|
|
217
|
+
this.hideMenu();
|
|
218
|
+
|
|
219
|
+
const nodeIds = this.#getNodesAnimatedByMesh(pickingInfo.pickedMesh);
|
|
220
|
+
if (!nodeIds.length) {
|
|
205
221
|
return;
|
|
206
222
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
223
|
+
const openingAnimations = [];
|
|
224
|
+
nodeIds.forEach((nodeId) => {
|
|
225
|
+
const openingAnimation = this.#getOpeningAnimationByNode(nodeId);
|
|
226
|
+
if (!openingAnimation) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
openingAnimations.push(openingAnimation);
|
|
230
|
+
});
|
|
212
231
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
* Cleans up the highlight layer, GUI texture, and internal animation/node lists.
|
|
216
|
-
* Should be called when the controller is no longer needed to prevent memory leaks.
|
|
217
|
-
* @public
|
|
218
|
-
*/
|
|
219
|
-
dispose() {
|
|
220
|
-
if (this.#highlightLayer) {
|
|
221
|
-
this.#highlightLayer.dispose();
|
|
222
|
-
this.#highlightLayer = null;
|
|
223
|
-
}
|
|
224
|
-
if (this.#advancedDynamicTexture) {
|
|
225
|
-
this.#advancedDynamicTexture.dispose();
|
|
226
|
-
this.#advancedDynamicTexture = null;
|
|
227
|
-
}
|
|
228
|
-
this.#animatedNodes = [];
|
|
229
|
-
this.#openingAnimations = [];
|
|
230
|
-
const observer = this.#scene.onPointerObservable._observers.find((observer) => observer.callback.name.includes("#onAnimationPointerObservable"));
|
|
231
|
-
if (observer) {
|
|
232
|
-
this.#scene.onPointerObservable.remove(observer);
|
|
233
|
-
}
|
|
232
|
+
const startedAnimation = openingAnimations.find((animation) => animation.state !== OpeningAnimation.states.closed);
|
|
233
|
+
startedAnimation ? startedAnimation.showControls(this.#canvas, openingAnimations) : openingAnimations[0].showControls(this.#canvas, openingAnimations);
|
|
234
234
|
}
|
|
235
235
|
}
|