@combeenation/3d-viewer 7.1.0 → 7.1.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@combeenation/3d-viewer",
3
- "version": "7.1.0",
3
+ "version": "7.1.1",
4
4
  "description": "Combeenation 3D Viewer",
5
5
  "homepage": "https://github.com/Combeenation/3d-viewer#readme",
6
6
  "bugs": {
@@ -34,7 +34,7 @@ import { Mesh } from '@babylonjs/core/Meshes/mesh';
34
34
  import { ScreenshotTools } from '@babylonjs/core/Misc/screenshotTools';
35
35
  import { WebXRSessionManager } from '@babylonjs/core/XR/webXRSessionManager';
36
36
  import { Scene } from '@babylonjs/core/scene';
37
- import { isString } from 'lodash-es';
37
+ import { isArray, isString } from 'lodash-es';
38
38
 
39
39
  /**
40
40
  * The main exposed object. This is the entry point into the application
@@ -46,6 +46,8 @@ import { isString } from 'lodash-es';
46
46
  * The class does nothing on its own and needs to {@link bootstrap}
47
47
  */
48
48
  export class Viewer extends EventBroadcaster {
49
+ public static readonly BOUNDING_BOX_NAME = '__bounding_box__';
50
+
49
51
  protected _scene: Scene | null = null;
50
52
 
51
53
  protected _animationManager: AnimationManager | null = null;
@@ -270,7 +272,7 @@ export class Viewer extends EventBroadcaster {
270
272
  * @emits {@link Event.BOOTSTRAP_START}
271
273
  * @emits {@link Event.BOOTSTRAP_END}
272
274
  */
273
- public async bootstrap(tagManagerParameterValues: TagManagerParameterValue[]): Promise<Viewer> {
275
+ public async bootstrap(tagManagerParameterValues?: TagManagerParameterValue[]): Promise<Viewer> {
274
276
  this.broadcastEvent(Event.BOOTSTRAP_START, this);
275
277
  let indexJson;
276
278
  if (isString(this.structureJson)) {
@@ -299,7 +301,7 @@ export class Viewer extends EventBroadcaster {
299
301
  const setupJson = await loadJson<SetupJson>(indexJson.setup);
300
302
  indexJson.setup = setupJson;
301
303
  }
302
- await this.createVariantInstances();
304
+ await this.createVariantInstances(tagManagerParameterValues);
303
305
  }
304
306
  this.broadcastEvent(Event.VARIANT_INSTANCES_READY, this);
305
307
  // create gltf export manager
@@ -308,10 +310,6 @@ export class Viewer extends EventBroadcaster {
308
310
  window.addEventListener('resize', debounce(this.resize.bind(this), 100));
309
311
  // wait until scene is completely ready
310
312
  await this.scene.whenReadyAsync();
311
- // set tag manager values
312
- if (tagManagerParameterValues) {
313
- await this.tagManager.setParameterValues(tagManagerParameterValues);
314
- }
315
313
  // event broadcasting
316
314
  this.broadcastEvent(Event.BOOTSTRAP_END, this);
317
315
  // render loop
@@ -462,13 +460,11 @@ export class Viewer extends EventBroadcaster {
462
460
  throw new Error('There are currently no meshes on the scene.');
463
461
  }
464
462
  this.scene.render(); // CB-6062: workaround for BoundingBox not respecting render loop
465
- const bbName = '__bounding_box__';
466
-
467
463
  const { max, min } = this.scene.meshes
468
464
  .filter(mesh => {
469
465
  const isEnabled = mesh.isEnabled();
470
466
  // ignore the existing bounding box mesh for calculating the current one
471
- const isNotBBoxMesh = bbName !== mesh.id;
467
+ const isNotBBoxMesh = Viewer.BOUNDING_BOX_NAME !== mesh.id;
472
468
  // ignore meshes with invalid bounding infos
473
469
  const hasValidBBoxInfo = mesh.getBoundingInfo().boundingSphere.radius > 0;
474
470
  // ignore excluded meshes
@@ -486,9 +482,9 @@ export class Viewer extends EventBroadcaster {
486
482
  { max: new Vector3(), min: new Vector3() }
487
483
  );
488
484
 
489
- let boundingBox = this.scene.getMeshByName(bbName) as Mesh;
485
+ let boundingBox = this.scene.getMeshByName(Viewer.BOUNDING_BOX_NAME) as Mesh;
490
486
  if (!boundingBox) {
491
- boundingBox = new Mesh(bbName, this.scene);
487
+ boundingBox = new Mesh(Viewer.BOUNDING_BOX_NAME, this.scene);
492
488
  }
493
489
  boundingBox.setBoundingInfo(new BoundingInfo(min, max));
494
490
  return boundingBox;
@@ -719,10 +715,15 @@ export class Viewer extends EventBroadcaster {
719
715
  /**
720
716
  * Batch creation of multiple {@link VariantInstance} objects with a {@link SetupJson} object passed
721
717
  */
722
- protected async createVariantInstances(): Promise<VariantInstance[]> {
718
+ protected async createVariantInstances(
719
+ tagManagerParameterValues?: TagManagerParameterValue[]
720
+ ): Promise<VariantInstance[]> {
723
721
  const setupJson = SpecStorage.get<SetupJson>('setup');
724
722
  const instances: VariantInstance[] = [];
725
723
  for (const instanceDefinition of setupJson.instances) {
724
+ if (isArray(tagManagerParameterValues)) {
725
+ instanceDefinition.tagManagerParameterValues = tagManagerParameterValues;
726
+ }
726
727
  // don't create the instance right away if `lazy` is set, register it for later creation (on first usage) instead
727
728
  // however if the variant should be `visible` by default, `lazy` loading doesn't make sense and should therefore
728
729
  // be overruled by the `visible` flag
@@ -730,13 +731,13 @@ export class Viewer extends EventBroadcaster {
730
731
  this.variantInstances.register(instanceDefinition);
731
732
  continue;
732
733
  }
733
- instances.push(
734
- await this.variantInstances.create(
735
- instanceDefinition.variant,
736
- instanceDefinition.name,
737
- instanceDefinition.parameters
738
- )
734
+ const instance = await this.variantInstances.create(
735
+ instanceDefinition.variant,
736
+ instanceDefinition.name,
737
+ instanceDefinition.parameters,
738
+ instanceDefinition.tagManagerParameterValues
739
739
  );
740
+ instances.push(instance);
740
741
  }
741
742
  return instances;
742
743
  }
@@ -1,3 +1,4 @@
1
+ import { Viewer } from '../classes/viewer';
1
2
  import { injectNodeMetadata } from '../util/babylonHelper';
2
3
  import { isMeshIncludedInExclusionList } from '../util/structureHelper';
3
4
  import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial';
@@ -113,7 +114,7 @@ export class GltfExportManager {
113
114
  if (!node.isEnabled()) {
114
115
  return false;
115
116
  }
116
- if ((node.name as string).startsWith('__bounding_box__')) {
117
+ if ((node.name as string).startsWith(Viewer.BOUNDING_BOX_NAME)) {
117
118
  return false;
118
119
  }
119
120
  if (excluded && node instanceof Mesh && isMeshIncludedInExclusionList(node, excluded)) {
@@ -1,6 +1,7 @@
1
1
  import { Event, emitter } from '../classes/event';
2
2
  import { FuzzyMap } from '../classes/fuzzyMap';
3
3
  import { Parameter } from '../classes/parameter';
4
+ import { Viewer } from '../classes/viewer';
4
5
  import {
5
6
  assertMeshCapability,
6
7
  cloneTransformNodeMaterial,
@@ -236,9 +237,14 @@ export class TagManager {
236
237
  * new node gets the state of the {@link TagManager}'s {@link parameters} applied.
237
238
  */
238
239
  public registerNewTransformNodeObservers(scene: Scene) {
239
- const onNewTransformNodeAdded = async (node: TransformNode) => {
240
- await this.viewer.scene.whenReadyAsync();
241
- await this.applyExistingParameterValuesTo([node]);
240
+ const onNewTransformNodeAdded = (node: TransformNode) => {
241
+ if (node.name === Viewer.BOUNDING_BOX_NAME || !this.viewer.variantInstances.areAllDefinitionsCreated) {
242
+ // Avoid duplicate calls here. The parameter values are already applied when a variant instance has finished
243
+ // creating (see event listener in viewer for VARIANT_INSTANCE_CREATED). This callback should only trigger when
244
+ // a consumer "manually" clones a node.
245
+ return;
246
+ }
247
+ this.applyExistingParameterValuesTo([node]).then();
242
248
  };
243
249
  scene.onNewTransformNodeAddedObservable.makeObserverBottomPriority(
244
250
  scene.onNewTransformNodeAddedObservable.add(onNewTransformNodeAdded)!
@@ -43,18 +43,24 @@ export class VariantInstanceManager extends EventBroadcaster {
43
43
  * Gets all instances.
44
44
  */
45
45
  get all() {
46
- const all: VariantInstance[] = [];
47
- this.variantInstances.forEach(variantInstance => all.push(variantInstance));
48
- return all;
46
+ return [...this.variantInstances.values()];
49
47
  }
50
48
 
51
49
  /**
52
50
  * Gets all instance definitions.
53
51
  */
54
52
  get allDefinitions() {
55
- const all: VariantInstanceDefinition[] = [];
56
- this.variantInstanceDefinitions.forEach(definition => all.push(definition));
57
- return all;
53
+ return [...this.variantInstanceDefinitions.values()];
54
+ }
55
+
56
+ /**
57
+ * Gets whether all definitions have been created.
58
+ */
59
+ get areAllDefinitionsCreated(): boolean {
60
+ const createdDefinitions = this.allDefinitions.filter(
61
+ definition => this.all.filter(instance => instance.name === definition.name).length > 0
62
+ );
63
+ return this.allDefinitions.length === createdDefinitions.length;
58
64
  }
59
65
 
60
66
  /**
@@ -94,15 +100,15 @@ export class VariantInstanceManager extends EventBroadcaster {
94
100
  // 3) see if there's a definition of that name, create an instance from it and store the related promise
95
101
  if (this.variantInstanceDefinitions.has(name)) {
96
102
  const definition = this.variantInstanceDefinitions.get(name)!; // cannot be null
97
- const vip = this.createFromDefinition(definition);
98
- this.variantInstancePromises.set(name, vip);
103
+ const variantInstancePromise = this.createFromDefinition(definition);
104
+ this.variantInstancePromises.set(name, variantInstancePromise);
99
105
  // remove promise after it has been finished
100
- vip.then(() => this.variantInstancePromises.delete(name));
106
+ variantInstancePromise.then(() => this.variantInstancePromises.delete(name));
101
107
 
102
- return vip;
108
+ return variantInstancePromise;
103
109
  }
104
110
 
105
- //* if we are here, no instance definition of that name exists. throw error.
111
+ // if we are here, no instance definition of that name exists. throw error.
106
112
  throw Error(`VariantInstance with name "${name}" neither created nor configured.`);
107
113
  }
108
114
 
@@ -114,13 +120,15 @@ export class VariantInstanceManager extends EventBroadcaster {
114
120
  public async create(
115
121
  dottedPath: DottedPathArgument,
116
122
  name?: string,
117
- parameters?: ParameterBag
123
+ parameters?: ParameterBag,
124
+ tagManagerParameterValues?: TagManagerParameterValue[]
118
125
  ): Promise<VariantInstance> {
119
126
  const variant = DottedPath.create(dottedPath).path;
120
127
  const definition = {
121
128
  name: this.ensureUniqueName(name ? name : variant),
122
129
  variant: variant,
123
130
  parameters: parameters,
131
+ tagManagerParameterValues: tagManagerParameterValues,
124
132
  };
125
133
  return await this.createFromDefinition(definition);
126
134
  }
@@ -277,6 +285,10 @@ export class VariantInstanceManager extends EventBroadcaster {
277
285
  const variant = await this.rootVariant.getDescendant(definition.variant);
278
286
  const variantInstance = await VariantInstance.createLiving(variant, definition.name, definition.parameters);
279
287
  this.variantInstances.set(definition.name, variantInstance);
288
+ // set tag manager parameter values if all definitions has been created.
289
+ if (definition.tagManagerParameterValues && this.areAllDefinitionsCreated) {
290
+ await this.viewer.tagManager.setParameterValues(definition.tagManagerParameterValues);
291
+ }
280
292
  this.broadcastEvent(Event.VARIANT_INSTANCE_CREATED, variantInstance);
281
293
  return variantInstance;
282
294
  }
@@ -353,6 +353,7 @@ type VariantInstanceDefinition = {
353
353
  name?: string;
354
354
  variant: DottedPathArgument;
355
355
  parameters?: ParameterBag;
356
+ tagManagerParameterValues?: TagManagerParameterValue[];
356
357
  lazy?: boolean;
357
358
  };
358
359