@preference-sl/pref-viewer 2.1.1 → 2.1.3

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 +45 -27
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.3",
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
@@ -36,7 +36,7 @@
36
36
  * viewer.setAttribute("model", "https://example.com/models/anotherModel.glb");
37
37
  *
38
38
  * -----------------------------------------------------------------------------
39
- * Implementation code below with added console logs for debugging
39
+ * Implementation code below with updated preprocessUrl
40
40
  * -----------------------------------------------------------------------------
41
41
  */
42
42
 
@@ -60,14 +60,17 @@ class PrefViewer extends HTMLElement {
60
60
  this._createCanvas();
61
61
  this._wrapCanvas();
62
62
 
63
- // Initialize properties
63
+ // These will be set in _initializeBabylon()
64
64
  this.engine = null;
65
65
  this.scene = null;
66
66
  this.camera = null;
67
67
  this.hemiLight = null;
68
68
  this.dirLight = null;
69
- this.modelUrl = null;
70
69
  this._onWindowResize = null;
70
+
71
+ // modelUrl might be provided via attribute before connectedCallback
72
+ this.modelUrl = null;
73
+ this._hasInitialized = false;
71
74
  }
72
75
 
73
76
  static get observedAttributes() {
@@ -75,17 +78,20 @@ class PrefViewer extends HTMLElement {
75
78
  }
76
79
 
77
80
  attributeChangedCallback(name, _oldValue, newValue) {
78
- console.log(`PrefViewer: attributeChangedCallback - ${name} changed to ${newValue}`);
81
+ console.log(`PrefViewer: attributeChangedCallback - ${name} -> ${newValue}`);
79
82
  if (name === "model" && newValue) {
80
83
  this.modelUrl = newValue;
81
84
  console.log(`PrefViewer: modelUrl set to ${this.modelUrl}`);
82
- this._reloadModel();
85
+ // Only reload if initialization has already happened
86
+ if (this._hasInitialized) {
87
+ this._reloadModel();
88
+ }
83
89
  }
84
90
  }
85
91
 
86
92
  connectedCallback() {
87
93
  console.log("PrefViewer: connectedCallback");
88
- // If no `model` attribute is present, use default bundled GLTF
94
+ // 1) Determine modelUrl now that element is connected
89
95
  if (!this.hasAttribute("model")) {
90
96
  this.modelUrl = new URL("./models/patata.gltf", import.meta.url).href;
91
97
  console.log(`PrefViewer: no model attribute, defaulting to ${this.modelUrl}`);
@@ -93,7 +99,15 @@ class PrefViewer extends HTMLElement {
93
99
  this.modelUrl = this.getAttribute("model");
94
100
  console.log(`PrefViewer: model attribute present, using ${this.modelUrl}`);
95
101
  }
102
+
103
+ // 2) Initialize Babylon (engine + scene + camera + lights + hooks)
96
104
  this._initializeBabylon();
105
+
106
+ // 3) Mark that initialization is done
107
+ this._hasInitialized = true;
108
+
109
+ // 4) Load whatever modelUrl we have
110
+ this._reloadModel();
97
111
  }
98
112
 
99
113
  disconnectedCallback() {
@@ -127,28 +141,39 @@ class PrefViewer extends HTMLElement {
127
141
 
128
142
  _initializeBabylon() {
129
143
  console.log("PrefViewer: _initializeBabylon - creating engine and scene");
130
- // 1) Create engine and scene
144
+
145
+ // 1) Create the Babylon engine & scene
131
146
  this.engine = new Engine(this.canvas, true, { alpha: true });
132
147
  this.scene = new Scene(this.engine);
133
148
  this.scene.clearColor = new Color4(1, 1, 1, 1);
134
149
 
135
- // 2) Hook into Babylon’s GLTF loader so "https://..." URIs aren't prefixed with blob:
150
+ // 2) Hook into Babylon’s GLTF loader so that any URIs starting with "blob:…"
151
+ // get stripped off before we check for an absolute "https://".
136
152
  console.log("PrefViewer: Adding preprocessUrl hook");
137
153
  SceneLoader.OnPluginActivatedObservable.add((plugin) => {
138
154
  console.log(`PrefViewer: Plugin activated - ${plugin.name}`);
139
155
  if (plugin.name === "gltf" || plugin.name === "gltf2") {
140
156
  plugin.preprocessUrl = (url) => {
141
- // Normalize backslashes to forward slashes
142
- const fixed = url.replace(/\\/g, "/");
143
- console.log(`PrefViewer: preprocessUrl received "${url}", normalized to "${fixed}"`);
144
- // If it starts with http:// or https://, return as-is:
145
- if (/^https?:\/\//i.test(fixed)) {
146
- console.log(`PrefViewer: preprocessUrl returning absolute URL "${fixed}"`);
147
- return fixed;
157
+ // a) If the loader already prepended "blob:…", strip it out.
158
+ // Regex explanation: ^blob:(?:file|https?|ftp):\/\/[^\/]+\/(.*)
159
+ // basically removes the entire "blob:http://localhost:3000/" prefix.
160
+ const stripped = url.replace(
161
+ /^blob:(?:http|https|file):\/\/[^\/]+\/(.+)/i,
162
+ "$1"
163
+ );
164
+ // b) Normalize backslashes "\" → forward slashes "/"
165
+ const fixedSlashes = stripped.replace(/\\/g, "/");
166
+ console.log(
167
+ `PrefViewer: preprocessUrl received "${url}", stripped to "${stripped}", normalized to "${fixedSlashes}"`
168
+ );
169
+ // c) If it now starts with "http://" or "https://", return it as an absolute URL:
170
+ if (/^https?:\/\//i.test(fixedSlashes)) {
171
+ console.log(`PrefViewer: preprocessUrl returning absolute URL "${fixedSlashes}"`);
172
+ return fixedSlashes;
148
173
  }
149
- // Otherwise, leave it (Babylon will treat it relative to the blob)
150
- console.log(`PrefViewer: preprocessUrl returning relative URL "${fixed}"`);
151
- return fixed;
174
+ // d) Otherwise, return the relative path (Babylon will resolve it relative to the blob if needed)
175
+ console.log(`PrefViewer: preprocessUrl returning relative URL "${fixedSlashes}"`);
176
+ return fixedSlashes;
152
177
  };
153
178
  }
154
179
  });
@@ -158,11 +183,11 @@ class PrefViewer extends HTMLElement {
158
183
  this._createCamera();
159
184
  this._createLights();
160
185
 
161
- // 4) Hook up input/event handlers
186
+ // 4) Hook up input/event handlers (e.g. wheel-to-zoom)
162
187
  console.log("PrefViewer: _setupEventListeners");
163
188
  this._setupEventListeners();
164
189
 
165
- // 5) Start render loop
190
+ // 5) Start Babylon’s render loop
166
191
  console.log("PrefViewer: Starting render loop");
167
192
  this.engine.runRenderLoop(() => {
168
193
  if (this.scene) {
@@ -174,10 +199,6 @@ class PrefViewer extends HTMLElement {
174
199
  this.engine.resize();
175
200
  };
176
201
  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
202
  }
182
203
 
183
204
  _createCamera() {
@@ -196,7 +217,6 @@ class PrefViewer extends HTMLElement {
196
217
 
197
218
  _createLights() {
198
219
  console.log("PrefViewer: _createLights");
199
- // Simple hemispheric + directional as a starting point
200
220
  this.hemiLight = new HemisphericLight(
201
221
  "hemiLight",
202
222
  new Vector3(0, 1, 0),
@@ -218,7 +238,6 @@ class PrefViewer extends HTMLElement {
218
238
  // Zoom toward point-of-interest on wheel scroll
219
239
  this.canvas.addEventListener("wheel", (evt) => {
220
240
  if (!this.scene || !this.camera) return;
221
-
222
241
  const pickResult = this.scene.pick(
223
242
  this.scene.pointerX,
224
243
  this.scene.pointerY
@@ -226,7 +245,6 @@ class PrefViewer extends HTMLElement {
226
245
  const pivotPoint = pickResult.hit
227
246
  ? pickResult.pickedPoint.clone()
228
247
  : this.camera.target.clone();
229
-
230
248
  this.camera.target = pivotPoint;
231
249
  this.camera.inertialRadiusOffset +=
232
250
  evt.deltaY * this.camera.wheelPrecision * 0.01;