@preference-sl/pref-viewer 2.10.0-beta.14 → 2.10.0-beta.15

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 +171 -46
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@preference-sl/pref-viewer",
3
- "version": "2.10.0-beta.14",
3
+ "version": "2.10.0-beta.15",
4
4
  "description": "Web Component to preview GLTF models with Babylon.js",
5
5
  "author": "Alex Moreno Palacio <amoreno@preference.es>",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -47,7 +47,9 @@ import { DracoCompression } from "@babylonjs/core/Meshes/Compression/dracoCompre
47
47
  import { initDb, loadModel } from "./gltf-storage.js";
48
48
 
49
49
  class PrefViewer extends HTMLElement {
50
- #initialized = false;
50
+ initialized = false;
51
+ loaded = false;
52
+ loading = false;
51
53
 
52
54
  #data = {
53
55
  containers: {
@@ -162,7 +164,7 @@ class PrefViewer extends HTMLElement {
162
164
  break;
163
165
  case "show-model":
164
166
  data = value.toLowerCase?.() === "true";
165
- if (this.#initialized) {
167
+ if (this.initialized) {
166
168
  data ? this.showModel() : this.hideModel();
167
169
  } else {
168
170
  this.#data.containers.model.show = data;
@@ -170,7 +172,7 @@ class PrefViewer extends HTMLElement {
170
172
  break;
171
173
  case "show-scene":
172
174
  data = value.toLowerCase?.() === "true";
173
- if (this.#initialized) {
175
+ if (this.initialized) {
174
176
  data ? this.showScene() : this.hideScene();
175
177
  } else {
176
178
  this.#data.containers.environment.show = data;
@@ -184,18 +186,19 @@ class PrefViewer extends HTMLElement {
184
186
  const error = 'PrefViewer: provide "models" as array of model and environment';
185
187
  console.error(error);
186
188
  this.dispatchEvent(
187
- new CustomEvent("model-error", {
188
- detail: { error: new Error(error) },
189
+ new CustomEvent("scene-error", {
189
190
  bubbles: true,
191
+ cancelable: false,
190
192
  composed: true,
193
+ detail: { error: new Error(error) },
191
194
  })
192
195
  );
193
196
  return false;
194
197
  }
195
198
 
196
199
  this.#initializeBabylon();
200
+ this.initialized = true;
197
201
  this.#loadContainers(true, true, true);
198
- this.#initialized = true;
199
202
  }
200
203
 
201
204
  disconnectedCallback() {
@@ -225,14 +228,71 @@ class PrefViewer extends HTMLElement {
225
228
  this.shadowRoot.append(this.#wrapper);
226
229
  }
227
230
 
231
+ #setStatusSceneLoading(detail) {
232
+ this.loaded = false;
233
+ this.loading = true;
234
+ if (this.hasAttribute("loaded")) {
235
+ this.removeAttribute("loaded");
236
+ }
237
+ this.setAttribute("loading", "");
238
+ this.dispatchEvent(
239
+ new CustomEvent("scene-loading", {
240
+ bubbles: true,
241
+ cancelable: false,
242
+ composed: true,
243
+ detail: detail,
244
+ })
245
+ );
246
+ }
247
+
248
+ #setStatusSceneLoaded(detail) {
249
+ this.loaded = true;
250
+ this.loading = false;
251
+ if (this.hasAttribute("loading")) {
252
+ this.removeAttribute("loading");
253
+ }
254
+ this.setAttribute("loaded", "");
255
+ this.dispatchEvent(
256
+ new CustomEvent("scene-loaded", {
257
+ bubbles: true,
258
+ cancelable: false,
259
+ composed: true,
260
+ detail: detail,
261
+ })
262
+ );
263
+ }
264
+
265
+ #setStatusOptionsLoading(detail) {
266
+ this.dispatchEvent(
267
+ new CustomEvent("options-loading", {
268
+ bubbles: true,
269
+ cancelable: false,
270
+ composed: true,
271
+ detail: detail,
272
+ })
273
+ );
274
+ }
275
+
276
+ #setStatusOptionsLoaded(detail) {
277
+ this.dispatchEvent(
278
+ new CustomEvent("options-loaded", {
279
+ bubbles: true,
280
+ cancelable: false,
281
+ composed: true,
282
+ detail: detail,
283
+ })
284
+ );
285
+ }
286
+
228
287
  // Data
229
288
  #checkCameraChanged(options) {
230
289
  if (!options || !options.camera) {
231
290
  return false;
232
291
  }
233
- this.#data.options.camera.changed = options.camera && options.camera !== this.#data.options.camera.value ? true : false;
234
- this.#data.options.camera.value = this.#data.options.camera.changed ? options.camera : this.#data.options.camera.value;
235
- return this.#data.options.camera.changed;
292
+ const cameraChanged = options.camera && options.camera !== this.#data.options.camera.value ? true : false
293
+ this.#data.options.camera.changed = cameraChanged ? { oldValue: this.#data.options.camera.value, success: false } : false;
294
+ this.#data.options.camera.value = cameraChanged ? options.camera : this.#data.options.camera.value;
295
+ return cameraChanged;
236
296
  }
237
297
 
238
298
  #checkMaterialsChanged(options) {
@@ -242,8 +302,9 @@ class PrefViewer extends HTMLElement {
242
302
  let someChanged = false;
243
303
  Object.keys(this.#data.options.materials).forEach((material) => {
244
304
  const key = `${material}Material`;
245
- this.#data.options.materials[material].changed = options[key] && options[key] !== this.#data.options.materials[material].value ? true : false;
246
- this.#data.options.materials[material].value = this.#data.options.materials[material].changed ? options[key] : this.#data.options.materials[material].value;
305
+ const materialChanged = options[key] && options[key] !== this.#data.options.materials[material].value ? true : false;
306
+ this.#data.options.materials[material].changed = materialChanged ? { oldValue: this.#data.options.materials[material].value, success: false } : false;
307
+ this.#data.options.materials[material].value = materialChanged ? options[key] : this.#data.options.materials[material].value;
247
308
  someChanged = someChanged || this.#data.options.materials[material].changed;
248
309
  });
249
310
  return someChanged;
@@ -252,6 +313,7 @@ class PrefViewer extends HTMLElement {
252
313
  #storeChangedFlagsForContainer(container) {
253
314
  container.timestamp = container.changed.timestamp;
254
315
  container.size = container.changed.size;
316
+ container.changed.success = true;
255
317
  }
256
318
 
257
319
  #resetChangedFlags() {
@@ -340,8 +402,8 @@ class PrefViewer extends HTMLElement {
340
402
  this.#camera.lowerRadiusLimit = 5;
341
403
  this.#camera.upperRadiusLimit = 20;
342
404
  this.#camera.metadata = { locked: false }
343
- this.#camera = this.#camera;
344
405
  this.#camera.attachControl(this.#canvas, true);
406
+ this.#scene.activeCamera = this.#camera;
345
407
  }
346
408
 
347
409
  #createLights() {
@@ -398,13 +460,13 @@ class PrefViewer extends HTMLElement {
398
460
  if (xhr.status === 200) {
399
461
  const size = parseInt(xhr.getResponseHeader("Content-Length"));
400
462
  const timestamp = new Date(xhr.getResponseHeader("Last-Modified")).toISOString();
401
- resolve(size, timestamp);
463
+ resolve([size, timestamp]);
402
464
  } else {
403
- resolve(0, null);
465
+ resolve([0, null]);
404
466
  }
405
467
  };
406
468
  xhr.onerror = () => {
407
- resolve(0, null);
469
+ resolve([0, null]);
408
470
  };
409
471
  xhr.send();
410
472
  });
@@ -468,10 +530,10 @@ class PrefViewer extends HTMLElement {
468
530
  }
469
531
 
470
532
  const containers = [];
471
- if (this.#data.containers.model.assetContainer && (this.#data.containers.model.assetContainer.changed || optionMaterial.changed)) {
533
+ if (this.#data.containers.model.assetContainer && (this.#data.containers.model.changed || optionMaterial.changed)) {
472
534
  containers.push(this.#data.containers.model.assetContainer);
473
535
  }
474
- if (this.#data.containers.environment.assetContainer && (this.#data.containers.environment.assetContainer.changed || optionMaterial.changed)) {
536
+ if (this.#data.containers.environment.assetContainer && (this.#data.containers.environment.changed || optionMaterial.changed)) {
475
537
  containers.push(this.#data.containers.environment.assetContainer);
476
538
  }
477
539
  if (containers.length === 0) {
@@ -488,6 +550,12 @@ class PrefViewer extends HTMLElement {
488
550
  })
489
551
  );
490
552
 
553
+ if (someSetted) {
554
+ optionMaterial.changed.success = true;
555
+ } else {
556
+ optionMaterial.value = optionMaterial.changed.oldValue;
557
+ }
558
+
491
559
  return someSetted;
492
560
  }
493
561
 
@@ -501,21 +569,32 @@ class PrefViewer extends HTMLElement {
501
569
  }
502
570
 
503
571
  #setOptionsCamera() {
504
- if (!this.#data.options.camera.value || (!this.#data.options.camera.changed && !this.#data.containers.model.assetContainer.changed)) {
572
+ if (!this.#data.options.camera.value || (!this.#data.options.camera.changed && !this.#data.containers.model.changed && !this.#data.containers.environment.changed)) {
505
573
  return false;
506
574
  }
507
575
 
508
- let camera = this.#data.containers.model.assetContainer?.cameras.find((cam) => cam.name === this.#data.options.camera.value) || null;
576
+ let camera = this.#data.containers.model.assetContainer?.cameras.find((thisCamera) => thisCamera.name === this.#data.options.camera.value) || this.#data.containers.environment.assetContainer?.cameras.find((thisCamera) => thisCamera.name === this.#data.options.camera.value) || null;
509
577
  if (!camera) {
510
- return false;
578
+ if (this.#data.options.camera.changed?.oldValue && this.#data.options.camera.changed?.oldValue !== this.#data.options.camera.value) {
579
+ camera = this.#data.containers.model.assetContainer?.cameras.find((thisCamera) => thisCamera.name === this.#data.options.camera.changed.oldValue) || this.#data.containers.environment.assetContainer?.cameras.find((thisCamera) => thisCamera.name === his.#data.options.camera.changed.oldValue) || null;
580
+ }
581
+ if (camera){
582
+ camera.metadata = { locked: this.#data.options.camera.changed.oldLocked };
583
+ this.#data.options.camera.value = this.#data.options.camera.changed.oldValue;
584
+ this.#data.options.camera.locked = this.#data.options.camera.changed.oldLocked;
585
+ } else {
586
+ camera = this.#camera;
587
+ this.#data.options.camera.value = null;
588
+ this.#data.options.camera.locked = this.#camera.metadata.locked;
589
+ }
590
+ this.#data.options.camera.changed.success = false;
591
+ } else {
592
+ camera.metadata = { locked: this.#data.options.camera.locked };
511
593
  }
512
-
513
- camera.metadata = { locked: this.#data.options.camera.locked };
514
- if (!this.#data.options.camera.locked) {
594
+ if (!this.#data.options.camera.locked && this.#data.options.camera.value !== null) {
515
595
  camera.attachControl(this.#canvas, true);
516
596
  }
517
597
  this.#scene.activeCamera = camera;
518
-
519
598
  return true;
520
599
  }
521
600
 
@@ -559,7 +638,7 @@ class PrefViewer extends HTMLElement {
559
638
  if (object.timestamp === container.timestamp) {
560
639
  return false;
561
640
  } else {
562
- container.changed = { timestamp: object.timestamp, size: object.size };
641
+ container.changed = { timestamp: object.timestamp, size: object.size, success: false };
563
642
  }
564
643
  }
565
644
 
@@ -578,17 +657,17 @@ class PrefViewer extends HTMLElement {
578
657
  if (container.timestamp === null && container.size === size) {
579
658
  return false;
580
659
  } else {
581
- container.changed = { timestamp: null, size: size };
660
+ container.changed = { timestamp: null, size: size, success: false };
582
661
  }
583
662
  }
584
663
  } else {
585
664
  const extMatch = source.match(/\.(gltf|glb)(\?|#|$)/i);
586
665
  extension = extMatch ? `.${extMatch[1].toLowerCase()}` : ".gltf";
587
- const { fileSize, fileTimestamp } = await this.#getServerFileDataHeader(source);
588
- if (container.timestamp === fileTimestamp && container.size === fileSize) {
666
+ const [fileSize, fileTimestamp ] = await this.#getServerFileDataHeader(source);
667
+ if (container.size === fileSize && container.timestamp === fileTimestamp) {
589
668
  return false;
590
669
  } else {
591
- container.changed = { timestamp: fileTimestamp, size: fileSize };
670
+ container.changed = { timestamp: fileTimestamp, size: fileSize, success: false };
592
671
  }
593
672
  }
594
673
 
@@ -605,12 +684,26 @@ class PrefViewer extends HTMLElement {
605
684
  return LoadAssetContainerAsync(file || source, this.#scene, options);
606
685
  }
607
686
 
608
- async #loadContainers(loadModel = true, loadEnvironment = true, loadMaterials = true) {
687
+ async #loadContainers(loadModel = true, loadEnvironment = true, loadMaterials = true) {
609
688
  const promiseArray = [];
610
689
  promiseArray.push(loadModel ? this.#loadAssetContainer(this.#data.containers.model) : false);
611
690
  promiseArray.push(loadEnvironment ? this.#loadAssetContainer(this.#data.containers.environment) : false);
612
691
  promiseArray.push(loadMaterials ? this.#loadAssetContainer(this.#data.containers.materials) : false);
613
692
 
693
+ const loadingDetail = {
694
+ model: !!this.#data.containers.model.changed,
695
+ environment: !!this.#data.containers.environment.changed,
696
+ materials: !!this.#data.containers.materials.changed,
697
+ options: {
698
+ camera: !!this.#data.options.camera.changed,
699
+ inneWallMaterial: !!this.#data.options.materials.innerWall.changed,
700
+ outerWallMaterial: !!this.#data.options.materials.outerWall.changed,
701
+ innerFloorMaterial: !!this.#data.options.materials.innerFloor.changed,
702
+ outerFloorMaterial: !!this.#data.options.materials.outerFloor.changed,
703
+ },
704
+ };
705
+ this.#setStatusSceneLoading(loadingDetail);
706
+
614
707
  Promise.allSettled(promiseArray)
615
708
  .then(async (values) => {
616
709
  const modelContainer = values[0];
@@ -639,24 +732,33 @@ class PrefViewer extends HTMLElement {
639
732
  this.#setOptionsMaterials();
640
733
  this.#setOptionsCamera();
641
734
  this.#setVisibilityOfWallAndFloorInModel();
735
+
736
+ const loadedDetail = {
737
+ model: !!this.#data.containers.model.changed?.success,
738
+ environment: !!this.#data.containers.environment.changed?.success,
739
+ materials: !!this.#data.containers.materials.changed?.success,
740
+ options: {
741
+ camera: !!this.#data.options.camera.changed?.success,
742
+ inneWallMaterial: !!this.#data.options.materials.innerWall.changed?.success,
743
+ outerWallMaterial: !!this.#data.options.materials.outerWall.changed?.success,
744
+ innerFloorMaterial: !!this.#data.options.materials.innerFloor.changed?.success,
745
+ outerFloorMaterial: !!this.#data.options.materials.outerFloor.changed?.success,
746
+ },
747
+ };
748
+
749
+ this.#setStatusSceneLoaded(loadedDetail);
642
750
 
643
751
  this.#resetChangedFlags();
644
-
645
- this.dispatchEvent(
646
- new CustomEvent("model-loaded", {
647
- detail: { success: "" },
648
- bubbles: true,
649
- composed: true,
650
- })
651
- );
652
752
  })
653
753
  .catch((error) => {
754
+ this.loaded = true;
654
755
  console.error("PrefViewer: failed to load model", error);
655
756
  this.dispatchEvent(
656
- new CustomEvent("model-error", {
657
- detail: { error: error },
757
+ new CustomEvent("scene-error", {
658
758
  bubbles: true,
759
+ cancelable: false,
659
760
  composed: true,
761
+ detail: { error: error },
660
762
  })
661
763
  );
662
764
  });
@@ -682,22 +784,45 @@ class PrefViewer extends HTMLElement {
682
784
  this.#checkMaterialsChanged(config.options);
683
785
  }
684
786
 
685
- this.#initialized && this.#loadContainers(true, true, true);
787
+ this.initialized && this.#loadContainers(true, true, true);
686
788
  }
687
789
 
688
790
  setOptions(options) {
689
791
  if (!options) {
690
792
  return false;
691
793
  }
794
+
795
+ const cameraChanged = this.#checkCameraChanged(options);
796
+ const materialsChanged = this.#checkMaterialsChanged(options);
797
+
798
+ const loadingDetail = {
799
+ camera: !!this.#data.options.camera.changed,
800
+ inneWallMaterial: !!this.#data.options.materials.innerWall.changed,
801
+ outerWallMaterial: !!this.#data.options.materials.outerWall.changed,
802
+ innerFloorMaterial: !!this.#data.options.materials.innerFloor.changed,
803
+ outerFloorMaterial: !!this.#data.options.materials.outerFloor.changed,
804
+ };
805
+ this.#setStatusOptionsLoading(loadingDetail);
806
+
692
807
  let someSetted = false;
693
- if (this.#checkCameraChanged(options)) {
808
+ if (cameraChanged) {
694
809
  someSetted = someSetted || this.#setOptionsCamera();
695
810
  }
696
- if (this.#checkMaterialsChanged(options)) {
811
+ if (materialsChanged) {
697
812
  someSetted = someSetted || this.#setOptionsMaterials();
698
813
  }
814
+
815
+ const loadedDetail = {
816
+ camera: !!this.#data.options.camera.changed?.success,
817
+ inneWallMaterial: !!this.#data.options.materials.innerWall.changed?.success,
818
+ outerWallMaterial: !!this.#data.options.materials.outerWall.changed?.success,
819
+ innerFloorMaterial: !!this.#data.options.materials.innerFloor.changed?.success,
820
+ outerFloorMaterial: !!this.#data.options.materials.outerFloor.changed?.success,
821
+ };
822
+ this.#setStatusOptionsLoaded(loadedDetail);
823
+
699
824
  this.#resetChangedFlags();
700
- debugger;
825
+
701
826
  return someSetted;
702
827
  }
703
828
 
@@ -708,7 +833,7 @@ class PrefViewer extends HTMLElement {
708
833
  }
709
834
  this.#data.containers.model.storage = model.storage || null;
710
835
  this.#data.containers.model.show = model.visible !== undefined ? model.visible : this.#data.containers.model.show;
711
- this.#initialized && this.#loadContainers(true, false, false);
836
+ this.initialized && this.#loadContainers(true, false, false);
712
837
  }
713
838
 
714
839
  loadScene(scene) {
@@ -718,7 +843,7 @@ class PrefViewer extends HTMLElement {
718
843
  }
719
844
  this.#data.containers.environment.storage = scene.storage || null;
720
845
  this.#data.containers.environment.show = scene.visible !== undefined ? scene.visible : this.#data.containers.environment.show;
721
- this.#initialized && this.#loadContainers(false, true, false);
846
+ this.initialized && this.#loadContainers(false, true, false);
722
847
  }
723
848
 
724
849
  showModel() {