@combeenation/3d-viewer 8.0.0 → 9.0.0
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/dist/lib-cjs/api/classes/element.js +20 -25
- package/dist/lib-cjs/api/classes/element.js.map +1 -1
- package/dist/lib-cjs/api/classes/parameter.d.ts +46 -0
- package/dist/lib-cjs/api/classes/parameter.js +103 -0
- package/dist/lib-cjs/api/classes/parameter.js.map +1 -1
- package/dist/lib-cjs/api/classes/variant.d.ts +8 -0
- package/dist/lib-cjs/api/classes/variant.js +17 -5
- package/dist/lib-cjs/api/classes/variant.js.map +1 -1
- package/dist/lib-cjs/api/classes/viewer.d.ts +2 -2
- package/dist/lib-cjs/api/classes/viewer.js +9 -8
- package/dist/lib-cjs/api/classes/viewer.js.map +1 -1
- package/dist/lib-cjs/api/classes/viewerLight.js +1 -1
- package/dist/lib-cjs/api/classes/viewerLight.js.map +1 -1
- package/dist/lib-cjs/api/manager/gltfExportManager.d.ts +1 -0
- package/dist/lib-cjs/api/manager/gltfExportManager.js +7 -2
- package/dist/lib-cjs/api/manager/gltfExportManager.js.map +1 -1
- package/dist/lib-cjs/api/manager/tagManager.d.ts +25 -23
- package/dist/lib-cjs/api/manager/tagManager.js +176 -98
- package/dist/lib-cjs/api/manager/tagManager.js.map +1 -1
- package/dist/lib-cjs/api/manager/variantInstanceManager.d.ts +1 -1
- package/dist/lib-cjs/api/manager/variantInstanceManager.js +5 -7
- package/dist/lib-cjs/api/manager/variantInstanceManager.js.map +1 -1
- package/dist/lib-cjs/api/util/babylonHelper.d.ts +5 -3
- package/dist/lib-cjs/api/util/babylonHelper.js +51 -14
- package/dist/lib-cjs/api/util/babylonHelper.js.map +1 -1
- package/dist/lib-cjs/api/util/globalTypes.d.ts +26 -4
- package/dist/lib-cjs/api/util/resourceHelper.js +9 -1
- package/dist/lib-cjs/api/util/resourceHelper.js.map +1 -1
- package/dist/lib-cjs/api/util/sceneLoaderHelper.js +1 -1
- package/dist/lib-cjs/api/util/sceneLoaderHelper.js.map +1 -1
- package/dist/lib-cjs/api/util/structureHelper.d.ts +6 -6
- package/dist/lib-cjs/api/util/structureHelper.js +31 -28
- package/dist/lib-cjs/api/util/structureHelper.js.map +1 -1
- package/dist/lib-cjs/buildinfo.json +1 -1
- package/dist/lib-cjs/commonjs.tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/src/api/classes/element.ts +24 -34
- package/src/api/classes/parameter.ts +109 -0
- package/src/api/classes/variant.ts +20 -6
- package/src/api/classes/viewer.ts +12 -14
- package/src/api/classes/viewerLight.ts +2 -2
- package/src/api/manager/gltfExportManager.ts +8 -3
- package/src/api/manager/tagManager.ts +209 -122
- package/src/api/manager/variantInstanceManager.ts +5 -8
- package/src/api/util/babylonHelper.ts +60 -13
- package/src/api/util/globalTypes.ts +32 -4
- package/src/api/util/resourceHelper.ts +10 -3
- package/src/api/util/sceneLoaderHelper.ts +2 -2
- package/src/api/util/structureHelper.ts +29 -27
|
@@ -4,18 +4,16 @@ import { Parameter } from '../classes/parameter';
|
|
|
4
4
|
import { Viewer } from '../classes/viewer';
|
|
5
5
|
import {
|
|
6
6
|
assertMeshCapability,
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
drawPaintableOnMaterial,
|
|
8
|
+
injectMetadata,
|
|
9
9
|
mapTags,
|
|
10
10
|
setMaterial,
|
|
11
|
-
setMaterialColor,
|
|
12
|
-
setMaterialMetallness,
|
|
13
|
-
setMaterialRoughness,
|
|
14
11
|
} from '../util/babylonHelper';
|
|
15
|
-
import {
|
|
12
|
+
import { createImageFromImgSrc, createImageFromSvg } from '../util/resourceHelper';
|
|
16
13
|
import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
|
|
17
14
|
import { Tags } from '@babylonjs/core/Misc/tags';
|
|
18
|
-
import
|
|
15
|
+
import isSvg from 'is-svg';
|
|
16
|
+
import { clone, get, merge, uniq } from 'lodash-es';
|
|
19
17
|
|
|
20
18
|
export class TagManager {
|
|
21
19
|
public readonly parameters: TagManagerParameterBag = new FuzzyMap();
|
|
@@ -37,7 +35,7 @@ export class TagManager {
|
|
|
37
35
|
tagName: string,
|
|
38
36
|
parameterName: string,
|
|
39
37
|
value: ParameterValue
|
|
40
|
-
): Promise<
|
|
38
|
+
): Promise<TagManagerParameterObserverResultBag> {
|
|
41
39
|
return await this.handleParameter({ tagName: tagName }, parameterName, value);
|
|
42
40
|
}
|
|
43
41
|
|
|
@@ -49,22 +47,35 @@ export class TagManager {
|
|
|
49
47
|
nodeName: string,
|
|
50
48
|
parameterName: string,
|
|
51
49
|
value: ParameterValue
|
|
52
|
-
): Promise<
|
|
50
|
+
): Promise<TagManagerParameterObserverResultBag> {
|
|
53
51
|
return await this.handleParameter({ nodeName: nodeName }, parameterName, value);
|
|
54
52
|
}
|
|
55
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Calls the {@link ParameterObserver} for given {@link Parameter} and applies the {@link ParameterValue} on all
|
|
56
|
+
* materials with given materialName.
|
|
57
|
+
*/
|
|
58
|
+
public async setMaterialParameterValue(
|
|
59
|
+
materialName: string,
|
|
60
|
+
parameterName: string,
|
|
61
|
+
value: ParameterValue
|
|
62
|
+
): Promise<TagManagerParameterObserverResultBag> {
|
|
63
|
+
return await this.handleParameter({ materialName: materialName }, parameterName, value);
|
|
64
|
+
}
|
|
65
|
+
|
|
56
66
|
/**
|
|
57
67
|
* Splits the passed {@link TagManagerParameterValue}s into individual values and calls all {@link ParameterObserver}s
|
|
58
68
|
* of all {@link Parameter}s with the respective {@link TagManagerSubject} and {@link ParameterValue}. The result is a
|
|
59
|
-
* map of passed {@link TagManagerParameterValue}s and the associated {@link
|
|
69
|
+
* map of passed {@link TagManagerParameterValue}s and the associated {@link TagManagerParameterObserverResult} of the
|
|
60
70
|
* {@link ParameterObserver}.
|
|
61
71
|
*/
|
|
62
72
|
public async setParameterValues(
|
|
63
73
|
values: TagManagerParameterValue[]
|
|
64
|
-
): Promise<Map<TagManagerParameterValue,
|
|
65
|
-
const observerResultMap: Map<TagManagerParameterValue,
|
|
66
|
-
const tagPromises: Promise<
|
|
67
|
-
const nodePromises: Promise<
|
|
74
|
+
): Promise<Map<TagManagerParameterValue, TagManagerParameterObserverResultBag>> {
|
|
75
|
+
const observerResultMap: Map<TagManagerParameterValue, TagManagerParameterObserverResultBag> = new Map();
|
|
76
|
+
const tagPromises: Promise<TagManagerParameterObserverResultBag>[] = [];
|
|
77
|
+
const nodePromises: Promise<TagManagerParameterObserverResultBag>[] = [];
|
|
78
|
+
const materialPromises: Promise<TagManagerParameterObserverResultBag>[] = [];
|
|
68
79
|
for (const value of values) {
|
|
69
80
|
const subject: TagManagerSubject = {};
|
|
70
81
|
if (value.tagName) {
|
|
@@ -73,6 +84,9 @@ export class TagManager {
|
|
|
73
84
|
if (value.nodeName) {
|
|
74
85
|
subject.nodeName = value.nodeName;
|
|
75
86
|
}
|
|
87
|
+
if (value.materialName) {
|
|
88
|
+
subject.materialName = value.materialName;
|
|
89
|
+
}
|
|
76
90
|
const observerResultPromise = this.handleParameter(subject, value.parameterName, value.value);
|
|
77
91
|
observerResultPromise.then(result => observerResultMap.set(value, result));
|
|
78
92
|
if (value.tagName) {
|
|
@@ -81,32 +95,37 @@ export class TagManager {
|
|
|
81
95
|
if (value.nodeName) {
|
|
82
96
|
nodePromises.push(observerResultPromise);
|
|
83
97
|
}
|
|
98
|
+
if (value.materialName) {
|
|
99
|
+
materialPromises.push(observerResultPromise);
|
|
100
|
+
}
|
|
84
101
|
}
|
|
85
102
|
await Promise.all(tagPromises);
|
|
86
103
|
await Promise.all(nodePromises);
|
|
104
|
+
await Promise.all(materialPromises);
|
|
87
105
|
return observerResultMap;
|
|
88
106
|
}
|
|
89
107
|
|
|
90
108
|
/**
|
|
91
109
|
* Gets a list of {@link TagManagerSubject}s that are present in both the state of the {@link TagManager}'s
|
|
92
|
-
* {@link parameters} and the given
|
|
110
|
+
* {@link parameters} and the given object.
|
|
93
111
|
*/
|
|
94
|
-
public getSubjectsFor(
|
|
112
|
+
public getSubjectsFor(object: TransformNode | Material): TagManagerSubject[] {
|
|
95
113
|
return [...this.parameters.keys()].filter(
|
|
96
114
|
subject =>
|
|
97
|
-
(subject.tagName && Tags.MatchesQuery(
|
|
98
|
-
(subject.nodeName &&
|
|
115
|
+
(subject.tagName && Tags.MatchesQuery(object, subject.tagName)) ||
|
|
116
|
+
(subject.nodeName && object.name === subject.nodeName) ||
|
|
117
|
+
(subject.materialName && object.name === subject.materialName)
|
|
99
118
|
);
|
|
100
119
|
}
|
|
101
120
|
|
|
102
121
|
/**
|
|
103
122
|
* Gets a list of {@link TagManagerSubject}s that are present in both the state of the {@link TagManager}'s
|
|
104
|
-
* {@link parameters} and the given
|
|
123
|
+
* {@link parameters} and the given objects.
|
|
105
124
|
*/
|
|
106
|
-
public getApplicableSubjectsFor(
|
|
125
|
+
public getApplicableSubjectsFor(objects: (TransformNode | Material)[]): TagManagerSubject[] {
|
|
107
126
|
let applicableSubjects: TagManagerSubject[] = [];
|
|
108
|
-
for (const
|
|
109
|
-
const subjects = this.getSubjectsFor(
|
|
127
|
+
for (const object of objects) {
|
|
128
|
+
const subjects = this.getSubjectsFor(object);
|
|
110
129
|
applicableSubjects = [...applicableSubjects, ...subjects];
|
|
111
130
|
}
|
|
112
131
|
return uniq(applicableSubjects);
|
|
@@ -117,12 +136,12 @@ export class TagManager {
|
|
|
117
136
|
*/
|
|
118
137
|
public async applyExistingParameterValuesFor(
|
|
119
138
|
subjects: TagManagerSubject[]
|
|
120
|
-
): Promise<Map<TagManagerSubject,
|
|
121
|
-
const observerResultMap: Map<TagManagerSubject,
|
|
122
|
-
let tagPromises: Promise<
|
|
123
|
-
let nodePromises: Promise<
|
|
139
|
+
): Promise<Map<TagManagerSubject, TagManagerParameterObserverResultBag>> {
|
|
140
|
+
const observerResultMap: Map<TagManagerSubject, TagManagerParameterObserverResultBag> = new Map();
|
|
141
|
+
let tagPromises: Promise<TagManagerParameterObserverResultBag>[] = [];
|
|
142
|
+
let nodePromises: Promise<TagManagerParameterObserverResultBag>[] = [];
|
|
143
|
+
let materialPromises: Promise<TagManagerParameterObserverResultBag>[] = [];
|
|
124
144
|
for (const subject of subjects) {
|
|
125
|
-
this.clearAppliedNodeMetadataParameters(this.getNodesBySubject(subject));
|
|
126
145
|
const observerResultPromises = this.handleParameterBag(subject, this.parameters.get(subject)!);
|
|
127
146
|
for (const observerResultPromise of observerResultPromises) {
|
|
128
147
|
observerResultPromise.then(result => observerResultMap.set(subject, result));
|
|
@@ -133,9 +152,13 @@ export class TagManager {
|
|
|
133
152
|
if (subject.nodeName) {
|
|
134
153
|
nodePromises = [...nodePromises, ...observerResultPromises];
|
|
135
154
|
}
|
|
155
|
+
if (subject.materialName) {
|
|
156
|
+
materialPromises = [...materialPromises, ...observerResultPromises];
|
|
157
|
+
}
|
|
136
158
|
}
|
|
137
159
|
await Promise.all(tagPromises);
|
|
138
160
|
await Promise.all(nodePromises);
|
|
161
|
+
await Promise.all(materialPromises);
|
|
139
162
|
return observerResultMap;
|
|
140
163
|
}
|
|
141
164
|
|
|
@@ -144,15 +167,15 @@ export class TagManager {
|
|
|
144
167
|
* {@link TagManager}'s {@link parameters} are applied to all given nodes.
|
|
145
168
|
*/
|
|
146
169
|
public async applyExistingParameterValuesTo(
|
|
147
|
-
|
|
148
|
-
): Promise<Map<TagManagerSubject,
|
|
149
|
-
return this.applyExistingParameterValuesFor(this.getApplicableSubjectsFor(
|
|
170
|
+
objects: (TransformNode | Material)[]
|
|
171
|
+
): Promise<Map<TagManagerSubject, TagManagerParameterObserverResultBag>> {
|
|
172
|
+
return this.applyExistingParameterValuesFor(this.getApplicableSubjectsFor(objects));
|
|
150
173
|
}
|
|
151
174
|
|
|
152
175
|
/**
|
|
153
176
|
* Applies all existing states of the {@link TagManager}'s {@link parameters} for all {@link TagManagerSubject}s.
|
|
154
177
|
*/
|
|
155
|
-
public async applyExistingParameterValues(): Promise<Map<TagManagerSubject,
|
|
178
|
+
public async applyExistingParameterValues(): Promise<Map<TagManagerSubject, TagManagerParameterObserverResultBag>> {
|
|
156
179
|
return this.applyExistingParameterValuesFor([...this.parameters.keys()]);
|
|
157
180
|
}
|
|
158
181
|
|
|
@@ -248,18 +271,46 @@ export class TagManager {
|
|
|
248
271
|
}
|
|
249
272
|
|
|
250
273
|
/**
|
|
251
|
-
*
|
|
252
|
-
|
|
274
|
+
* Gets all materials for given {@link TagManagerSubject} on the Babylon.js scene.
|
|
275
|
+
*/
|
|
276
|
+
public getMaterialsBySubject(subject: TagManagerSubject, predicate?: (material: Material) => boolean): Material[] {
|
|
277
|
+
let materials: Material[] = [];
|
|
278
|
+
if (subject.tagName) {
|
|
279
|
+
materials = [...materials, ...this.viewer.scene.getMaterialByTags(subject.tagName, predicate)];
|
|
280
|
+
}
|
|
281
|
+
if (subject.materialName) {
|
|
282
|
+
materials = [...materials, this.viewer.scene.getMaterialByName(subject.materialName)].filter(
|
|
283
|
+
t => !!t && (!predicate || predicate(t))
|
|
284
|
+
) as Material[];
|
|
285
|
+
}
|
|
286
|
+
return materials;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Registers observers that are called on every new object added to the Babylon.js scene.
|
|
291
|
+
* The observers ensure that each new object gets the state of the {@link TagManager}'s {@link parameters} applied.
|
|
253
292
|
*/
|
|
254
|
-
public
|
|
293
|
+
public registerNewObjectObservers(scene: Scene) {
|
|
294
|
+
// nodes and meshes
|
|
255
295
|
const onNewTransformNodeAdded = (node: TransformNode) => {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
296
|
+
/* NOTE:
|
|
297
|
+
Removed the check for created instances here since it is not guaranteed that all instances
|
|
298
|
+
created means that there is no scenario where new nodes should get TagManager parameters applied.
|
|
299
|
+
Instead, we check for the state to be enabled via the `onEnabledStateChangedObservable` below.
|
|
300
|
+
*/
|
|
301
|
+
//if (node.name === Viewer.BOUNDING_BOX_NAME || !this.viewer.variantInstances.areAllDefinitionsCreated) {
|
|
302
|
+
if (node.name === Viewer.BOUNDING_BOX_NAME) {
|
|
260
303
|
return;
|
|
261
304
|
}
|
|
262
|
-
|
|
305
|
+
const onEnabledStateChangedObserver = node.onEnabledStateChangedObservable.add(async state => {
|
|
306
|
+
if (!state) {
|
|
307
|
+
// if the node is disabled, means ignoring also "ghost nodes"
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
await this.applyExistingParameterValuesTo([node]);
|
|
311
|
+
node.onEnabledStateChangedObservable.remove(onEnabledStateChangedObserver);
|
|
312
|
+
});
|
|
313
|
+
node.onEnabledStateChangedObservable.makeObserverBottomPriority(onEnabledStateChangedObserver!);
|
|
263
314
|
};
|
|
264
315
|
scene.onNewTransformNodeAddedObservable.makeObserverBottomPriority(
|
|
265
316
|
scene.onNewTransformNodeAddedObservable.add(onNewTransformNodeAdded)!
|
|
@@ -267,6 +318,21 @@ export class TagManager {
|
|
|
267
318
|
scene.onNewMeshAddedObservable.makeObserverBottomPriority(
|
|
268
319
|
scene.onNewMeshAddedObservable.add(onNewTransformNodeAdded)!
|
|
269
320
|
);
|
|
321
|
+
// materials
|
|
322
|
+
const onNewMaterialAdded = (material: Material) => {
|
|
323
|
+
/* NOTE:
|
|
324
|
+
We have to wait until a material is bound to a Mesh. In all other scenarios, the material
|
|
325
|
+
is not "fully ready" or even empty (without working attributes/properties).
|
|
326
|
+
*/
|
|
327
|
+
const onMaterialBindObserver = material.onBindObservable.add(async abstractMesh => {
|
|
328
|
+
await this.applyExistingParameterValuesTo([material]);
|
|
329
|
+
material.onBindObservable.remove(onMaterialBindObserver);
|
|
330
|
+
});
|
|
331
|
+
material.onBindObservable.makeObserverBottomPriority(onMaterialBindObserver!);
|
|
332
|
+
};
|
|
333
|
+
scene.onNewMaterialAddedObservable.makeObserverBottomPriority(
|
|
334
|
+
scene.onNewMaterialAddedObservable.add(onNewMaterialAdded)!
|
|
335
|
+
);
|
|
270
336
|
}
|
|
271
337
|
|
|
272
338
|
/**
|
|
@@ -275,12 +341,7 @@ export class TagManager {
|
|
|
275
341
|
*/
|
|
276
342
|
protected addParameterObservers(): TagManager {
|
|
277
343
|
this.parameterObservers.set(Parameter.VISIBLE, async payload => {
|
|
278
|
-
|
|
279
|
-
try {
|
|
280
|
-
visible = Parameter.parseBoolean(payload.newValue);
|
|
281
|
-
} catch (e) {
|
|
282
|
-
return false;
|
|
283
|
-
}
|
|
344
|
+
const visible = Parameter.parseBoolean(payload.newValue);
|
|
284
345
|
if (visible === true) {
|
|
285
346
|
for (const node of payload.nodes) {
|
|
286
347
|
node.setEnabled(true);
|
|
@@ -317,57 +378,76 @@ export class TagManager {
|
|
|
317
378
|
}
|
|
318
379
|
return true;
|
|
319
380
|
});
|
|
320
|
-
this.parameterObservers.set(Parameter.
|
|
321
|
-
const
|
|
322
|
-
for (const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
381
|
+
this.parameterObservers.set(Parameter.COLOR, async payload => {
|
|
382
|
+
const color = Parameter.parseColor(payload.newValue);
|
|
383
|
+
for (const material of payload.materials) {
|
|
384
|
+
const materialCls = material.getClassName();
|
|
385
|
+
switch (materialCls) {
|
|
386
|
+
case 'PBRMaterial':
|
|
387
|
+
(material as PBRMaterial).albedoColor = color.toLinearSpace();
|
|
388
|
+
break;
|
|
389
|
+
case 'StandardMaterial':
|
|
390
|
+
(material as StandardMaterial).diffuseColor = color;
|
|
391
|
+
break;
|
|
392
|
+
default:
|
|
393
|
+
throw new Error(`Setting color for material of instance "${materialCls}" not implemented (yet).`);
|
|
332
394
|
}
|
|
333
|
-
setMaterialColor(node, parsedValue, false);
|
|
334
395
|
}
|
|
335
396
|
return true;
|
|
336
397
|
});
|
|
337
|
-
this.parameterObservers.set(Parameter.
|
|
338
|
-
const
|
|
339
|
-
for (const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
398
|
+
this.parameterObservers.set(Parameter.ROUGHNESS, async payload => {
|
|
399
|
+
const roughness = Parameter.parseNumber(payload.newValue);
|
|
400
|
+
for (const material of payload.materials) {
|
|
401
|
+
const materialCls = material.getClassName();
|
|
402
|
+
switch (materialCls) {
|
|
403
|
+
case 'PBRMaterial':
|
|
404
|
+
(material as PBRMaterial).roughness = roughness;
|
|
405
|
+
break;
|
|
406
|
+
case 'StandardMaterial':
|
|
407
|
+
(material as StandardMaterial).roughness = roughness;
|
|
408
|
+
break;
|
|
409
|
+
default:
|
|
410
|
+
throw new Error(`Setting roughness for material of instance "${materialCls}" not implemented (yet).`);
|
|
349
411
|
}
|
|
350
|
-
setMaterialRoughness(node, parsedValue, false);
|
|
351
412
|
}
|
|
352
413
|
return true;
|
|
353
414
|
});
|
|
354
|
-
this.parameterObservers.set(Parameter.
|
|
355
|
-
const
|
|
356
|
-
for (const
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
injectNodeMetadata(node, { dirty: { material: { color: payload.oldValue } } }, false);
|
|
365
|
-
}
|
|
415
|
+
this.parameterObservers.set(Parameter.METALLIC, async payload => {
|
|
416
|
+
const metallic = Parameter.parseNumber(payload.newValue);
|
|
417
|
+
for (const material of payload.materials) {
|
|
418
|
+
const materialCls = material.getClassName();
|
|
419
|
+
switch (materialCls) {
|
|
420
|
+
case 'PBRMaterial':
|
|
421
|
+
(material as PBRMaterial).metallic = metallic;
|
|
422
|
+
break;
|
|
423
|
+
default:
|
|
424
|
+
throw new Error(`Setting metallic for material of instance "${materialCls}" not implemented (yet).`);
|
|
366
425
|
}
|
|
367
|
-
setMaterialMetallness(node, parsedValue, false);
|
|
368
426
|
}
|
|
369
427
|
return true;
|
|
370
428
|
});
|
|
429
|
+
this.parameterObservers.set(Parameter.PAINTABLE, async payload => {
|
|
430
|
+
const paintableValue: PaintableValue = Parameter.parsePaintableValue(payload.newValue);
|
|
431
|
+
|
|
432
|
+
// check if value is svg or image source, do the conversion accordingly
|
|
433
|
+
const srcIsSvg = isSvg(paintableValue.src);
|
|
434
|
+
if (!srcIsSvg && paintableValue.src.includes('<svg') && paintableValue.src.includes('</svg>')) {
|
|
435
|
+
// seems like the user tried to use a SVG string, as <svg> tags are used
|
|
436
|
+
// inform the user that this is not a valid SVG string
|
|
437
|
+
throw new Error(`Setting paintable value failed: "${paintableValue.src}" is no valid SVG string.`);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const imageSource: CanvasImageSource = srcIsSvg
|
|
441
|
+
? await createImageFromSvg(paintableValue.src)
|
|
442
|
+
: await createImageFromImgSrc(paintableValue.src);
|
|
443
|
+
|
|
444
|
+
// apply image source on desired material(s)
|
|
445
|
+
for (const material of payload.materials) {
|
|
446
|
+
drawPaintableOnMaterial(material, imageSource, this.viewer.scene, paintableValue.options);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
return true;
|
|
450
|
+
});
|
|
371
451
|
return this;
|
|
372
452
|
}
|
|
373
453
|
|
|
@@ -379,8 +459,8 @@ export class TagManager {
|
|
|
379
459
|
protected handleParameterBag(
|
|
380
460
|
subject: TagManagerSubject,
|
|
381
461
|
parameters: ParameterBag
|
|
382
|
-
): Promise<
|
|
383
|
-
const observerPromises: Promise<
|
|
462
|
+
): Promise<TagManagerParameterObserverResultBag>[] {
|
|
463
|
+
const observerPromises: Promise<TagManagerParameterObserverResultBag>[] = [];
|
|
384
464
|
for (const parameter in parameters) {
|
|
385
465
|
observerPromises.push(this.handleParameter(subject, parameter, parameters[parameter]));
|
|
386
466
|
}
|
|
@@ -397,36 +477,61 @@ export class TagManager {
|
|
|
397
477
|
subject: TagManagerSubject,
|
|
398
478
|
parameter: string,
|
|
399
479
|
parameterValue: ParameterValue
|
|
400
|
-
): Promise<
|
|
480
|
+
): Promise<TagManagerParameterObserverResultBag> {
|
|
401
481
|
Parameter.assertParameter(Parameter.declarations, parameter, parameterValue);
|
|
402
|
-
if (!this.parameterObservers.has(parameter)) {
|
|
403
|
-
return Promise.resolve(false);
|
|
404
|
-
}
|
|
405
482
|
const parameterBag = this.parameters.get(subject) || {};
|
|
406
483
|
const oldValue = parameterBag[parameter];
|
|
407
|
-
|
|
408
|
-
|
|
484
|
+
const parameterObserverResultBag: TagManagerParameterObserverResultBag = {
|
|
485
|
+
subject: subject,
|
|
486
|
+
parameter: parameter,
|
|
487
|
+
nodes: [],
|
|
488
|
+
materials: [],
|
|
489
|
+
oldValue: oldValue,
|
|
490
|
+
newValue: parameterValue,
|
|
491
|
+
parameterObserverResult: false,
|
|
492
|
+
};
|
|
493
|
+
if (!this.parameterObservers.has(parameter)) {
|
|
494
|
+
return Promise.resolve(parameterObserverResultBag);
|
|
409
495
|
}
|
|
410
496
|
this.parameters.set(subject, parameterBag);
|
|
411
497
|
this.parameters.get(subject)![parameter] = parameterValue;
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
498
|
+
// get objects by subject and filter nodes by state
|
|
499
|
+
const nodes = this.getNodesBySubject(subject).filter(
|
|
500
|
+
o => o.metadata?.tagManager?.parameters?.[parameter] !== parameterValue
|
|
501
|
+
);
|
|
502
|
+
const materials = this.getMaterialsBySubject(subject).filter(
|
|
503
|
+
o => o.metadata?.tagManager?.parameters?.[parameter] !== parameterValue
|
|
504
|
+
);
|
|
505
|
+
if (nodes.length === 0 && materials.length === 0) {
|
|
506
|
+
return Promise.resolve(parameterObserverResultBag);
|
|
415
507
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
// reset to old value if observer was not successful
|
|
420
|
-
this.parameters.get(subject)![parameter] = oldValue;
|
|
508
|
+
// store state in objects
|
|
509
|
+
for (const object of [...nodes, ...materials]) {
|
|
510
|
+
injectMetadata(object, { tagManager: { parameters: { [parameter]: parameterValue } } }, false);
|
|
421
511
|
}
|
|
422
|
-
|
|
512
|
+
|
|
513
|
+
const observer = this.parameterObservers.get(parameter)!;
|
|
514
|
+
const result = await observer({
|
|
423
515
|
subject: subject,
|
|
424
|
-
parameter: parameter,
|
|
425
516
|
nodes: nodes,
|
|
426
|
-
|
|
517
|
+
materials: materials,
|
|
427
518
|
newValue: parameterValue,
|
|
428
|
-
|
|
519
|
+
oldValue: oldValue,
|
|
429
520
|
});
|
|
521
|
+
|
|
522
|
+
if (result === false) {
|
|
523
|
+
// reset to old value if observer was not successful
|
|
524
|
+
this.parameters.get(subject)![parameter] = oldValue;
|
|
525
|
+
// store old state in objects
|
|
526
|
+
for (const object of [...nodes, ...materials]) {
|
|
527
|
+
injectMetadata(object, { tagManager: { parameters: { [parameter]: oldValue } } }, false);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
parameterObserverResultBag.nodes = nodes;
|
|
531
|
+
parameterObserverResultBag.materials = materials;
|
|
532
|
+
parameterObserverResultBag.parameterObserverResult = result;
|
|
533
|
+
emitter.emit(Event.TAG_MANAGER_PARAMETER_COMMITTED, parameterObserverResultBag);
|
|
534
|
+
return parameterObserverResultBag;
|
|
430
535
|
}
|
|
431
536
|
|
|
432
537
|
/**
|
|
@@ -441,17 +546,14 @@ export class TagManager {
|
|
|
441
546
|
if (oldNode) {
|
|
442
547
|
accNodeMapping[oldNode.name] = curNode.name;
|
|
443
548
|
}
|
|
444
|
-
|
|
445
549
|
return accNodeMapping;
|
|
446
550
|
}, {} as TagMapping);
|
|
447
|
-
|
|
448
551
|
for (const subject of this.parameters.keys()) {
|
|
449
552
|
const isNode = subject.nodeName;
|
|
450
553
|
const newName = isNode ? nodeMapping[subject.nodeName] : tagMapping[subject.tagName];
|
|
451
554
|
if (!newName) {
|
|
452
555
|
continue;
|
|
453
556
|
}
|
|
454
|
-
|
|
455
557
|
const newSubject = clone(subject);
|
|
456
558
|
newSubject[isNode ? 'nodeName' : 'tagName'] = newName;
|
|
457
559
|
const parameterBag = clone(this.parameters.get(subject)!);
|
|
@@ -459,19 +561,4 @@ export class TagManager {
|
|
|
459
561
|
this.parameters.set(newSubject, parameterBag);
|
|
460
562
|
}
|
|
461
563
|
}
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
* Clears the applied {@link ParameterBag} state of the node's metadata to ensure that observers trigger (once again).
|
|
465
|
-
* This is necessary e.g. after mapping tags when a nodeName subject shall override the parameterValue of a mapped
|
|
466
|
-
* tag.
|
|
467
|
-
* @protected
|
|
468
|
-
*/
|
|
469
|
-
protected clearAppliedNodeMetadataParameters(nodes: TransformNode[]): void {
|
|
470
|
-
for (const node of nodes) {
|
|
471
|
-
if (!node.metadata?.tagManager?.parameters) {
|
|
472
|
-
continue;
|
|
473
|
-
}
|
|
474
|
-
node.metadata.tagManager.parameters = {};
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
564
|
}
|
|
@@ -120,15 +120,13 @@ export class VariantInstanceManager extends EventBroadcaster {
|
|
|
120
120
|
public async create(
|
|
121
121
|
dottedPath: DottedPathArgument,
|
|
122
122
|
name?: string,
|
|
123
|
-
parameters?: ParameterBag
|
|
124
|
-
tagManagerParameterValues?: TagManagerParameterValue[]
|
|
123
|
+
parameters?: ParameterBag
|
|
125
124
|
): Promise<VariantInstance> {
|
|
126
125
|
const variant = DottedPath.create(dottedPath).path;
|
|
127
126
|
const definition = {
|
|
128
127
|
name: this.ensureUniqueName(name ? name : variant),
|
|
129
128
|
variant: variant,
|
|
130
129
|
parameters: parameters,
|
|
131
|
-
tagManagerParameterValues: tagManagerParameterValues,
|
|
132
130
|
};
|
|
133
131
|
return await this.createFromDefinition(definition);
|
|
134
132
|
}
|
|
@@ -246,7 +244,10 @@ export class VariantInstanceManager extends EventBroadcaster {
|
|
|
246
244
|
this.variantInstances.set(definition.name, variantInstanceClone);
|
|
247
245
|
reportDuplicateNodeNames(duplicateNodeNames(this.viewer.scene.getNodes(), n => n instanceof TransformNode));
|
|
248
246
|
this.viewer.tagManager.mapNodesAndTags(variantInstanceClone.variant.elementNodesFlat, tagMapping ?? {});
|
|
249
|
-
await this.viewer.tagManager.applyExistingParameterValuesTo(
|
|
247
|
+
await this.viewer.tagManager.applyExistingParameterValuesTo([
|
|
248
|
+
...variantInstanceClone.variant.elementNodesFlat,
|
|
249
|
+
...variantInstanceClone.variant.elementAbstractMeshesFlat.map(n => n.material!).filter(m => !!m),
|
|
250
|
+
]);
|
|
250
251
|
variantInstance.broadcastEvent(Event.VARIANT_INSTANCE_CLONED, variantInstanceClone);
|
|
251
252
|
return variantInstanceClone;
|
|
252
253
|
}
|
|
@@ -285,10 +286,6 @@ export class VariantInstanceManager extends EventBroadcaster {
|
|
|
285
286
|
const variant = await this.rootVariant.getDescendant(definition.variant);
|
|
286
287
|
const variantInstance = await VariantInstance.createLiving(variant, definition.name, definition.parameters);
|
|
287
288
|
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
|
-
}
|
|
292
289
|
this.broadcastEvent(Event.VARIANT_INSTANCE_CREATED, variantInstance);
|
|
293
290
|
return variantInstance;
|
|
294
291
|
}
|