@colijnit/configurator 1.0.19 → 1.0.21

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 (158) hide show
  1. package/.idea/Configurator.iml +12 -0
  2. package/.idea/codeStyles/Project.xml +21 -0
  3. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  4. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  5. package/.idea/misc.xml +9 -0
  6. package/.idea/modules.xml +8 -0
  7. package/.idea/vcs.xml +6 -0
  8. package/angular.json +193 -0
  9. package/configurator.iml +11 -0
  10. package/dist/configurator/index.html +14 -0
  11. package/dist/configurator/main-es2015.js +3129 -0
  12. package/dist/configurator/main-es2015.js.map +1 -0
  13. package/dist/configurator/main-es5.js +5482 -0
  14. package/dist/configurator/main-es5.js.map +1 -0
  15. package/dist/configurator/polyfills-es2015.js +4520 -0
  16. package/dist/configurator/polyfills-es2015.js.map +1 -0
  17. package/dist/configurator/polyfills-es5.js +18375 -0
  18. package/dist/configurator/polyfills-es5.js.map +1 -0
  19. package/dist/configurator/runtime-es2015.js +155 -0
  20. package/dist/configurator/runtime-es2015.js.map +1 -0
  21. package/dist/configurator/runtime-es5.js +155 -0
  22. package/dist/configurator/runtime-es5.js.map +1 -0
  23. package/dist/configurator/styles-es2015.js +450 -0
  24. package/dist/configurator/styles-es2015.js.map +1 -0
  25. package/dist/configurator/styles-es5.js +432 -0
  26. package/dist/configurator/styles-es5.js.map +1 -0
  27. package/dist/configurator/vendor-es2015.js +155551 -0
  28. package/dist/configurator/vendor-es2015.js.map +1 -0
  29. package/dist/configurator/vendor-es5.js +183588 -0
  30. package/dist/configurator/vendor-es5.js.map +1 -0
  31. package/ng-package.json +9 -0
  32. package/package.json +47 -14
  33. package/src/app/app.component.ts +222 -0
  34. package/src/app/app.module.ts +34 -0
  35. package/src/app/builder.ts +480 -0
  36. package/src/app/components/answers/answer/answer.component.ts +61 -0
  37. package/src/app/components/answers/answers.component.ts +41 -0
  38. package/src/app/components/answers/answers.module.ts +26 -0
  39. package/src/app/components/selections/selections.component.ts +131 -0
  40. package/src/app/components/selections/selections.module.ts +20 -0
  41. package/src/app/components/shared/loader/loader.component.scss +33 -0
  42. package/src/app/components/shared/loader/loader.component.ts +20 -0
  43. package/src/app/components/shared/shared.module.ts +16 -0
  44. package/src/app/directives/visibility-observer-master.directive.ts +71 -0
  45. package/src/app/directives/visibility-observer.directive.ts +74 -0
  46. package/src/app/services/configurator.service.ts +86 -0
  47. package/src/app/services/image-cache.service.ts +56 -0
  48. package/src/app/services/locator.service.ts +6 -0
  49. package/src/environments/environment.prod.ts +3 -0
  50. package/src/environments/environment.ts +8 -0
  51. package/src/helper/variation-helper.ts +220 -0
  52. package/src/index.html +14 -0
  53. package/src/main.ts +11 -0
  54. package/src/model/material.ts +22 -0
  55. package/src/model/variation-settings.ts +14 -0
  56. package/src/model/variation.ts +11 -0
  57. package/src/polyfills.ts +73 -0
  58. package/{public_api.d.ts → src/public_api.ts} +6 -6
  59. package/src/style/shared.scss +173 -0
  60. package/src/style/styles.scss +45 -0
  61. package/src/tsconfig.app.json +16 -0
  62. package/src/tsconfig.spec.json +19 -0
  63. package/src/utils/asset.utils.ts +88 -0
  64. package/src/utils/file.utils.ts +156 -0
  65. package/src/utils/file.utils.unit.test.ts +8 -0
  66. package/src/utils/image.utils.ts +54 -0
  67. package/src/utils/object.utils.ts +52 -0
  68. package/src/utils/scene-utils.ts +119 -0
  69. package/src/utils/threed.utils.ts +219 -0
  70. package/src/utils/variation-utils.ts +216 -0
  71. package/tsconfig.json +23 -0
  72. package/tslint.json +132 -0
  73. package/app/builder.d.ts +0 -53
  74. package/app/components/answers/answer/answer.component.d.ts +0 -11
  75. package/app/components/answers/answers.component.d.ts +0 -8
  76. package/app/components/answers/answers.module.d.ts +0 -2
  77. package/app/components/selections/selections.component.d.ts +0 -22
  78. package/app/components/selections/selections.module.d.ts +0 -2
  79. package/app/components/shared/loader/loader.component.d.ts +0 -2
  80. package/app/components/shared/shared.module.d.ts +0 -2
  81. package/app/directives/visibility-observer-master.directive.d.ts +0 -9
  82. package/app/directives/visibility-observer.directive.d.ts +0 -13
  83. package/app/services/configurator.service.d.ts +0 -22
  84. package/app/services/image-cache.service.d.ts +0 -10
  85. package/app/services/locator.service.d.ts +0 -4
  86. package/bundles/colijnit-configurator.umd.js +0 -2745
  87. package/bundles/colijnit-configurator.umd.js.map +0 -1
  88. package/bundles/colijnit-configurator.umd.min.js +0 -17
  89. package/bundles/colijnit-configurator.umd.min.js.map +0 -1
  90. package/colijnit-configurator.d.ts +0 -10
  91. package/colijnit-configurator.metadata.json +0 -1
  92. package/esm2015/app/builder.js +0 -477
  93. package/esm2015/app/components/answers/answer/answer.component.js +0 -69
  94. package/esm2015/app/components/answers/answers.component.js +0 -43
  95. package/esm2015/app/components/answers/answers.module.js +0 -29
  96. package/esm2015/app/components/selections/selections.component.js +0 -134
  97. package/esm2015/app/components/selections/selections.module.js +0 -23
  98. package/esm2015/app/components/shared/loader/loader.component.js +0 -24
  99. package/esm2015/app/components/shared/shared.module.js +0 -21
  100. package/esm2015/app/directives/visibility-observer-master.directive.js +0 -51
  101. package/esm2015/app/directives/visibility-observer.directive.js +0 -57
  102. package/esm2015/app/services/configurator.service.js +0 -94
  103. package/esm2015/app/services/image-cache.service.js +0 -66
  104. package/esm2015/app/services/locator.service.js +0 -10
  105. package/esm2015/colijnit-configurator.js +0 -11
  106. package/esm2015/helper/variation-helper.js +0 -216
  107. package/esm2015/model/material.js +0 -11
  108. package/esm2015/model/variation-settings.js +0 -6
  109. package/esm2015/model/variation.js +0 -3
  110. package/esm2015/public_api.js +0 -7
  111. package/esm2015/utils/asset.utils.js +0 -74
  112. package/esm2015/utils/file.utils.js +0 -139
  113. package/esm2015/utils/image.utils.js +0 -52
  114. package/esm2015/utils/object.utils.js +0 -49
  115. package/esm2015/utils/scene-utils.js +0 -94
  116. package/esm2015/utils/threed.utils.js +0 -222
  117. package/esm2015/utils/variation-utils.js +0 -224
  118. package/esm5/app/builder.js +0 -591
  119. package/esm5/app/components/answers/answer/answer.component.js +0 -64
  120. package/esm5/app/components/answers/answers.component.js +0 -27
  121. package/esm5/app/components/answers/answers.module.js +0 -32
  122. package/esm5/app/components/selections/selections.component.js +0 -104
  123. package/esm5/app/components/selections/selections.module.js +0 -26
  124. package/esm5/app/components/shared/loader/loader.component.js +0 -16
  125. package/esm5/app/components/shared/shared.module.js +0 -24
  126. package/esm5/app/directives/visibility-observer-master.directive.js +0 -64
  127. package/esm5/app/directives/visibility-observer.directive.js +0 -59
  128. package/esm5/app/services/configurator.service.js +0 -160
  129. package/esm5/app/services/image-cache.service.js +0 -69
  130. package/esm5/app/services/locator.service.js +0 -13
  131. package/esm5/colijnit-configurator.js +0 -11
  132. package/esm5/helper/variation-helper.js +0 -268
  133. package/esm5/model/material.js +0 -13
  134. package/esm5/model/variation-settings.js +0 -8
  135. package/esm5/model/variation.js +0 -7
  136. package/esm5/public_api.js +0 -7
  137. package/esm5/utils/asset.utils.js +0 -106
  138. package/esm5/utils/file.utils.js +0 -151
  139. package/esm5/utils/image.utils.js +0 -56
  140. package/esm5/utils/object.utils.js +0 -56
  141. package/esm5/utils/scene-utils.js +0 -98
  142. package/esm5/utils/threed.utils.js +0 -279
  143. package/esm5/utils/variation-utils.js +0 -327
  144. package/fesm2015/colijnit-configurator.js +0 -2109
  145. package/fesm2015/colijnit-configurator.js.map +0 -1
  146. package/fesm5/colijnit-configurator.js +0 -2527
  147. package/fesm5/colijnit-configurator.js.map +0 -1
  148. package/helper/variation-helper.d.ts +0 -14
  149. package/model/material.d.ts +0 -17
  150. package/model/variation-settings.d.ts +0 -14
  151. package/model/variation.d.ts +0 -10
  152. package/utils/asset.utils.d.ts +0 -13
  153. package/utils/file.utils.d.ts +0 -27
  154. package/utils/image.utils.d.ts +0 -8
  155. package/utils/object.utils.d.ts +0 -7
  156. package/utils/scene-utils.d.ts +0 -7
  157. package/utils/threed.utils.d.ts +0 -16
  158. package/utils/variation-utils.d.ts +0 -12
