@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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +17 -60
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@preference-sl/pref-viewer",
3
- "version": "2.1.1",
3
+ "version": "2.1.2",
4
4
  "description": "Web Component to preview GLTF models with Babylon.js",
5
5
  "author": "Alex Moreno Palacio <amoreno@preference.es>",
6
6
  "license": "MIT",
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
- // Initialize properties
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} changed to ${newValue}`);
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
- this._reloadModel();
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
- // If no `model` attribute is present, use default bundled GLTF
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) {