@preference-sl/pref-viewer 2.1.1 → 2.1.2
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 -1
- package/src/index.js +17 -60
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,45 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* =============================================================================
|
|
3
|
-
* PrefViewer Web Component (JavaScript)
|
|
4
|
-
* =============================================================================
|
|
5
|
-
*
|
|
6
|
-
* Overview
|
|
7
|
-
* --------
|
|
8
|
-
* `PrefViewer` is a self-contained Web Component built with Babylon.js that:
|
|
9
|
-
* • Inserts a <canvas> into its shadow DOM to render a glTF model.
|
|
10
|
-
* • Creates and manages a Babylon Engine, Scene, ArcRotateCamera, and basic lighting.
|
|
11
|
-
* • Listens for a `model` attribute to load different glTF files (defaults to "./models/patata.gltf").
|
|
12
|
-
* • Automatically disposes previous meshes when switching models.
|
|
13
|
-
* • Dispatches “model-loaded” and “model-error” CustomEvents so host pages can react.
|
|
14
|
-
*
|
|
15
|
-
* Usage
|
|
16
|
-
* -----
|
|
17
|
-
* 1. **Import the script (module)**
|
|
18
|
-
* <script type="module" src="path/to/pref-viewer.js"></script>
|
|
19
|
-
*
|
|
20
|
-
* 2. **Place the custom element in your HTML**
|
|
21
|
-
* <pref-viewer
|
|
22
|
-
* model="https://example.com/models/myModel.gltf"
|
|
23
|
-
* style="width:800px; height:600px;">
|
|
24
|
-
* </pref-viewer>
|
|
25
|
-
*
|
|
26
|
-
* 3. **Listen for loading events (optional)**
|
|
27
|
-
* const viewer = document.querySelector("pref-viewer");
|
|
28
|
-
* viewer.addEventListener("model-loaded", (evt) => {
|
|
29
|
-
* console.log("Loaded meshes:", evt.detail.meshes);
|
|
30
|
-
* });
|
|
31
|
-
* viewer.addEventListener("model-error", (evt) => {
|
|
32
|
-
* console.error("Failed to load model:", evt.detail.error);
|
|
33
|
-
* });
|
|
34
|
-
*
|
|
35
|
-
* 4. **Change models at runtime**
|
|
36
|
-
* viewer.setAttribute("model", "https://example.com/models/anotherModel.glb");
|
|
37
|
-
*
|
|
38
|
-
* -----------------------------------------------------------------------------
|
|
39
|
-
* Implementation code below with added console logs for debugging
|
|
40
|
-
* -----------------------------------------------------------------------------
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
1
|
import {
|
|
44
2
|
Engine,
|
|
45
3
|
Scene,
|
|
@@ -60,14 +18,17 @@ class PrefViewer extends HTMLElement {
|
|
|
60
18
|
this._createCanvas();
|
|
61
19
|
this._wrapCanvas();
|
|
62
20
|
|
|
63
|
-
//
|
|
21
|
+
// These will be assigned in initBabylon():
|
|
64
22
|
this.engine = null;
|
|
65
23
|
this.scene = null;
|
|
66
24
|
this.camera = null;
|
|
67
25
|
this.hemiLight = null;
|
|
68
26
|
this.dirLight = null;
|
|
69
|
-
this.modelUrl = null;
|
|
70
27
|
this._onWindowResize = null;
|
|
28
|
+
|
|
29
|
+
// modelUrl may be set via attribute before connectedCallback
|
|
30
|
+
this.modelUrl = null;
|
|
31
|
+
this._hasInitialized = false;
|
|
71
32
|
}
|
|
72
33
|
|
|
73
34
|
static get observedAttributes() {
|
|
@@ -75,17 +36,20 @@ class PrefViewer extends HTMLElement {
|
|
|
75
36
|
}
|
|
76
37
|
|
|
77
38
|
attributeChangedCallback(name, _oldValue, newValue) {
|
|
78
|
-
console.log(`PrefViewer: attributeChangedCallback - ${name}
|
|
39
|
+
console.log(`PrefViewer: attributeChangedCallback - ${name} -> ${newValue}`);
|
|
79
40
|
if (name === "model" && newValue) {
|
|
80
41
|
this.modelUrl = newValue;
|
|
81
42
|
console.log(`PrefViewer: modelUrl set to ${this.modelUrl}`);
|
|
82
|
-
|
|
43
|
+
// Only reload if we've already initialized Babylon
|
|
44
|
+
if (this._hasInitialized) {
|
|
45
|
+
this._reloadModel();
|
|
46
|
+
}
|
|
83
47
|
}
|
|
84
48
|
}
|
|
85
49
|
|
|
86
50
|
connectedCallback() {
|
|
87
51
|
console.log("PrefViewer: connectedCallback");
|
|
88
|
-
//
|
|
52
|
+
// 1) Determine modelUrl (either from attribute or default)
|
|
89
53
|
if (!this.hasAttribute("model")) {
|
|
90
54
|
this.modelUrl = new URL("./models/patata.gltf", import.meta.url).href;
|
|
91
55
|
console.log(`PrefViewer: no model attribute, defaulting to ${this.modelUrl}`);
|
|
@@ -93,7 +57,13 @@ class PrefViewer extends HTMLElement {
|
|
|
93
57
|
this.modelUrl = this.getAttribute("model");
|
|
94
58
|
console.log(`PrefViewer: model attribute present, using ${this.modelUrl}`);
|
|
95
59
|
}
|
|
60
|
+
|
|
61
|
+
// 2) Now initialize Babylon
|
|
96
62
|
this._initializeBabylon();
|
|
63
|
+
// 3) Mark that init is done
|
|
64
|
+
this._hasInitialized = true;
|
|
65
|
+
// 4) Finally, load whatever modelUrl we have
|
|
66
|
+
this._reloadModel();
|
|
97
67
|
}
|
|
98
68
|
|
|
99
69
|
disconnectedCallback() {
|
|
@@ -138,15 +108,12 @@ class PrefViewer extends HTMLElement {
|
|
|
138
108
|
console.log(`PrefViewer: Plugin activated - ${plugin.name}`);
|
|
139
109
|
if (plugin.name === "gltf" || plugin.name === "gltf2") {
|
|
140
110
|
plugin.preprocessUrl = (url) => {
|
|
141
|
-
// Normalize backslashes to forward slashes
|
|
142
111
|
const fixed = url.replace(/\\/g, "/");
|
|
143
112
|
console.log(`PrefViewer: preprocessUrl received "${url}", normalized to "${fixed}"`);
|
|
144
|
-
// If it starts with http:// or https://, return as-is:
|
|
145
113
|
if (/^https?:\/\//i.test(fixed)) {
|
|
146
114
|
console.log(`PrefViewer: preprocessUrl returning absolute URL "${fixed}"`);
|
|
147
115
|
return fixed;
|
|
148
116
|
}
|
|
149
|
-
// Otherwise, leave it (Babylon will treat it relative to the blob)
|
|
150
117
|
console.log(`PrefViewer: preprocessUrl returning relative URL "${fixed}"`);
|
|
151
118
|
return fixed;
|
|
152
119
|
};
|
|
@@ -174,15 +141,10 @@ class PrefViewer extends HTMLElement {
|
|
|
174
141
|
this.engine.resize();
|
|
175
142
|
};
|
|
176
143
|
window.addEventListener("resize", this._onWindowResize);
|
|
177
|
-
|
|
178
|
-
// 6) Load the initial model (if modelUrl is already set)
|
|
179
|
-
console.log("PrefViewer: _initializeBabylon calling _reloadModel");
|
|
180
|
-
this._reloadModel();
|
|
181
144
|
}
|
|
182
145
|
|
|
183
146
|
_createCamera() {
|
|
184
147
|
console.log("PrefViewer: _createCamera");
|
|
185
|
-
// ArcRotateCamera that orbits around origin
|
|
186
148
|
this.camera = new ArcRotateCamera(
|
|
187
149
|
"camera",
|
|
188
150
|
Math.PI / 2,
|
|
@@ -196,7 +158,6 @@ class PrefViewer extends HTMLElement {
|
|
|
196
158
|
|
|
197
159
|
_createLights() {
|
|
198
160
|
console.log("PrefViewer: _createLights");
|
|
199
|
-
// Simple hemispheric + directional as a starting point
|
|
200
161
|
this.hemiLight = new HemisphericLight(
|
|
201
162
|
"hemiLight",
|
|
202
163
|
new Vector3(0, 1, 0),
|
|
@@ -215,10 +176,8 @@ class PrefViewer extends HTMLElement {
|
|
|
215
176
|
|
|
216
177
|
_setupEventListeners() {
|
|
217
178
|
console.log("PrefViewer: _setupEventListeners");
|
|
218
|
-
// Zoom toward point-of-interest on wheel scroll
|
|
219
179
|
this.canvas.addEventListener("wheel", (evt) => {
|
|
220
180
|
if (!this.scene || !this.camera) return;
|
|
221
|
-
|
|
222
181
|
const pickResult = this.scene.pick(
|
|
223
182
|
this.scene.pointerX,
|
|
224
183
|
this.scene.pointerY
|
|
@@ -226,7 +185,6 @@ class PrefViewer extends HTMLElement {
|
|
|
226
185
|
const pivotPoint = pickResult.hit
|
|
227
186
|
? pickResult.pickedPoint.clone()
|
|
228
187
|
: this.camera.target.clone();
|
|
229
|
-
|
|
230
188
|
this.camera.target = pivotPoint;
|
|
231
189
|
this.camera.inertialRadiusOffset +=
|
|
232
190
|
evt.deltaY * this.camera.wheelPrecision * 0.01;
|
|
@@ -293,7 +251,6 @@ class PrefViewer extends HTMLElement {
|
|
|
293
251
|
});
|
|
294
252
|
}
|
|
295
253
|
|
|
296
|
-
// ====== Cleanup ======
|
|
297
254
|
_disposeEngine() {
|
|
298
255
|
console.log("PrefViewer: _disposeEngine");
|
|
299
256
|
if (this.engine) {
|