@@ -0,0 +1,480 @@
1
+ import * as THREE from "three";
2
+ import {Options} from "@colijnit/ioneconnector/build/model/options";
3
+ import {DataServiceResponseData} from "@colijnit/ioneconnector/build/model/data-service-response-data";
4
+ import {DecoNode} from "@colijnit/configuratorapi/build/model/deco-node";
5
+ import {BusinessObjectFactory} from "@colijnit/ioneconnector/build/service/business-object-factory";
6
+ import {Selection} from "@colijnit/configuratorapi/build/model/selection";
7
+ import {DecoNodeType} from "@colijnit/configuratorapi/build/enum/deco-node-type.enum";
8
+ import {ThreedUtils} from "../utils/threed.utils";
9
+ import {DecoNodeKind} from "@colijnit/configuratorapi/build/enum/deco-node-kind.enum";
10
+ import {SceneUtils} from "../utils/scene-utils";
11
+ import {VariationHelper} from "../helper/variation-helper";
12
+ import {Article} from "@colijnit/configuratorapi/build/model/article";
13
+ import {ConfiguratorService} from './services/configurator.service';
14
+ import {Scene} from 'three';
15
+ import {Injectable} from '@angular/core';
16
+ import {Answer} from '@colijnit/configuratorapi/build/model/answer';
17
+ import {BehaviorSubject} from 'rxjs';
18
+ import {ServiceLocator} from './services/locator.service';
19
+ import {QuestionAndAnswers} from '@colijnit/configuratorapi/build/model/question-and-answers';
20
+
21
+ @Injectable()
22
+ export class Builder {
23
+
24
+ public selectionsReceived: BehaviorSubject<Selection[]> = new BehaviorSubject<Selection[]>([]);
25
+ public answersReceived: BehaviorSubject<Answer[]> = new BehaviorSubject<Answer[]>([]);
26
+ public modelLoaded: BehaviorSubject<THREE.Object3D> = new BehaviorSubject<THREE.Object3D>(null);
27
+
28
+ private _scene: THREE.Scene;
29
+ private _instanceId: string;
30
+ private _sku: string;
31
+ private _goodId: number;
32
+ private _selections: Selection[] = [];
33
+ private _answers: Answer[] = [];
34
+ private _decos: DecoNode[] = [];
35
+ private _placedAdjustables: any[] = [];
36
+ private _placedAddables: any[] = [];
37
+ private _adjustables: any[] = [];
38
+ private _addables: any[] = [];
39
+
40
+ private _boFactory: BusinessObjectFactory;
41
+ private _source: THREE.Object3D;
42
+ private _threedUtils: ThreedUtils;
43
+ private _variationHelper: VariationHelper;
44
+ private _articleCache: Map<string, Article> = new Map();
45
+ private _configuratorService: ConfiguratorService;
46
+
47
+ constructor(scene: Scene, options: Options, useInAngular: boolean) {
48
+ this._boFactory = new BusinessObjectFactory();
49
+ this._threedUtils = new ThreedUtils();
50
+ this._variationHelper = new VariationHelper();
51
+
52
+ if (!scene) {
53
+ throw 'No scene object provided!';
54
+ }
55
+ if (!options) {
56
+ throw 'No connection options provided!';
57
+ }
58
+ if (useInAngular) {
59
+ this._configuratorService = ServiceLocator.injector.get(ConfiguratorService);
60
+ } else {
61
+ this._configuratorService = new ConfiguratorService(undefined);
62
+ }
63
+ this._configuratorService.initApi(options);
64
+ this._scene = scene;
65
+ }
66
+
67
+ public async buildModel(sku?: string, instanceId?: string, goodId?: number): Promise<THREE.Object3D> {
68
+ if (!this._scene) {
69
+ return;
70
+ }
71
+ try {
72
+ await this._setInstanceId(sku, instanceId, goodId);
73
+ await this._prepareConfiguration(this._sku, this._goodId);
74
+ if (this._source) {
75
+ await this._configuratorService.setInstanceToConfigure(this._instanceId);
76
+ const promises: Promise<any>[] = [];
77
+ promises.push(this.getQuestionAndAnswers());
78
+ promises.push(this._getSelections(this._instanceId));
79
+ promises.push(this._getDecos());
80
+ await Promise.all(promises);
81
+ if (this._answers.length > 0) {
82
+ return;
83
+ }
84
+ this._linkSelectionsAndDecos();
85
+ return this._build(this._instanceId);
86
+ } else {
87
+ throw 'GLB source not found!';
88
+ }
89
+ } catch (e) {
90
+ throw e;
91
+ }
92
+ }
93
+
94
+ public initNodeInstance(goodId: number): Promise<any> {
95
+ return this._configuratorService.initNodeInstance(goodId);
96
+ }
97
+
98
+ public destroy(): void {
99
+ this._threedUtils.clearCache();
100
+ this._variationHelper.clearCache();
101
+ }
102
+
103
+ public async selectSelection(selection: Selection): Promise<void> {
104
+ await this._configuratorService.selectSelection(selection, false);
105
+ this.getQuestionAndAnswers();
106
+ }
107
+
108
+ public async getQuestionAndAnswers(publicationCode?: number): Promise<void> {
109
+ const questionsAndAnswers: QuestionAndAnswers = await this._configuratorService.getQuestionAndAnswers(false, publicationCode);
110
+ this._answers = questionsAndAnswers.answers;
111
+ this.answersReceived.next(questionsAndAnswers.answers);
112
+ }
113
+
114
+ public async selectAnswer(answer: Answer): Promise<void> {
115
+ await this._configuratorService.selectAnswer(answer, false);
116
+ this.modelLoaded.next(await this.buildModel());
117
+ }
118
+
119
+ private async _setInstanceId(sku: string, instanceId?: string, goodId?: number): Promise<void> {
120
+ if (!instanceId && !this._instanceId) {
121
+ if (!goodId) {
122
+ goodId = await this._getGoodIdFromSku(sku);
123
+ }
124
+ this._goodId = goodId;
125
+ const result: DataServiceResponseData = await this.initNodeInstance(this._goodId);
126
+ if (result && result.resultObject) {
127
+ this._instanceId = result.resultObject;
128
+ } else {
129
+ throw 'Failed to initialize node instance';
130
+ }
131
+ } else if (!this._instanceId) {
132
+ this._instanceId = instanceId;
133
+ }
134
+ if (!this._sku) {
135
+ this._sku = sku;
136
+ }
137
+ }
138
+
139
+ private async _prepareConfiguration(sku: string, goodId?: number): Promise<void> {
140
+ const article: Article = await this._getArticle(sku, goodId);
141
+ if (article && article.assetUrl) {
142
+ this._source = await this._threedUtils.download3DSource(article.assetUrl)
143
+ .catch((error) => {
144
+ throw error;
145
+ });
146
+ if (article.contentDeliveryUrl) {
147
+ this._variationHelper.assetPath =
148
+ article.contentDeliveryUrl +
149
+ (article.contentDeliveryUrl.endsWith('/') ? '' : '/') +
150
+ (article.distSchema ? article.distSchema : 'UP_DBA');
151
+ }
152
+ }
153
+ }
154
+
155
+ private async _build(instanceId: string): Promise<THREE.Object3D> {
156
+ this._reset();
157
+ const adjustables: Selection[] = this._getAdjustables();
158
+ if (adjustables && adjustables.length > 0) {
159
+ const obj: THREE.Object3D = new THREE.Object3D();
160
+ obj.visible = false; // no need to render visualy
161
+ this._scene.add(obj);
162
+ let connected = false;
163
+ for (let i = 0, len: number = adjustables.length; i < len; i++) {
164
+ const adjustable: THREE.Object3D = this._createAdjustable(obj, adjustables[i]);
165
+ if (adjustable) {
166
+ for (let ii = 0, lenii: number = this._placedAdjustables.length; ii < lenii; ii++) {
167
+ if (SceneUtils.TrySelectorConnection(this._scene,
168
+ obj, this._placedAdjustables[ii], adjustable)) {
169
+ this._placedAdjustables[ii].visible = true;
170
+ adjustable.visible = true;
171
+ connected = true;
172
+ break;
173
+ }
174
+ connected = false;
175
+ }
176
+ }
177
+ if (!connected && this._placedAdjustables.length > 1) {
178
+ console.warn('No connection found for: ', adjustable.name);
179
+ }
180
+ }
181
+ this._placeAddables(obj);
182
+ this._updatePivot(obj);
183
+ await this._loadVariations(obj, instanceId);
184
+ this._scene.remove(obj);
185
+ return obj;
186
+ } else {
187
+ throw 'No adjustables found!';
188
+ // this._building = false;
189
+ // if (this.selections.length < 2) {
190
+ // this._errorService.addError(this.activeInstance, {message: 'NO_SELECTIONS_OR_DECOS', description: 'NO_SELECTIONS_OR_DECOS_INFO'});
191
+ // this.buildFinished.next({instanceId: this.activeInstance, resultType: ResultType.NoSelections});
192
+ // } else if (this.decos.size === 0) {
193
+ // this._errorService.addError(this.activeInstance, {message: 'NO_SELECTIONS_OR_DECOS', description: 'NO_SELECTIONS_OR_DECOS_INFO'});
194
+ // this.buildFinished.next({instanceId: this.activeInstance, resultType: ResultType.NoDecoNodes});
195
+ // } else {
196
+ // this._errorService.addError(this.activeInstance, {message: 'NO_ADJUSTABLES', description: 'NO_ADJUSTABLES_INFO'});
197
+ // this.buildFinished.next({instanceId: this.activeInstance, resultType: ResultType.NoAdjustables});
198
+ // }
199
+ }
200
+ }
201
+
202
+ private _prepareTheSelections(): void {
203
+ // get generic variations
204
+ const globalVariations: DecoNode[] = this._selections
205
+ .filter(s => s.generic && (s.decoNode as any).variation && !s.decoNode.type)
206
+ .map((value: Selection, index: number, array: Selection[]) => {
207
+ // find selection of variation
208
+ const sel: Selection = this._selections.find(s => s.artNodeIdDeco === (value.decoNode as any).variation.id);
209
+ if (sel) {
210
+ (value.decoNode as any).variation.supplierArticleNr = sel.supplierArticleNr;
211
+ }
212
+ (value.decoNode as any).variation.materialId = value.hdecoGameObject;
213
+ return (value.decoNode as any).variation;
214
+ });
215
+
216
+ // const usedVariations: FurniturePartVariation[] = [];
217
+ let globalVariationsRewrite: boolean = true;
218
+
219
+ const len: number = this._selections.length;
220
+ let lastAdded: Selection;
221
+ let lastAdjustable: Selection;
222
+ let newPart: boolean = false;
223
+ let previousPresLevel: number = -1;
224
+ let positioning: any;
225
+ for (let i = 0; i < len; i++) {
226
+ const selection: Selection = this._selections[i];
227
+ if (selection.presentationLevel === 1) {
228
+ positioning = selection.hdecoPositioning;
229
+ }
230
+ if (selection.presentationLevel > previousPresLevel) {
231
+ selection.hdecoPositioning = selection.hdecoPositioning || positioning;
232
+ }
233
+ if (selection.decoNode) {
234
+ if (selection.decoNode.type === DecoNodeType.Variation) {
235
+ if (lastAdded) {
236
+ if (newPart) {
237
+ lastAdded.variations = [selection.decoNode];
238
+ } else {
239
+ lastAdded.variations.push(selection.decoNode);
240
+ }
241
+ newPart = false;
242
+ } else {
243
+ if (globalVariationsRewrite) {
244
+ globalVariations.length = 0;
245
+ globalVariationsRewrite = false;
246
+ }
247
+ globalVariations.push(selection.decoNode);
248
+ }
249
+ // const variation: FurniturePartVariation = new FurniturePartVariation();
250
+ // variation.BrandId = selection.decoNode.brandId;
251
+ // variation.Description = selection.decoNode.gameObjectName;
252
+ // variation.MaterialId = (selection.decoNode as any).materialId;
253
+ // variation.SupplierArticleNr = (selection.decoNode as any).supplierArticleNr;
254
+ // usedVariations.push(variation);
255
+ // this._upsertFurniture(this.activeInstance, {
256
+ // Variation: selection.decoNode.brandId,
257
+ // VariationDescription: selection.decoNode.gameObjectName,
258
+ // SupplierArticleNr: (selection.decoNode as any).supplierArticleNr
259
+ // });
260
+ } else if (selection.decoNode.type === DecoNodeType.Part &&
261
+ typeof selection.decoNode.gameObjectName === 'string' &&
262
+ selection.decoNode.gameObjectName.length) {
263
+ if (selection.decoNode.kind === DecoNodeKind.Adjustable) {
264
+ selection.variations = globalVariations;
265
+ this._adjustables.push(selection);
266
+ if (!lastAdded || lastAdded.nodeId !== selection.nodeId) {
267
+ newPart = true;
268
+ }
269
+ lastAdded = selection;
270
+ lastAdjustable = selection;
271
+ } else if (selection.decoNode.kind === DecoNodeKind.Addable) {
272
+ selection.variations = lastAdjustable ? lastAdjustable.variations : globalVariations;
273
+ if (lastAdjustable) {
274
+ lastAdjustable.addables.push(selection);
275
+ }
276
+ this._addables.push(selection);
277
+ if (!lastAdded || lastAdded.nodeId !== selection.nodeId) {
278
+ newPart = true;
279
+ }
280
+ lastAdded = selection;
281
+ }
282
+ }
283
+ }
284
+ previousPresLevel = selection.presentationLevel;
285
+ }
286
+ // this._upsertFurniture(this.activeInstance,
287
+ // {Variations: usedVariations});
288
+ }
289
+
290
+ private _createAdjustable(parent: THREE.Object3D, adj: Selection): THREE.Object3D {
291
+ let obj: any = this._source ? this._source.getObjectByName(adj.decoNode.gameObjectName) : null;
292
+ if (!obj) {
293
+ // in case of glb files, the importer removes dots from names
294
+ const name = adj.decoNode.gameObjectName.replace(/[.]/g, '');
295
+ obj = this._source ? this._source.getObjectByName(name) : null;
296
+ if (!obj) {
297
+ // console.warn(`No object with name ${adj.decoNode.gameObjectName} found!`);
298
+ return null;
299
+ }
300
+ }
301
+ let adjustable: any = obj.clone();
302
+ adjustable.name = this._createUniqueName(parent, obj);
303
+ adjustable.userData.selection = adj;
304
+ adjustable.position.set(0, 0, 0);
305
+ adjustable.visible = true;
306
+ parent.add(adjustable);
307
+ // the object being added to the customFloorGroup is being recreated so we loose the reference
308
+ // therefor we need to retrieve the created object again
309
+ // adjustable = parent.getObjectByName(adjustable.name);
310
+ this._placedAdjustables.push(adjustable);
311
+ return adjustable;
312
+ }
313
+
314
+ private _createAddable(parent: THREE.Object3D, add: Selection, part2?: any, part1?: any): THREE.Object3D {
315
+ const obj: any = this._source.getObjectByName(add.decoNode.gameObjectName);
316
+ if (!obj) {
317
+ return null;
318
+ }
319
+ // const selection: Selection = this._getSelectionFromId(adj.artNodeIdDeco);
320
+ const addable: any = obj.clone();
321
+ addable.name = this._createUniqueName(parent, obj);
322
+ addable.userData.selection = add;
323
+ addable.position.set(0, 0, 0);
324
+ addable.visible = true;
325
+ if (part1 && part2) {
326
+ parent.add(addable);
327
+ this._placedAddables.push(addable);
328
+ return addable;
329
+ }
330
+ return addable;
331
+ }
332
+
333
+ private _placeAddables(parent: THREE.Object3D): void {
334
+ const len: number = this._placedAdjustables.length;
335
+ for (let i = 0; i < len; i++) {
336
+ if (this._placedAdjustables[i].userData.hasOwnProperty('selection') && this._placedAdjustables[i].userData.selection) {
337
+ const adjustableSelection: Selection = this._placedAdjustables[i].userData.selection;
338
+ if (adjustableSelection) {
339
+ const lena: number = adjustableSelection.addables.length;
340
+ let conAddable: any;
341
+ for (let ia = 0; ia < lena; ia++) {
342
+ SceneUtils.TrySelectorConnection(this._scene,
343
+ parent, this._placedAdjustables[i], adjustableSelection.addables[ia],
344
+ (add, part2?, part1?) => this._createAddable(parent, add, part2, part1));
345
+ if (conAddable) {
346
+ SceneUtils.TrySelectorConnection(this._scene,
347
+ parent, conAddable, adjustableSelection.addables[ia],
348
+ (add, part2?, part1?) => this._createAddable(parent, add, part2, part1));
349
+ }
350
+ conAddable = this._placedAddables[this._placedAddables.length - 1];
351
+ }
352
+ }
353
+ }
354
+ }
355
+ }
356
+
357
+ private _createUniqueName(parent: THREE.Object3D, obj: THREE.Object3D): string {
358
+ let iteration = 0;
359
+ let name = obj.name;
360
+ let existingObj = parent.getObjectByName(name);
361
+ while (existingObj) {
362
+ iteration++;
363
+ name = obj.name + (iteration !== 0 ? ('_' + iteration) : '');
364
+ existingObj = parent.getObjectByName(name);
365
+ }
366
+ return name;
367
+ }
368
+
369
+ private async _getGoodIdFromSku(sku: string): Promise<number> {
370
+ const response: DataServiceResponseData = await this._configuratorService.getGoodIdFromSku(sku, false);
371
+ if (response.validationResult.success && response.resultObject) {
372
+ return response.resultObject;
373
+ }
374
+ }
375
+
376
+ private async _getArticle(sku: string, goodId: number): Promise<Article> {
377
+ if (this._articleCache.has(sku)) {
378
+ return this._articleCache.get(sku);
379
+ }
380
+ if (!goodId) {
381
+ goodId = await this._getGoodIdFromSku(sku)
382
+ .catch((error) => {
383
+ throw `Article with sku ${sku} not found!`;
384
+ });
385
+ }
386
+ let article: Article;
387
+ const articleResponse: DataServiceResponseData = await this._configuratorService.getArticleQuickSel(goodId, false);
388
+ if (articleResponse.validationResult.success && articleResponse.resultObject) {
389
+ if (articleResponse.resultObject.hasOwnProperty('oArticle')) {
390
+ const obj = Array.isArray(articleResponse.resultObject['oArticle']) ? articleResponse.resultObject['oArticle'][0] : articleResponse.resultObject['oArticle'];
391
+ article = <Article>this._boFactory.makeWithRawBackendData(Article, obj);
392
+ } else {
393
+ article = <Article>this._boFactory.makeWithRawBackendData(Article, articleResponse.resultObject);
394
+ }
395
+ }
396
+ this._articleCache.set(sku, article);
397
+ return article;
398
+ }
399
+
400
+ private async _getSelections(instanceId: string, publicationCode?: number): Promise<void> {
401
+ this._selections = [];
402
+ const selectionResponse: DataServiceResponseData = await this._configuratorService.getSelections(false, publicationCode);
403
+ if (selectionResponse.resultObjects && selectionResponse.resultObjects.length > 0) {
404
+ this._selections = <Selection[]>this._boFactory.makeBOArrayFromRawBackendDataArray(Selection, selectionResponse.resultObjects);
405
+ this._selections.forEach(s => s.instanceId = instanceId);
406
+ // const filtered: Selection[] = this._selections.filter(s => s.nodeType !== NodeType.Article && s.presentationLevel === 1);
407
+ this.selectionsReceived.next(this._selections);
408
+ } else {
409
+ throw 'No selections found!';
410
+ }
411
+ }
412
+
413
+ private async _getDecos(): Promise<void> {
414
+ this._decos = [];
415
+ const decosResponse: DataServiceResponseData = await this._configuratorService.getDecos(false);
416
+ if (decosResponse.resultObjects && decosResponse.resultObjects.length > 0) {
417
+ this._decos = <DecoNode[]>this._boFactory.makeBOArrayFromRawBackendDataArray(DecoNode, decosResponse.resultObjects);
418
+ } else {
419
+ throw 'No deconodes found!';
420
+ }
421
+ }
422
+
423
+ private _linkSelectionsAndDecos(): void {
424
+ const len: number = this._selections.length;
425
+ for (let i = 0; i < len; i++) {
426
+ let id: string = this._selections[i].artNodeIdDeco;
427
+ // if (this._useNodeIdToLink) {
428
+ // id = `${this._selections[i].node}_${this._selections[i].artNodeIdDeco}`;
429
+ // }
430
+ let deco: any = this._decos.find(d => d.id === id);
431
+ if (!deco) {
432
+ deco = new DecoNode();
433
+ }
434
+ const variation: any = this._getVariations().find(v => v.parentId === this._selections[i].artNodeIdDeco);
435
+ if (variation) {
436
+ deco.variation = variation;
437
+ }
438
+ this._selections[i].decoNode = deco;
439
+ }
440
+ }
441
+
442
+ private _getVariations(): DecoNode[] {
443
+ return this._decos.filter((deco: DecoNode) => {
444
+ return deco.type === DecoNodeType.Variation;
445
+ });
446
+ }
447
+
448
+ private async _loadVariations(obj: THREE.Object3D, instanceId: string): Promise<void> {
449
+ await this._variationHelper.loadPart(obj, this._adjustables, true);
450
+ await this._variationHelper.loadVariation(instanceId, obj, this._adjustables, true);
451
+ await this._variationHelper.loadVariation(instanceId, obj, this._addables, true);
452
+ }
453
+
454
+ private _getAdjustables(): Selection[] {
455
+ return this._selections.filter(s => {
456
+ const node: DecoNode = s.decoNode;
457
+ return node && node.gameObjectName && node.type === DecoNodeType.Part && node.kind === DecoNodeKind.Adjustable;
458
+ });
459
+ }
460
+
461
+ private _updatePivot(obj: THREE.Object3D) {
462
+ const boundingBox = new THREE.Box3().setFromObject(obj);
463
+ const bbCenterPivot = new THREE.Vector3();
464
+ boundingBox.getCenter(bbCenterPivot);
465
+ const delta: THREE.Vector3 = new THREE.Vector3().sub(bbCenterPivot).setY(Math.abs(Math.min(boundingBox.min.y, 0)));
466
+
467
+ obj.children.forEach((child: any) => {
468
+ child.position.add(delta);
469
+ });
470
+ obj.updateWorldMatrix(false, true);
471
+ }
472
+
473
+ private _reset(): void {
474
+ this._placedAddables.length = 0;
475
+ this._placedAdjustables.length = 0;
476
+ this._adjustables.length = 0;
477
+ this._addables.length = 0;
478
+ this._prepareTheSelections();
479
+ }
480
+ }
@@ -0,0 +1,61 @@
1
+ import {Component, Input, OnInit} from '@angular/core';
2
+ import {ImageCacheService} from '../../../services/image-cache.service';
3
+ import {Answer} from '@colijnit/configuratorapi/build/model/answer';
4
+ import {animate, state, style, transition, trigger} from '@angular/animations';
5
+
6
+ @Component({
7
+ selector: 'answer',
8
+ template: `
9
+ <div class="ione-configurator">
10
+ <div class="answer-wrapper">
11
+ <div class="answer-content" @answerAppear>
12
+ <div class="answer-thumbnail">
13
+ <rp-loader *ngIf="answer.imageData === ''"></rp-loader>
14
+ <img *ngIf="answer.imageData !== '' && answer.imageData !== null" class="answer-img" [src]="answer.imageData">
15
+ </div>
16
+ <div class="answer-title-wrapper">
17
+ <span class="answer-title" [textContent]="answer.commercialAnswer"></span>
18
+ </div>
19
+ <div class="price">
20
+ <span class="price-value"></span>
21
+ </div>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ `,
26
+ styleUrls: [
27
+ '../../../../style/shared.scss'
28
+ ],
29
+ animations: [
30
+ trigger('answerAppear', [
31
+ state('void', style({'background': '#dbdbdb'})),
32
+ state('white', style({'background': 'white'})),
33
+ transition('void <=> *', animate(500))
34
+ ])
35
+ ]
36
+ })
37
+ export class AnswerComponent implements OnInit {
38
+ @Input()
39
+ public answer: Answer;
40
+
41
+ @Input()
42
+ public set showing(value: boolean) {
43
+ this.answer.imageData = '';
44
+ if (value && this.answer.answer !== 'Skip / Cancel') {
45
+ this._loadThumbnail(this.answer);
46
+ } else {
47
+ this.answer.imageData = null;
48
+ }
49
+ }
50
+
51
+ constructor(private _imageCacheService: ImageCacheService) { }
52
+
53
+ public ngOnInit(): void {
54
+ }
55
+
56
+ private async _loadThumbnail(answer: Answer): Promise<void> {
57
+ await this._imageCacheService.getImageForSelectionOrAnswer(answer).then((imageSrc: string) => {
58
+ answer.imageData = imageSrc === "" ? null : imageSrc;
59
+ });
60
+ }
61
+ }
@@ -0,0 +1,41 @@
1
+ import {Component, EventEmitter, Input, Output} from '@angular/core';
2
+ import {Answer} from "@colijnit/configuratorapi/build/model/answer";
3
+
4
+ @Component({
5
+ selector: "answers",
6
+ template: `
7
+ <div class="ione-configurator">
8
+ <div class="rp-answers-slideout">
9
+ <h2 class="answers-title" [textContent]="selectionTitle"></h2>
10
+ <div class="answers-container" visibilityObserverMaster>
11
+ <answer *ngFor="let answer of answers"
12
+ (click)="answerClick.emit(answer)"
13
+ [answer]="answer"
14
+ visibilityObserver
15
+ #intersection="intersection"
16
+ [observerEnabled]="true"
17
+ [showing]="intersection.isIntersecting"
18
+ ></answer>
19
+ </div>
20
+
21
+ </div>
22
+ </div>
23
+ `,
24
+ styleUrls: [
25
+ '../../../style/shared.scss'
26
+ ]
27
+ })
28
+
29
+ export class AnswersComponent {
30
+ @Input()
31
+ public answers: Answer[] = [];
32
+
33
+ @Input()
34
+ public selectionTitle: string;
35
+
36
+ @Output()
37
+ public answerClick: EventEmitter<Answer> = new EventEmitter<Answer>();
38
+
39
+ constructor() {}
40
+
41
+ }
@@ -0,0 +1,26 @@
1
+ import {NgModule} from "@angular/core";
2
+ import {CommonModule} from "@angular/common";
3
+ import {AnswersComponent} from "./answers.component";
4
+ import { AnswerComponent } from './answer/answer.component';
5
+ import {VisibilityObserverDirective} from '../../directives/visibility-observer.directive';
6
+ import {VisibilityObserverMasterDirective} from '../../directives/visibility-observer-master.directive';
7
+ import {SharedModule} from '../shared/shared.module';
8
+
9
+ @NgModule({
10
+ imports: [
11
+ CommonModule,
12
+ SharedModule
13
+ ],
14
+ declarations: [
15
+ AnswersComponent,
16
+ AnswerComponent,
17
+ VisibilityObserverDirective,
18
+ VisibilityObserverMasterDirective
19
+ ],
20
+ exports: [
21
+ AnswersComponent
22
+ ]
23
+ })
24
+ export class AnswersModule {
25
+
26
+ }