@colijnit/homedecorator 261.20.4 → 261.20.6

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.
@@ -43,9 +43,7 @@ import { XRControllerModelFactory } from 'three/examples/jsm/webxr/XRControllerM
43
43
  import { RGBFormat, LinearToneMapping, AgXToneMapping, LinearFilter as LinearFilter$1, LinearSRGBColorSpace as LinearSRGBColorSpace$1, SrcAlphaSaturateFactor, FloatType as FloatType$1 } from 'three/src/constants.js';
44
44
  import md5 from 'md5';
45
45
  import { NodeType } from '@colijnit/configuratorapi/build/enum/node-type.enum';
46
- import { ConfiguratorStatisticsEnvironment } from '@colijnit/configuratorapi/build/model/configurator-statistics-environment';
47
46
  import { Options } from '@colijnit/ioneconnector/build/model/options';
48
- import { FrozenArticle } from '@colijnit/configuratorapi/build/model/frozen-article';
49
47
  import { SelectorWithOptions } from '@colijnit/configuratorapi/build/model/selector-with-options';
50
48
  import { ImageUtils } from '@colijnit/configuratorapi/build/utils/image-utils';
51
49
  import * as i1 from '@angular/common/http';
@@ -82,7 +80,7 @@ import { DecoNodeType } from '@colijnit/configuratorapi/build/enum/deco-node-typ
82
80
  import JSZip from 'jszip';
83
81
  import { Answer } from '@colijnit/configuratorapi/build/model/answer';
84
82
  import { SelectorStructure } from '@colijnit/configuratorapi/build/model/selector-structure.bo';
85
- import { Evaluator, Brush, HOLLOW_SUBTRACTION } from 'three-bvh-csg';
83
+ import { Evaluator, Brush, SUBTRACTION } from 'three-bvh-csg';
86
84
  import { Line2 } from 'three/examples/jsm/lines/Line2.js';
87
85
  import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js';
88
86
  import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js';
@@ -252,6 +250,7 @@ var MessageType;
252
250
  MessageType["ChangeArticleConfigurationType"] = "ChangeArticleConfigurationType";
253
251
  MessageType["RenderUploadProgress"] = "RenderUploadProgress";
254
252
  MessageType["RenderUploadFinished"] = "RenderUploadFinished";
253
+ MessageType["RenderFinished"] = "RenderFinished";
255
254
  MessageType["RemoveSlowConnectionToast"] = "RemoveSlowConnectionToast";
256
255
  MessageType["OpenConfigurator"] = "OpenConfigurator";
257
256
  })(MessageType || (MessageType = {}));
@@ -3433,6 +3432,8 @@ const roomColor = '#ffecc147'; // '#f9f9f9';
3433
3432
  const selectedRoomColor = '#f9f9f9'; // same as roomColor for now
3434
3433
  const roomPolygonOffset = -0.3; // negative is offset to the inside
3435
3434
  const cornerTolerance = 0.2;
3435
+ // two walls count as collinear when the angle at the shared corner is within this margin of 180°
3436
+ const collinearAngleTolerance = Math.PI / 180; // ~1 degree
3436
3437
  const defaultWallColor = 0xffffff;
3437
3438
  const defaultEdgeColor = 0xcccccc;
3438
3439
  // wall config
@@ -3983,6 +3984,18 @@ class HomedecoratorConnectorAdapterService {
3983
3984
  // public getJsonMatchTableArticles(): Promise<void> {
3984
3985
  // return this.connector.getJsonMatchTableArticles();
3985
3986
  // }
3987
+ async prepareArticleForCart(goodId, quantity = 1, shouldGetArticleTree = false, showLoader = true, instanceId = undefined) {
3988
+ const response = await this.articleApi.prepareArticleForCart('Homedecorator', 'Sales', 'Homedecorator', goodId, shouldGetArticleTree, quantity, instanceId, showLoader);
3989
+ if (response && response.validationResult && response.validationResult.success) {
3990
+ if (typeof response.resultObject !== 'string') {
3991
+ return this._boFactory.makeWithRawBackendData(ArticleFullObject, response.resultObject);
3992
+ }
3993
+ return response.resultObject;
3994
+ }
3995
+ else {
3996
+ return null;
3997
+ }
3998
+ }
3986
3999
  async setInstanceToConfigure(id) {
3987
4000
  try {
3988
4001
  if (id !== null) {
@@ -6840,8 +6853,8 @@ class HomedecoratorConnectorService {
6840
6853
  googleTranslateEnabled() {
6841
6854
  return this._connector.googleTranslateEnabled();
6842
6855
  }
6843
- getJsonConfiguredArticles(goodId, goodType, quantity, externalSource = false, showLoader = true, instanceId, configuratorStatistics) {
6844
- return this._connector.getJsonConfiguredArticles(goodId, goodType, quantity, externalSource, showLoader, instanceId, configuratorStatistics);
6856
+ prepareArticleForCart(goodId, quantity, externalSource = false, showLoader = true, instanceId) {
6857
+ return this._connector.prepareArticleForCart(goodId, quantity, !!externalSource, showLoader, instanceId);
6845
6858
  }
6846
6859
  // public getJsonMatchTableArticles(): Promise<any> {
6847
6860
  // return this._connector.getJsonMatchTableArticles();
@@ -6874,7 +6887,7 @@ class HomedecoratorConnectorService {
6874
6887
  });
6875
6888
  this.articleReceived.next(article);
6876
6889
  this._article = article;
6877
- this._articlePrice = article.price;
6890
+ this._articlePrice = article ? article.price : null;
6878
6891
  // Sometimes the sku is not returned in Article
6879
6892
  this._article.sku = sku;
6880
6893
  return article;
@@ -7160,23 +7173,21 @@ class HomedecoratorConnectorService {
7160
7173
  });
7161
7174
  }
7162
7175
  async addToCart(goodId, goodType, quantity, instanceId, externalSource) {
7163
- let json;
7164
- const statistics = new ConfiguratorStatisticsEnvironment();
7165
- statistics.userType = 'Homedecorator';
7166
- statistics.transactionType = 'Sales';
7167
- statistics.actionDomain = 'Homedecorator';
7168
- statistics.sessionId = this._settingsService.settings.session ? this._settingsService.settings.session.sessionId : 'unknown';
7169
- statistics.webHost = window.location.host;
7170
- statistics.bundleHost = window.location.host;
7171
- json = await this.getJsonConfiguredArticles(goodId, goodType, quantity, externalSource, true, instanceId, statistics);
7172
- const frozenArticle = JSON.parse(json);
7176
+ const response = await this.prepareArticleForCart(goodId, quantity, externalSource, true, instanceId);
7177
+ let article;
7178
+ if (typeof response === 'string') {
7179
+ article = JSON.parse(response);
7180
+ }
7181
+ else {
7182
+ article = response;
7183
+ }
7173
7184
  this._googleTagManager.sendEvent(GoogleTagManagerEvent.AddToCart, {
7174
- 'articleNr': frozenArticle.articleNr,
7175
- 'product': frozenArticle.articleName,
7176
- 'composition': frozenArticle instanceof FrozenArticle ? frozenArticle.compositions : frozenArticle.configurationText
7185
+ 'articleNr': article.selectorData ? article.selectorData.articleNr : article.articleNr,
7186
+ 'product': article.selectorData ? article.selectorData.articleName : article.name,
7187
+ 'composition': article.selectorData ? article.selectorData.configurationText : article.configuration
7177
7188
  });
7178
- this._messageService.emit(MessageType.ArticleCreated, json);
7179
- return json;
7189
+ this._messageService.emit(MessageType.ArticleCreated, article);
7190
+ return article;
7180
7191
  }
7181
7192
  handleAnswersReceived() {
7182
7193
  this._preloadCachedImages(this.activeAnswers);
@@ -9820,8 +9831,8 @@ class OutputSettings {
9820
9831
  }
9821
9832
  class SceneSettings {
9822
9833
  }
9823
- let RenderSettings$1 = class RenderSettings {
9824
- };
9834
+ class RenderSettings {
9835
+ }
9825
9836
  class Camera {
9826
9837
  }
9827
9838
  class CameraDOF {
@@ -10026,7 +10037,7 @@ class ApiServiceModule {
10026
10037
  };
10027
10038
  }
10028
10039
  _setRenderSettings(renderParameters) {
10029
- const settings = new RenderSettings$1();
10040
+ const settings = new RenderSettings();
10030
10041
  settings.width = renderParameters.width;
10031
10042
  settings.height = renderParameters.height;
10032
10043
  settings.outputType = OutputType.Jpeg;
@@ -10036,7 +10047,7 @@ class ApiServiceModule {
10036
10047
  return settings;
10037
10048
  }
10038
10049
  _setProductRenderSettings(renderParameters) {
10039
- const settings = new RenderSettings$1();
10050
+ const settings = new RenderSettings();
10040
10051
  settings.width = renderParameters.width;
10041
10052
  settings.height = renderParameters.height;
10042
10053
  settings.outputType = OutputType.Jpeg;
@@ -14780,7 +14791,7 @@ class BaseWall extends Mesh {
14780
14791
  this.remove(item);
14781
14792
  this.onItems = this.onItems.filter(i => i !== item);
14782
14793
  this.itemsChanged = true;
14783
- this._reCreateWallGeometry();
14794
+ // this._reCreateWallGeometry();
14784
14795
  }
14785
14796
  resetRoom() {
14786
14797
  this.oppositeCache.clear();
@@ -15064,12 +15075,26 @@ class BaseWall extends Mesh {
15064
15075
  this.items
15065
15076
  .filter((item) => item.getMaskedGeometry())
15066
15077
  .forEach((item) => {
15067
- const geo = item.getMaskedGeometry();
15078
+ // Subtract the opening as a single material group. A multi-group mask (a BoxGeometry has 6
15079
+ // groups) makes SUBTRACTION emit triangles for only the groups that actually cut the wall,
15080
+ // leaving empty groups that crash the evaluator (assignBufferData reads an absent group).
15081
+ // Clone first so the item's own geometry is never mutated or disposed by the wall.
15082
+ const geo = item.getMaskedGeometry().clone();
15083
+ geo.clearGroups();
15068
15084
  const holesBrush = new Brush(geo);
15085
+ holesBrush.material = this.material[this.frontMaterialIndex];
15069
15086
  holesBrush.position.copy(item.position);
15070
15087
  holesBrush.quaternion.copy(item.quaternion);
15071
15088
  holesBrush.updateMatrixWorld();
15072
- this.brush = this._evaluator.evaluate(this.brush, holesBrush, HOLLOW_SUBTRACTION);
15089
+ try {
15090
+ this.brush = this._evaluator.evaluate(this.brush, holesBrush, SUBTRACTION);
15091
+ }
15092
+ catch (e) {
15093
+ // The mask produced no geometry - it doesn't intersect the wall (e.g. a transient placement
15094
+ // position before the item is positioned on the wall). SUBTRACTION then leaves an empty
15095
+ // material group that the evaluator chokes on. Skip this hole; the cut runs again once the
15096
+ // item is positioned correctly (see InWallItem.placeOnWall). this.brush is left untouched.
15097
+ }
15073
15098
  this._tempHoles.push(holesBrush);
15074
15099
  });
15075
15100
  const newGeometry = this.brush.geometry;
@@ -15107,6 +15132,22 @@ class Wall extends BaseWall {
15107
15132
  this.userData = new Object();
15108
15133
  const cloned = new this.constructor(new Corner(this.start.x, this.start.y), new Corner(this.end.x, this.end.y), this.height, this.thickness, this.frontColor, this.backColor, this.version, this.frontTexture, this.backTexture, false);
15109
15134
  Object3D.prototype.copy.call(cloned, this, recursive);
15135
+ // Object3D.copy does not carry over geometry, so the constructor's plain box (built with an
15136
+ // empty items list, i.e. without window/door openings) would survive. A recursive clone -
15137
+ // such as the scene clone used for GLB export - must preserve the CSG-cut geometry. Use an
15138
+ // owned copy so disposing the export scene cannot free the live wall's geometry. The
15139
+ // non-recursive clone (the intersection wall) intentionally keeps its solid box for raycasting.
15140
+ if (recursive && this.geometry) {
15141
+ const cutGeometry = this.geometry.clone();
15142
+ cloned.geometry = cutGeometry;
15143
+ // The constructor built colour-only materials (createTextures = false), so the live wall's
15144
+ // textures would be missing from the export. Copy the live materials, cloned together with
15145
+ // their textures, so the export scene owns its own copies - disposing that scene must not
15146
+ // free the textures still in use by the live wall.
15147
+ ObjectUtils.DisposeMaterial(cloned.material);
15148
+ const clonedMaterial = ObjectUtils.CloneMaterial(this.material, false);
15149
+ cloned.material = clonedMaterial;
15150
+ }
15110
15151
  cloned.userData = tempUserData;
15111
15152
  this.userData = tempUserData;
15112
15153
  return cloned;
@@ -15269,14 +15310,50 @@ class WallService {
15269
15310
  if (!wall || !corner) {
15270
15311
  return;
15271
15312
  }
15272
- this.createNewWall(corner, wall.getEnd(), wall.height, wall.thickness);
15313
+ // Capture items + world position before the split: afterwards they must be
15314
+ // distributed across the correct wall segment (otherwise they all stay on the
15315
+ // shortened wall and shift along as its center moves).
15316
+ const itemWorldPositions = [];
15317
+ [...wall.items, ...wall.onItems].forEach((item) => {
15318
+ if (item instanceof WallItem) {
15319
+ const worldPosition = new Vector3();
15320
+ item.getWorldPosition(worldPosition);
15321
+ itemWorldPositions.push({ item, x: worldPosition.x, z: worldPosition.z });
15322
+ }
15323
+ });
15324
+ const newWall = this.createNewWall(corner, wall.getEnd(), wall.height, wall.thickness);
15273
15325
  const prevCorner = wall.getEnd();
15274
15326
  wall.setEnd(corner);
15327
+ // setEnd only swaps the corner reference; rebuild the 3D geometry of the shortened wall
15328
+ wall.cornerMoved();
15275
15329
  corner.removeDuplicateWalls();
15276
15330
  prevCorner.removeDuplicateWalls();
15331
+ // Re-place each item on the wall segment it falls on, at its original world position.
15332
+ itemWorldPositions.forEach(({ item, x, z }) => {
15333
+ const candidates = [wall, newWall].filter((w) => this.walls.indexOf(w) !== -1);
15334
+ if (candidates.length === 0) {
15335
+ return;
15336
+ }
15337
+ const target = candidates.length === 1 ? candidates[0] : this._closestWallForPoint(candidates, x, z);
15338
+ item.moveTo2dPosition(x, z, target);
15339
+ });
15277
15340
  this._updatePrevAndNextWalls();
15278
15341
  this._prepareOrphanWalls();
15279
15342
  }
15343
+ /** Picks the wall whose closest point (clamped to the segment) is nearest to (x, z). */
15344
+ _closestWallForPoint(walls, x, z) {
15345
+ let best = walls[0];
15346
+ let bestDistance = Number.POSITIVE_INFINITY;
15347
+ walls.forEach((w) => {
15348
+ const closest = w.closestPointTo(x, z);
15349
+ const distance = Utils$1.Distance(x, z, closest.x, closest.y);
15350
+ if (distance < bestDistance) {
15351
+ bestDistance = distance;
15352
+ best = w;
15353
+ }
15354
+ });
15355
+ return best;
15356
+ }
15280
15357
  updatePrevWall(wallId, prevWallId) {
15281
15358
  if (wallId && prevWallId) {
15282
15359
  const wall = this.walls.find(w => w.wallId === wallId);
@@ -15358,6 +15435,56 @@ class WallService {
15358
15435
  Utils$1.RemoveValue(this.walls, wall);
15359
15436
  wall.removeWall();
15360
15437
  }
15438
+ /** Merges two collinear walls around a degree-2 corner into a single wall. */
15439
+ joinCollinearWallsAt(corner) {
15440
+ const attached = [...corner.wallStarts, ...corner.wallEnds];
15441
+ if (attached.length !== 2) {
15442
+ return;
15443
+ }
15444
+ const keep = attached[0];
15445
+ const absorb = attached[1];
15446
+ const farKeep = keep.getStart() === corner ? keep.getEnd() : keep.getStart();
15447
+ const farAbsorb = absorb.getStart() === corner ? absorb.getEnd() : absorb.getStart();
15448
+ if (farKeep === farAbsorb) {
15449
+ return; // safety: degenerate case
15450
+ }
15451
+ if (!this._areCollinearThroughCorner(farKeep, corner, farAbsorb)) {
15452
+ return; // not in line with each other -> leave as is
15453
+ }
15454
+ // Capture the world position of all items on BOTH walls before the structural change.
15455
+ // Items already on 'keep' must be re-placed too: extending 'keep' shifts its center, so
15456
+ // their (fixed) local position would otherwise map to a different world position.
15457
+ const itemWorldPositions = [];
15458
+ [...keep.items, ...keep.onItems, ...absorb.items, ...absorb.onItems].forEach((item) => {
15459
+ if (item instanceof WallItem) {
15460
+ const worldPosition = new Vector3();
15461
+ item.getWorldPosition(worldPosition);
15462
+ itemWorldPositions.push({ item, x: worldPosition.x, z: worldPosition.z });
15463
+ }
15464
+ });
15465
+ // extend 'keep' so it spans from farKeep to farAbsorb
15466
+ if (keep.getEnd() === corner) {
15467
+ keep.setEnd(farAbsorb);
15468
+ }
15469
+ else {
15470
+ keep.setStart(farAbsorb);
15471
+ }
15472
+ // setStart/setEnd only swaps the corner reference; rebuild the 3D geometry and
15473
+ // transform for the new span (otherwise the old mesh stays in place).
15474
+ keep.cornerMoved();
15475
+ // Re-place each item on the merged wall at its original world position.
15476
+ // moveTo2dPosition sets currentWall to 'keep', detaches the item from 'absorb' and
15477
+ // bounds the position within the wall (doors/windows get their opening re-cut).
15478
+ itemWorldPositions.forEach(({ item, x, z }) => item.moveTo2dPosition(x, z, keep));
15479
+ this.removeWall(absorb); // also detaches from corner -> corner becomes orphan
15480
+ this._updatePrevAndNextWalls();
15481
+ this._prepareOrphanWalls();
15482
+ }
15483
+ /** True when the two walls are in line through 'corner' (angle ~180°). */
15484
+ _areCollinearThroughCorner(a, corner, b) {
15485
+ const angle = Utils$1.Angle(a.x - corner.x, a.y - corner.y, b.x - corner.x, b.y - corner.y);
15486
+ return Math.abs(Math.abs(angle) - Math.PI) < collinearAngleTolerance;
15487
+ }
15361
15488
  updateWallHeights(newHeight) {
15362
15489
  this.walls.forEach(wall => {
15363
15490
  wall.height = newHeight / 100;
@@ -16948,6 +17075,9 @@ class WallItem extends Item {
16948
17075
  else {
16949
17076
  DistanceUtils.UpdateSideDistances(this.distancesObject, this, this.currentWall, this.worldPosVec.clone(), this.getHalfSize(), this.worldRotation.y);
16950
17077
  }
17078
+ // The arrows are built in the item's x/y plane at z ~= 0 (the item origin). For an in-wall item that
17079
+ // origin is the wall centre, so push the whole group forward to the wall face like the labels.
17080
+ this.distancesObject.position.z = this._measurementZOffset();
16951
17081
  this.add(this.distancesObject);
16952
17082
  return null;
16953
17083
  }
@@ -16989,12 +17119,20 @@ class WallItem extends Item {
16989
17119
  }
16990
17120
  return new Vector3();
16991
17121
  }
17122
+ /**
17123
+ * Local z at which measurement labels/distance arrows are drawn so they sit just in front of the wall.
17124
+ * Surface-mounted items sit on the wall face, so a small offset suffices. In-wall items override this
17125
+ * (they are centred inside the wall, so the offset must clear half the wall thickness).
17126
+ */
17127
+ _measurementZOffset() {
17128
+ return 0.01;
17129
+ }
16992
17130
  _createHeightMeasurement() {
16993
17131
  this.heightMesh = MeasurementUtils.makeHeightTextMesh(this.getHeight(), itemMeasurementsTextColor, itemMeasurementsTextSize, false, true);
16994
17132
  this.heightMesh.geometry.computeBoundingBox();
16995
17133
  const width = this.heightMesh.geometry.boundingBox.max.x - this.heightMesh.geometry.boundingBox.min.x;
16996
17134
  this.heightMesh.name = this.heightMeshName;
16997
- this.heightMesh.position.set(-this.halfSize.x - width, this.showDistances ? this._measurementYPositionOffset : 0, 0.01);
17135
+ this.heightMesh.position.set(-this.halfSize.x - width, this.showDistances ? this._measurementYPositionOffset : 0, this._measurementZOffset());
16998
17136
  this.add(this.heightMesh);
16999
17137
  }
17000
17138
  _createWidthMeasurement() {
@@ -17002,7 +17140,7 @@ class WallItem extends Item {
17002
17140
  this.widthMesh.geometry.computeBoundingBox();
17003
17141
  const width = this.widthMesh.geometry.boundingBox.max.x - this.widthMesh.geometry.boundingBox.min.x;
17004
17142
  this.widthMesh.name = this.widthMeshName;
17005
- this.widthMesh.position.set(0 - (width / 2), this.halfSize.y, 0.01);
17143
+ this.widthMesh.position.set(0 - (width / 2), this.halfSize.y, this._measurementZOffset());
17006
17144
  this.add(this.widthMesh);
17007
17145
  }
17008
17146
  _getMaskedGeometry() {
@@ -17090,10 +17228,9 @@ class WallItem extends Item {
17090
17228
  // if elevation is higher than the wall, use maxY
17091
17229
  // vec3.y = Math.min(this._getMaxY(wall) / 2, this.halfSize.y + this.elevation);
17092
17230
  vec3.y = Math.min(maxY, this.halfSize.y + this.elevation);
17093
- }
17094
- else if (this.elevationAdjustable && this.onWall) {
17095
- // if the item is adjustable & is placed on the wall
17096
- vec3.y = Math.min(this._getMaxY(wall), this.halfSize.y + this.elevation);
17231
+ // } else if (this.elevationAdjustable && this.onWall) { /* no idea why this is done, but it causes problems for positioning items */
17232
+ // // if the item is adjustable & is placed on the wall
17233
+ // vec3.y = Math.min(this._getMaxY(wall), this.halfSize.y + this.elevation);
17097
17234
  }
17098
17235
  else {
17099
17236
  if (vec3.y < minY) {
@@ -17191,6 +17328,8 @@ class InWallItem extends WallItem {
17191
17328
  this._openCloseIndicatorColor = '#606E8C';
17192
17329
  this._frameWidth = 0.07;
17193
17330
  this._frameDepth = 0.1;
17331
+ /** Extra depth added on top of the wall thickness so the dynamically built mask always pierces the wall. */
17332
+ this._maskDepthMargin = 0.1;
17194
17333
  this._isWindow = false;
17195
17334
  this._doorpost = false;
17196
17335
  this._setDefault();
@@ -17214,6 +17353,25 @@ class InWallItem extends WallItem {
17214
17353
  ObjectUtils.DisposeMaterial(this.frameMaterial);
17215
17354
  ObjectUtils.DisposeMaterial(this.doorMaterialFront);
17216
17355
  ObjectUtils.DisposeMaterial(this.windowMaterial);
17356
+ if (this._customMaskGeometry) {
17357
+ this._customMaskGeometry.dispose();
17358
+ this._customMaskGeometry = undefined;
17359
+ }
17360
+ }
17361
+ /**
17362
+ * Custom doors/windows are built at runtime and have no GLB `_mask` mesh, so the base lookup finds
17363
+ * nothing usable. Return the dynamically generated opening mask instead. Build it lazily here so any
17364
+ * instance (incl. clones that never ran createCustomMesh) yields a mask as soon as the wall asks for
17365
+ * one - otherwise the wall is left solid for that item.
17366
+ */
17367
+ getMaskedGeometry() {
17368
+ if (this.isCustom) {
17369
+ if (!this._customMaskGeometry && this.getWidth() > 0 && this.getHeight() > 0) {
17370
+ this._updateCustomMaskGeometry(this.getWidth(), this.getHeight());
17371
+ }
17372
+ return this._customMaskGeometry ? this._customMaskGeometry : null;
17373
+ }
17374
+ return super.getMaskedGeometry();
17217
17375
  }
17218
17376
  updateOpeningObject() {
17219
17377
  if (this.openCloseIndicatorObject) {
@@ -17265,6 +17423,10 @@ class InWallItem extends WallItem {
17265
17423
  this.createCustomMesh(this.getWidth(), this.getHeight());
17266
17424
  }
17267
17425
  super.placeOnWall(wall);
17426
+ // super.placeOnWall positions the item on the wall (_boundMove) only AFTER the initial addItem cut,
17427
+ // and _boundMove itself does not redraw. Re-cut now so the opening is subtracted at the item's final
17428
+ // position (the addItem cut ran at a transient position where the mask may not intersect the wall).
17429
+ this.redrawWall();
17268
17430
  }
17269
17431
  /** */
17270
17432
  getWallOffset() {
@@ -17344,16 +17506,22 @@ class InWallItem extends WallItem {
17344
17506
  return meshes;
17345
17507
  }
17346
17508
  else {
17347
- const visibleMeshes = [];
17348
- if (!this.visible) {
17349
- return [];
17350
- }
17351
- this.traverse(c => {
17352
- if (c.visible && !this.excludedMeshes.includes(c.name) && c instanceof Mesh) {
17353
- visibleMeshes.push(c);
17354
- }
17355
- });
17356
- return visibleMeshes;
17509
+ return super.getVisibleMeshes();
17510
+ // const visibleMeshes: (Mesh)[] = [];
17511
+ // if (!this.visible) {
17512
+ // return [];
17513
+ // }
17514
+ // this.traverse(c => {
17515
+ // if (c.visible &&
17516
+ // !this.excludedMeshes.includes(c.name) &&
17517
+ // !ObjectUtils.ChildOf(c, this.heightMeshName) &&
17518
+ // !ObjectUtils.ChildOf(c, this.widthMeshName) &&
17519
+ // !ObjectUtils.ChildOf(c, this.distancesObjectName) &&
17520
+ // c instanceof Mesh) {
17521
+ // visibleMeshes.push(c);
17522
+ // }
17523
+ // });
17524
+ // return visibleMeshes;
17357
17525
  }
17358
17526
  }
17359
17527
  async createTextureMaterial(options) {
@@ -17396,6 +17564,8 @@ class InWallItem extends WallItem {
17396
17564
  createCustomMesh(width, height) {
17397
17565
  const halfWidth = width / 2;
17398
17566
  const halfFrame = (this._frameWidth / 2);
17567
+ // Rebuild the opening mask on every (re)build so it tracks the current size of the custom item.
17568
+ this._updateCustomMaskGeometry(width, height);
17399
17569
  this.leftFrame = this._createFrameSide(this._frameWidth, this._getHeightFrame(height), this._frameDepth);
17400
17570
  this.leftFrame.rotation.set(this._isWindow ? 180 * (Math.PI / 180) : 0, 0, 0);
17401
17571
  this.leftFrame.position.x = -halfWidth + halfFrame;
@@ -17429,7 +17599,9 @@ class InWallItem extends WallItem {
17429
17599
  }
17430
17600
  this.customMesh = new THREE.Mesh(customGeo, this._isWindow ? this.windowMaterial : this.doorMaterialFront);
17431
17601
  this.customMesh.castShadow = this._isWindow ? false : !this.isGlass;
17432
- this.customMesh.renderOrder = -1;
17602
+ // Windows are transparent glass: let them render in the normal (post-opaque) transparent pass so
17603
+ // you see through the opening. renderOrder -1 (before opaque) is kept for the opaque door panel.
17604
+ this.customMesh.renderOrder = this._isWindow ? 0 : -1;
17433
17605
  this.customMesh.name = 'customMesh';
17434
17606
  if (this._isWindow) {
17435
17607
  this.customMesh.name += 'Window';
@@ -17549,17 +17721,22 @@ class InWallItem extends WallItem {
17549
17721
  this.frameMaterial = new THREE.MeshPhongMaterial({ side: side, name: 'frameMaterial' });
17550
17722
  this.frameMaterial.color = new THREE.Color(this.frameColor);
17551
17723
  if (this._isWindow) {
17552
- this.windowMaterial = new THREE.MeshPhongMaterial({ side: side, color: this.windowColor, name: 'windowMaterial' });
17724
+ // Name must contain 'glass' so MaterialUtils.ShowHideMaterials keeps it transparent when the wall
17725
+ // is shown - otherwise it forces transparent=false/opacity=1 and the pane looks solid.
17726
+ this.windowMaterial = new THREE.MeshPhongMaterial({ side: side, color: this.windowColor, name: 'windowGlassMaterial' });
17553
17727
  this.windowMaterial.transparent = true;
17554
17728
  this.windowMaterial.alphaTest = 0;
17555
17729
  this.windowMaterial.opacity = 0.2;
17556
17730
  this.windowMaterial.map = undefined;
17731
+ // Glass must not write depth, otherwise it occludes the view through the wall opening and the
17732
+ // pane looks solid instead of see-through.
17733
+ this.windowMaterial.depthWrite = false;
17557
17734
  this.windowMaterial.needsUpdate = true;
17558
- this.windowMaterial.side = THREE.FrontSide;
17735
+ // this.windowMaterial.side = THREE.FrontSide;
17559
17736
  this.object.material = [this.frameMaterial, this.windowMaterial];
17560
17737
  }
17561
17738
  else {
17562
- this.doorMaterialFront = new THREE.MeshPhongMaterial({ side: side, name: 'doorMaterialFront' });
17739
+ this.doorMaterialFront = new THREE.MeshPhongMaterial({ side: side, name: 'doorGlassMaterialFront' });
17563
17740
  this.doorMaterialFront.color = new THREE.Color(this.doorColor);
17564
17741
  if (this._doorpost) {
17565
17742
  this.doorMaterialFront.transparent = true;
@@ -17568,6 +17745,22 @@ class InWallItem extends WallItem {
17568
17745
  this.object.material = [this.frameMaterial, this.doorMaterialFront];
17569
17746
  }
17570
17747
  }
17748
+ /**
17749
+ * Builds the geometry used to subtract the opening from the wall. It spans the full width/height of
17750
+ * the custom item and is made deeper than the wall (plus a margin) so the CSG subtraction always
17751
+ * pierces the wall completely. base-wall positions it via the item's own position/quaternion, so the
17752
+ * box is centred on the item origin (the opening centre on the wall plane).
17753
+ */
17754
+ _updateCustomMaskGeometry(width, height) {
17755
+ const wallThickness = this.currentWall ? this.currentWall.thickness : 0.5;
17756
+ const maskDepth = wallThickness + (2 * this._maskDepthMargin);
17757
+ if (this._customMaskGeometry) {
17758
+ this._customMaskGeometry.dispose();
17759
+ }
17760
+ // The wall (base-wall) subtracts this as a single group, so the BoxGeometry's material groups are
17761
+ // irrelevant here - we only need a box of the right opening size and a depth that pierces the wall.
17762
+ this._customMaskGeometry = new BoxGeometry(width, height, maskDepth);
17763
+ }
17571
17764
  _getHeightFrame(height) {
17572
17765
  return height - (this._isWindow ? 2 * (this._frameWidth - 0.02) : this._frameWidth - 0.02);
17573
17766
  }
@@ -17698,6 +17891,13 @@ class InWallItem extends WallItem {
17698
17891
  this._createDepthMeasurement();
17699
17892
  }
17700
17893
  }
17894
+ /**
17895
+ * In-wall items sit centred inside the wall (getWallOffset() === 0), so the labels/arrows must clear
17896
+ * half the wall thickness to end up in front of the wall face instead of buried inside it.
17897
+ */
17898
+ _measurementZOffset() {
17899
+ return (this.currentWall ? this.currentWall.thickness / 2 : 0) + 0.02;
17900
+ }
17701
17901
  _createDepthMeasurement() {
17702
17902
  const depth = this.opening && this.opening.double ? Math.round((this.getWidth() / 2) * 100) / 100 : this.getWidth();
17703
17903
  this.depthMesh = MeasurementUtils.makeDepthTextMesh(depth, 0xFF00FF, 0.08, false, true);
@@ -18120,6 +18320,15 @@ class ItemService {
18120
18320
  }
18121
18321
  // todo: fix the any
18122
18322
  addItem(obj, addToScene = true) {
18323
+ // Wall-only custom shapes/cylinders live exclusively on their wall (wall.onItems) and are added to
18324
+ // the scene graph by placeOnWall() via Wall.addOnItem(). They must NOT also be tracked here: keeping
18325
+ // them in `items` double-lists them on save (getFurniture/getNonFurniture read items + wall.onItems)
18326
+ // and the scene.add() below would re-parent them off the wall, breaking their world position. They
18327
+ // are disposed together with their wall and surfaced for save/selection through wall.onItems.
18328
+ // (Detected via itemType rather than instanceof to avoid an item.service <-> wall-item-class import cycle.)
18329
+ if (obj && obj.metadata && (isCustomShapeWallType(obj.metadata.itemType) || isCustomCylinderWallType(obj.metadata.itemType))) {
18330
+ return;
18331
+ }
18123
18332
  this.items.push(obj);
18124
18333
  if (addToScene) {
18125
18334
  this._sceneService.addObject(obj);
@@ -18153,7 +18362,7 @@ class ItemService {
18153
18362
  getFurniture() {
18154
18363
  const allItems = this.items.concat(...this.items.map(i => {
18155
18364
  if (i instanceof Wall) {
18156
- return i.items.filter(wi => !wi.configurable).concat(i.onItems.filter(woi => !woi.configurable));
18365
+ return i.items.concat(i.onItems);
18157
18366
  }
18158
18367
  })).filter(i => i !== undefined);
18159
18368
  return allItems
@@ -19502,7 +19711,11 @@ class BluePrintFloorplanService extends BaseBluePrintService {
19502
19711
  return this.wallService.createWall(start, end, height, thickness);
19503
19712
  }
19504
19713
  removeWall(wall) {
19714
+ const corner1 = wall.getStart();
19715
+ const corner2 = wall.getEnd();
19505
19716
  this.roomService.removeWall(wall);
19717
+ this.wallService.joinCollinearWallsAt(corner1);
19718
+ this.wallService.joinCollinearWallsAt(corner2);
19506
19719
  this.cornerService.removeOrphanCorners();
19507
19720
  this.update();
19508
19721
  }
@@ -22917,7 +23130,25 @@ class SceneEventService {
22917
23130
  }
22918
23131
  this._switchState(SceneEventState.DND);
22919
23132
  this._dragAndDropService.draggedStatus.dragEnter();
22920
- const vec3 = z ? new Vector3(x, y, z) : this.intersectingVec3(new Vector2(x, y));
23133
+ let screenPoint = new Vector2(x, y);
23134
+ const useViewportCentre = !z && x === 0 && y === 0 && !!this._element;
23135
+ if (useViewportCentre) {
23136
+ // The object library adds items with a (0,0) sentinel (there is no real cursor). Screen (0,0) is
23137
+ // the top-left corner, so the floor raycast lands at an arbitrary, camera-dependent spot. Use the
23138
+ // viewport centre instead.
23139
+ screenPoint = new Vector2(this._element.clientWidth / 2, this._element.clientHeight / 2);
23140
+ }
23141
+ const vec3 = z ? new Vector3(x, y, z) : this.intersectingVec3(screenPoint);
23142
+ if (useViewportCentre && isWallType(draggedData.type)) {
23143
+ // No cursor was used (library add), so there is no hit wall and getClosestWall() on a floor point
23144
+ // picks an arbitrary wall. Target the wall whose front the camera is looking at instead, and seed
23145
+ // it so the existing _changeWall() flow attaches the item to that wall. getClosestWall() itself is
23146
+ // left untouched (project loading via presets.service relies on it).
23147
+ const facingWall = this._wallMostFacingCamera();
23148
+ if (facingWall) {
23149
+ this._dragAndDropService.intersectedWall = { object: facingWall, point: vec3 ? vec3.clone() : new Vector3() };
23150
+ }
23151
+ }
22921
23152
  if (this._dragAndDropService.draggedItem) {
22922
23153
  this._dragAndDropService.draggedStatus.objectLoaded();
22923
23154
  this._dragAndDropService.updateDraggedPosition(vec3);
@@ -22929,6 +23160,35 @@ class SceneEventService {
22929
23160
  this._dragAndDropService.dragFloorDecoration(this._floorIntersection(this._sceneService.positionInSceneToScreen(vec3)));
22930
23161
  }
22931
23162
  }
23163
+ /**
23164
+ * The wall whose front face the camera is looking at most directly. Used to pick a sensible target
23165
+ * wall when an item is added without a cursor (object library). A wall's front normal is its +Z axis
23166
+ * in world space; the wall most facing the camera maximises frontNormal · (cameraPos - wallPos), which
23167
+ * naturally excludes the transparent near wall (its front points away from the camera).
23168
+ */
23169
+ _wallMostFacingCamera() {
23170
+ const walls = this._wallService.walls;
23171
+ if (!walls || !walls.length) {
23172
+ return null;
23173
+ }
23174
+ const cameraPosition = this._cameraService.camera.position;
23175
+ const wallPosition = new Vector3();
23176
+ const frontNormal = new Vector3();
23177
+ const toCamera = new Vector3();
23178
+ let best = null;
23179
+ let bestDot = -Infinity;
23180
+ for (const wall of walls) {
23181
+ wall.getWorldPosition(wallPosition);
23182
+ wall.getWorldDirection(frontNormal).normalize();
23183
+ toCamera.subVectors(cameraPosition, wallPosition).normalize();
23184
+ const dot = frontNormal.dot(toCamera);
23185
+ if (dot > bestDot) {
23186
+ bestDot = dot;
23187
+ best = wall;
23188
+ }
23189
+ }
23190
+ return best;
23191
+ }
22932
23192
  intersectingVec3(vec2, intersection) {
22933
23193
  if (!intersection) {
22934
23194
  const gIntersections = this._groundIntersections(vec2);
@@ -28159,64 +28419,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
28159
28419
  type: Injectable
28160
28420
  }], ctorParameters: () => [{ type: ThreedInPhotoBuildService }, { type: ThreedInPhotoViewService }, { type: ThreedInPhotoConnectionService }, { type: ThreedInPhotoSceneService }, { type: ThreedInPhotoRenderService }, { type: i1$2.MatDialog }, { type: SceneEventService }, { type: CameraService }, { type: ViewModeService }] });
28161
28421
 
28162
- var ConnectionStatus;
28163
- (function (ConnectionStatus) {
28164
- ConnectionStatus[ConnectionStatus["IsUndefined"] = 0] = "IsUndefined";
28165
- ConnectionStatus[ConnectionStatus["IsConnected"] = 1] = "IsConnected";
28166
- ConnectionStatus[ConnectionStatus["TryingToConnect"] = 2] = "TryingToConnect";
28167
- ConnectionStatus[ConnectionStatus["IsDisConnected"] = 3] = "IsDisConnected";
28168
- })(ConnectionStatus || (ConnectionStatus = {}));
28169
-
28170
- var RenderStatus;
28171
- (function (RenderStatus) {
28172
- RenderStatus[RenderStatus["IsUndefined"] = 0] = "IsUndefined";
28173
- RenderStatus[RenderStatus["IsRunning"] = 1] = "IsRunning";
28174
- RenderStatus[RenderStatus["IsSuccess"] = 2] = "IsSuccess";
28175
- RenderStatus[RenderStatus["IsStopped"] = 3] = "IsStopped";
28176
- RenderStatus[RenderStatus["IsWaiting"] = 4] = "IsWaiting";
28177
- })(RenderStatus || (RenderStatus = {}));
28178
-
28179
- class RenderQueueItem {
28180
- constructor() {
28181
- this.startDateTime = new Date();
28182
- this.rendered = false;
28183
- this.renderProgress = 0;
28184
- this.renderIterations = 0;
28185
- this.renderStatus = RenderStatus.IsUndefined;
28186
- }
28187
- }
28188
-
28189
- var ToastType;
28190
- (function (ToastType) {
28191
- ToastType[ToastType["Success"] = 0] = "Success";
28192
- ToastType[ToastType["Warning"] = 1] = "Warning";
28193
- ToastType[ToastType["Error"] = 2] = "Error";
28194
- })(ToastType || (ToastType = {}));
28195
-
28196
- class Toast {
28197
- constructor() {
28198
- this.type = ToastType.Success;
28199
- }
28200
- }
28201
-
28202
- class RenderData {
28203
- constructor() {
28204
- this.cameraFOV = 45;
28205
- }
28206
- }
28207
-
28208
- class RenderSettings {
28209
- constructor() {
28210
- this.camRotationX = 0.24;
28211
- this.camRotationY = 0;
28212
- this.environmentName = '';
28213
- this.environmentHdr = '';
28214
- this.environmentRotation = 0;
28215
- this.environmentIntensity = null;
28216
- this.extraLights = [];
28217
- }
28218
- }
28219
-
28220
28422
  class ExportObject {
28221
28423
  }
28222
28424
 
@@ -28308,6 +28510,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
28308
28510
  type: Injectable
28309
28511
  }], ctorParameters: () => [{ type: HomedecoratorSettingsService }, { type: HomedecoratorConnectorAdapterService }, { type: ThreedselectorService }] });
28310
28512
 
28513
+ var RenderStatus;
28514
+ (function (RenderStatus) {
28515
+ RenderStatus[RenderStatus["IsUndefined"] = 0] = "IsUndefined";
28516
+ RenderStatus[RenderStatus["IsRunning"] = 1] = "IsRunning";
28517
+ RenderStatus[RenderStatus["IsSuccess"] = 2] = "IsSuccess";
28518
+ RenderStatus[RenderStatus["IsStopped"] = 3] = "IsStopped";
28519
+ RenderStatus[RenderStatus["IsWaiting"] = 4] = "IsWaiting";
28520
+ })(RenderStatus || (RenderStatus = {}));
28521
+
28522
+ class RenderQueueItem {
28523
+ constructor() {
28524
+ this.startDateTime = new Date();
28525
+ this.rendered = false;
28526
+ this.renderProgress = 0;
28527
+ this.renderIterations = 0;
28528
+ this.renderStatus = RenderStatus.IsUndefined;
28529
+ }
28530
+ }
28531
+
28311
28532
  class ToastService {
28312
28533
  constructor(_dictionaryService) {
28313
28534
  this._dictionaryService = _dictionaryService;
@@ -28324,597 +28545,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
28324
28545
  type: Injectable
28325
28546
  }], ctorParameters: () => [{ type: HomedecoratorDictionaryService }] });
28326
28547
 
28327
- class RenderService {
28328
- static MakeWindowMaterialTransparent(material) {
28329
- // console.log(material);
28330
- material.transparent = true;
28331
- material.opacity = Math.min(material.opacity, 0.4);
28332
- return material;
28333
- }
28334
- constructor(_settingsService, _exportService, _cameraService, _sceneService, _toastService, _messageBusService, _googleTagManager, _roomService, _floorService) {
28335
- this._settingsService = _settingsService;
28336
- this._exportService = _exportService;
28337
- this._cameraService = _cameraService;
28338
- this._sceneService = _sceneService;
28339
- this._toastService = _toastService;
28340
- this._messageBusService = _messageBusService;
28341
- this._googleTagManager = _googleTagManager;
28342
- this._roomService = _roomService;
28343
- this._floorService = _floorService;
28344
- this.renderModes = RenderModes;
28345
- this.streaming = {};
28346
- this.renderedRoomImages = [];
28347
- this.connectionStatus = ConnectionStatus.IsUndefined;
28348
- this.renders = [];
28349
- this.cameraPositions = [];
28350
- this.imageSizes = [
28351
- { id: 1, name: ' 720p (HD)', width: 1280, height: 720 },
28352
- { id: 2, name: '1080P (HD)', width: 1920, height: 1080 },
28353
- { id: 3, name: '1440p (2K)', width: 2560, height: 1440 },
28354
- { id: 4, name: '2160p (4K)', width: 4096, height: 2160 }
28355
- ];
28356
- this.lightnings = [
28357
- { id: 1, name: 'Light', settings: [] },
28358
- { id: 2, name: 'Medium', settings: [] },
28359
- { id: 3, name: 'Heay', settings: [] }
28360
- ];
28361
- this.renderEnvironments = [
28362
- { id: 1, name: 'None', hdrFile: '', intensity: 1.0 },
28363
- { id: 2, name: 'Modern city', hdrFile: 'canary_wharf_2k.hdr', intensity: 2.5 },
28364
- { id: 3, name: 'City park', hdrFile: 'dresden_moat_2k.hdr', intensity: 2.5 },
28365
- { id: 4, name: 'Night in the city', hdrFile: 'hansaplatz_2k.hdr', intensity: 1.0 },
28366
- { id: 5, name: 'Night in the countryside', hdrFile: 'kloppenheim_02_2k.hdr', intensity: 1.0 },
28367
- { id: 6, name: 'Forest', hdrFile: 'nagoya_wall_path_2k.hdr', intensity: 1.0 },
28368
- { id: 7, name: 'Snow', hdrFile: 'snowy_forest_path_01_2k.hdr', intensity: 1.0 },
28369
- { id: 8, name: 'Pasture', hdrFile: 'spruit_sunrise_2k.hdr', intensity: 1.0 },
28370
- { id: 9, name: 'Field', hdrFile: 'sunflowers_2k.hdr', intensity: 1.0 },
28371
- { id: 10, name: 'Old city and canals', hdrFile: 'tears_of_steel_bridge_2k.hdr', intensity: 1.0 },
28372
- { id: 11, name: 'Estate', hdrFile: 'tiergarten_2k.hdr', intensity: 1.0 },
28373
- { id: 12, name: 'Beach', hdrFile: 'umhlanga_sunrise_2k.hdr', intensity: 2.5 },
28374
- { id: 13, name: 'Residential area with park', hdrFile: 'urban_street_01_2k.hdr', intensity: 1.0 },
28375
- { id: 14, name: 'Residential area', hdrFile: 'urban_street_03_2k.hdr', intensity: 1.0 },
28376
- ];
28377
- this.renderScenes = [
28378
- { id: 1, name: 'scene_grass_cycles_MRP', sceneAssetId: 'scene_grass_cycles_MRP' },
28379
- { id: 2, name: 'scene_lake_cycles_MRP', sceneAssetId: 'scene_lake_cycles_MRP' },
28380
- { id: 3, name: 'scene_sky_cycles_MRP', sceneAssetId: 'scene_sky_cycles_MRP' },
28381
- { id: 4, name: 'scene_garden_cycles_MRP', sceneAssetId: 'scene_garden_cycles_MRP' },
28382
- { id: 5, name: 'scene_nature_cycles_MRP', sceneAssetId: 'scene_nature_cycles_MRP' },
28383
- { id: 5, name: 'scene_01', sceneAssetId: 'scene_01' }
28384
- ];
28385
- this._ceilingLightMargin = 0.5;
28386
- this.selectedImageSize = 2;
28387
- this.selectedEnvironment = 1;
28388
- this.selectedRenderScene = this.renderScenes[0].sceneAssetId;
28389
- this.blendFilesRender = this._settingsService.settings.blendFilesRender;
28390
- this.positions = 1;
28391
- this.save = false;
28392
- this.renderRoomImageChanged = new BehaviorSubject('');
28393
- this.renderingStarted = new Subject();
28394
- this.renderImageChanged = new BehaviorSubject('');
28395
- this.renderQueue = [];
28396
- this.currentQueueRenderItem = new RenderQueueItem();
28397
- this.currentProductHash = '';
28398
- this._subs = [];
28399
- this.sceneData = {};
28400
- this._subs.push(this._settingsService.settingsLoaded.subscribe((loaded) => {
28401
- if (loaded) {
28402
- this.serverData = this._settingsService.settings.renderParameters;
28403
- if (this.serverData) {
28404
- this.serverData.setup = false;
28405
- this.checkConnection();
28406
- this._renderServiceHeartBeat();
28407
- }
28408
- }
28409
- }));
28410
- }
28411
- ngOnDestroy() {
28412
- this._subs.forEach(s => s.unsubscribe());
28413
- }
28414
- async checkConnection() {
28415
- //
28416
- // if (this.service.validate() === false) {
28417
- //
28418
- // try {
28419
- //
28420
- // const url = `${(this.serverData.secure ? 'wss' : 'ws')}://${this.serverData.host}:${this.serverData.port}/service/`;
28421
- // await this.service.connect(url).then(() => {
28422
- // this.serverData.setup = true;
28423
- // }).catch((rej) => {
28424
- // });
28425
- //
28426
- // this.service.on('error', async (object) => {
28427
- // this.serverData.setup = false;
28428
- // if (this.connectionStatus !== ConnectionStatus.TryingToConnect) {
28429
- // this.connectionStatus = ConnectionStatus.IsDisConnected;
28430
- // }
28431
- // await this._onRenderError();
28432
- // });
28433
- // this.service.on('close', async (object) => {
28434
- // this.serverData.setup = false;
28435
- // if (this.connectionStatus !== ConnectionStatus.TryingToConnect) {
28436
- // this.connectionStatus = ConnectionStatus.IsDisConnected;
28437
- // }
28438
- // await this._onRenderClose();
28439
- // });
28440
- //
28441
- // } catch (err) {
28442
- //
28443
- // this.serverData.setup = false;
28444
- // }
28445
- // }
28446
- }
28447
- _renderServiceHeartBeat() {
28448
- setInterval(() => {
28449
- if (this.connectionStatus === ConnectionStatus.IsDisConnected) {
28450
- if (this._settingsService.settings.options.showRenderConnectionInfo) {
28451
- const toast = new Toast();
28452
- toast.message = 'CONNECTION_WITH_RENDER_SERVICE_LOST';
28453
- toast.type = ToastType.Error;
28454
- this._toastService.showToast(toast);
28455
- }
28456
- this.connectionStatus = ConnectionStatus.TryingToConnect;
28457
- this.checkConnection();
28458
- }
28459
- else if (this.connectionStatus === ConnectionStatus.TryingToConnect) {
28460
- if (this.serverData.setup === false) {
28461
- this._messageBusService.emit(MessageType.RenderServiceTryToConnect);
28462
- this.checkConnection();
28463
- }
28464
- else {
28465
- if (this._settingsService.settings.options.showRenderConnectionInfo) {
28466
- const toast = new Toast();
28467
- toast.message = 'RE_CONNECTED_WITH_RENDER_SERVICE';
28468
- toast.type = ToastType.Success;
28469
- this._toastService.showToast(toast);
28470
- }
28471
- this.connectionStatus = ConnectionStatus.IsConnected;
28472
- }
28473
- }
28474
- else if (this.connectionStatus === ConnectionStatus.IsConnected) {
28475
- this._messageBusService.emit(MessageType.RenderServiceConnected);
28476
- }
28477
- }, 2000);
28478
- }
28479
- getRenderParameters(type) {
28480
- const params = new RenderData();
28481
- if (type !== RenderModes.RenderIone) {
28482
- const currentImageSize = this.getImageSizeOnId(this.selectedImageSize);
28483
- params.imageWidth = Number(currentImageSize.width);
28484
- params.imageHeight = Number(currentImageSize.height);
28485
- }
28486
- params.configuredItem = this._getConfiguredFurnitureItem();
28487
- params.cameraFOV = this._cameraService.camera.fov;
28488
- params.type = type;
28489
- if (type === this.renderModes.RenderShop) {
28490
- params.cameraFOV = 30;
28491
- if (this._settingsService.settings.renderParameters.settings !== undefined) {
28492
- params.settings = this._settingsService.settings.renderParameters.settings;
28493
- }
28494
- }
28495
- else if (type === this.renderModes.RenderRoom) {
28496
- const renderEnvironment = this.getRenderEnvironmentOnId(this.selectedEnvironment);
28497
- params.settings = new RenderSettings();
28498
- params.settings.environmentHdr = renderEnvironment.hdrFile;
28499
- params.settings.environmentIntensity = renderEnvironment.intensity;
28500
- const floorPlanHasRooms = this._roomService.rooms[0];
28501
- const ceilingOrFloor = floorPlanHasRooms ? this._roomService.rooms[0].ceilingPlane : this._floorService.getFloorPlane();
28502
- const bb = new Box3().setFromObject(ceilingOrFloor);
28503
- const bbSize = new Vector3();
28504
- bb.getSize(bbSize);
28505
- params.settings.extraLights = [
28506
- {
28507
- x1: bb.min.x + this._ceilingLightMargin,
28508
- z1: bb.min.z + this._ceilingLightMargin,
28509
- x2: bb.max.x - this._ceilingLightMargin,
28510
- z2: bb.max.z - this._ceilingLightMargin,
28511
- height: floorPlanHasRooms ? ceilingOrFloor.position.y : 2.6,
28512
- }
28513
- ];
28514
- }
28515
- return params;
28516
- }
28517
- // The GLTFExporter needs lights to be configured like this,
28518
- // otherwise they will all point in the same direction.
28519
- _fixLight(element) {
28520
- element.target.parent = element;
28521
- element.lookAt(element.target.position);
28522
- element.target.position.x = 0;
28523
- element.target.position.y = 0;
28524
- element.target.position.z = -1;
28525
- }
28526
- _elementMustBeRemoved(element) {
28527
- if (element.type === 'PerspectiveCamera') {
28528
- return true;
28529
- }
28530
- if (!element.name) {
28531
- return false;
28532
- }
28533
- const lcName = element.name.toLowerCase();
28534
- // elements with a name starting with c_ are connectors,
28535
- // which should not be visible.
28536
- if (lcName.startsWith('c_')) {
28537
- return true;
28538
- }
28539
- if (element.name.startsWith('snapping-preview-mesh')) {
28540
- return true;
28541
- }
28542
- return false;
28543
- }
28544
- async _exportToGlb() {
28545
- const assetPath = this._settingsService.settings.assetPath;
28546
- // The ground plane looks odd in renders.
28547
- // The hud-ring and hud-circle are the walkthrough mode marker,
28548
- // which is not supposed to be rendered.
28549
- const elementsToRemove = ['ground-plane', 'hud-ring', 'hud-circle'];
28550
- let scene;
28551
- try {
28552
- scene = this._sceneService.scene.clone();
28553
- elementsToRemove.forEach(elementName => {
28554
- const selectedObject = scene.getObjectByName(elementName);
28555
- scene.remove(selectedObject);
28556
- });
28557
- // Using the parents, because scene.remove does not seem to work correctly.
28558
- const parents = [];
28559
- scene.traverse(element => {
28560
- if (element instanceof DirectionalLight || element instanceof SpotLight) {
28561
- this._fixLight(element);
28562
- }
28563
- if (element.visible === false) {
28564
- // console.log("Element " + element.name + " was invisible, making it visible.");
28565
- element.visible = true;
28566
- }
28567
- if (element instanceof Mesh && element.name && element.name.startsWith('customMeshWindow')) {
28568
- let hasCustomTexture = false;
28569
- if (element.material instanceof Material$1) {
28570
- if (element.material instanceof MeshPhongMaterial && element.material.map) {
28571
- hasCustomTexture = true;
28572
- }
28573
- element.material = RenderService.MakeWindowMaterialTransparent(element.material);
28574
- }
28575
- else if (Array.isArray(element.material)) {
28576
- element.material.forEach(function (material, index) {
28577
- if (material instanceof MeshPhongMaterial && material.map) {
28578
- hasCustomTexture = true;
28579
- }
28580
- element.material[index] = RenderService.MakeWindowMaterialTransparent(material);
28581
- });
28582
- }
28583
- if (!hasCustomTexture) {
28584
- element.name = 'glass';
28585
- }
28586
- }
28587
- if (this._elementMustBeRemoved(element)) {
28588
- parents.push(element.parent);
28589
- }
28590
- });
28591
- parents.forEach(parent => {
28592
- for (let i = parent.children.length - 1; i >= 0; i--) {
28593
- if (this._elementMustBeRemoved(parent.children[i])) {
28594
- parent.remove(parent.children[i]);
28595
- }
28596
- }
28597
- });
28598
- scene.add(this._cameraService.camera.clone());
28599
- const options = {
28600
- trs: false,
28601
- onlyVisible: false,
28602
- truncateDrawRange: true,
28603
- binary: true,
28604
- forceIndices: false,
28605
- forcePowerOfTwoTextures: false,
28606
- // maxTextureSize: 500,
28607
- embedImages: true,
28608
- };
28609
- const exporter = new GLTFExporter();
28610
- let filename = '';
28611
- return new Promise((resolve, reject) => {
28612
- exporter.parse(scene, async (exportedScene) => {
28613
- const blob = new Blob([exportedScene], { type: 'application/octet-stream' });
28614
- const result = await FileUtils.SaveGLBFile(blob, assetPath);
28615
- if (result !== false) {
28616
- filename = result.path;
28617
- }
28618
- resolve(filename);
28619
- }, () => {
28620
- }, options);
28621
- });
28622
- }
28623
- catch (e) {
28624
- throw (e);
28625
- }
28626
- }
28627
- async startRendering() {
28628
- if (this.renderQueue.length > 0) {
28629
- await this.checkConnection();
28630
- if (this.renderQueue[0].renderProgress === 0 || this.renderQueue[0].renderProgress === undefined) {
28631
- this.renderQueue[0].renderStatus = RenderStatus.IsRunning;
28632
- this.currentQueueRenderItem = this.renderQueue[0];
28633
- this.renderQueue.shift();
28634
- this.currentQueueRenderItem.params.glbPath = await this._exportToGlb()
28635
- .catch((e) => {
28636
- return Promise.reject(e);
28637
- });
28638
- await this._startRenderLoop();
28639
- }
28640
- }
28641
- }
28642
- async _colijnRenderScene(params) {
28643
- return new Promise((resolve, reject) => {
28644
- const requestParams = [{
28645
- id: 1,
28646
- jsonrpc: '2.0',
28647
- method: 'colijn_render_scene_from_glb',
28648
- params: params
28649
- }];
28650
- const xhr = new XMLHttpRequest();
28651
- xhr.open('POST', this._getRenderServiceUrl());
28652
- xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
28653
- xhr.onload = () => {
28654
- if (xhr.status >= 200 && xhr.status < 300) {
28655
- resolve(JSON.parse(xhr.responseText));
28656
- }
28657
- else {
28658
- reject(xhr.statusText);
28659
- }
28660
- };
28661
- xhr.onerror = () => reject(xhr.statusText);
28662
- xhr.send(JSON.stringify(requestParams));
28663
- });
28664
- }
28665
- async _startRenderLoop() {
28666
- // temporary solution because large request over websockets are not working because of an error in the software of migenius
28667
- let [info] = await this._colijnRenderScene(this.currentQueueRenderItem.params);
28668
- info = info.result;
28669
- /*
28670
- const [ info ] = await this.service.queue_commands()
28671
- .queue(new Command('colijn_render_scene', this.currentQueueRenderItem.params), true)
28672
- .execute();
28673
- */
28674
- this.currentQueueRenderItem.host = this._settingsService.settings.url;
28675
- this.currentQueueRenderItem.key = info.scene_name;
28676
- this.currentQueueRenderItem.type = this.currentQueueRenderItem.params.type;
28677
- this.currentQueueRenderItem.startDateTime = new Date();
28678
- this.currentQueueRenderItem.imageSize = this.currentQueueRenderItem.params.imageWidth + ' x ' + this.currentQueueRenderItem.params.imageHeight;
28679
- this._setRenderProgress(RenderStatus.IsRunning, 0, 0);
28680
- this.sceneData = info;
28681
- if (!this.sceneData || this.sceneData.error) {
28682
- return;
28683
- }
28684
- if (this.sceneData.image_info && this.sceneData.image_info.needs_render === true) {
28685
- this.currentQueueRenderItem.rendered = true;
28686
- await this._startRenderStream();
28687
- }
28688
- else {
28689
- this._afterRendering();
28690
- }
28691
- }
28692
- async _quitRenderLoop() {
28693
- // if (this.sceneData.loop_name !== undefined && this.service.validate() !== false) {
28694
- // const [] = await this.service.queue_commands()
28695
- // .queue(new Command('render_loop_quit', {
28696
- // render_loop_name: this.sceneData.loop_name
28697
- // }))
28698
- // .execute();
28699
- // this.service.remove_stream(this.sceneData.loop_name);
28700
- // }
28701
- }
28702
- async _startRenderStream() {
28703
- //
28704
- // try {
28705
- //
28706
- // this.streaming.stream = this.service.create_stream();
28707
- // await this.streaming.stream.start({render_loop_name: this.sceneData.loop_name, image_format: 'jpg', quality: '100'});
28708
- //
28709
- // this.streaming.stream.on('image', async (object) => {
28710
- // this._htmlImageDisplay(object, null);
28711
- // const [progress] = await this.service.queue_commands()
28712
- // .queue(new Command('render_loop_get_render_progress', {
28713
- // render_loop_name: this.sceneData.loop_name
28714
- // }), true)
28715
- // .execute();
28716
- //
28717
- // if (progress.progression !== undefined) {
28718
- // this._setRenderProgress(RenderStatus.IsRunning, Math.ceil((progress.progression * 100)), progress.iteration);
28719
- // }
28720
- //
28721
- // if (object.result === 1) {
28722
- //
28723
- // await this.service.queue_commands()
28724
- // .queue(new Command('render_loop_save_to_disk', {
28725
- // render_loop_name: this.sceneData.loop_name,
28726
- // format: 'jpg',
28727
- // quality: 90,
28728
- // path: this.sceneData.image_info.url
28729
- // }), true)
28730
- // .execute();
28731
- //
28732
- // if (this.streaming.stream !== undefined) {
28733
- // this.streaming.stream.stop();
28734
- // }
28735
- // await this._quitRenderLoop();
28736
- // this._afterRendering();
28737
- // return;
28738
- //
28739
- // } else if (object.result < 0) {
28740
- //
28741
- // await this._onRenderError();
28742
- // return;
28743
- // }
28744
- // });
28745
- //
28746
- // } catch (err) {
28747
- //
28748
- // await this._onRenderError();
28749
- // return;
28750
- // }
28751
- }
28752
- _setRenderProgress(status, progress, iterations) {
28753
- if (!this.serverData) {
28754
- return;
28755
- }
28756
- this.currentQueueRenderItem.endDateTime = new Date();
28757
- this.currentQueueRenderItem.renderStatus = status;
28758
- this.currentQueueRenderItem.renderProgress = progress;
28759
- if (iterations > 0) {
28760
- this.currentQueueRenderItem.renderIterations = iterations;
28761
- }
28762
- if (this.serverData.renderMode === RenderModes.RenderIone) {
28763
- const render = this.getRenderOnId(this.currentQueueRenderItem.params.render.id);
28764
- render.status = status;
28765
- render.progress = progress;
28766
- }
28767
- }
28768
- async _onRenderError() {
28769
- this._setRenderProgress(RenderStatus.IsStopped, 0, 0);
28770
- await this._quitRenderLoop();
28771
- }
28772
- async _onRenderClose() {
28773
- this._setRenderProgress(RenderStatus.IsStopped, 0, 0);
28774
- }
28775
- _afterRendering() {
28776
- if (!this.serverData) {
28777
- return;
28778
- }
28779
- this._setRenderProgress(RenderStatus.IsSuccess, 100, 0);
28780
- const imageUrl = this._settingsService.settings.assetPath.replace('content43/', '') + this.sceneData.image_info.url;
28781
- if (this.serverData.renderMode === RenderModes.RenderRoom) {
28782
- this.renderedRoomImages.unshift(imageUrl);
28783
- }
28784
- this.renderImageChanged.next(imageUrl);
28785
- if (this.serverData.renderMode === RenderModes.RenderIone) {
28786
- const render = this.getRenderOnId(this.currentQueueRenderItem.params.render.id);
28787
- render.url = imageUrl;
28788
- }
28789
- const configuredItem = this.currentQueueRenderItem.params.configuredItem;
28790
- const isSingleItem = this.serverData.renderMode !== RenderModes.RenderRoom;
28791
- this._googleTagManager.sendEvent(GoogleTagManagerEvent.Render, {
28792
- 'articleNr': isSingleItem ? configuredItem.sku : 'renderRoom',
28793
- 'product': isSingleItem ? configuredItem.name : 'renderRoom',
28794
- 'dimensions': this.currentQueueRenderItem.imageSize
28795
- });
28796
- this.startRendering();
28797
- }
28798
- _getRenderServiceUrl() {
28799
- return `${(this.serverData.secure ? 'https' : 'http')}://${this.serverData.host}:${this.serverData.port}`;
28800
- }
28801
- forceRenderImage() {
28802
- const floorGroup = this._getFirstCustomFloorItemFromScene();
28803
- if (floorGroup !== null) {
28804
- this._checkVisibleUpdates(floorGroup, true);
28805
- }
28806
- }
28807
- async _checkVisibleUpdates(furniture, forceRender = false) {
28808
- if (!this.serverData) {
28809
- return;
28810
- }
28811
- if (!furniture) {
28812
- return;
28813
- }
28814
- if (this.serverData.renderMode === this.renderModes.RenderIone) {
28815
- const object = this._exportService.getExportObjectFromCustomFloorGroup(furniture);
28816
- this.currentProductHash = object.defaultRenderPath;
28817
- }
28818
- else if (this.serverData.renderMode === this.renderModes.RenderShop) {
28819
- const object = this._exportService.getExportObjectFromCustomFloorGroup(furniture);
28820
- if (!(JSON.stringify(this.prevItem) !== JSON.stringify(object) || forceRender)) {
28821
- return;
28822
- }
28823
- this.renderingStarted.next();
28824
- this.prevItem = object;
28825
- const queueItem = new RenderQueueItem();
28826
- queueItem.params = this.getRenderParameters(this.renderModes.RenderShop);
28827
- queueItem.params.cameraMatrix = this._cameraService.camera.matrixWorldInverse.elements;
28828
- queueItem.params.forceRender = forceRender;
28829
- this.renderQueue = [];
28830
- this.renderQueue.push(queueItem);
28831
- await this.startRendering();
28832
- }
28833
- }
28834
- _htmlImageDisplay(image, urlCreator) {
28835
- try {
28836
- urlCreator = urlCreator || (window ? (window.URL || window.webkitURL) : undefined);
28837
- }
28838
- catch (e) {
28839
- }
28840
- const blob = new Blob([image.image], { type: image.mime_type });
28841
- const url = urlCreator.createObjectURL(blob);
28842
- this.renderRoomImageChanged.next(url);
28843
- }
28844
- getRenderOnId(id) {
28845
- let returnRender = null;
28846
- this.renders.forEach((x) => {
28847
- if (x.id === id) {
28848
- returnRender = x;
28849
- }
28850
- });
28851
- return returnRender;
28852
- }
28853
- getImageSizeOnId(id) {
28854
- let returnSize = null;
28855
- this.imageSizes.forEach((x) => {
28856
- if (x.id === id) {
28857
- returnSize = x;
28858
- }
28859
- });
28860
- return returnSize;
28861
- }
28862
- getRenderEnvironmentOnId(id) {
28863
- let returnEnvironment = null;
28864
- this.renderEnvironments.forEach((renderEnvironment) => {
28865
- if (renderEnvironment.id === id) {
28866
- returnEnvironment = renderEnvironment;
28867
- return;
28868
- }
28869
- });
28870
- return returnEnvironment;
28871
- }
28872
- getLightningOnId(id) {
28873
- let returnLightning = null;
28874
- this.lightnings.forEach((x) => {
28875
- if (x.id === id) {
28876
- returnLightning = x;
28877
- }
28878
- });
28879
- return returnLightning;
28880
- }
28881
- /******************************************** Export functions ********************************************/
28882
- _getFirstCustomFloorItemFromScene() {
28883
- const children = this._sceneService.scene.children;
28884
- if (children.length <= 0) {
28885
- return null;
28886
- }
28887
- for (let a = 0; a < children.length; a++) {
28888
- if (children[a] instanceof CustomFloorItem) {
28889
- return children[a];
28890
- }
28891
- if (children[a] instanceof ItemGroup) {
28892
- const itemGroup = children[a];
28893
- if (itemGroup.items.length > 0) {
28894
- itemGroup.items.forEach((item) => {
28895
- if (item instanceof CustomFloorItem) {
28896
- return item;
28897
- }
28898
- });
28899
- }
28900
- }
28901
- }
28902
- return null;
28903
- }
28904
- _getConfiguredFurnitureItem() {
28905
- const floorgroup = this._getFirstCustomFloorItemFromScene();
28906
- if (floorgroup === null) {
28907
- return null;
28908
- }
28909
- return this._exportService.getExportObjectFromCustomFloorGroup(floorgroup);
28910
- }
28911
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: RenderService, deps: [{ token: HomedecoratorSettingsService }, { token: ExportService }, { token: CameraService }, { token: SceneService }, { token: ToastService }, { token: MessageBusService }, { token: GoogleTagManagerService }, { token: RoomService }, { token: FloorService }], target: i0.ɵɵFactoryTarget.Injectable }); }
28912
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: RenderService }); }
28913
- }
28914
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: RenderService, decorators: [{
28915
- type: Injectable
28916
- }], ctorParameters: () => [{ type: HomedecoratorSettingsService }, { type: ExportService }, { type: CameraService }, { type: SceneService }, { type: ToastService }, { type: MessageBusService }, { type: GoogleTagManagerService }, { type: RoomService }, { type: FloorService }] });
28917
-
28918
28548
  class LoadFurnitureWithoutSceneService extends LoadFurnitureBaseService {
28919
28549
  loadFurniture(furnitureData, shouldCopyInstance, looseOriginalConfiguration, standAlone, fromScratch, fromPreset, loadFromProject) {
28920
28550
  throw new Error('Method not implemented.');
@@ -28957,7 +28587,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
28957
28587
  type: Injectable
28958
28588
  }], ctorParameters: () => [{ type: LoadFurnitureService }, { type: LoadFurnitureWithoutSceneService }, { type: HomedecoratorSettingsService }, { type: HomedecoratorConnectorService }] });
28959
28589
 
28960
- class NewRenderService {
28590
+ class RenderService {
28961
28591
  constructor(messageService, _settingsService, _buildFurnitureService, _cameraService, _sceneService, _ione, _ioneConnectorAdapter, _threedSelectorService, _toastService, _messageBusService, _googleTagManager, _roomService, _floorService, _wallService, _ceilingService, _loadFurnitureService, _utilsService, _presetService, _apiServiceModule, _appEventService, _dictionaryService) {
28962
28592
  this.messageService = messageService;
28963
28593
  this._settingsService = _settingsService;
@@ -28981,15 +28611,20 @@ class NewRenderService {
28981
28611
  this._appEventService = _appEventService;
28982
28612
  this._dictionaryService = _dictionaryService;
28983
28613
  this.renderImageChanged = new BehaviorSubject('');
28984
- this.renderImageError = new BehaviorSubject('');
28614
+ this.renderImageError = new Subject();
28985
28615
  this.blenderRenderStarted = new Subject();
28986
28616
  this.renderUpdateImageChanged = new BehaviorSubject(undefined);
28987
28617
  this.renderRoomImageChanged = new BehaviorSubject('');
28988
28618
  this.currentQueueRenderItem = new RenderQueueItem();
28989
28619
  this.renderedRoomImages = [];
28620
+ this.blendFilesRender = false;
28990
28621
  this._overWriteTransparency = false;
28991
28622
  this._subs = [];
28992
- this._subs.push(this.messageService.subscribe(MessageType.BlenderRenderFileReady, (file) => this.procesRenderFile(file)));
28623
+ this._subs.push(this.messageService.subscribe(MessageType.BlenderRenderFileReady, (file) => this.procesRenderFile(file)), this._settingsService.settingsLoaded.subscribe((loaded) => {
28624
+ if (loaded) {
28625
+ this.blendFilesRender = this._settingsService.settings.blendFilesRender;
28626
+ }
28627
+ }));
28993
28628
  }
28994
28629
  ngOnDestroy() {
28995
28630
  this._subs.forEach(s => s.unsubscribe());
@@ -29014,7 +28649,14 @@ class NewRenderService {
29014
28649
  }
29015
28650
  }
29016
28651
  async renderRoom(settings, preview = false) {
29017
- const sceneData = await this._exportToGlb();
28652
+ let sceneData;
28653
+ try {
28654
+ sceneData = await this._exportToGlb();
28655
+ }
28656
+ catch (e) {
28657
+ this.renderImageError.next(this._dictionaryService.get(e.message));
28658
+ return;
28659
+ }
29018
28660
  const data = this._getDataForRoomRender(settings);
29019
28661
  data.files = {
29020
28662
  glbData: this._arrayBufferToBase64(sceneData)
@@ -29038,6 +28680,21 @@ class NewRenderService {
29038
28680
  let scene;
29039
28681
  try {
29040
28682
  scene = this._sceneService.scene.clone(true);
28683
+ const masksToRemove = new Map();
28684
+ scene.traverse((child) => {
28685
+ if (child.parent && child instanceof Mesh && child.name && child.name.toLowerCase().indexOf('_mask') > -1) {
28686
+ masksToRemove.set(child.parent.uuid, child.uuid);
28687
+ }
28688
+ });
28689
+ masksToRemove.forEach((maskUuid, parentUuid) => {
28690
+ const parent = scene.getObjectByProperty('uuid', parentUuid);
28691
+ if (parent) {
28692
+ const mask = parent.getObjectByProperty('uuid', maskUuid);
28693
+ if (mask) {
28694
+ parent.remove(mask);
28695
+ }
28696
+ }
28697
+ });
29041
28698
  const lightsToRemove = scene.children.filter(c => c instanceof Light);
29042
28699
  lightsToRemove.forEach(light => {
29043
28700
  if ((light instanceof SpotLight || light instanceof DirectionalLight) && light.target) {
@@ -29058,6 +28715,10 @@ class NewRenderService {
29058
28715
  if (!this._cameraService.isCameraFacingFront(wall) && !wall.orphan && !wall.isInnerWall()) {
29059
28716
  wall.name = 'CULLING_wall';
29060
28717
  }
28718
+ wall.userData = {};
28719
+ // for (let i = wall.children.length; i >= 0; i--) {
28720
+ // wall.remove(wall.children[i]);
28721
+ // }
29061
28722
  });
29062
28723
  const ceilings = scene.children.filter(c => c.name && c.name === this._ceilingService.ceilingName);
29063
28724
  ceilings.forEach(ceiling => {
@@ -29076,7 +28737,9 @@ class NewRenderService {
29076
28737
  embedImages: true,
29077
28738
  };
29078
28739
  scene.name = 'mrp_room_' + scene.uuid;
29079
- const glb = await this._getGlbFromObject(scene, options);
28740
+ const glb = await this._getGlbFromObject(scene, options).catch((error) => {
28741
+ throw (error);
28742
+ });
29080
28743
  // this._utilsService.downloadFile(scene.name + '.glb', new Blob([glb], {type: 'model/gltf-binary'}));
29081
28744
  ObjectUtils.DisposeObject(scene);
29082
28745
  scene = null;
@@ -29091,7 +28754,8 @@ class NewRenderService {
29091
28754
  return new Promise((resolve, reject) => {
29092
28755
  exporter.parse(object, async (exportedScene) => {
29093
28756
  resolve(exportedScene);
29094
- }, () => {
28757
+ }, (error) => {
28758
+ reject(error);
29095
28759
  }, options);
29096
28760
  });
29097
28761
  }
@@ -29210,7 +28874,19 @@ class NewRenderService {
29210
28874
  method: 'POST',
29211
28875
  data: JSON.stringify(data),
29212
28876
  url: `${host}getRenderFromGlb`,
29213
- responseType: 'json'
28877
+ responseType: 'json',
28878
+ onUploadProgress: (progressEvent) => {
28879
+ const total = progressEvent.total ?? 0;
28880
+ if (total > 0) {
28881
+ const percent = Math.round((progressEvent.loaded * 100) / total);
28882
+ this._messageBusService.emit(MessageType.RenderUploadProgress, percent);
28883
+ if (percent >= 100) {
28884
+ this._messageBusService.emit(MessageType.RenderUploadFinished, true);
28885
+ }
28886
+ }
28887
+ }
28888
+ }).catch((error) => {
28889
+ return error;
29214
28890
  });
29215
28891
  if (result.status === 200) {
29216
28892
  // const image = `data:${result.data.fileType};base64,${result.data.image}`;
@@ -29231,7 +28907,12 @@ class NewRenderService {
29231
28907
  this.renderImageError.next(this._dictionaryService.get('BLENDER_PRODUCT_RENDER_ERROR'));
29232
28908
  }
29233
28909
  // Remove the loading indicator.
29234
- this._messageBusService.emit(MessageType.RenderUploadFinished, true);
28910
+ this._messageBusService.emit(MessageType.RenderFinished, true);
28911
+ }
28912
+ else {
28913
+ this.renderImageChanged.next('');
28914
+ this.renderImageError.next(this._dictionaryService.get('BLENDER_PRODUCT_RENDER_ERROR'));
28915
+ this._messageBusService.emit(MessageType.RenderFinished, true);
29235
28916
  }
29236
28917
  }
29237
28918
  }
@@ -29550,10 +29231,10 @@ class NewRenderService {
29550
29231
  this._overWriteTransparency = true;
29551
29232
  }
29552
29233
  }
29553
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NewRenderService, deps: [{ token: MessageBusService }, { token: HomedecoratorSettingsService }, { token: SwitchBuildFurnitureService }, { token: CameraService }, { token: SceneService }, { token: HomedecoratorConnectorService }, { token: HomedecoratorConnectorAdapterService }, { token: ThreedselectorService }, { token: ToastService }, { token: MessageBusService }, { token: GoogleTagManagerService }, { token: RoomService }, { token: FloorService }, { token: WallService }, { token: CeilingService }, { token: SwitchLoadFurnitureService }, { token: UtilsService }, { token: PresetsService }, { token: ApiServiceModule }, { token: HomedecoratorAppEventService }, { token: HomedecoratorDictionaryService }], target: i0.ɵɵFactoryTarget.Injectable }); }
29554
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NewRenderService }); }
29234
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: RenderService, deps: [{ token: MessageBusService }, { token: HomedecoratorSettingsService }, { token: SwitchBuildFurnitureService }, { token: CameraService }, { token: SceneService }, { token: HomedecoratorConnectorService }, { token: HomedecoratorConnectorAdapterService }, { token: ThreedselectorService }, { token: ToastService }, { token: MessageBusService }, { token: GoogleTagManagerService }, { token: RoomService }, { token: FloorService }, { token: WallService }, { token: CeilingService }, { token: SwitchLoadFurnitureService }, { token: UtilsService }, { token: PresetsService }, { token: ApiServiceModule }, { token: HomedecoratorAppEventService }, { token: HomedecoratorDictionaryService }], target: i0.ɵɵFactoryTarget.Injectable }); }
29235
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: RenderService }); }
29555
29236
  }
29556
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NewRenderService, decorators: [{
29237
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: RenderService, decorators: [{
29557
29238
  type: Injectable
29558
29239
  }], ctorParameters: () => [{ type: MessageBusService }, { type: HomedecoratorSettingsService }, { type: SwitchBuildFurnitureService }, { type: CameraService }, { type: SceneService }, { type: HomedecoratorConnectorService }, { type: HomedecoratorConnectorAdapterService }, { type: ThreedselectorService }, { type: ToastService }, { type: MessageBusService }, { type: GoogleTagManagerService }, { type: RoomService }, { type: FloorService }, { type: WallService }, { type: CeilingService }, { type: SwitchLoadFurnitureService }, { type: UtilsService }, { type: PresetsService }, { type: ApiServiceModule }, { type: HomedecoratorAppEventService }, { type: HomedecoratorDictionaryService }] });
29559
29240
 
@@ -30415,6 +30096,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
30415
30096
  type: Injectable
30416
30097
  }], ctorParameters: () => [{ type: HomedecoratorSettingsService }, { type: HomedecoratorConnectorService }] });
30417
30098
 
30099
+ var ToastType;
30100
+ (function (ToastType) {
30101
+ ToastType[ToastType["Success"] = 0] = "Success";
30102
+ ToastType[ToastType["Warning"] = 1] = "Warning";
30103
+ ToastType[ToastType["Error"] = 2] = "Error";
30104
+ })(ToastType || (ToastType = {}));
30105
+
30106
+ class Toast {
30107
+ constructor() {
30108
+ this.type = ToastType.Success;
30109
+ }
30110
+ }
30111
+
30418
30112
  class ConnectionHeathService {
30419
30113
  constructor(_http, _settingService, _toastService, _messageService) {
30420
30114
  this._http = _http;
@@ -30799,9 +30493,9 @@ class FloorplanRenderService {
30799
30493
  }
30800
30494
  this._clear();
30801
30495
  this._drawGrid();
30802
- // if (this.diagramBackground && this.showDiagramBackground) {
30803
- // this._drawBackground();
30804
- // }
30496
+ if (this.diagramBackground && this.showDiagramBackground) {
30497
+ this._drawBackground();
30498
+ }
30805
30499
  this._drawRooms();
30806
30500
  this._drawWallsWithNoRoom();
30807
30501
  if (this._state.showWallItemMeasurements && this._state.activeItem) {
@@ -30841,6 +30535,24 @@ class FloorplanRenderService {
30841
30535
  ContextUtils.DrawLine(context, 0, gridSpacing * y + offsetY, canvas.width, gridSpacing * y + offsetY, gridWidth, gridColor);
30842
30536
  }
30843
30537
  }
30538
+ _drawBackground() {
30539
+ const context = this._state.context;
30540
+ if (this.diagramBackgroundActiveZoom) {
30541
+ if (this.diagramBackgroundCurrentScale <= this._coordinatesService.viewScale) {
30542
+ this.diagramBackgroundWidth = this.diagramBackgroundWidth * this._coordinatesService.scalingFactor;
30543
+ this.diagramBackgroundHeight = this.diagramBackgroundHeight * this._coordinatesService.scalingFactor;
30544
+ }
30545
+ else {
30546
+ this.diagramBackgroundWidth = this.diagramBackgroundWidth * (1 / this._coordinatesService.scalingFactor);
30547
+ this.diagramBackgroundHeight = this.diagramBackgroundHeight * (1 / this._coordinatesService.scalingFactor);
30548
+ }
30549
+ this.diagramBackgroundActiveZoom = false;
30550
+ }
30551
+ this.diagramBackgroundCurrentScale = this._coordinatesService.viewScale;
30552
+ context.globalAlpha = this.diagramBackgroundAlpha;
30553
+ context.drawImage(this.diagramBackground, Math.abs(this._coordinatesService.originX) - (this.diagramBackgroundWidth * this.diagramBackgroundScale / 2), Math.abs(this._coordinatesService.originY) - (this.diagramBackgroundHeight * this.diagramBackgroundScale / 2), this.diagramBackgroundWidth * this.diagramBackgroundScale, this.diagramBackgroundHeight * this.diagramBackgroundScale);
30554
+ context.globalAlpha = 1;
30555
+ }
30844
30556
  _drawRooms() {
30845
30557
  const rooms = this._state.rooms;
30846
30558
  rooms.forEach(room => {
@@ -31499,9 +31211,8 @@ const APPLICATION_SERVICES_PROVIDERS = [
31499
31211
  DynamicCameraService,
31500
31212
  ThreedInPhotoInitializerService,
31501
31213
  ThreedInPhotoBuildService,
31502
- RenderService,
31503
31214
  ExportService,
31504
- NewRenderService,
31215
+ RenderService,
31505
31216
  AppInitializerService,
31506
31217
  JsonUtilsService,
31507
31218
  RalService,
@@ -33745,108 +33456,142 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
33745
33456
  class BlenderRenderSettings {
33746
33457
  }
33747
33458
 
33748
- class RenderProgressComponent {
33749
- set show(show) {
33750
- this._show = show;
33751
- if (show) {
33752
- this._progressService.progressBarType = ProgressType.Upload;
33753
- this._progressService.total = 100;
33459
+ // A pipe for appending strings to other strings in view templates.
33460
+ class AppendPipe {
33461
+ transform(value, append) {
33462
+ if (!value) {
33463
+ return '';
33754
33464
  }
33755
- else {
33756
- this._progressService.progressBarType = ProgressType.Download;
33757
- this._progressService.total = 0;
33465
+ if (!append) {
33466
+ return value;
33758
33467
  }
33468
+ return value + append;
33759
33469
  }
33760
- get show() {
33761
- return this._show;
33762
- }
33763
- get progressValue() {
33764
- return this.progress + '/ 100%';
33765
- }
33766
- constructor(_messageService, _progressService) {
33470
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppendPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
33471
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.16", ngImport: i0, type: AppendPipe, isStandalone: false, name: "append" }); }
33472
+ }
33473
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppendPipe, decorators: [{
33474
+ type: Pipe,
33475
+ args: [{
33476
+ name: 'append',
33477
+ standalone: false
33478
+ }]
33479
+ }] });
33480
+
33481
+ class RenderProgressComponent {
33482
+ constructor(_messageService) {
33767
33483
  this._messageService = _messageService;
33768
- this._progressService = _progressService;
33484
+ this.title = 'UPLOADING_ROOM';
33769
33485
  this.progress = 0;
33486
+ this.rendering = false;
33770
33487
  this._subs = [];
33771
- this._show = false;
33772
- this._subs.push(this._messageService.subscribe(MessageType.RenderUploadProgress, (progress) => this.updateProgress(progress)));
33488
+ this._subs.push(this._messageService.subscribe(MessageType.RenderUploadFinished, (ready) => {
33489
+ if (ready) {
33490
+ this.title = 'RENDERING_ROOM';
33491
+ this.rendering = true;
33492
+ }
33493
+ }), this._messageService.subscribe(MessageType.RenderUploadProgress, (progress) => this.updateProgress(progress)));
33773
33494
  }
33774
33495
  ngOnDestroy() {
33775
33496
  this._subs.forEach(sub => sub.unsubscribe());
33776
33497
  }
33777
33498
  updateProgress(progress) {
33778
- this.progress = progress;
33779
- this._progressService.progress = progress;
33499
+ this.progress = Math.max(0, Math.min(100, progress));
33780
33500
  }
33781
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: RenderProgressComponent, deps: [{ token: MessageBusService }, { token: ProgressService }], target: i0.ɵɵFactoryTarget.Component }); }
33782
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: RenderProgressComponent, isStandalone: false, selector: "rp-render-progress", inputs: { show: "show", title: "title" }, ngImport: i0, template: `
33783
- @if (show) {
33501
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: RenderProgressComponent, deps: [{ token: MessageBusService }], target: i0.ɵɵFactoryTarget.Component }); }
33502
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: RenderProgressComponent, isStandalone: false, selector: "rp-render-progress", ngImport: i0, template: `
33784
33503
  <div class="render-progress-model">
33785
33504
  <div class="model">
33786
33505
  <div class="model-header-container">
33787
- <h3 class="model-header" [textContent]="title"></h3>
33788
- <div class="close" (click)="show = false">
33789
- <mat-icon class="homedecorator-material-icons">cancel</mat-icon>
33790
- </div>
33506
+ <h3 class="model-header" [textContent]="title | localize"></h3>
33507
+ <!--
33508
+ <div class="close" (click)="show = false">
33509
+ <mat-icon class="homedecorator-material-icons">cancel</mat-icon>
33510
+ </div>
33511
+ -->
33791
33512
  </div>
33792
33513
  <div class="model-content-container">
33793
- <span class="progress-text" [textContent]="progressValue"></span>
33514
+ @if (!rendering) {
33515
+ <div class="progress-bar" role="progressbar" [attr.aria-valuenow]="progress" aria-valuemin="0" aria-valuemax="100">
33516
+ <div class="progress-bar-fill" [style.width.%]="progress"></div>
33517
+ <span class="progress-bar-text" [textContent]="progress.toString() | append:'%'"></span>
33518
+ </div>
33519
+ } @else {
33520
+ <span class="loading-dots" aria-hidden="true">
33521
+ <span></span>
33522
+ <span></span>
33523
+ <span></span>
33524
+ </span>
33525
+ }
33794
33526
  </div>
33795
33527
  </div>
33796
33528
  </div>
33797
- }
33798
- `, isInline: true, styles: [".render-progress-model{position:fixed;inset:0;z-index:100;background-color:#0003}.render-progress-model .model{width:400px;position:relative;top:20%;left:50%;margin-left:-200px;background:#fff;border-radius:10px;box-sizing:border-box;box-shadow:1px 0 20px #0000001f}.render-progress-model .model .model-header-container{display:flex;justify-content:space-between;border-bottom:1px solid #c5c3c6;padding:20px 20px 10px;align-items:center}.render-progress-model .model .model-header-container .close mat-icon{fill:#c5c3c6;color:#c5c3c6;cursor:pointer;transition:all .2s ease}.render-progress-model .model .model-header-container .close:hover mat-icon{fill:#46494c;color:#46494c}.render-progress-model .model .model-content-container{padding:20px}.render-progress-model .model .model-content-container .progress-text{text-align:center;margin-top:10px;display:block}.render-progress-model .model .model-content-container .progress-container{width:100%;height:25px;background-color:#e0e0e0;border-radius:12px;overflow:hidden}.render-progress-model .model .model-content-container .progress-fill{height:100%;background-color:#da9803;transition:width .3s ease-in-out}\n"], dependencies: [{ kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] }); }
33529
+ `, isInline: true, styles: [".render-progress-model{position:fixed;inset:0;z-index:100;background-color:#0003}.render-progress-model .model{width:400px;position:relative;top:20%;left:50%;margin-left:-200px;background:#fff;border-radius:10px;box-sizing:border-box;box-shadow:1px 0 20px #0000001f}.render-progress-model .model .model-header-container{display:flex;justify-content:space-between;border-bottom:1px solid #c5c3c6;padding:20px 20px 10px;align-items:center}.render-progress-model .model .model-header-container .close mat-icon{fill:#c5c3c6;color:#c5c3c6;cursor:pointer;transition:all .2s ease}.render-progress-model .model .model-header-container .close:hover mat-icon{fill:#46494c;color:#46494c}.render-progress-model .model .model-content-container{display:flex;justify-content:center;padding:20px}.render-progress-model .model .model-content-container .progress-container{width:100%;height:25px;background-color:#e0e0e0;border-radius:12px;overflow:hidden}.render-progress-model .model .model-content-container .progress-bar{position:relative;width:100%;height:18px;overflow:hidden;border-radius:999px;background-color:#e5e7eb}.render-progress-model .model .model-content-container .progress-bar-text{position:absolute;inset:0;color:#171721;display:flex;align-items:center;justify-content:center}.render-progress-model .model .model-content-container .progress-bar-fill{height:100%;width:0;background:linear-gradient(90deg,#da9803,#fff);transition:width .3s ease}.render-progress-model .model .model-content-container .loading-dots{display:inline-flex;gap:2px;margin-left:4px}.render-progress-model .model .model-content-container .loading-dots span{width:4px;height:4px;border-radius:50%;background-color:#171721;opacity:.25;animation:loading-dot 1.2s infinite ease-in-out}.render-progress-model .model .model-content-container .loading-dots span:nth-child(2){animation-delay:.2s}.render-progress-model .model .model-content-container .loading-dots span:nth-child(3){animation-delay:.4s}@keyframes loading-dot{0%,80%,to{opacity:.25;transform:translateY(0)}40%{opacity:1;transform:translateY(-2px)}}\n"], dependencies: [{ kind: "pipe", type: LocalizePipe, name: "localize" }, { kind: "pipe", type: AppendPipe, name: "append" }] }); }
33799
33530
  }
33800
33531
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: RenderProgressComponent, decorators: [{
33801
33532
  type: Component,
33802
33533
  args: [{ selector: 'rp-render-progress', template: `
33803
- @if (show) {
33804
33534
  <div class="render-progress-model">
33805
33535
  <div class="model">
33806
33536
  <div class="model-header-container">
33807
- <h3 class="model-header" [textContent]="title"></h3>
33808
- <div class="close" (click)="show = false">
33809
- <mat-icon class="homedecorator-material-icons">cancel</mat-icon>
33810
- </div>
33537
+ <h3 class="model-header" [textContent]="title | localize"></h3>
33538
+ <!--
33539
+ <div class="close" (click)="show = false">
33540
+ <mat-icon class="homedecorator-material-icons">cancel</mat-icon>
33541
+ </div>
33542
+ -->
33811
33543
  </div>
33812
33544
  <div class="model-content-container">
33813
- <span class="progress-text" [textContent]="progressValue"></span>
33545
+ @if (!rendering) {
33546
+ <div class="progress-bar" role="progressbar" [attr.aria-valuenow]="progress" aria-valuemin="0" aria-valuemax="100">
33547
+ <div class="progress-bar-fill" [style.width.%]="progress"></div>
33548
+ <span class="progress-bar-text" [textContent]="progress.toString() | append:'%'"></span>
33549
+ </div>
33550
+ } @else {
33551
+ <span class="loading-dots" aria-hidden="true">
33552
+ <span></span>
33553
+ <span></span>
33554
+ <span></span>
33555
+ </span>
33556
+ }
33814
33557
  </div>
33815
33558
  </div>
33816
33559
  </div>
33817
- }
33818
- `, standalone: false, styles: [".render-progress-model{position:fixed;inset:0;z-index:100;background-color:#0003}.render-progress-model .model{width:400px;position:relative;top:20%;left:50%;margin-left:-200px;background:#fff;border-radius:10px;box-sizing:border-box;box-shadow:1px 0 20px #0000001f}.render-progress-model .model .model-header-container{display:flex;justify-content:space-between;border-bottom:1px solid #c5c3c6;padding:20px 20px 10px;align-items:center}.render-progress-model .model .model-header-container .close mat-icon{fill:#c5c3c6;color:#c5c3c6;cursor:pointer;transition:all .2s ease}.render-progress-model .model .model-header-container .close:hover mat-icon{fill:#46494c;color:#46494c}.render-progress-model .model .model-content-container{padding:20px}.render-progress-model .model .model-content-container .progress-text{text-align:center;margin-top:10px;display:block}.render-progress-model .model .model-content-container .progress-container{width:100%;height:25px;background-color:#e0e0e0;border-radius:12px;overflow:hidden}.render-progress-model .model .model-content-container .progress-fill{height:100%;background-color:#da9803;transition:width .3s ease-in-out}\n"] }]
33819
- }], ctorParameters: () => [{ type: MessageBusService }, { type: ProgressService }], propDecorators: { show: [{
33820
- type: Input
33821
- }], title: [{
33822
- type: Input
33823
- }] } });
33560
+ `, standalone: false, styles: [".render-progress-model{position:fixed;inset:0;z-index:100;background-color:#0003}.render-progress-model .model{width:400px;position:relative;top:20%;left:50%;margin-left:-200px;background:#fff;border-radius:10px;box-sizing:border-box;box-shadow:1px 0 20px #0000001f}.render-progress-model .model .model-header-container{display:flex;justify-content:space-between;border-bottom:1px solid #c5c3c6;padding:20px 20px 10px;align-items:center}.render-progress-model .model .model-header-container .close mat-icon{fill:#c5c3c6;color:#c5c3c6;cursor:pointer;transition:all .2s ease}.render-progress-model .model .model-header-container .close:hover mat-icon{fill:#46494c;color:#46494c}.render-progress-model .model .model-content-container{display:flex;justify-content:center;padding:20px}.render-progress-model .model .model-content-container .progress-container{width:100%;height:25px;background-color:#e0e0e0;border-radius:12px;overflow:hidden}.render-progress-model .model .model-content-container .progress-bar{position:relative;width:100%;height:18px;overflow:hidden;border-radius:999px;background-color:#e5e7eb}.render-progress-model .model .model-content-container .progress-bar-text{position:absolute;inset:0;color:#171721;display:flex;align-items:center;justify-content:center}.render-progress-model .model .model-content-container .progress-bar-fill{height:100%;width:0;background:linear-gradient(90deg,#da9803,#fff);transition:width .3s ease}.render-progress-model .model .model-content-container .loading-dots{display:inline-flex;gap:2px;margin-left:4px}.render-progress-model .model .model-content-container .loading-dots span{width:4px;height:4px;border-radius:50%;background-color:#171721;opacity:.25;animation:loading-dot 1.2s infinite ease-in-out}.render-progress-model .model .model-content-container .loading-dots span:nth-child(2){animation-delay:.2s}.render-progress-model .model .model-content-container .loading-dots span:nth-child(3){animation-delay:.4s}@keyframes loading-dot{0%,80%,to{opacity:.25;transform:translateY(0)}40%{opacity:1;transform:translateY(-2px)}}\n"] }]
33561
+ }], ctorParameters: () => [{ type: MessageBusService }] });
33824
33562
 
33825
33563
  class RenderControlsComponent {
33826
33564
  get disablePictureButton() {
33827
- return this._newRenderService.currentQueueRenderItem.renderStatus === this.renderStatus.IsRunning;
33565
+ return this.renderService.currentQueueRenderItem.renderStatus === this.renderStatus.IsRunning;
33828
33566
  }
33829
- constructor(renderService, messageService, viewModeService, settingsService, iconService, _dialog, _sceneService, _cameraService, _configurationService, _settingsService, _newRenderService, _utilsService, _roomService, _wallMeasurementsService, _connectionHealthService, _dictionaryService) {
33830
- this.renderService = renderService;
33567
+ constructor(messageService, viewModeService, settingsService, iconService, renderService, _dialog, _sceneService, _cameraService, _configurationService, _settingsService, _utilsService, _roomService, _wallMeasurementsService, _connectionHealthService, _dictionaryService, _dialogService) {
33831
33568
  this.messageService = messageService;
33832
33569
  this.viewModeService = viewModeService;
33833
33570
  this.settingsService = settingsService;
33834
33571
  this.iconService = iconService;
33572
+ this.renderService = renderService;
33835
33573
  this._dialog = _dialog;
33836
33574
  this._sceneService = _sceneService;
33837
33575
  this._cameraService = _cameraService;
33838
33576
  this._configurationService = _configurationService;
33839
33577
  this._settingsService = _settingsService;
33840
- this._newRenderService = _newRenderService;
33841
33578
  this._utilsService = _utilsService;
33842
33579
  this._roomService = _roomService;
33843
33580
  this._wallMeasurementsService = _wallMeasurementsService;
33844
33581
  this._connectionHealthService = _connectionHealthService;
33845
33582
  this._dictionaryService = _dictionaryService;
33583
+ this._dialogService = _dialogService;
33846
33584
  this.viewModes = ViewMode;
33847
33585
  this.renderStatus = RenderStatus;
33848
33586
  this.icons = IconEnum;
33849
33587
  this.renderModes = RenderModes;
33588
+ this.imageSizes = [
33589
+ { id: 1, name: ' 720p (HD)', width: 1280, height: 720 },
33590
+ { id: 2, name: '1080P (HD)', width: 1920, height: 1080 },
33591
+ { id: 3, name: '1440p (2K)', width: 2560, height: 1440 },
33592
+ { id: 4, name: '2160p (4K)', width: 4096, height: 2160 }
33593
+ ];
33594
+ this.selectedImageSize = this.imageSizes[1];
33850
33595
  this.hdriIntensity = 1;
33851
33596
  this.hdriRotation = 0;
33852
33597
  this.lightingExposure = 1;
@@ -33859,14 +33604,22 @@ class RenderControlsComponent {
33859
33604
  this.showCullingErrorDialog = false;
33860
33605
  this.startUploading = false;
33861
33606
  this._subs = [];
33862
- this._subs.push(this.messageService.subscribe(MessageType.BlenderRenderPreviewReady, (file) => this.showPreview(file)), this.messageService.subscribe(MessageType.RenderUploadFinished, (ready) => this.hideUploadDialog(ready)), this.messageService.subscribe(MessageType.RenderError, () => this.hideUploadDialog(true)), this._cameraService.cameraMovementChanged.subscribe(() => {
33607
+ this._subs.push(this.messageService.subscribe(MessageType.BlenderRenderPreviewReady, (file) => this.showPreview(file)), this.messageService.subscribe(MessageType.RenderFinished, (ready) => this.hideUploadDialog(ready)), this.messageService.subscribe(MessageType.RenderError, () => this.hideUploadDialog(true)), this._cameraService.cameraMovementChanged.subscribe(() => {
33863
33608
  this._validateRenderPosition();
33864
33609
  // Make sure when the camera moves, we recheck the position and if we still need to show the render warning.
33610
+ }), this.renderService.renderImageError.subscribe((error) => {
33611
+ if (error) {
33612
+ this.hideUploadDialog(true);
33613
+ this._dialogService.showDialog({ data: { title: 'Error', messages: [{ message: error }], type: 'error' } });
33614
+ }
33865
33615
  }));
33866
33616
  }
33867
33617
  ngOnInit() {
33868
33618
  this.getRenderScenesFromSettings();
33869
33619
  }
33620
+ ngOnDestroy() {
33621
+ this._subs.forEach((sub) => sub.unsubscribe());
33622
+ }
33870
33623
  showRenderForm(event) {
33871
33624
  this.inPictureMode = !this.inPictureMode;
33872
33625
  this._validateRenderPosition();
@@ -33880,16 +33633,14 @@ class RenderControlsComponent {
33880
33633
  this.startUploading = false;
33881
33634
  }
33882
33635
  }
33883
- createBlenderRender() {
33636
+ createBlenderRender(preview = false) {
33884
33637
  if (!this.showCullingErrorDialog) {
33885
33638
  if (this.viewModeService.isTopViewActive()) {
33886
33639
  this._wallMeasurementsService.prepMeasurementsForRender();
33887
33640
  }
33888
- this.messageService.emit(MessageType.ShowLoadingIndicator, { title: this._dictionaryService.get('PREPARE_TO_RENDER') });
33889
33641
  this.startUploading = true;
33890
33642
  // only render when the showCullingErrorDialog is false
33891
33643
  // this.messageService.emit(MessageType.ShowLoadingIndicator, {title: 'Uploading...'});
33892
- const renderSize = this.renderService.getImageSizeOnId(this.renderService.selectedImageSize);
33893
33644
  const renderSceneAssetId = this.selectedRenderScene;
33894
33645
  if (this.lightingExposure < 1) {
33895
33646
  this.lightingExposure = 1;
@@ -33897,15 +33648,15 @@ class RenderControlsComponent {
33897
33648
  this._validateRenderPosition(); // Check the camera position
33898
33649
  const allowCulling = this._allowCulling(this.hasError);
33899
33650
  const renderInput = new BlenderRenderSettings();
33900
- renderInput.height = renderSize.height;
33901
- renderInput.width = renderSize.width;
33651
+ renderInput.height = preview ? 150 : this.selectedImageSize.height;
33652
+ renderInput.width = preview ? 275 : this.selectedImageSize.width;
33902
33653
  renderInput.sceneAsset = renderSceneAssetId;
33903
33654
  renderInput.hdriIntensity = this.hdriIntensity;
33904
33655
  renderInput.hdriRotation = this.hdriRotation;
33905
33656
  renderInput.lightingExposure = this.lightingExposure;
33906
33657
  renderInput.allowCulling = allowCulling;
33907
33658
  // this._utilsService.prepRoomForRender(false, renderInput);
33908
- this._newRenderService.renderRoom(renderInput);
33659
+ this.renderService.renderRoom(renderInput, preview);
33909
33660
  if (this.viewModeService.isTopViewActive()) {
33910
33661
  this._wallMeasurementsService.restoreMeasurementsAfterRender();
33911
33662
  }
@@ -33933,35 +33684,6 @@ class RenderControlsComponent {
33933
33684
  this._cameraService.camera.position.set(movingPosition.x, movingPosition.y, movingPosition.z);
33934
33685
  this._cameraService.cameraMovementChanged.next();
33935
33686
  }
33936
- createPreviewRender() {
33937
- if (!this.showCullingErrorDialog) {
33938
- if (this.viewModeService.isTopViewActive()) {
33939
- this._wallMeasurementsService.prepMeasurementsForRender();
33940
- }
33941
- const renderSceneAssetId = this.selectedRenderScene;
33942
- // this.messageService.emit(MessageType.ShowLoadingIndicator, {title: 'Uploading...'});
33943
- // this.messageService.emit(MessageType.ShowLoadingIndicator, {title: this._dictionaryService.get('PREPARE_TO_RENDER')});
33944
- this.startUploading = true;
33945
- if (this.lightingExposure < 1) {
33946
- this.lightingExposure = 1;
33947
- }
33948
- this._validateRenderPosition(); // Check the camera position
33949
- const allowCulling = this._allowCulling(this.hasError);
33950
- const renderInput = new BlenderRenderSettings();
33951
- renderInput.height = 150;
33952
- renderInput.width = 275;
33953
- renderInput.sceneAsset = renderSceneAssetId;
33954
- renderInput.hdriIntensity = this.hdriIntensity;
33955
- renderInput.hdriRotation = this.hdriRotation;
33956
- renderInput.lightingExposure = this.lightingExposure;
33957
- renderInput.allowCulling = allowCulling;
33958
- // this._utilsService.prepRoomForRender(false, renderInput, true);
33959
- this._newRenderService.renderRoom(renderInput, true);
33960
- if (this.viewModeService.isTopViewActive()) {
33961
- this._wallMeasurementsService.restoreMeasurementsAfterRender();
33962
- }
33963
- }
33964
- }
33965
33687
  showPreview(image) {
33966
33688
  this.blenderPreviewRender = image;
33967
33689
  }
@@ -34046,465 +33768,413 @@ class RenderControlsComponent {
34046
33768
  // }
34047
33769
  // return allowCulling;
34048
33770
  }
34049
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: RenderControlsComponent, deps: [{ token: RenderService }, { token: MessageBusService }, { token: ViewModeService }, { token: HomedecoratorSettingsService }, { token: HomedecoratorIconCacheService }, { token: i1$2.MatDialog }, { token: SceneService }, { token: CameraService }, { token: ConfigurationService }, { token: HomedecoratorSettingsService }, { token: NewRenderService }, { token: UtilsService }, { token: RoomService }, { token: WallMeasurementsService }, { token: ConnectionHeathService }, { token: HomedecoratorDictionaryService }], target: i0.ɵɵFactoryTarget.Component }); }
33771
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: RenderControlsComponent, deps: [{ token: MessageBusService }, { token: ViewModeService }, { token: HomedecoratorSettingsService }, { token: HomedecoratorIconCacheService }, { token: RenderService }, { token: i1$2.MatDialog }, { token: SceneService }, { token: CameraService }, { token: ConfigurationService }, { token: HomedecoratorSettingsService }, { token: UtilsService }, { token: RoomService }, { token: WallMeasurementsService }, { token: ConnectionHeathService }, { token: HomedecoratorDictionaryService }, { token: DialogService }], target: i0.ɵɵFactoryTarget.Component }); }
34050
33772
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: RenderControlsComponent, isStandalone: false, selector: "rp-render-controls", viewQueries: [{ propertyName: "renderButton", first: true, predicate: ["renderButton"], descendants: true }], ngImport: i0, template: `
34051
- @if (renderService.serverData && renderService.serverData.renderMode !== renderService.renderModes.RenderShop) {
34052
- <div class="render-container"
34053
- >
34054
- @if (renderService.currentQueueRenderItem.renderStatus === renderStatus.IsRunning || renderService.currentQueueRenderItem.renderStatus === renderStatus.IsSuccess) {
34055
- <div class="render-progress"
34056
- >
34057
- {{ (renderService.currentQueueRenderItem.renderStatus === renderStatus.IsSuccess && renderService.currentQueueRenderItem.renderProgress === 100 ? "RENDER_READY" : "") | localize }}
34058
- {{ (renderService.currentQueueRenderItem.renderStatus === renderStatus.IsSuccess && renderService.currentQueueRenderItem.renderProgress !== 100 ? "RENDER_STOPPED" : "") | localize }}
34059
- {{ (renderService.currentQueueRenderItem.renderStatus === renderStatus.IsRunning) ? renderService.currentQueueRenderItem.renderProgress + "%" : "" }}
34060
- </div>
34061
- }
34062
- <!-- the Yellow render indicators -->
34063
- @if (inPictureMode) {
34064
- <div class="render-indicators">
34065
- <div class="render-indicator-top-left"></div>
34066
- <div class="render-indicator-top-right"></div>
34067
- <div class="render-indicator-bottom-left"></div>
34068
- <div class="render-indicator-bottom-right"></div>
34069
- </div>
34070
- }
34071
- @if (inPictureMode) {
34072
- <div class="render-popup-container">
34073
- <div class="render-popup-header">
34074
- <h3>
34075
- <span>{{ 'PICTURE_MODE' | localize }}</span>
34076
- @if (hasError) {
34077
- <co-icon class="renderErrorIcon" [iconData]="iconService.getIcon(icons.TriangleExclamation)"
34078
- [matTooltip]="'BLENDER_RENDER_ERROR' | localize"></co-icon>
34079
- }
34080
- </h3>
34081
- <button
34082
- class="close-popup-container"
34083
- (click)="resetBlenderRenderScene()">
34084
- <co-icon [iconData]="iconService.getIcon(icons.Cross)"></co-icon>
34085
- </button>
34086
- </div>
34087
- <div class="render-popup-preview">
34088
- @if (blenderPreviewRender) {
34089
- <img [src]="blenderPreviewRender" alt="">
34090
- }
34091
- @if (!blenderPreviewRender) {
34092
- <div class="render-popup-preview-placeholder">
34093
- <span>{{ 'PREVIEW' | localize }}</span>
34094
- </div>
34095
- }
34096
- <button
34097
- class="render-popup-refresh-preview"
34098
- (click)="createPreviewRender()"
34099
- >
34100
- <co-icon [iconData]="iconService.getIcon(icons.RetryButton)"></co-icon>
34101
- </button>
34102
- </div>
34103
- @if (renderService.blendFilesRender) {
34104
- <div class="render-popup-dropdown">
34105
- <div class="toggleable" (click)="toggleRenderSettings()">
34106
- <p>
34107
- @if (!showRenderSettings) {
34108
- <span [textContent]="'RENDER_ADVANCED_SETTINGS_SHOW' | localize"></span>
34109
- }
34110
- @if (showRenderSettings) {
34111
- <span [textContent]="'RENDER_ADVANCED_SETTINGS_HIDE' | localize"></span>
34112
- }
34113
- </p>
34114
- <co-icon [ngClass]="{'icon-rotate': showRenderSettings}"
34115
- [iconData]="iconService.getIcon(icons.ArrowPointDown)"></co-icon>
34116
- </div>
34117
- @if (showRenderSettings) {
34118
- <div class="advanced-render-settings">
34119
- <div class="setting-part-container">
34120
- @if (renderService.serverData.renderMode === renderModes.RenderRoom) {
34121
- <mat-form-field
34122
- class="face-select-form"
34123
- >
34124
- <mat-label>{{ "ENVIRONMENT" | localize }}</mat-label>
34125
- <mat-select [(ngModel)]="selectedRenderScene" (selectionChange)="updateBlenderSceneSettings($event)">
34126
- @for (scene of sceneList; track scene) {
34127
- <mat-option
34128
- [value]="scene">{{ scene.name }}
34129
- </mat-option>
34130
- }
34131
- </mat-select>
34132
- </mat-form-field>
33773
+ <div class="render-container">
33774
+ @if (startUploading) {
33775
+ <rp-render-progress></rp-render-progress>
33776
+ }
33777
+ <!-- the Yellow render indicators -->
33778
+ @if (inPictureMode) {
33779
+ <div class="render-indicators">
33780
+ <div class="render-indicator-top-left"></div>
33781
+ <div class="render-indicator-top-right"></div>
33782
+ <div class="render-indicator-bottom-left"></div>
33783
+ <div class="render-indicator-bottom-right"></div>
33784
+ </div>
33785
+ <div class="render-popup-container">
33786
+ <div class="render-popup-header">
33787
+ <h3>
33788
+ <span>{{ 'PICTURE_MODE' | localize }}</span>
33789
+ @if (hasError) {
33790
+ <co-icon class="renderErrorIcon" [iconData]="iconService.getIcon(icons.TriangleExclamation)"
33791
+ [matTooltip]="'BLENDER_RENDER_ERROR' | localize"></co-icon>
33792
+ }
33793
+ </h3>
33794
+ <button
33795
+ class="close-popup-container"
33796
+ (click)="resetBlenderRenderScene()">
33797
+ <co-icon [iconData]="iconService.getIcon(icons.Cross)"></co-icon>
33798
+ </button>
33799
+ </div>
33800
+ <div class="render-popup-preview">
33801
+ @if (blenderPreviewRender) {
33802
+ <img [src]="blenderPreviewRender" alt="">
34133
33803
  }
34134
- </div>
34135
- <div class="setting-part-container">
34136
- <mat-form-field class="third-width">
34137
- <mat-label [textContent]="'ENVIRONMENT_LIGHT' | localize"></mat-label>
34138
- <input
34139
- [type]="'number'"
34140
- matInput
34141
- [(ngModel)]="hdriIntensity"
34142
- (ngModelChange)="hdriIntensity = +$event">
34143
- </mat-form-field>
34144
- <div class="setting-part-buttons">
34145
- <button class="amount-button" (click)="hdriIntensity = +hdriIntensity - 1">
34146
- <co-icon [iconData]="iconService.getIcon(icons.CircleMinusLight)"></co-icon>
34147
- </button>
34148
- <button class="amount-button" (click)="hdriIntensity = +hdriIntensity + 1">
34149
- <co-icon [iconData]="iconService.getIcon(icons.CirclePlusLight)"></co-icon>
34150
- </button>
34151
- </div>
34152
- <div class="setting-part-slider">
34153
- <mat-slider class="value" min="1" max="20" step="1" [(ngModel)]="hdriIntensity"></mat-slider>
34154
- </div>
34155
- </div>
34156
- <div class="setting-part-container">
34157
- <mat-form-field class="third-width">
34158
- <mat-label [textContent]="'ROTATION' | localize"></mat-label>
34159
- <input
34160
- [type]="'number'"
34161
- matInput
34162
- [(ngModel)]="hdriRotation"
34163
- (ngModelChange)="hdriRotation = +$event">
34164
- </mat-form-field>
34165
- <div class="setting-part-buttons">
34166
- <button class="amount-button" (click)="hdriRotation = +hdriRotation - 1">
34167
- <co-icon [iconData]="iconService.getIcon(icons.CircleMinusLight)"></co-icon>
34168
- </button>
34169
- <button class="amount-button" (click)="hdriRotation = +hdriRotation + 1">
34170
- <co-icon [iconData]="iconService.getIcon(icons.CirclePlusLight)"></co-icon>
34171
- </button>
33804
+ @if (!blenderPreviewRender) {
33805
+ <div class="render-popup-preview-placeholder">
33806
+ <span>{{ 'PREVIEW' | localize }}</span>
34172
33807
  </div>
34173
- <div class="setting-part-slider">
34174
- <mat-slider class="value" min="0" max="360" step="1" [(ngModel)]="hdriRotation"></mat-slider>
34175
- </div>
34176
- </div>
34177
- <div class="setting-part-container">
34178
- <mat-form-field class="third-width">
34179
- <mat-label [textContent]="'LIGHTS' | localize"></mat-label>
34180
- <input
34181
- [type]="'number'"
34182
- matInput
34183
- [(ngModel)]="lightingExposure"
34184
- (ngModelChange)="lightingExposure = +$event">
34185
- </mat-form-field>
34186
- <div class="setting-part-buttons">
34187
- <button class="amount-button" (click)="lightingExposure = +lightingExposure - 1">
34188
- <co-icon [iconData]="iconService.getIcon(icons.CircleMinusLight)"></co-icon>
34189
- </button>
34190
- <button class="amount-button" (click)="lightingExposure = +lightingExposure + 1">
34191
- <co-icon [iconData]="iconService.getIcon(icons.CirclePlusLight)"></co-icon>
34192
- </button>
34193
- </div>
34194
- <div class="setting-part-slider">
34195
- <mat-slider class="value" min="1" max="10" step="1" [(ngModel)]="lightingExposure"></mat-slider>
34196
- </div>
34197
- </div>
34198
- </div>
34199
33808
  }
34200
- </div>
33809
+ <button class="render-popup-refresh-preview" (click)="createBlenderRender(true)">
33810
+ <co-icon [iconData]="iconService.getIcon(icons.RetryButton)"></co-icon>
33811
+ </button>
33812
+ </div>
33813
+ @if (renderService.blendFilesRender) {
33814
+ <div class="render-popup-dropdown">
33815
+ <div class="toggleable" (click)="toggleRenderSettings()">
33816
+ <p>
33817
+ @if (!showRenderSettings) {
33818
+ <span [textContent]="'RENDER_ADVANCED_SETTINGS_SHOW' | localize"></span>
33819
+ }
33820
+ @if (showRenderSettings) {
33821
+ <span [textContent]="'RENDER_ADVANCED_SETTINGS_HIDE' | localize"></span>
33822
+ }
33823
+ </p>
33824
+ <co-icon [ngClass]="{'icon-rotate': showRenderSettings}"
33825
+ [iconData]="iconService.getIcon(icons.ArrowPointDown)"></co-icon>
33826
+ </div>
33827
+ @if (showRenderSettings) {
33828
+ <div class="advanced-render-settings">
33829
+ <div class="setting-part-container">
33830
+ <mat-form-field
33831
+ class="face-select-form"
33832
+ >
33833
+ <mat-label>{{ "ENVIRONMENT" | localize }}</mat-label>
33834
+ <mat-select [(ngModel)]="selectedRenderScene" (selectionChange)="updateBlenderSceneSettings($event)">
33835
+ @for (scene of sceneList; track scene) {
33836
+ <mat-option
33837
+ [value]="scene">{{ scene.name }}
33838
+ </mat-option>
33839
+ }
33840
+ </mat-select>
33841
+ </mat-form-field>
33842
+ </div>
33843
+ <div class="setting-part-container">
33844
+ <mat-form-field class="third-width">
33845
+ <mat-label [textContent]="'ENVIRONMENT_LIGHT' | localize"></mat-label>
33846
+ <input
33847
+ [type]="'number'"
33848
+ matInput
33849
+ [(ngModel)]="hdriIntensity"
33850
+ (ngModelChange)="hdriIntensity = +$event">
33851
+ </mat-form-field>
33852
+ <div class="setting-part-buttons">
33853
+ <button class="amount-button" (click)="hdriIntensity = +hdriIntensity - 1">
33854
+ <co-icon [iconData]="iconService.getIcon(icons.CircleMinusLight)"></co-icon>
33855
+ </button>
33856
+ <button class="amount-button" (click)="hdriIntensity = +hdriIntensity + 1">
33857
+ <co-icon [iconData]="iconService.getIcon(icons.CirclePlusLight)"></co-icon>
33858
+ </button>
33859
+ </div>
33860
+ <div class="setting-part-slider">
33861
+ <mat-slider class="value" min="1" max="20" step="1" [(ngModel)]="hdriIntensity"></mat-slider>
33862
+ </div>
33863
+ </div>
33864
+ <div class="setting-part-container">
33865
+ <mat-form-field class="third-width">
33866
+ <mat-label [textContent]="'ROTATION' | localize"></mat-label>
33867
+ <input
33868
+ [type]="'number'"
33869
+ matInput
33870
+ [(ngModel)]="hdriRotation"
33871
+ (ngModelChange)="hdriRotation = +$event">
33872
+ </mat-form-field>
33873
+ <div class="setting-part-buttons">
33874
+ <button class="amount-button" (click)="hdriRotation = +hdriRotation - 1">
33875
+ <co-icon [iconData]="iconService.getIcon(icons.CircleMinusLight)"></co-icon>
33876
+ </button>
33877
+ <button class="amount-button" (click)="hdriRotation = +hdriRotation + 1">
33878
+ <co-icon [iconData]="iconService.getIcon(icons.CirclePlusLight)"></co-icon>
33879
+ </button>
33880
+ </div>
33881
+ <div class="setting-part-slider">
33882
+ <mat-slider class="value" min="0" max="360" step="1" [(ngModel)]="hdriRotation"></mat-slider>
33883
+ </div>
33884
+ </div>
33885
+ <div class="setting-part-container">
33886
+ <mat-form-field class="third-width">
33887
+ <mat-label [textContent]="'LIGHTS' | localize"></mat-label>
33888
+ <input
33889
+ [type]="'number'"
33890
+ matInput
33891
+ [(ngModel)]="lightingExposure"
33892
+ (ngModelChange)="lightingExposure = +$event">
33893
+ </mat-form-field>
33894
+ <div class="setting-part-buttons">
33895
+ <button class="amount-button" (click)="lightingExposure = +lightingExposure - 1">
33896
+ <co-icon [iconData]="iconService.getIcon(icons.CircleMinusLight)"></co-icon>
33897
+ </button>
33898
+ <button class="amount-button" (click)="lightingExposure = +lightingExposure + 1">
33899
+ <co-icon [iconData]="iconService.getIcon(icons.CirclePlusLight)"></co-icon>
33900
+ </button>
33901
+ </div>
33902
+ <div class="setting-part-slider">
33903
+ <mat-slider class="value" min="1" max="10" step="1" [(ngModel)]="lightingExposure"></mat-slider>
33904
+ </div>
33905
+ </div>
33906
+ </div>
33907
+ }
33908
+ </div>
34201
33909
  }
34202
- @if (renderService.serverData.renderMode === renderModes.RenderRoom) {
34203
- <div class="render-popup-dropdown">
33910
+ <div class="render-popup-dropdown">
34204
33911
  <mat-form-field class="face-select-form">
34205
- <mat-label>{{ "IMAGE_SIZE" | localize }}</mat-label>
34206
- <mat-select [(ngModel)]="renderService.selectedImageSize">
34207
- @for (size of renderService.imageSizes; track size) {
34208
- <mat-option [value]="size.id">{{ size.name }} {{ size.width }}
34209
- x{{ size.height }}
34210
- </mat-option>
34211
- }
34212
- </mat-select>
33912
+ <mat-label>{{ "IMAGE_SIZE" | localize }}</mat-label>
33913
+ <mat-select [(value)]="selectedImageSize">
33914
+ @for (size of imageSizes; track size) {
33915
+ <mat-option [value]="size">{{ size.name }} {{ size.width }}
33916
+ x{{ size.height }}
33917
+ </mat-option>
33918
+ }
33919
+ </mat-select>
34213
33920
  </mat-form-field>
34214
- </div>
34215
- }
33921
+ </div>
34216
33922
  <div class="render-popup-button-container">
34217
- <button class="render-popup-button photo-button"
34218
- (click)="createBlenderRender()"
34219
- title="{{'MAKE_A_PICTURE' | localize}}"
34220
- [disabled]="disablePictureButton">
34221
- <co-icon [iconData]="iconService.getIcon(icons.CircleCheck)"></co-icon>
34222
- {{ 'MAKE_A_PICTURE' | localize }}
34223
- </button>
34224
- <button
34225
- class="render-popup-button cancel-button"
34226
- (click)="resetBlenderRenderScene()">
34227
- <co-icon [iconData]="iconService.getIcon(icons.CircleXmark)"></co-icon>
34228
- {{ 'CLOSE_PHOTO_MODE' | localize }}
34229
- </button>
33923
+ <button class="render-popup-button photo-button"
33924
+ (click)="createBlenderRender()"
33925
+ title="{{'MAKE_A_PICTURE' | localize}}"
33926
+ [disabled]="disablePictureButton">
33927
+ <co-icon [iconData]="iconService.getIcon(icons.CircleCheck)"></co-icon>
33928
+ {{ 'MAKE_A_PICTURE' | localize }}
33929
+ </button>
33930
+ <button
33931
+ class="render-popup-button cancel-button"
33932
+ (click)="resetBlenderRenderScene()">
33933
+ <co-icon [iconData]="iconService.getIcon(icons.CircleXmark)"></co-icon>
33934
+ {{ 'CLOSE_PHOTO_MODE' | localize }}
33935
+ </button>
34230
33936
  </div>
34231
- </div>
34232
- }
34233
- @if (showCullingErrorDialog) {
34234
- <div class="render-warning">
33937
+ </div>
33938
+ }
33939
+ @if (showCullingErrorDialog) {
33940
+ <div class="render-warning">
34235
33941
  <div class="render-warming-header">
34236
- <h2>{{ 'BLENDER_RENDER_ERROR_TITLE' | localize }}</h2>
34237
- <div class="render-warning-close" (click)="showCullingErrorDialog = false">
34238
- <mat-icon class="homedecorator-material-icons">cancel</mat-icon>
34239
- </div>
33942
+ <h2>{{ 'BLENDER_RENDER_ERROR_TITLE' | localize }}</h2>
33943
+ <div class="render-warning-close" (click)="showCullingErrorDialog = false">
33944
+ <mat-icon class="homedecorator-material-icons">cancel</mat-icon>
33945
+ </div>
34240
33946
  </div>
34241
33947
  <div class="render-warning-body">
34242
- <p>{{ 'BLENDER_RENDER_WARNING_CULLING' | localize }}</p>
33948
+ <p>{{ 'BLENDER_RENDER_WARNING_CULLING' | localize }}</p>
34243
33949
  </div>
34244
33950
  <div class="render-warning-footer">
34245
- <button
34246
- class="render-popup-button cancel-button"
34247
- (click)="showCullingErrorDialog = false">
34248
- <co-icon [iconData]="iconService.getIcon(icons.CircleXmark)"></co-icon>
34249
- {{ 'CLOSE' | localize }}
34250
- </button>
33951
+ <button
33952
+ class="render-popup-button cancel-button"
33953
+ (click)="showCullingErrorDialog = false">
33954
+ <co-icon [iconData]="iconService.getIcon(icons.CircleXmark)"></co-icon>
33955
+ {{ 'CLOSE' | localize }}
33956
+ </button>
34251
33957
  </div>
34252
- </div>
34253
- }
34254
- <rp-render-progress
34255
- [title]="'PREPARE_TO_RENDER' | localize"
34256
- [show]="startUploading"
34257
- >
34258
- </rp-render-progress>
34259
- <button
34260
- #renderButton
34261
- mat-raised-button
34262
- matTooltip="{{'RENDER_TAKE_A_PICTURE' | localize}}"
34263
- [id]="'standalone_render_picture'"
34264
- [class.active]="(
34265
- (renderService.serverData.renderMode === renderService.renderModes.RenderRoom && viewModeService.viewMode === viewModes.WalkThrough) ||
34266
- (renderService.serverData.renderMode === renderService.renderModes.RenderIone))"
34267
- (click)="showRenderForm($event)"
34268
- >
34269
- <mat-icon class="icon homedecorator-material-icons"
34270
- aria-hidden="true">{{ (renderService.currentQueueRenderItem.renderStatus === renderStatus.IsRunning ? 'open_in_browser' : 'photo_camera') }}
34271
- </mat-icon>
34272
- </button>
34273
- </div>
33958
+ </div>
34274
33959
  }
34275
-
34276
- `, isInline: true, styles: [".render-container{position:relative}.render-container .render-popup-container{background:#ffffffb3;padding:10px 25px 25px;border-radius:5px;box-shadow:0 1px 5px #0000001f}.render-container .render-popup-container .render-popup-header{display:flex;justify-content:space-between;font-family:inherit}.render-container .render-popup-container .render-popup-header h3{display:flex;justify-content:space-between}.render-container .render-popup-container .render-popup-header h3 ::ng-deep .renderErrorIcon{width:20px;height:20px;margin-left:20px}.render-container .render-popup-container .render-popup-header h3 ::ng-deep .renderErrorIcon svg,.render-container .render-popup-container .render-popup-header h3 ::ng-deep .renderErrorIcon svg polygon{fill:#dc143c}.render-container .render-popup-container .render-popup-header .close-popup-container{cursor:pointer;border:none;background:none;float:none;height:auto;width:auto}.render-container .render-popup-container .render-popup-button-container{display:flex;justify-content:space-between;font-family:inherit}.render-container .render-popup-container .render-popup-button-container .render-popup-button{float:none;width:100%;max-width:130px;border-radius:3px;cursor:pointer;border:none;display:flex;height:40px;align-items:center;justify-content:space-evenly}.render-container .render-popup-container .render-popup-button-container .render-popup-button ::ng-deep co-icon{display:inline-block;height:18px;width:18px}.render-container .render-popup-container .render-popup-button-container .render-popup-button ::ng-deep co-icon svg path{fill:#fff}.render-container .render-popup-container .render-popup-button-container .photo-button{color:#fff;background-color:#dda73f}.render-container .render-popup-container .render-popup-button-container .cancel-button{color:#fff;background-color:#5b6875}.render-container .render-popup-container .render-popup-preview{background-color:#fff;min-height:150px;min-width:275px;margin:5px 0;position:relative;width:275px;height:150px}.render-container .render-popup-container .render-popup-preview .render-popup-preview-placeholder{background-color:#fff;display:flex;justify-content:space-around;align-items:center;vertical-align:middle;min-height:150px;border:1px solid #ddd;color:#ddd;font-size:14px}.render-container .render-popup-container .render-popup-preview .render-popup-refresh-preview{position:absolute;bottom:0;right:0;cursor:pointer;border-radius:0;border:none;height:30px;width:30px;background-color:#dda73f;color:#fff;margin:0}.render-container .render-popup-container .render-popup-preview .render-popup-refresh-preview ::ng-deep co-icon svg path{fill:#fff}.render-container .render-popup-container .render-popup-dropdown{margin:5px 0;width:100%}.render-container .render-popup-container .render-popup-dropdown .toggleable{cursor:pointer;display:flex;justify-content:right;align-content:center}.render-container .render-popup-container .render-popup-dropdown .toggleable p{padding:0;margin:0;font-size:12px;line-height:30px}.render-container .render-popup-container .render-popup-dropdown .toggleable .icon-rotate{transform:rotate(180deg)}.render-container .render-popup-container .render-popup-dropdown .mat-mdc-form-field{width:100%;font-size:14px}.render-container .render-popup-container .render-popup-dropdown .mat-mdc-form-field ::ng-deep .mat-mdc-form-field-flex{background-color:#fff;color:#000;padding:3px 6px;border:1px solid #ddd}.render-container .render-popup-container .render-popup-dropdown .mat-mdc-form-field ::ng-deep .mat-mdc-form-field-underline{display:none}.render-container .render-popup-container .render-popup-dropdown .mat-mdc-form-field ::ng-deep .mat-mdc-form-field-wrapper{padding-bottom:0}.render-container .render-popup-container .render-popup-dropdown .setting-part-container{display:flex;justify-content:space-between;align-items:center;margin-bottom:5px}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .third-width{width:32%}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .setting-part-buttons .amount-button{float:none;box-sizing:border-box;padding:2px;background:none;cursor:pointer;border:none;width:25px;height:25px;margin:0 5px}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .setting-part-buttons .amount-button co-icon{display:block;width:25px;height:25px}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .setting-part-buttons .amount-button co-icon ::ng-deep svg{fill:#5b6875}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .setting-part-slider .mat-slider-horizontal{min-width:110px;height:28px}.render-container .render-progress{float:left;min-width:50px;border-radius:25px;line-height:50px;text-align:center;padding:0 60px 0 20px;background:#fff;color:#74b77f;font-weight:700;margin:0 -50px 0 0}.render-container .render-input-container{float:right}.render-container .render-input-container input{width:100px;height:24px;margin:5px 0;padding:0 10px;font-size:14px}.render-container button{pointer-events:all;width:50px;height:50px;float:right;border-radius:100%;position:relative;z-index:2;margin-bottom:10px}.render-container button.active{background:#74b77f;color:#fff}.render-container button>*{pointer-events:none}.render-indicators div{position:fixed;width:100px;height:100px}.render-indicators .render-indicator-top-left{left:5vw;top:10vh;border-left:10px solid #dda73f;border-top:10px solid #dda73f;border-top-left-radius:20px}.render-indicators .render-indicator-top-right{right:5vw;top:10vh;border-right:10px solid #dda73f;border-top:10px solid #dda73f;border-top-right-radius:20px}.render-indicators .render-indicator-bottom-left{left:5vw;bottom:5vh;border-left:10px solid #dda73f;border-bottom:10px solid #dda73f;border-bottom-left-radius:20px}.render-indicators .render-indicator-bottom-right{right:5vw;bottom:5vh;border-right:10px solid #dda73f;border-bottom:10px solid #dda73f;border-bottom-right-radius:20px}.render-warning{width:500px;position:fixed;top:20%;left:calc(50% - 250px);border-radius:15px;box-sizing:border-box;background-color:#fff;box-shadow:1px 0 20px #0000001f}.render-warning .render-warming-header{display:flex;justify-content:space-between;border-bottom:1px solid #c5c3c6;padding:20px 20px 10px;align-items:center}.render-warning .render-warming-header h2{padding:0;margin:0}.render-warning .render-warming-header .render-warning-close mat-icon{fill:#c5c3c6;color:#c5c3c6;cursor:pointer;transition:all .2s ease}.render-warning .render-warming-header .render-warning-close:hover mat-icon{fill:#46494c;color:#46494c}.render-warning .render-warning-body{padding:10px 20px}.render-warning .render-warning-footer{display:flex;justify-content:center;padding:0 20px 10px}.render-warning .render-warning-footer .render-popup-button{float:none;width:110px;border-radius:3px;cursor:pointer;border:none;display:flex;height:40px;align-items:center;justify-content:space-evenly;color:#fff;background-color:#5b6875}.render-warning .render-warning-footer .render-popup-button ::ng-deep co-icon{display:inline-block;height:18px;width:18px}.render-warning .render-warning-footer .render-popup-button ::ng-deep co-icon svg path{fill:#fff}\n"], dependencies: [{ kind: "directive", type: i2$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: i4$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: i3$2.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i2$3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$3.MatLabel, selector: "mat-label" }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i13.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i13.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i5.IconComponent, selector: "co-icon", inputs: ["icon", "iconData"] }, { kind: "component", type: i4$2.MatSlider, selector: "mat-slider", inputs: ["disabled", "discrete", "showTickMarks", "min", "color", "disableRipple", "max", "step", "displayWith"], exportAs: ["matSlider"] }, { kind: "component", type: RenderProgressComponent, selector: "rp-render-progress", inputs: ["show", "title"] }, { kind: "pipe", type: LocalizePipe, name: "localize" }] }); }
33960
+ <button
33961
+ #renderButton
33962
+ mat-raised-button
33963
+ matTooltip="{{'RENDER_TAKE_A_PICTURE' | localize}}"
33964
+ [id]="'standalone_render_picture'"
33965
+ [class.active]="viewModeService.viewMode === viewModes.WalkThrough"
33966
+ (click)="showRenderForm($event)">
33967
+ <mat-icon class="icon homedecorator-material-icons"
33968
+ aria-hidden="true">{{ 'photo_camera' }}
33969
+ </mat-icon>
33970
+ </button>
33971
+ </div>
33972
+ `, isInline: true, styles: [".render-container{position:relative}.render-container .render-popup-container{background:#ffffffb3;padding:10px 25px 25px;border-radius:5px;box-shadow:0 1px 5px #0000001f}.render-container .render-popup-container .render-popup-header{display:flex;justify-content:space-between;font-family:inherit}.render-container .render-popup-container .render-popup-header h3{display:flex;justify-content:space-between}.render-container .render-popup-container .render-popup-header h3 ::ng-deep .renderErrorIcon{width:20px;height:20px;margin-left:20px}.render-container .render-popup-container .render-popup-header h3 ::ng-deep .renderErrorIcon svg,.render-container .render-popup-container .render-popup-header h3 ::ng-deep .renderErrorIcon svg polygon{fill:#dc143c}.render-container .render-popup-container .render-popup-header .close-popup-container{cursor:pointer;border:none;background:none;float:none;height:auto;width:auto}.render-container .render-popup-container .render-popup-button-container{display:flex;justify-content:space-between;font-family:inherit}.render-container .render-popup-container .render-popup-button-container .render-popup-button{float:none;width:100%;max-width:130px;border-radius:3px;cursor:pointer;border:none;display:flex;height:40px;align-items:center;justify-content:space-evenly}.render-container .render-popup-container .render-popup-button-container .render-popup-button ::ng-deep co-icon{display:inline-block;height:18px;width:18px}.render-container .render-popup-container .render-popup-button-container .render-popup-button ::ng-deep co-icon svg path{fill:#fff}.render-container .render-popup-container .render-popup-button-container .photo-button{color:#fff;background-color:#dda73f}.render-container .render-popup-container .render-popup-button-container .cancel-button{color:#fff;background-color:#5b6875}.render-container .render-popup-container .render-popup-preview{background-color:#fff;min-height:150px;min-width:275px;margin:5px 0;position:relative;width:275px;height:150px}.render-container .render-popup-container .render-popup-preview .render-popup-preview-placeholder{background-color:#fff;display:flex;justify-content:space-around;align-items:center;vertical-align:middle;min-height:150px;border:1px solid #ddd;color:#ddd;font-size:14px}.render-container .render-popup-container .render-popup-preview .render-popup-refresh-preview{position:absolute;bottom:0;right:0;cursor:pointer;border-radius:0;border:none;height:30px;width:30px;background-color:#dda73f;color:#fff;margin:0}.render-container .render-popup-container .render-popup-preview .render-popup-refresh-preview ::ng-deep co-icon svg path{fill:#fff}.render-container .render-popup-container .render-popup-dropdown{margin:5px 0;width:100%}.render-container .render-popup-container .render-popup-dropdown .toggleable{cursor:pointer;display:flex;justify-content:right;align-content:center}.render-container .render-popup-container .render-popup-dropdown .toggleable p{padding:0;margin:0;font-size:12px;line-height:30px}.render-container .render-popup-container .render-popup-dropdown .toggleable .icon-rotate{transform:rotate(180deg)}.render-container .render-popup-container .render-popup-dropdown .mat-mdc-form-field{width:100%;font-size:14px}.render-container .render-popup-container .render-popup-dropdown .mat-mdc-form-field ::ng-deep .mat-mdc-form-field-flex{background-color:#fff;color:#000;padding:3px 6px;border:1px solid #ddd}.render-container .render-popup-container .render-popup-dropdown .mat-mdc-form-field ::ng-deep .mat-mdc-form-field-underline{display:none}.render-container .render-popup-container .render-popup-dropdown .mat-mdc-form-field ::ng-deep .mat-mdc-form-field-wrapper{padding-bottom:0}.render-container .render-popup-container .render-popup-dropdown .setting-part-container{display:flex;justify-content:space-between;align-items:center;margin-bottom:5px}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .third-width{width:32%}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .setting-part-buttons .amount-button{float:none;box-sizing:border-box;padding:2px;background:none;cursor:pointer;border:none;width:25px;height:25px;margin:0 5px}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .setting-part-buttons .amount-button co-icon{display:block;width:25px;height:25px}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .setting-part-buttons .amount-button co-icon ::ng-deep svg{fill:#5b6875}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .setting-part-slider .mat-slider-horizontal{min-width:110px;height:28px}.render-container .render-progress{float:left;min-width:50px;border-radius:25px;line-height:50px;text-align:center;padding:0 60px 0 20px;background:#fff;color:#74b77f;font-weight:700;margin:0 -50px 0 0}.render-container .render-input-container{float:right}.render-container .render-input-container input{width:100px;height:24px;margin:5px 0;padding:0 10px;font-size:14px}.render-container button{pointer-events:all;width:50px;height:50px;float:right;border-radius:100%;position:relative;z-index:2;margin-bottom:10px}.render-container button.active{background:#74b77f;color:#fff}.render-container button>*{pointer-events:none}.render-indicators div{position:fixed;width:100px;height:100px}.render-indicators .render-indicator-top-left{left:5vw;top:10vh;border-left:10px solid #dda73f;border-top:10px solid #dda73f;border-top-left-radius:20px}.render-indicators .render-indicator-top-right{right:5vw;top:10vh;border-right:10px solid #dda73f;border-top:10px solid #dda73f;border-top-right-radius:20px}.render-indicators .render-indicator-bottom-left{left:5vw;bottom:5vh;border-left:10px solid #dda73f;border-bottom:10px solid #dda73f;border-bottom-left-radius:20px}.render-indicators .render-indicator-bottom-right{right:5vw;bottom:5vh;border-right:10px solid #dda73f;border-bottom:10px solid #dda73f;border-bottom-right-radius:20px}.render-warning{width:500px;position:fixed;top:20%;left:calc(50% - 250px);border-radius:15px;box-sizing:border-box;background-color:#fff;box-shadow:1px 0 20px #0000001f}.render-warning .render-warming-header{display:flex;justify-content:space-between;border-bottom:1px solid #c5c3c6;padding:20px 20px 10px;align-items:center}.render-warning .render-warming-header h2{padding:0;margin:0}.render-warning .render-warming-header .render-warning-close mat-icon{fill:#c5c3c6;color:#c5c3c6;cursor:pointer;transition:all .2s ease}.render-warning .render-warming-header .render-warning-close:hover mat-icon{fill:#46494c;color:#46494c}.render-warning .render-warning-body{padding:10px 20px}.render-warning .render-warning-footer{display:flex;justify-content:center;padding:0 20px 10px}.render-warning .render-warning-footer .render-popup-button{float:none;width:110px;border-radius:3px;cursor:pointer;border:none;display:flex;height:40px;align-items:center;justify-content:space-evenly;color:#fff;background-color:#5b6875}.render-warning .render-warning-footer .render-popup-button ::ng-deep co-icon{display:inline-block;height:18px;width:18px}.render-warning .render-warning-footer .render-popup-button ::ng-deep co-icon svg path{fill:#fff}\n"], dependencies: [{ kind: "directive", type: i2$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: i4$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: i3$2.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i2$3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$3.MatLabel, selector: "mat-label" }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i13.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i13.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i5.IconComponent, selector: "co-icon", inputs: ["icon", "iconData"] }, { kind: "component", type: i4$2.MatSlider, selector: "mat-slider", inputs: ["disabled", "discrete", "showTickMarks", "min", "color", "disableRipple", "max", "step", "displayWith"], exportAs: ["matSlider"] }, { kind: "component", type: RenderProgressComponent, selector: "rp-render-progress" }, { kind: "pipe", type: LocalizePipe, name: "localize" }] }); }
34277
33973
  }
34278
33974
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: RenderControlsComponent, decorators: [{
34279
33975
  type: Component,
34280
33976
  args: [{ selector: 'rp-render-controls', template: `
34281
- @if (renderService.serverData && renderService.serverData.renderMode !== renderService.renderModes.RenderShop) {
34282
- <div class="render-container"
34283
- >
34284
- @if (renderService.currentQueueRenderItem.renderStatus === renderStatus.IsRunning || renderService.currentQueueRenderItem.renderStatus === renderStatus.IsSuccess) {
34285
- <div class="render-progress"
34286
- >
34287
- {{ (renderService.currentQueueRenderItem.renderStatus === renderStatus.IsSuccess && renderService.currentQueueRenderItem.renderProgress === 100 ? "RENDER_READY" : "") | localize }}
34288
- {{ (renderService.currentQueueRenderItem.renderStatus === renderStatus.IsSuccess && renderService.currentQueueRenderItem.renderProgress !== 100 ? "RENDER_STOPPED" : "") | localize }}
34289
- {{ (renderService.currentQueueRenderItem.renderStatus === renderStatus.IsRunning) ? renderService.currentQueueRenderItem.renderProgress + "%" : "" }}
34290
- </div>
34291
- }
34292
- <!-- the Yellow render indicators -->
34293
- @if (inPictureMode) {
34294
- <div class="render-indicators">
34295
- <div class="render-indicator-top-left"></div>
34296
- <div class="render-indicator-top-right"></div>
34297
- <div class="render-indicator-bottom-left"></div>
34298
- <div class="render-indicator-bottom-right"></div>
34299
- </div>
34300
- }
34301
- @if (inPictureMode) {
34302
- <div class="render-popup-container">
34303
- <div class="render-popup-header">
34304
- <h3>
34305
- <span>{{ 'PICTURE_MODE' | localize }}</span>
34306
- @if (hasError) {
34307
- <co-icon class="renderErrorIcon" [iconData]="iconService.getIcon(icons.TriangleExclamation)"
34308
- [matTooltip]="'BLENDER_RENDER_ERROR' | localize"></co-icon>
34309
- }
34310
- </h3>
34311
- <button
34312
- class="close-popup-container"
34313
- (click)="resetBlenderRenderScene()">
34314
- <co-icon [iconData]="iconService.getIcon(icons.Cross)"></co-icon>
34315
- </button>
34316
- </div>
34317
- <div class="render-popup-preview">
34318
- @if (blenderPreviewRender) {
34319
- <img [src]="blenderPreviewRender" alt="">
34320
- }
34321
- @if (!blenderPreviewRender) {
34322
- <div class="render-popup-preview-placeholder">
34323
- <span>{{ 'PREVIEW' | localize }}</span>
34324
- </div>
34325
- }
34326
- <button
34327
- class="render-popup-refresh-preview"
34328
- (click)="createPreviewRender()"
34329
- >
34330
- <co-icon [iconData]="iconService.getIcon(icons.RetryButton)"></co-icon>
34331
- </button>
34332
- </div>
34333
- @if (renderService.blendFilesRender) {
34334
- <div class="render-popup-dropdown">
34335
- <div class="toggleable" (click)="toggleRenderSettings()">
34336
- <p>
34337
- @if (!showRenderSettings) {
34338
- <span [textContent]="'RENDER_ADVANCED_SETTINGS_SHOW' | localize"></span>
34339
- }
34340
- @if (showRenderSettings) {
34341
- <span [textContent]="'RENDER_ADVANCED_SETTINGS_HIDE' | localize"></span>
34342
- }
34343
- </p>
34344
- <co-icon [ngClass]="{'icon-rotate': showRenderSettings}"
34345
- [iconData]="iconService.getIcon(icons.ArrowPointDown)"></co-icon>
34346
- </div>
34347
- @if (showRenderSettings) {
34348
- <div class="advanced-render-settings">
34349
- <div class="setting-part-container">
34350
- @if (renderService.serverData.renderMode === renderModes.RenderRoom) {
34351
- <mat-form-field
34352
- class="face-select-form"
34353
- >
34354
- <mat-label>{{ "ENVIRONMENT" | localize }}</mat-label>
34355
- <mat-select [(ngModel)]="selectedRenderScene" (selectionChange)="updateBlenderSceneSettings($event)">
34356
- @for (scene of sceneList; track scene) {
34357
- <mat-option
34358
- [value]="scene">{{ scene.name }}
34359
- </mat-option>
34360
- }
34361
- </mat-select>
34362
- </mat-form-field>
33977
+ <div class="render-container">
33978
+ @if (startUploading) {
33979
+ <rp-render-progress></rp-render-progress>
33980
+ }
33981
+ <!-- the Yellow render indicators -->
33982
+ @if (inPictureMode) {
33983
+ <div class="render-indicators">
33984
+ <div class="render-indicator-top-left"></div>
33985
+ <div class="render-indicator-top-right"></div>
33986
+ <div class="render-indicator-bottom-left"></div>
33987
+ <div class="render-indicator-bottom-right"></div>
33988
+ </div>
33989
+ <div class="render-popup-container">
33990
+ <div class="render-popup-header">
33991
+ <h3>
33992
+ <span>{{ 'PICTURE_MODE' | localize }}</span>
33993
+ @if (hasError) {
33994
+ <co-icon class="renderErrorIcon" [iconData]="iconService.getIcon(icons.TriangleExclamation)"
33995
+ [matTooltip]="'BLENDER_RENDER_ERROR' | localize"></co-icon>
33996
+ }
33997
+ </h3>
33998
+ <button
33999
+ class="close-popup-container"
34000
+ (click)="resetBlenderRenderScene()">
34001
+ <co-icon [iconData]="iconService.getIcon(icons.Cross)"></co-icon>
34002
+ </button>
34003
+ </div>
34004
+ <div class="render-popup-preview">
34005
+ @if (blenderPreviewRender) {
34006
+ <img [src]="blenderPreviewRender" alt="">
34363
34007
  }
34364
- </div>
34365
- <div class="setting-part-container">
34366
- <mat-form-field class="third-width">
34367
- <mat-label [textContent]="'ENVIRONMENT_LIGHT' | localize"></mat-label>
34368
- <input
34369
- [type]="'number'"
34370
- matInput
34371
- [(ngModel)]="hdriIntensity"
34372
- (ngModelChange)="hdriIntensity = +$event">
34373
- </mat-form-field>
34374
- <div class="setting-part-buttons">
34375
- <button class="amount-button" (click)="hdriIntensity = +hdriIntensity - 1">
34376
- <co-icon [iconData]="iconService.getIcon(icons.CircleMinusLight)"></co-icon>
34377
- </button>
34378
- <button class="amount-button" (click)="hdriIntensity = +hdriIntensity + 1">
34379
- <co-icon [iconData]="iconService.getIcon(icons.CirclePlusLight)"></co-icon>
34380
- </button>
34381
- </div>
34382
- <div class="setting-part-slider">
34383
- <mat-slider class="value" min="1" max="20" step="1" [(ngModel)]="hdriIntensity"></mat-slider>
34384
- </div>
34385
- </div>
34386
- <div class="setting-part-container">
34387
- <mat-form-field class="third-width">
34388
- <mat-label [textContent]="'ROTATION' | localize"></mat-label>
34389
- <input
34390
- [type]="'number'"
34391
- matInput
34392
- [(ngModel)]="hdriRotation"
34393
- (ngModelChange)="hdriRotation = +$event">
34394
- </mat-form-field>
34395
- <div class="setting-part-buttons">
34396
- <button class="amount-button" (click)="hdriRotation = +hdriRotation - 1">
34397
- <co-icon [iconData]="iconService.getIcon(icons.CircleMinusLight)"></co-icon>
34398
- </button>
34399
- <button class="amount-button" (click)="hdriRotation = +hdriRotation + 1">
34400
- <co-icon [iconData]="iconService.getIcon(icons.CirclePlusLight)"></co-icon>
34401
- </button>
34008
+ @if (!blenderPreviewRender) {
34009
+ <div class="render-popup-preview-placeholder">
34010
+ <span>{{ 'PREVIEW' | localize }}</span>
34402
34011
  </div>
34403
- <div class="setting-part-slider">
34404
- <mat-slider class="value" min="0" max="360" step="1" [(ngModel)]="hdriRotation"></mat-slider>
34405
- </div>
34406
- </div>
34407
- <div class="setting-part-container">
34408
- <mat-form-field class="third-width">
34409
- <mat-label [textContent]="'LIGHTS' | localize"></mat-label>
34410
- <input
34411
- [type]="'number'"
34412
- matInput
34413
- [(ngModel)]="lightingExposure"
34414
- (ngModelChange)="lightingExposure = +$event">
34415
- </mat-form-field>
34416
- <div class="setting-part-buttons">
34417
- <button class="amount-button" (click)="lightingExposure = +lightingExposure - 1">
34418
- <co-icon [iconData]="iconService.getIcon(icons.CircleMinusLight)"></co-icon>
34419
- </button>
34420
- <button class="amount-button" (click)="lightingExposure = +lightingExposure + 1">
34421
- <co-icon [iconData]="iconService.getIcon(icons.CirclePlusLight)"></co-icon>
34422
- </button>
34423
- </div>
34424
- <div class="setting-part-slider">
34425
- <mat-slider class="value" min="1" max="10" step="1" [(ngModel)]="lightingExposure"></mat-slider>
34426
- </div>
34427
- </div>
34428
- </div>
34429
34012
  }
34430
- </div>
34013
+ <button class="render-popup-refresh-preview" (click)="createBlenderRender(true)">
34014
+ <co-icon [iconData]="iconService.getIcon(icons.RetryButton)"></co-icon>
34015
+ </button>
34016
+ </div>
34017
+ @if (renderService.blendFilesRender) {
34018
+ <div class="render-popup-dropdown">
34019
+ <div class="toggleable" (click)="toggleRenderSettings()">
34020
+ <p>
34021
+ @if (!showRenderSettings) {
34022
+ <span [textContent]="'RENDER_ADVANCED_SETTINGS_SHOW' | localize"></span>
34023
+ }
34024
+ @if (showRenderSettings) {
34025
+ <span [textContent]="'RENDER_ADVANCED_SETTINGS_HIDE' | localize"></span>
34026
+ }
34027
+ </p>
34028
+ <co-icon [ngClass]="{'icon-rotate': showRenderSettings}"
34029
+ [iconData]="iconService.getIcon(icons.ArrowPointDown)"></co-icon>
34030
+ </div>
34031
+ @if (showRenderSettings) {
34032
+ <div class="advanced-render-settings">
34033
+ <div class="setting-part-container">
34034
+ <mat-form-field
34035
+ class="face-select-form"
34036
+ >
34037
+ <mat-label>{{ "ENVIRONMENT" | localize }}</mat-label>
34038
+ <mat-select [(ngModel)]="selectedRenderScene" (selectionChange)="updateBlenderSceneSettings($event)">
34039
+ @for (scene of sceneList; track scene) {
34040
+ <mat-option
34041
+ [value]="scene">{{ scene.name }}
34042
+ </mat-option>
34043
+ }
34044
+ </mat-select>
34045
+ </mat-form-field>
34046
+ </div>
34047
+ <div class="setting-part-container">
34048
+ <mat-form-field class="third-width">
34049
+ <mat-label [textContent]="'ENVIRONMENT_LIGHT' | localize"></mat-label>
34050
+ <input
34051
+ [type]="'number'"
34052
+ matInput
34053
+ [(ngModel)]="hdriIntensity"
34054
+ (ngModelChange)="hdriIntensity = +$event">
34055
+ </mat-form-field>
34056
+ <div class="setting-part-buttons">
34057
+ <button class="amount-button" (click)="hdriIntensity = +hdriIntensity - 1">
34058
+ <co-icon [iconData]="iconService.getIcon(icons.CircleMinusLight)"></co-icon>
34059
+ </button>
34060
+ <button class="amount-button" (click)="hdriIntensity = +hdriIntensity + 1">
34061
+ <co-icon [iconData]="iconService.getIcon(icons.CirclePlusLight)"></co-icon>
34062
+ </button>
34063
+ </div>
34064
+ <div class="setting-part-slider">
34065
+ <mat-slider class="value" min="1" max="20" step="1" [(ngModel)]="hdriIntensity"></mat-slider>
34066
+ </div>
34067
+ </div>
34068
+ <div class="setting-part-container">
34069
+ <mat-form-field class="third-width">
34070
+ <mat-label [textContent]="'ROTATION' | localize"></mat-label>
34071
+ <input
34072
+ [type]="'number'"
34073
+ matInput
34074
+ [(ngModel)]="hdriRotation"
34075
+ (ngModelChange)="hdriRotation = +$event">
34076
+ </mat-form-field>
34077
+ <div class="setting-part-buttons">
34078
+ <button class="amount-button" (click)="hdriRotation = +hdriRotation - 1">
34079
+ <co-icon [iconData]="iconService.getIcon(icons.CircleMinusLight)"></co-icon>
34080
+ </button>
34081
+ <button class="amount-button" (click)="hdriRotation = +hdriRotation + 1">
34082
+ <co-icon [iconData]="iconService.getIcon(icons.CirclePlusLight)"></co-icon>
34083
+ </button>
34084
+ </div>
34085
+ <div class="setting-part-slider">
34086
+ <mat-slider class="value" min="0" max="360" step="1" [(ngModel)]="hdriRotation"></mat-slider>
34087
+ </div>
34088
+ </div>
34089
+ <div class="setting-part-container">
34090
+ <mat-form-field class="third-width">
34091
+ <mat-label [textContent]="'LIGHTS' | localize"></mat-label>
34092
+ <input
34093
+ [type]="'number'"
34094
+ matInput
34095
+ [(ngModel)]="lightingExposure"
34096
+ (ngModelChange)="lightingExposure = +$event">
34097
+ </mat-form-field>
34098
+ <div class="setting-part-buttons">
34099
+ <button class="amount-button" (click)="lightingExposure = +lightingExposure - 1">
34100
+ <co-icon [iconData]="iconService.getIcon(icons.CircleMinusLight)"></co-icon>
34101
+ </button>
34102
+ <button class="amount-button" (click)="lightingExposure = +lightingExposure + 1">
34103
+ <co-icon [iconData]="iconService.getIcon(icons.CirclePlusLight)"></co-icon>
34104
+ </button>
34105
+ </div>
34106
+ <div class="setting-part-slider">
34107
+ <mat-slider class="value" min="1" max="10" step="1" [(ngModel)]="lightingExposure"></mat-slider>
34108
+ </div>
34109
+ </div>
34110
+ </div>
34111
+ }
34112
+ </div>
34431
34113
  }
34432
- @if (renderService.serverData.renderMode === renderModes.RenderRoom) {
34433
- <div class="render-popup-dropdown">
34114
+ <div class="render-popup-dropdown">
34434
34115
  <mat-form-field class="face-select-form">
34435
- <mat-label>{{ "IMAGE_SIZE" | localize }}</mat-label>
34436
- <mat-select [(ngModel)]="renderService.selectedImageSize">
34437
- @for (size of renderService.imageSizes; track size) {
34438
- <mat-option [value]="size.id">{{ size.name }} {{ size.width }}
34439
- x{{ size.height }}
34440
- </mat-option>
34441
- }
34442
- </mat-select>
34116
+ <mat-label>{{ "IMAGE_SIZE" | localize }}</mat-label>
34117
+ <mat-select [(value)]="selectedImageSize">
34118
+ @for (size of imageSizes; track size) {
34119
+ <mat-option [value]="size">{{ size.name }} {{ size.width }}
34120
+ x{{ size.height }}
34121
+ </mat-option>
34122
+ }
34123
+ </mat-select>
34443
34124
  </mat-form-field>
34444
- </div>
34445
- }
34125
+ </div>
34446
34126
  <div class="render-popup-button-container">
34447
- <button class="render-popup-button photo-button"
34448
- (click)="createBlenderRender()"
34449
- title="{{'MAKE_A_PICTURE' | localize}}"
34450
- [disabled]="disablePictureButton">
34451
- <co-icon [iconData]="iconService.getIcon(icons.CircleCheck)"></co-icon>
34452
- {{ 'MAKE_A_PICTURE' | localize }}
34453
- </button>
34454
- <button
34455
- class="render-popup-button cancel-button"
34456
- (click)="resetBlenderRenderScene()">
34457
- <co-icon [iconData]="iconService.getIcon(icons.CircleXmark)"></co-icon>
34458
- {{ 'CLOSE_PHOTO_MODE' | localize }}
34459
- </button>
34127
+ <button class="render-popup-button photo-button"
34128
+ (click)="createBlenderRender()"
34129
+ title="{{'MAKE_A_PICTURE' | localize}}"
34130
+ [disabled]="disablePictureButton">
34131
+ <co-icon [iconData]="iconService.getIcon(icons.CircleCheck)"></co-icon>
34132
+ {{ 'MAKE_A_PICTURE' | localize }}
34133
+ </button>
34134
+ <button
34135
+ class="render-popup-button cancel-button"
34136
+ (click)="resetBlenderRenderScene()">
34137
+ <co-icon [iconData]="iconService.getIcon(icons.CircleXmark)"></co-icon>
34138
+ {{ 'CLOSE_PHOTO_MODE' | localize }}
34139
+ </button>
34460
34140
  </div>
34461
- </div>
34462
- }
34463
- @if (showCullingErrorDialog) {
34464
- <div class="render-warning">
34141
+ </div>
34142
+ }
34143
+ @if (showCullingErrorDialog) {
34144
+ <div class="render-warning">
34465
34145
  <div class="render-warming-header">
34466
- <h2>{{ 'BLENDER_RENDER_ERROR_TITLE' | localize }}</h2>
34467
- <div class="render-warning-close" (click)="showCullingErrorDialog = false">
34468
- <mat-icon class="homedecorator-material-icons">cancel</mat-icon>
34469
- </div>
34146
+ <h2>{{ 'BLENDER_RENDER_ERROR_TITLE' | localize }}</h2>
34147
+ <div class="render-warning-close" (click)="showCullingErrorDialog = false">
34148
+ <mat-icon class="homedecorator-material-icons">cancel</mat-icon>
34149
+ </div>
34470
34150
  </div>
34471
34151
  <div class="render-warning-body">
34472
- <p>{{ 'BLENDER_RENDER_WARNING_CULLING' | localize }}</p>
34152
+ <p>{{ 'BLENDER_RENDER_WARNING_CULLING' | localize }}</p>
34473
34153
  </div>
34474
34154
  <div class="render-warning-footer">
34475
- <button
34476
- class="render-popup-button cancel-button"
34477
- (click)="showCullingErrorDialog = false">
34478
- <co-icon [iconData]="iconService.getIcon(icons.CircleXmark)"></co-icon>
34479
- {{ 'CLOSE' | localize }}
34480
- </button>
34155
+ <button
34156
+ class="render-popup-button cancel-button"
34157
+ (click)="showCullingErrorDialog = false">
34158
+ <co-icon [iconData]="iconService.getIcon(icons.CircleXmark)"></co-icon>
34159
+ {{ 'CLOSE' | localize }}
34160
+ </button>
34481
34161
  </div>
34482
- </div>
34483
- }
34484
- <rp-render-progress
34485
- [title]="'PREPARE_TO_RENDER' | localize"
34486
- [show]="startUploading"
34487
- >
34488
- </rp-render-progress>
34489
- <button
34490
- #renderButton
34491
- mat-raised-button
34492
- matTooltip="{{'RENDER_TAKE_A_PICTURE' | localize}}"
34493
- [id]="'standalone_render_picture'"
34494
- [class.active]="(
34495
- (renderService.serverData.renderMode === renderService.renderModes.RenderRoom && viewModeService.viewMode === viewModes.WalkThrough) ||
34496
- (renderService.serverData.renderMode === renderService.renderModes.RenderIone))"
34497
- (click)="showRenderForm($event)"
34498
- >
34499
- <mat-icon class="icon homedecorator-material-icons"
34500
- aria-hidden="true">{{ (renderService.currentQueueRenderItem.renderStatus === renderStatus.IsRunning ? 'open_in_browser' : 'photo_camera') }}
34501
- </mat-icon>
34502
- </button>
34503
- </div>
34162
+ </div>
34504
34163
  }
34505
-
34506
- `, standalone: false, styles: [".render-container{position:relative}.render-container .render-popup-container{background:#ffffffb3;padding:10px 25px 25px;border-radius:5px;box-shadow:0 1px 5px #0000001f}.render-container .render-popup-container .render-popup-header{display:flex;justify-content:space-between;font-family:inherit}.render-container .render-popup-container .render-popup-header h3{display:flex;justify-content:space-between}.render-container .render-popup-container .render-popup-header h3 ::ng-deep .renderErrorIcon{width:20px;height:20px;margin-left:20px}.render-container .render-popup-container .render-popup-header h3 ::ng-deep .renderErrorIcon svg,.render-container .render-popup-container .render-popup-header h3 ::ng-deep .renderErrorIcon svg polygon{fill:#dc143c}.render-container .render-popup-container .render-popup-header .close-popup-container{cursor:pointer;border:none;background:none;float:none;height:auto;width:auto}.render-container .render-popup-container .render-popup-button-container{display:flex;justify-content:space-between;font-family:inherit}.render-container .render-popup-container .render-popup-button-container .render-popup-button{float:none;width:100%;max-width:130px;border-radius:3px;cursor:pointer;border:none;display:flex;height:40px;align-items:center;justify-content:space-evenly}.render-container .render-popup-container .render-popup-button-container .render-popup-button ::ng-deep co-icon{display:inline-block;height:18px;width:18px}.render-container .render-popup-container .render-popup-button-container .render-popup-button ::ng-deep co-icon svg path{fill:#fff}.render-container .render-popup-container .render-popup-button-container .photo-button{color:#fff;background-color:#dda73f}.render-container .render-popup-container .render-popup-button-container .cancel-button{color:#fff;background-color:#5b6875}.render-container .render-popup-container .render-popup-preview{background-color:#fff;min-height:150px;min-width:275px;margin:5px 0;position:relative;width:275px;height:150px}.render-container .render-popup-container .render-popup-preview .render-popup-preview-placeholder{background-color:#fff;display:flex;justify-content:space-around;align-items:center;vertical-align:middle;min-height:150px;border:1px solid #ddd;color:#ddd;font-size:14px}.render-container .render-popup-container .render-popup-preview .render-popup-refresh-preview{position:absolute;bottom:0;right:0;cursor:pointer;border-radius:0;border:none;height:30px;width:30px;background-color:#dda73f;color:#fff;margin:0}.render-container .render-popup-container .render-popup-preview .render-popup-refresh-preview ::ng-deep co-icon svg path{fill:#fff}.render-container .render-popup-container .render-popup-dropdown{margin:5px 0;width:100%}.render-container .render-popup-container .render-popup-dropdown .toggleable{cursor:pointer;display:flex;justify-content:right;align-content:center}.render-container .render-popup-container .render-popup-dropdown .toggleable p{padding:0;margin:0;font-size:12px;line-height:30px}.render-container .render-popup-container .render-popup-dropdown .toggleable .icon-rotate{transform:rotate(180deg)}.render-container .render-popup-container .render-popup-dropdown .mat-mdc-form-field{width:100%;font-size:14px}.render-container .render-popup-container .render-popup-dropdown .mat-mdc-form-field ::ng-deep .mat-mdc-form-field-flex{background-color:#fff;color:#000;padding:3px 6px;border:1px solid #ddd}.render-container .render-popup-container .render-popup-dropdown .mat-mdc-form-field ::ng-deep .mat-mdc-form-field-underline{display:none}.render-container .render-popup-container .render-popup-dropdown .mat-mdc-form-field ::ng-deep .mat-mdc-form-field-wrapper{padding-bottom:0}.render-container .render-popup-container .render-popup-dropdown .setting-part-container{display:flex;justify-content:space-between;align-items:center;margin-bottom:5px}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .third-width{width:32%}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .setting-part-buttons .amount-button{float:none;box-sizing:border-box;padding:2px;background:none;cursor:pointer;border:none;width:25px;height:25px;margin:0 5px}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .setting-part-buttons .amount-button co-icon{display:block;width:25px;height:25px}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .setting-part-buttons .amount-button co-icon ::ng-deep svg{fill:#5b6875}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .setting-part-slider .mat-slider-horizontal{min-width:110px;height:28px}.render-container .render-progress{float:left;min-width:50px;border-radius:25px;line-height:50px;text-align:center;padding:0 60px 0 20px;background:#fff;color:#74b77f;font-weight:700;margin:0 -50px 0 0}.render-container .render-input-container{float:right}.render-container .render-input-container input{width:100px;height:24px;margin:5px 0;padding:0 10px;font-size:14px}.render-container button{pointer-events:all;width:50px;height:50px;float:right;border-radius:100%;position:relative;z-index:2;margin-bottom:10px}.render-container button.active{background:#74b77f;color:#fff}.render-container button>*{pointer-events:none}.render-indicators div{position:fixed;width:100px;height:100px}.render-indicators .render-indicator-top-left{left:5vw;top:10vh;border-left:10px solid #dda73f;border-top:10px solid #dda73f;border-top-left-radius:20px}.render-indicators .render-indicator-top-right{right:5vw;top:10vh;border-right:10px solid #dda73f;border-top:10px solid #dda73f;border-top-right-radius:20px}.render-indicators .render-indicator-bottom-left{left:5vw;bottom:5vh;border-left:10px solid #dda73f;border-bottom:10px solid #dda73f;border-bottom-left-radius:20px}.render-indicators .render-indicator-bottom-right{right:5vw;bottom:5vh;border-right:10px solid #dda73f;border-bottom:10px solid #dda73f;border-bottom-right-radius:20px}.render-warning{width:500px;position:fixed;top:20%;left:calc(50% - 250px);border-radius:15px;box-sizing:border-box;background-color:#fff;box-shadow:1px 0 20px #0000001f}.render-warning .render-warming-header{display:flex;justify-content:space-between;border-bottom:1px solid #c5c3c6;padding:20px 20px 10px;align-items:center}.render-warning .render-warming-header h2{padding:0;margin:0}.render-warning .render-warming-header .render-warning-close mat-icon{fill:#c5c3c6;color:#c5c3c6;cursor:pointer;transition:all .2s ease}.render-warning .render-warming-header .render-warning-close:hover mat-icon{fill:#46494c;color:#46494c}.render-warning .render-warning-body{padding:10px 20px}.render-warning .render-warning-footer{display:flex;justify-content:center;padding:0 20px 10px}.render-warning .render-warning-footer .render-popup-button{float:none;width:110px;border-radius:3px;cursor:pointer;border:none;display:flex;height:40px;align-items:center;justify-content:space-evenly;color:#fff;background-color:#5b6875}.render-warning .render-warning-footer .render-popup-button ::ng-deep co-icon{display:inline-block;height:18px;width:18px}.render-warning .render-warning-footer .render-popup-button ::ng-deep co-icon svg path{fill:#fff}\n"] }]
34507
- }], ctorParameters: () => [{ type: RenderService }, { type: MessageBusService }, { type: ViewModeService }, { type: HomedecoratorSettingsService }, { type: HomedecoratorIconCacheService }, { type: i1$2.MatDialog }, { type: SceneService }, { type: CameraService }, { type: ConfigurationService }, { type: HomedecoratorSettingsService }, { type: NewRenderService }, { type: UtilsService }, { type: RoomService }, { type: WallMeasurementsService }, { type: ConnectionHeathService }, { type: HomedecoratorDictionaryService }], propDecorators: { renderButton: [{
34164
+ <button
34165
+ #renderButton
34166
+ mat-raised-button
34167
+ matTooltip="{{'RENDER_TAKE_A_PICTURE' | localize}}"
34168
+ [id]="'standalone_render_picture'"
34169
+ [class.active]="viewModeService.viewMode === viewModes.WalkThrough"
34170
+ (click)="showRenderForm($event)">
34171
+ <mat-icon class="icon homedecorator-material-icons"
34172
+ aria-hidden="true">{{ 'photo_camera' }}
34173
+ </mat-icon>
34174
+ </button>
34175
+ </div>
34176
+ `, standalone: false, styles: [".render-container{position:relative}.render-container .render-popup-container{background:#ffffffb3;padding:10px 25px 25px;border-radius:5px;box-shadow:0 1px 5px #0000001f}.render-container .render-popup-container .render-popup-header{display:flex;justify-content:space-between;font-family:inherit}.render-container .render-popup-container .render-popup-header h3{display:flex;justify-content:space-between}.render-container .render-popup-container .render-popup-header h3 ::ng-deep .renderErrorIcon{width:20px;height:20px;margin-left:20px}.render-container .render-popup-container .render-popup-header h3 ::ng-deep .renderErrorIcon svg,.render-container .render-popup-container .render-popup-header h3 ::ng-deep .renderErrorIcon svg polygon{fill:#dc143c}.render-container .render-popup-container .render-popup-header .close-popup-container{cursor:pointer;border:none;background:none;float:none;height:auto;width:auto}.render-container .render-popup-container .render-popup-button-container{display:flex;justify-content:space-between;font-family:inherit}.render-container .render-popup-container .render-popup-button-container .render-popup-button{float:none;width:100%;max-width:130px;border-radius:3px;cursor:pointer;border:none;display:flex;height:40px;align-items:center;justify-content:space-evenly}.render-container .render-popup-container .render-popup-button-container .render-popup-button ::ng-deep co-icon{display:inline-block;height:18px;width:18px}.render-container .render-popup-container .render-popup-button-container .render-popup-button ::ng-deep co-icon svg path{fill:#fff}.render-container .render-popup-container .render-popup-button-container .photo-button{color:#fff;background-color:#dda73f}.render-container .render-popup-container .render-popup-button-container .cancel-button{color:#fff;background-color:#5b6875}.render-container .render-popup-container .render-popup-preview{background-color:#fff;min-height:150px;min-width:275px;margin:5px 0;position:relative;width:275px;height:150px}.render-container .render-popup-container .render-popup-preview .render-popup-preview-placeholder{background-color:#fff;display:flex;justify-content:space-around;align-items:center;vertical-align:middle;min-height:150px;border:1px solid #ddd;color:#ddd;font-size:14px}.render-container .render-popup-container .render-popup-preview .render-popup-refresh-preview{position:absolute;bottom:0;right:0;cursor:pointer;border-radius:0;border:none;height:30px;width:30px;background-color:#dda73f;color:#fff;margin:0}.render-container .render-popup-container .render-popup-preview .render-popup-refresh-preview ::ng-deep co-icon svg path{fill:#fff}.render-container .render-popup-container .render-popup-dropdown{margin:5px 0;width:100%}.render-container .render-popup-container .render-popup-dropdown .toggleable{cursor:pointer;display:flex;justify-content:right;align-content:center}.render-container .render-popup-container .render-popup-dropdown .toggleable p{padding:0;margin:0;font-size:12px;line-height:30px}.render-container .render-popup-container .render-popup-dropdown .toggleable .icon-rotate{transform:rotate(180deg)}.render-container .render-popup-container .render-popup-dropdown .mat-mdc-form-field{width:100%;font-size:14px}.render-container .render-popup-container .render-popup-dropdown .mat-mdc-form-field ::ng-deep .mat-mdc-form-field-flex{background-color:#fff;color:#000;padding:3px 6px;border:1px solid #ddd}.render-container .render-popup-container .render-popup-dropdown .mat-mdc-form-field ::ng-deep .mat-mdc-form-field-underline{display:none}.render-container .render-popup-container .render-popup-dropdown .mat-mdc-form-field ::ng-deep .mat-mdc-form-field-wrapper{padding-bottom:0}.render-container .render-popup-container .render-popup-dropdown .setting-part-container{display:flex;justify-content:space-between;align-items:center;margin-bottom:5px}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .third-width{width:32%}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .setting-part-buttons .amount-button{float:none;box-sizing:border-box;padding:2px;background:none;cursor:pointer;border:none;width:25px;height:25px;margin:0 5px}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .setting-part-buttons .amount-button co-icon{display:block;width:25px;height:25px}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .setting-part-buttons .amount-button co-icon ::ng-deep svg{fill:#5b6875}.render-container .render-popup-container .render-popup-dropdown .setting-part-container .setting-part-slider .mat-slider-horizontal{min-width:110px;height:28px}.render-container .render-progress{float:left;min-width:50px;border-radius:25px;line-height:50px;text-align:center;padding:0 60px 0 20px;background:#fff;color:#74b77f;font-weight:700;margin:0 -50px 0 0}.render-container .render-input-container{float:right}.render-container .render-input-container input{width:100px;height:24px;margin:5px 0;padding:0 10px;font-size:14px}.render-container button{pointer-events:all;width:50px;height:50px;float:right;border-radius:100%;position:relative;z-index:2;margin-bottom:10px}.render-container button.active{background:#74b77f;color:#fff}.render-container button>*{pointer-events:none}.render-indicators div{position:fixed;width:100px;height:100px}.render-indicators .render-indicator-top-left{left:5vw;top:10vh;border-left:10px solid #dda73f;border-top:10px solid #dda73f;border-top-left-radius:20px}.render-indicators .render-indicator-top-right{right:5vw;top:10vh;border-right:10px solid #dda73f;border-top:10px solid #dda73f;border-top-right-radius:20px}.render-indicators .render-indicator-bottom-left{left:5vw;bottom:5vh;border-left:10px solid #dda73f;border-bottom:10px solid #dda73f;border-bottom-left-radius:20px}.render-indicators .render-indicator-bottom-right{right:5vw;bottom:5vh;border-right:10px solid #dda73f;border-bottom:10px solid #dda73f;border-bottom-right-radius:20px}.render-warning{width:500px;position:fixed;top:20%;left:calc(50% - 250px);border-radius:15px;box-sizing:border-box;background-color:#fff;box-shadow:1px 0 20px #0000001f}.render-warning .render-warming-header{display:flex;justify-content:space-between;border-bottom:1px solid #c5c3c6;padding:20px 20px 10px;align-items:center}.render-warning .render-warming-header h2{padding:0;margin:0}.render-warning .render-warming-header .render-warning-close mat-icon{fill:#c5c3c6;color:#c5c3c6;cursor:pointer;transition:all .2s ease}.render-warning .render-warming-header .render-warning-close:hover mat-icon{fill:#46494c;color:#46494c}.render-warning .render-warning-body{padding:10px 20px}.render-warning .render-warning-footer{display:flex;justify-content:center;padding:0 20px 10px}.render-warning .render-warning-footer .render-popup-button{float:none;width:110px;border-radius:3px;cursor:pointer;border:none;display:flex;height:40px;align-items:center;justify-content:space-evenly;color:#fff;background-color:#5b6875}.render-warning .render-warning-footer .render-popup-button ::ng-deep co-icon{display:inline-block;height:18px;width:18px}.render-warning .render-warning-footer .render-popup-button ::ng-deep co-icon svg path{fill:#fff}\n"] }]
34177
+ }], ctorParameters: () => [{ type: MessageBusService }, { type: ViewModeService }, { type: HomedecoratorSettingsService }, { type: HomedecoratorIconCacheService }, { type: RenderService }, { type: i1$2.MatDialog }, { type: SceneService }, { type: CameraService }, { type: ConfigurationService }, { type: HomedecoratorSettingsService }, { type: UtilsService }, { type: RoomService }, { type: WallMeasurementsService }, { type: ConnectionHeathService }, { type: HomedecoratorDictionaryService }, { type: DialogService }], propDecorators: { renderButton: [{
34508
34178
  type: ViewChild,
34509
34179
  args: ['renderButton']
34510
34180
  }] } });
@@ -36472,11 +36142,6 @@ class FloorplannerComponent {
36472
36142
  this._lastNode = null;
36473
36143
  this._subs = [];
36474
36144
  this._selectedFloor = null;
36475
- this._diagramBackgroundScale = 1;
36476
- this._diagramBackgroundCurrentScale = 100;
36477
- this._diagramBackgroundActiveZoom = false;
36478
- this._diagramBackgroundAlpha = 0.5;
36479
- this._showDiagramBackground = true;
36480
36145
  this._readyToDraw = false;
36481
36146
  this._needsRedraw = false;
36482
36147
  Object.keys(this._configToSync).forEach((key) => {
@@ -36509,7 +36174,7 @@ class FloorplannerComponent {
36509
36174
  const dataUrl = this._canvas.toDataURL('image/jpeg');
36510
36175
  FileUtils.DownloadFromDataUri(dataUrl, `MyRoomplan${new Date().toISOString()}.jpeg`);
36511
36176
  }
36512
- }), this._messageBusService.subscribe(MessageType.StartWithEmptyRoom, () => this.showStartMessage()), this._messageBusService.subscribe(MessageType.LoadScaledDiagram, (input) => this.setDiagramSettings(input)), this._messageBusService.subscribe(MessageType.ToggleDiagram, () => this.toggleDiagram()));
36177
+ }), this._messageBusService.subscribe(MessageType.StartWithPreset, () => this._clearBackground()), this._messageBusService.subscribe(MessageType.LoadRoomFromPreset, () => this._clearBackground()), this._messageBusService.subscribe(MessageType.LoadRoomFromCloud, () => this._clearBackground()), this._messageBusService.subscribe(MessageType.NewRoom, () => this._clearBackground()), this._messageBusService.subscribe(MessageType.ResetRoomplan, () => this._clearBackground()), this._messageBusService.subscribe(MessageType.LoadScaledDiagram, () => this._clearBackground()), this._messageBusService.subscribe(MessageType.StartWithEmptyRoom, () => this.showStartMessage()), this._messageBusService.subscribe(MessageType.LoadScaledDiagram, (input) => this.setDiagramSettings(input)), this._messageBusService.subscribe(MessageType.ToggleDiagram, () => this.toggleDiagram()));
36513
36178
  this.touchMode = this._configurationService.getValue(ConfigurationKey.EnableTouch);
36514
36179
  this.currentDimensioning = this._configurationService.getValue(ConfigurationKey.DimensioningUnit);
36515
36180
  this.currentRoundingDecimals = this._configurationService.getValue(ConfigurationKey.RoundingDecimals);
@@ -36573,10 +36238,13 @@ class FloorplannerComponent {
36573
36238
  this._draw();
36574
36239
  });
36575
36240
  }
36576
- showStartMessage() {
36577
- if (this._diagramBackground) {
36578
- this._diagramBackground.src = '';
36241
+ _clearBackground() {
36242
+ if (this._renderService.diagramBackground) {
36243
+ this._renderService.diagramBackground = undefined;
36579
36244
  }
36245
+ }
36246
+ showStartMessage() {
36247
+ this._clearBackground();
36580
36248
  this._bluePrintService.reset();
36581
36249
  this.showStartingMessages = true;
36582
36250
  this._requestDraw();
@@ -36602,10 +36270,9 @@ class FloorplannerComponent {
36602
36270
  if (!this._coordinatesService.canZoomIn) {
36603
36271
  return;
36604
36272
  }
36605
- this._clear();
36606
36273
  this._coordinatesService.zoomIn();
36607
- this._diagramBackgroundScale *= this._coordinatesService.scalingFactor;
36608
- this._diagramBackgroundActiveZoom = true;
36274
+ this._renderService.diagramBackgroundScale *= this._coordinatesService.scalingFactor;
36275
+ this._renderService.diagramBackgroundActiveZoom = true;
36609
36276
  this._scale(this._coordinatesService.scalingFactor, this._coordinatesService.scalingFactor);
36610
36277
  this.resizeView();
36611
36278
  this._requestDraw();
@@ -36614,16 +36281,14 @@ class FloorplannerComponent {
36614
36281
  if (!this._coordinatesService.canZoomOut) {
36615
36282
  return;
36616
36283
  }
36617
- this._clear();
36618
36284
  this._coordinatesService.zoomOut();
36619
- this._diagramBackgroundScale *= (1 / this._coordinatesService.scalingFactor);
36620
- this._diagramBackgroundActiveZoom = true;
36285
+ this._renderService.diagramBackgroundScale *= (1 / this._coordinatesService.scalingFactor);
36286
+ this._renderService.diagramBackgroundActiveZoom = true;
36621
36287
  this._scale(1 / this._coordinatesService.scalingFactor, 1 / this._coordinatesService.scalingFactor);
36622
36288
  this.resizeView();
36623
36289
  this._requestDraw();
36624
36290
  }
36625
36291
  zoomReset() {
36626
- this._clear();
36627
36292
  this._scale(1 / this._viewScale, 1 / this._viewScale);
36628
36293
  this.reset();
36629
36294
  }
@@ -36968,15 +36633,15 @@ class FloorplannerComponent {
36968
36633
  this._coordinatesService.resetOrigin();
36969
36634
  this._viewScale = 100;
36970
36635
  this._bluePrintService.reset();
36971
- this._diagramBackground = input.background;
36972
- this._diagramBackgroundHeight = input.backgroundHeight;
36973
- this._diagramBackgroundWidth = input.backgroundWidth;
36974
- this._diagramScale = input.scale;
36636
+ this._renderService.diagramBackground = input.background;
36637
+ this._renderService.diagramBackgroundHeight = input.backgroundHeight;
36638
+ this._renderService.diagramBackgroundWidth = input.backgroundWidth;
36639
+ this._renderService.diagramBackgroundScale = input.scale;
36975
36640
  this._cameraZoom = input.cameraZoom;
36976
36641
  this._requestDraw();
36977
36642
  }
36978
36643
  toggleDiagram() {
36979
- this._showDiagramBackground = !this._showDiagramBackground;
36644
+ this._renderService.showDiagramBackground = !this._renderService.showDiagramBackground;
36980
36645
  this._requestDraw();
36981
36646
  }
36982
36647
  _removeWall() {
@@ -37050,23 +36715,6 @@ class FloorplannerComponent {
37050
36715
  await this._bluePrintService.update();
37051
36716
  this._requestDraw();
37052
36717
  }
37053
- _drawBackground() {
37054
- if (this._diagramBackgroundActiveZoom) {
37055
- if (this._diagramBackgroundCurrentScale <= this._viewScale) {
37056
- this._diagramBackgroundWidth = this._diagramBackgroundWidth * this._coordinatesService.scalingFactor;
37057
- this._diagramBackgroundHeight = this._diagramBackgroundHeight * this._coordinatesService.scalingFactor;
37058
- }
37059
- else {
37060
- this._diagramBackgroundWidth = this._diagramBackgroundWidth * (1 / this._coordinatesService.scalingFactor);
37061
- this._diagramBackgroundHeight = this._diagramBackgroundHeight * (1 / this._coordinatesService.scalingFactor);
37062
- }
37063
- this._diagramBackgroundActiveZoom = false;
37064
- }
37065
- this._diagramBackgroundCurrentScale = this._viewScale;
37066
- this._context.globalAlpha = this._diagramBackgroundAlpha;
37067
- this._context.drawImage(this._diagramBackground, Math.abs(this._coordinatesService.originX) - (this._diagramBackgroundWidth * this._diagramScale / 2), Math.abs(this._coordinatesService.originY) - (this._diagramBackgroundHeight * this._diagramScale / 2), this._diagramBackgroundWidth * this._diagramScale, this._diagramBackgroundHeight * this._diagramScale);
37068
- this._context.globalAlpha = 1;
37069
- }
37070
36718
  _handleWindowResize() {
37071
36719
  if (this._canvas) {
37072
36720
  const parent = this._canvas.parentElement;
@@ -37079,11 +36727,6 @@ class FloorplannerComponent {
37079
36727
  this._requestDraw();
37080
36728
  }
37081
36729
  }
37082
- _clear() {
37083
- if (this._context && this._canvas) {
37084
- this._context.clearRect(0, 0, this._canvas.width, this._canvas.height);
37085
- }
37086
- }
37087
36730
  _updateWallPosition() {
37088
36731
  if (this._wallLength) {
37089
36732
  const startPoint = this._lastNode;
@@ -42058,10 +41701,10 @@ class RoomPlannerComponent {
42058
41701
  if (object.metadata) {
42059
41702
  this.showContextMenu = false;
42060
41703
  await this._connectorAdapterService.initConnector(object.metadata.externalSettings ? object.metadata.externalSettings.settings : this.settingsService.settings, object.metadata.externalSettings ? object.metadata.externalSettings.name : undefined, false, object.metadata.externalSettings && object.metadata.externalSettings.externalSourceId ? object.metadata.externalSettings.externalSourceId : null);
42061
- const json = await this._connectorService.addToCart(+object.metadata.goodId, object.metadata.goodType, 1, object.metadata.itemId, !!(object.metadata.externalSettings && object.metadata.externalSettings.externalSourceId));
41704
+ const article = await this._connectorService.addToCart(+object.metadata.goodId, object.metadata.goodType, 1, object.metadata.itemId, !!(object.metadata.externalSettings && object.metadata.externalSettings.externalSourceId));
42062
41705
  if (object.metadata.externalSettings) {
42063
41706
  const externalSource = {
42064
- article: json,
41707
+ article: article,
42065
41708
  quantity: 1,
42066
41709
  catalogDefinition: object.metadata.externalSettings.catalogDefinition,
42067
41710
  externalSource: this._connectorAdapterService.getExternalSourceFromId(object.metadata.externalSettings.externalSourceId)
@@ -42069,7 +41712,7 @@ class RoomPlannerComponent {
42069
41712
  this._appEventService.addExternalSourceToCart.next(externalSource);
42070
41713
  }
42071
41714
  else {
42072
- this._appEventService.addToCart.next({ article: json, quantity: 1 });
41715
+ this._appEventService.addToCart.next({ article: article, quantity: 1 });
42073
41716
  }
42074
41717
  }
42075
41718
  }
@@ -46528,7 +46171,7 @@ class DrawDialogComponent {
46528
46171
  this.customerInputLenght = this.inputLength.nativeElement.value;
46529
46172
  }
46530
46173
  handleMouseDown(event) {
46531
- if (this.draftingMode === 'movement') {
46174
+ if (event.button === 2) { // right mouse button -> drag
46532
46175
  this.isDragging = true;
46533
46176
  this.dragStart.x = this.getEventLocation(event).x / this.cameraZoom - this.cameraOffset.x;
46534
46177
  this.dragStart.y = this.getEventLocation(event).y / this.cameraZoom - this.cameraOffset.y;
@@ -46541,11 +46184,9 @@ class DrawDialogComponent {
46541
46184
  }
46542
46185
  }
46543
46186
  handleMouseMove(event) {
46544
- if (this.draftingMode === 'movement') {
46545
- if (this.isDragging) {
46546
- this.cameraOffset.x = this.getEventLocation(event).x / this.cameraZoom - this.dragStart.x;
46547
- this.cameraOffset.y = this.getEventLocation(event).y / this.cameraZoom - this.dragStart.y;
46548
- }
46187
+ if (this.isDragging) {
46188
+ this.cameraOffset.x = this.getEventLocation(event).x / this.cameraZoom - this.dragStart.x;
46189
+ this.cameraOffset.y = this.getEventLocation(event).y / this.cameraZoom - this.dragStart.y;
46549
46190
  }
46550
46191
  }
46551
46192
  handleMouseUp(event) {
@@ -46555,22 +46196,6 @@ class DrawDialogComponent {
46555
46196
  }
46556
46197
  handleMouseLeave(event) {
46557
46198
  }
46558
- clickingZoom(option) {
46559
- const zoomIn = -0.5;
46560
- const zoomOut = 0.5;
46561
- const zoomReset = 1;
46562
- if (option === 'in') {
46563
- this.cameraZoom -= zoomIn;
46564
- }
46565
- else if (option === 'out') {
46566
- this.cameraZoom -= zoomOut;
46567
- }
46568
- else if (option === 'reset') {
46569
- this.cameraZoom = zoomReset;
46570
- }
46571
- this.cameraZoom = Math.min(this.cameraZoom, this.maxZoom);
46572
- this.cameraZoom = Math.max(this.cameraZoom, this.minZoom);
46573
- }
46574
46199
  handleMouseWheel(event) {
46575
46200
  const zoomAmount = event.deltaY * this.scrollSensitivity;
46576
46201
  if (!this.isDragging) {
@@ -46581,6 +46206,9 @@ class DrawDialogComponent {
46581
46206
  this.cameraZoom = Math.max(this.cameraZoom, this.minZoom);
46582
46207
  }
46583
46208
  }
46209
+ handleContextMenu(event) {
46210
+ return false;
46211
+ }
46584
46212
  getEventLocation(e) {
46585
46213
  if (e.touches && e.touches.length === 1) {
46586
46214
  return { x: e.touches[0].clientX, y: e.touches[0].clientY };
@@ -46664,11 +46292,11 @@ class DrawDialogComponent {
46664
46292
  return new Vector2(canvasX, canvasY);
46665
46293
  }
46666
46294
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DrawDialogComponent, deps: [{ token: MAT_DIALOG_DATA }, { token: i1$2.MatDialogRef }, { token: i1$2.MatDialog }, { token: MessageBusService }], target: i0.ɵɵFactoryTarget.Component }); }
46667
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DrawDialogComponent, isStandalone: false, selector: "rp-draw-dialog", viewQueries: [{ propertyName: "canvasElement", first: true, predicate: ["drawCanvas"], descendants: true, read: ElementRef, static: true }, { propertyName: "inputLength", first: true, predicate: ["inputLength"], descendants: true }, { propertyName: "hiddenImage", first: true, predicate: ["hiddenImage"], descendants: true }], ngImport: i0, template: "<div class=\"model-header\">\r\n <h1 mat-dialog-title>{{ 'OPEN_A_DIAGRAM' | localize }}</h1>\r\n <button (click)=\"cancelAndReset()\" class=\"close-button\">\r\n <mat-icon class=\"homedecorator-material-icons\">close</mat-icon>\r\n </button>\r\n</div>\r\n<div class=\"top-bar-container\">\r\n @if (draftingMode === 'movement') {\r\n <div class=\"zoom-button-containers\">\r\n <button (click)=\"clickingZoom('in')\">\r\n <mat-icon class=\"homedecorator-material-icons\">zoom_in</mat-icon>\r\n </button>\r\n <button (click)=\"clickingZoom('reset')\">\r\n <mat-icon class=\"homedecorator-material-icons\">all_out</mat-icon>\r\n </button>\r\n <button (click)=\"clickingZoom('out')\">\r\n <mat-icon class=\"homedecorator-material-icons\">zoom_out</mat-icon>\r\n </button>\r\n </div>\r\n }\r\n</div>\r\n<div class=\"main-button-container\">\r\n <mat-button-toggle-group\r\n class=\"mode-toggle\"\r\n (change)=\"setModus($event.value)\"\r\n [value]=\"draftingMode\">\r\n <mat-button-toggle [value]=\"'movement'\" [matTooltip]=\"'Zoom / verplaats modus'\">\r\n <mat-icon svgIcon=\"hand-pointer\"></mat-icon>\r\n </mat-button-toggle>\r\n <mat-button-toggle [value]=\"'scaling'\" [matTooltip]=\"'Maak referentie meting'\">\r\n <mat-icon svgIcon=\"pen-ruler\"></mat-icon>\r\n </mat-button-toggle>\r\n </mat-button-toggle-group>\r\n</div>\r\n\r\n<div class=\"canvas-wrapper\">\r\n <canvas\r\n #drawCanvas\r\n (mousedown)=\"handleMouseDown($event)\"\r\n (mousemove)=\"handleMouseMove($event)\"\r\n (mouseup)=\"handleMouseUp($event)\"\r\n (mouseleave)=\"handleMouseLeave($event)\"\r\n (wheel)=\"handleMouseWheel($event)\"\r\n ></canvas>\r\n</div>\r\n\r\n<div class=\"modal-footer\">\r\n @if (draftingMode === 'scaling') {\r\n <div class=\"reference-input-container\">\r\n <div class=\"input-button-container\">\r\n <input\r\n (change)=\"updateUserValue()\"\r\n [value]=\"customerInputLenght\"\r\n #inputLength\r\n type=\"number\"\r\n placeholder=\"{{ 'PDF_REFERENCE_PLACEHOLDER' | localize}}\"\r\n [attr.disabled]=\"this.measurePoints.length === 0 ? '' : null\"\r\n >\r\n <button (click)=\"resetPoints()\" title=\"Reset referentie meting\">\r\n <mat-icon class=\"homedecorator-material-icons\">refresh</mat-icon>\r\n </button>\r\n </div>\r\n <p class=\"helper-text\">{{ 'PDF_REFERENCE_HELPER' | localize }}</p>\r\n </div>\r\n }\r\n\r\n <div class=\"save-cancel-button-container\">\r\n @if (draftingMode === 'scaling') {\r\n <button (click)=\"submitLength()\" title=\"Opslaan\">\r\n <mat-icon class=\"homedecorator-material-icons\">check_circle</mat-icon>\r\n <span>{{'NEXT' | localize}}</span>\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n\r\n\r\n <img #hiddenImage src=\"\" style=\"display: none;\">\r\n", styles: ["canvas{position:relative}button{cursor:pointer;color:#fff;background:#da9803;border:1px solid #da9803;border-radius:3px;box-sizing:border-box;padding:5px;display:flex;align-items:center}button:hover{background:#da9803;color:#fff}.main-button-container{display:flex;justify-content:center;margin-bottom:15px}.main-button-container .mat-button-toggle-checked{background:#da9803;color:#fff}.model-header{display:flex;justify-content:space-between;align-items:start}.model-header .close-button{background:none;color:#333;border:none;padding:0}.modal-footer{display:flex;justify-content:space-between;align-items:flex-end;margin-top:30px}.reference-input-container .input-button-container{display:flex;align-items:center}.reference-input-container .input-button-container input{min-width:285px;border:1px solid #f7f7f9;border-radius:3px;height:35px;line-height:35px;box-sizing:border-box;padding:10px}.reference-input-container .input-button-container input:disabled{background:#f7f7f9;cursor:default}.reference-input-container .input-button-container button{border:none;display:inline-block}.reference-input-container .helper-text{font-size:13px;font-style:italic;margin:0;padding:0;display:block}.zoom-button-containers{display:flex;justify-items:center;justify-content:right}.zoom-button-containers button{margin:0 5px}.save-cancel-button-container{display:flex;justify-content:center;justify-items:center}.save-cancel-button-container button{margin:3px 10px;padding:8px 15px}.save-cancel-button-container button .homedecorator-material-icons{font-size:18px}.save-cancel-button-container button span{line-height:18px;font-size:15px}.canvas-wrapper{overflow:hidden;max-height:60vh;max-width:80vw}\n"], dependencies: [{ kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i4$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: i1$2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i10.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i10.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "pipe", type: LocalizePipe, name: "localize" }] }); }
46295
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DrawDialogComponent, isStandalone: false, selector: "rp-draw-dialog", viewQueries: [{ propertyName: "canvasElement", first: true, predicate: ["drawCanvas"], descendants: true, read: ElementRef, static: true }, { propertyName: "inputLength", first: true, predicate: ["inputLength"], descendants: true }, { propertyName: "hiddenImage", first: true, predicate: ["hiddenImage"], descendants: true }], ngImport: i0, template: "<div class=\"model-header\">\r\n <h1 mat-dialog-title>{{ 'OPEN_A_DIAGRAM' | localize }}</h1>\r\n <button (click)=\"cancelAndReset()\" class=\"close-button\">\r\n <mat-icon class=\"homedecorator-material-icons\">close</mat-icon>\r\n </button>\r\n</div>\r\n<div class=\"canvas-wrapper\">\r\n <canvas\r\n #drawCanvas\r\n (mousedown)=\"handleMouseDown($event)\"\r\n (mousemove)=\"handleMouseMove($event)\"\r\n (mouseup)=\"handleMouseUp($event)\"\r\n (mouseleave)=\"handleMouseLeave($event)\"\r\n (wheel)=\"handleMouseWheel($event)\"\r\n (contextmenu)=\"handleContextMenu($event)\"\r\n ></canvas>\r\n</div>\r\n\r\n<div class=\"modal-footer\">\r\n @if (draftingMode === 'scaling') {\r\n <div class=\"reference-input-container\">\r\n <div class=\"input-button-container\">\r\n <input\r\n (change)=\"updateUserValue()\"\r\n [value]=\"customerInputLenght\"\r\n #inputLength\r\n type=\"number\"\r\n placeholder=\"{{ 'PDF_REFERENCE_PLACEHOLDER' | localize}}\"\r\n [attr.disabled]=\"this.measurePoints.length === 0 ? '' : null\"\r\n >\r\n <button (click)=\"resetPoints()\" title=\"Reset referentie meting\">\r\n <mat-icon class=\"homedecorator-material-icons\">refresh</mat-icon>\r\n </button>\r\n </div>\r\n <p class=\"helper-text\">{{ 'PDF_REFERENCE_HELPER' | localize }}</p>\r\n </div>\r\n }\r\n\r\n <div class=\"save-cancel-button-container\">\r\n @if (draftingMode === 'scaling') {\r\n <button (click)=\"submitLength()\" title=\"Opslaan\">\r\n <mat-icon class=\"homedecorator-material-icons\">check_circle</mat-icon>\r\n <span>{{'NEXT' | localize}}</span>\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n\r\n\r\n <img #hiddenImage src=\"\" style=\"display: none;\">\r\n", styles: ["canvas{position:relative}button{cursor:pointer;color:#fff;background:#da9803;border:1px solid #da9803;border-radius:3px;box-sizing:border-box;padding:5px;display:flex;align-items:center}button:hover{background:#da9803;color:#fff}.main-button-container{display:flex;justify-content:center;margin-bottom:15px}.main-button-container .mat-button-toggle-checked{background:#da9803;color:#fff}.model-header{display:flex;justify-content:space-between;align-items:start}.model-header .close-button{background:none;color:#333;border:none;padding:0}.modal-footer{display:flex;justify-content:space-between;align-items:flex-end;margin-top:30px}.reference-input-container .input-button-container{display:flex;align-items:center}.reference-input-container .input-button-container input{min-width:285px;border:1px solid #f7f7f9;border-radius:3px;height:35px;line-height:35px;box-sizing:border-box;padding:10px}.reference-input-container .input-button-container input:disabled{background:#f7f7f9;cursor:default}.reference-input-container .input-button-container button{border:none;display:inline-block}.reference-input-container .helper-text{font-size:13px;font-style:italic;margin:0;padding:0;display:block}.zoom-button-containers{display:flex;justify-items:center;justify-content:right}.zoom-button-containers button{margin:0 5px}.save-cancel-button-container{display:flex;justify-content:center;justify-items:center}.save-cancel-button-container button{margin:3px 10px;padding:8px 15px}.save-cancel-button-container button .homedecorator-material-icons{font-size:18px}.save-cancel-button-container button span{line-height:18px;font-size:15px}.canvas-wrapper{overflow:hidden;max-height:60vh;max-width:80vw}\n"], dependencies: [{ kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i1$2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "pipe", type: LocalizePipe, name: "localize" }] }); }
46668
46296
  }
46669
46297
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DrawDialogComponent, decorators: [{
46670
46298
  type: Component,
46671
- args: [{ selector: 'rp-draw-dialog', standalone: false, template: "<div class=\"model-header\">\r\n <h1 mat-dialog-title>{{ 'OPEN_A_DIAGRAM' | localize }}</h1>\r\n <button (click)=\"cancelAndReset()\" class=\"close-button\">\r\n <mat-icon class=\"homedecorator-material-icons\">close</mat-icon>\r\n </button>\r\n</div>\r\n<div class=\"top-bar-container\">\r\n @if (draftingMode === 'movement') {\r\n <div class=\"zoom-button-containers\">\r\n <button (click)=\"clickingZoom('in')\">\r\n <mat-icon class=\"homedecorator-material-icons\">zoom_in</mat-icon>\r\n </button>\r\n <button (click)=\"clickingZoom('reset')\">\r\n <mat-icon class=\"homedecorator-material-icons\">all_out</mat-icon>\r\n </button>\r\n <button (click)=\"clickingZoom('out')\">\r\n <mat-icon class=\"homedecorator-material-icons\">zoom_out</mat-icon>\r\n </button>\r\n </div>\r\n }\r\n</div>\r\n<div class=\"main-button-container\">\r\n <mat-button-toggle-group\r\n class=\"mode-toggle\"\r\n (change)=\"setModus($event.value)\"\r\n [value]=\"draftingMode\">\r\n <mat-button-toggle [value]=\"'movement'\" [matTooltip]=\"'Zoom / verplaats modus'\">\r\n <mat-icon svgIcon=\"hand-pointer\"></mat-icon>\r\n </mat-button-toggle>\r\n <mat-button-toggle [value]=\"'scaling'\" [matTooltip]=\"'Maak referentie meting'\">\r\n <mat-icon svgIcon=\"pen-ruler\"></mat-icon>\r\n </mat-button-toggle>\r\n </mat-button-toggle-group>\r\n</div>\r\n\r\n<div class=\"canvas-wrapper\">\r\n <canvas\r\n #drawCanvas\r\n (mousedown)=\"handleMouseDown($event)\"\r\n (mousemove)=\"handleMouseMove($event)\"\r\n (mouseup)=\"handleMouseUp($event)\"\r\n (mouseleave)=\"handleMouseLeave($event)\"\r\n (wheel)=\"handleMouseWheel($event)\"\r\n ></canvas>\r\n</div>\r\n\r\n<div class=\"modal-footer\">\r\n @if (draftingMode === 'scaling') {\r\n <div class=\"reference-input-container\">\r\n <div class=\"input-button-container\">\r\n <input\r\n (change)=\"updateUserValue()\"\r\n [value]=\"customerInputLenght\"\r\n #inputLength\r\n type=\"number\"\r\n placeholder=\"{{ 'PDF_REFERENCE_PLACEHOLDER' | localize}}\"\r\n [attr.disabled]=\"this.measurePoints.length === 0 ? '' : null\"\r\n >\r\n <button (click)=\"resetPoints()\" title=\"Reset referentie meting\">\r\n <mat-icon class=\"homedecorator-material-icons\">refresh</mat-icon>\r\n </button>\r\n </div>\r\n <p class=\"helper-text\">{{ 'PDF_REFERENCE_HELPER' | localize }}</p>\r\n </div>\r\n }\r\n\r\n <div class=\"save-cancel-button-container\">\r\n @if (draftingMode === 'scaling') {\r\n <button (click)=\"submitLength()\" title=\"Opslaan\">\r\n <mat-icon class=\"homedecorator-material-icons\">check_circle</mat-icon>\r\n <span>{{'NEXT' | localize}}</span>\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n\r\n\r\n <img #hiddenImage src=\"\" style=\"display: none;\">\r\n", styles: ["canvas{position:relative}button{cursor:pointer;color:#fff;background:#da9803;border:1px solid #da9803;border-radius:3px;box-sizing:border-box;padding:5px;display:flex;align-items:center}button:hover{background:#da9803;color:#fff}.main-button-container{display:flex;justify-content:center;margin-bottom:15px}.main-button-container .mat-button-toggle-checked{background:#da9803;color:#fff}.model-header{display:flex;justify-content:space-between;align-items:start}.model-header .close-button{background:none;color:#333;border:none;padding:0}.modal-footer{display:flex;justify-content:space-between;align-items:flex-end;margin-top:30px}.reference-input-container .input-button-container{display:flex;align-items:center}.reference-input-container .input-button-container input{min-width:285px;border:1px solid #f7f7f9;border-radius:3px;height:35px;line-height:35px;box-sizing:border-box;padding:10px}.reference-input-container .input-button-container input:disabled{background:#f7f7f9;cursor:default}.reference-input-container .input-button-container button{border:none;display:inline-block}.reference-input-container .helper-text{font-size:13px;font-style:italic;margin:0;padding:0;display:block}.zoom-button-containers{display:flex;justify-items:center;justify-content:right}.zoom-button-containers button{margin:0 5px}.save-cancel-button-container{display:flex;justify-content:center;justify-items:center}.save-cancel-button-container button{margin:3px 10px;padding:8px 15px}.save-cancel-button-container button .homedecorator-material-icons{font-size:18px}.save-cancel-button-container button span{line-height:18px;font-size:15px}.canvas-wrapper{overflow:hidden;max-height:60vh;max-width:80vw}\n"] }]
46299
+ args: [{ selector: 'rp-draw-dialog', standalone: false, template: "<div class=\"model-header\">\r\n <h1 mat-dialog-title>{{ 'OPEN_A_DIAGRAM' | localize }}</h1>\r\n <button (click)=\"cancelAndReset()\" class=\"close-button\">\r\n <mat-icon class=\"homedecorator-material-icons\">close</mat-icon>\r\n </button>\r\n</div>\r\n<div class=\"canvas-wrapper\">\r\n <canvas\r\n #drawCanvas\r\n (mousedown)=\"handleMouseDown($event)\"\r\n (mousemove)=\"handleMouseMove($event)\"\r\n (mouseup)=\"handleMouseUp($event)\"\r\n (mouseleave)=\"handleMouseLeave($event)\"\r\n (wheel)=\"handleMouseWheel($event)\"\r\n (contextmenu)=\"handleContextMenu($event)\"\r\n ></canvas>\r\n</div>\r\n\r\n<div class=\"modal-footer\">\r\n @if (draftingMode === 'scaling') {\r\n <div class=\"reference-input-container\">\r\n <div class=\"input-button-container\">\r\n <input\r\n (change)=\"updateUserValue()\"\r\n [value]=\"customerInputLenght\"\r\n #inputLength\r\n type=\"number\"\r\n placeholder=\"{{ 'PDF_REFERENCE_PLACEHOLDER' | localize}}\"\r\n [attr.disabled]=\"this.measurePoints.length === 0 ? '' : null\"\r\n >\r\n <button (click)=\"resetPoints()\" title=\"Reset referentie meting\">\r\n <mat-icon class=\"homedecorator-material-icons\">refresh</mat-icon>\r\n </button>\r\n </div>\r\n <p class=\"helper-text\">{{ 'PDF_REFERENCE_HELPER' | localize }}</p>\r\n </div>\r\n }\r\n\r\n <div class=\"save-cancel-button-container\">\r\n @if (draftingMode === 'scaling') {\r\n <button (click)=\"submitLength()\" title=\"Opslaan\">\r\n <mat-icon class=\"homedecorator-material-icons\">check_circle</mat-icon>\r\n <span>{{'NEXT' | localize}}</span>\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n\r\n\r\n <img #hiddenImage src=\"\" style=\"display: none;\">\r\n", styles: ["canvas{position:relative}button{cursor:pointer;color:#fff;background:#da9803;border:1px solid #da9803;border-radius:3px;box-sizing:border-box;padding:5px;display:flex;align-items:center}button:hover{background:#da9803;color:#fff}.main-button-container{display:flex;justify-content:center;margin-bottom:15px}.main-button-container .mat-button-toggle-checked{background:#da9803;color:#fff}.model-header{display:flex;justify-content:space-between;align-items:start}.model-header .close-button{background:none;color:#333;border:none;padding:0}.modal-footer{display:flex;justify-content:space-between;align-items:flex-end;margin-top:30px}.reference-input-container .input-button-container{display:flex;align-items:center}.reference-input-container .input-button-container input{min-width:285px;border:1px solid #f7f7f9;border-radius:3px;height:35px;line-height:35px;box-sizing:border-box;padding:10px}.reference-input-container .input-button-container input:disabled{background:#f7f7f9;cursor:default}.reference-input-container .input-button-container button{border:none;display:inline-block}.reference-input-container .helper-text{font-size:13px;font-style:italic;margin:0;padding:0;display:block}.zoom-button-containers{display:flex;justify-items:center;justify-content:right}.zoom-button-containers button{margin:0 5px}.save-cancel-button-container{display:flex;justify-content:center;justify-items:center}.save-cancel-button-container button{margin:3px 10px;padding:8px 15px}.save-cancel-button-container button .homedecorator-material-icons{font-size:18px}.save-cancel-button-container button span{line-height:18px;font-size:15px}.canvas-wrapper{overflow:hidden;max-height:60vh;max-width:80vw}\n"] }]
46672
46300
  }], ctorParameters: () => [{ type: undefined, decorators: [{
46673
46301
  type: Inject,
46674
46302
  args: [MAT_DIALOG_DATA]
@@ -48273,7 +47901,7 @@ class ToolbarComponent {
48273
47901
  this.leftSidebar.close();
48274
47902
  }
48275
47903
  }
48276
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ToolbarComponent, deps: [{ token: AppStateService }, { token: PresetsService }, { token: MessageBusService }, { token: HomedecoratorSettingsService }, { token: LocalStorageService }, { token: HomedecoratorIconCacheService }, { token: ScreenSizeAnalysisService }, { token: i1$2.MatDialog }, { token: ToastService }, { token: HomedecoratorAppService }, { token: PermanentStoreService }, { token: UtilsService }, { token: ItemService }, { token: FloorService }, { token: AnimationService }, { token: DevelopmentService }, { token: NewRenderService }, { token: ThirdPartyModelService }, { token: LightPresetsService }, { token: HomedecoratorConnectorAdapterService }, { token: ConnectionHeathService }, { token: HomedecoratorAppEventService }], target: i0.ɵɵFactoryTarget.Component }); }
47904
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ToolbarComponent, deps: [{ token: AppStateService }, { token: PresetsService }, { token: MessageBusService }, { token: HomedecoratorSettingsService }, { token: LocalStorageService }, { token: HomedecoratorIconCacheService }, { token: ScreenSizeAnalysisService }, { token: i1$2.MatDialog }, { token: ToastService }, { token: HomedecoratorAppService }, { token: PermanentStoreService }, { token: UtilsService }, { token: ItemService }, { token: FloorService }, { token: AnimationService }, { token: DevelopmentService }, { token: RenderService }, { token: ThirdPartyModelService }, { token: LightPresetsService }, { token: HomedecoratorConnectorAdapterService }, { token: ConnectionHeathService }, { token: HomedecoratorAppEventService }], target: i0.ɵɵFactoryTarget.Component }); }
48277
47905
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: ToolbarComponent, isStandalone: false, selector: "rp-toolbar", outputs: { externalSave: "externalSave" }, host: { listeners: { "document:keydown": "handleKeyDown($event)" } }, viewQueries: [{ propertyName: "leftSidebar", first: true, predicate: ["leftSidebar"], descendants: true, static: true }], ngImport: i0, template: `
48278
47906
  <!--
48279
47907
  <div class="layer layer&#45;&#45;toolbar">
@@ -48803,7 +48431,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
48803
48431
  ])
48804
48432
  ] /*,
48805
48433
  changeDetection: ChangeDetectionStrategy.OnPush*/, standalone: false, styles: [":host{display:flex;flex-direction:column;position:absolute;top:0;z-index:100;height:100%;width:100%;pointer-events:none}:host h2{font-weight:600}:host h3{font-weight:600}:host .mat-toolbar.mat-primary{box-shadow:none;padding:0;background:transparent;height:40px;justify-content:space-between}:host .mat-toolbar .mat-icon{height:20px;width:20px;font-size:20px;line-height:20px}:host .hd-toolbar-spacer{display:flex;flex-basis:100%}:host .toast-wrapper{height:auto;position:absolute;top:0;left:50%;-webkit-user-select:none;user-select:none;pointer-events:none;background:#74b77f;padding:30px;border-radius:0 0 10px 10px;min-width:150px;max-width:90%;color:#fff;text-align:center;transform:translate(-50%,-100%)}:host .toast-wrapper.warning{background:#f17300}:host .toast-wrapper.error{background:#cc2936}:host ::ng-deep .drawer__header{display:flex;align-items:center;min-height:40px;margin-bottom:16px}:host ::ng-deep .drawer__header h2{margin:0 auto 0 0;font-weight:600}:host ::ng-deep .mat-headline-6{font-weight:600}:host ::ng-deep .mat-subtitle-1{font-weight:600}:host ::ng-deep mat-tab-header,:host ::ng-deep .FileDrop{margin-bottom:16px}:host ::ng-deep .tab--skin ::ng-deep .mat-tab-label{height:52px;min-width:auto}:host ::ng-deep .drawer p{white-space:pre-wrap}:host ::ng-deep .mat-divider{margin:16px 0 24px}:host ::ng-deep .mat-drawer-backdrop{display:none}.storage-error{min-width:30px;height:30px;display:flex;align-items:center;align-self:center;border-radius:50%;justify-content:center;background:#fff;color:#c00;font-size:25px;font-weight:700}.layer--toolbar{display:flex;flex-direction:column}.toolbar{display:flex;z-index:101;flex-wrap:nowrap}.toolbar .menu-icon{min-width:50px;display:flex;justify-content:center;margin-left:-16px}.toolbar .left-toolbar,.toolbar .right-toolbar{display:flex;align-items:center;background:#da9803;border-radius:0 0 10px;padding:0 20px 0 10px;box-shadow:0 3px 6px #00000029,0 3px 6px #0000003b;height:100%;gap:12px}.toolbar .right-toolbar{border-radius:0 0 0 10px;padding:0 5px 0 10px}.toolbar .toolbar-icon-list{display:flex;align-items:center;justify-content:center}.toolbar .toolbar-icon-sub{display:flex;align-items:center;justify-content:center;padding:0 10px;gap:5px;border-right:1px solid rgba(255,255,255,.3803921569)}.toolbar .toolbar-icon-sub:last-child{border-right:none}.toolbar .toolbar-icon-sub:first-child{border-left:1px solid rgba(255,255,255,.3803921569);margin-left:10px}.toolbar .toolbar-icon{height:30px;width:30px;display:flex;align-items:center;justify-content:center;cursor:pointer}.toolbar .toolbar-icon co-icon ::ng-deep{width:20px;height:20px}.toolbar .toolbar-icon co-icon ::ng-deep svg,.toolbar .toolbar-icon co-icon ::ng-deep path{fill:#fff}.toolbar .toolbar-icon co-icon.loading-green ::ng-deep svg,.toolbar .toolbar-icon co-icon.loading-green ::ng-deep path{fill:#74b77f}.toolbar .toolbar-icon co-icon.loading-orange ::ng-deep svg,.toolbar .toolbar-icon co-icon.loading-orange ::ng-deep path{fill:#f17300}.toolbar .toolbar-icon co-icon.loading-yellow ::ng-deep svg,.toolbar .toolbar-icon co-icon.loading-yellow ::ng-deep path{fill:#cc2936}.toolbar .toolbar-icon co-icon.loading-red ::ng-deep svg,.toolbar .toolbar-icon co-icon.loading-red ::ng-deep path{fill:#cc2936}.toolbar .toolbar-icon.search co-icon{height:30px;width:30px}.toolbar .toolbar-icon.disabled{cursor:default}.toolbar .toolbar-icon.disabled co-icon ::ng-deep svg{fill:#00000042}.toolbar-logo{height:20px}.secondary-logo{margin-left:20px}.toolbar__nav{display:flex;flex-direction:row;padding-top:0}.toolbar__nav .mat-mdc-list-item{color:#fff;height:40px}.toolbar-row{flex:auto;display:flex;flex-direction:column;padding:0;pointer-events:none;position:relative;align-items:baseline;height:100%}::ng-deep mat-toolbar-row .toolbar--secondary{width:50px;padding:15px 0;flex-direction:column;background:#17253391;height:100%;gap:5px}::ng-deep mat-toolbar-row .toolbar--secondary button ::ng-deep{width:30px;height:30px;line-height:30px;color:#fff;display:flex;justify-content:center}::ng-deep mat-toolbar-row .toolbar--secondary .add-to-cart-button button ::ng-deep{color:#da9803}.toolbar--secondary .drawer{flex:auto;pointer-events:none;background:transparent}.wip-card{margin-left:5px;padding:0 10px;color:#fff;background-color:#7a828a}.wip-card .mat-mdc-card-content{font-size:12px}.drawer-container{position:static;box-shadow:0 1px 3px #0000001f,0 1px 2px #0000003d}.drawer{width:420px;padding:16px;display:flex;flex-direction:column;left:50px}::ng-deep rp-category-library .mat-mdc-list-item ::ng-deep{border-color:#747c84}::ng-deep rp-category-library .mdc-list-item__primary-text{color:#000}::ng-deep rp-category-library .mdc-list-item:hover .mdc-list-item__primary-text{color:#000}.toolbar,.toolbar--secondary>*,.drawer-container>*,.drawer>*{pointer-events:all}.drawer__button{min-width:initial;padding:0;border:none;position:absolute;top:0;right:0;border-radius:50%}.blinker{animation:blinker 1s linear infinite}.badge-tooltip{position:relative}.badge-tooltip .mat-badge{position:absolute;margin:0;display:flex;align-items:center;justify-content:center;right:-2px;bottom:13px}.badge-tooltip .mat-badge .mat-badge-content{background-color:transparent;color:#b71c1c;border:1px solid #b71c1c;animation:bounce 2s ease-out;animation-iteration-count:infinite;right:initial;left:initial;position:relative;height:12px;width:12px;line-height:12px;font-size:10px;bottom:initial}::ng-deep .tooltip-red{background:#b71c1c}@keyframes bounce{0%{transform:scale(1) translateY(0)}10%{transform:scale(1.1,.9) translateY(0)}30%{transform:scale(.9,1.1) translateY(-20px)}50%{transform:scale(1.05,.95) translateY(0)}57%{transform:scale(1) translateY(-7px)}64%{transform:scale(1) translateY(0)}to{transform:scale(1) translateY(0)}}@keyframes blinker{50%{opacity:0}}::ng-deep .mat-mdc-menu-panel{width:256px!important}::ng-deep .mat-mdc-menu-panel .mat-mdc-menu-content{display:flex;flex-direction:column;padding-left:10px;padding-right:10px}::ng-deep mat-drawer-content.mat-drawer-content{display:flex;height:100%;flex-direction:column}\n"] }]
48806
- }], ctorParameters: () => [{ type: AppStateService }, { type: PresetsService }, { type: MessageBusService }, { type: HomedecoratorSettingsService }, { type: LocalStorageService }, { type: HomedecoratorIconCacheService }, { type: ScreenSizeAnalysisService }, { type: i1$2.MatDialog }, { type: ToastService }, { type: HomedecoratorAppService }, { type: PermanentStoreService }, { type: UtilsService }, { type: ItemService }, { type: FloorService }, { type: AnimationService }, { type: DevelopmentService }, { type: NewRenderService }, { type: ThirdPartyModelService }, { type: LightPresetsService }, { type: HomedecoratorConnectorAdapterService }, { type: ConnectionHeathService }, { type: HomedecoratorAppEventService }], propDecorators: { externalSave: [{
48434
+ }], ctorParameters: () => [{ type: AppStateService }, { type: PresetsService }, { type: MessageBusService }, { type: HomedecoratorSettingsService }, { type: LocalStorageService }, { type: HomedecoratorIconCacheService }, { type: ScreenSizeAnalysisService }, { type: i1$2.MatDialog }, { type: ToastService }, { type: HomedecoratorAppService }, { type: PermanentStoreService }, { type: UtilsService }, { type: ItemService }, { type: FloorService }, { type: AnimationService }, { type: DevelopmentService }, { type: RenderService }, { type: ThirdPartyModelService }, { type: LightPresetsService }, { type: HomedecoratorConnectorAdapterService }, { type: ConnectionHeathService }, { type: HomedecoratorAppEventService }], propDecorators: { externalSave: [{
48807
48435
  type: Output
48808
48436
  }], leftSidebar: [{
48809
48437
  type: ViewChild,
@@ -48984,28 +48612,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
48984
48612
  args: ['fileUpload']
48985
48613
  }] } });
48986
48614
 
48987
- // A pipe for appending strings to other strings in view templates.
48988
- class AppendPipe {
48989
- transform(value, append) {
48990
- if (!value) {
48991
- return '';
48992
- }
48993
- if (!append) {
48994
- return value;
48995
- }
48996
- return value + append;
48997
- }
48998
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppendPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
48999
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.16", ngImport: i0, type: AppendPipe, isStandalone: false, name: "append" }); }
49000
- }
49001
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppendPipe, decorators: [{
49002
- type: Pipe,
49003
- args: [{
49004
- name: 'append',
49005
- standalone: false
49006
- }]
49007
- }] });
49008
-
49009
48615
  class ProductCatalogComponent {
49010
48616
  get shown() {
49011
48617
  return this._showCatalog;
@@ -49428,7 +49034,7 @@ class HomedecoratorComponent {
49428
49034
  return this._settings;
49429
49035
  }
49430
49036
  constructor(appService, // don't remove this, needs to be created on a high level
49431
- controllerService, appState, presetsService, screenAnalysis, _iconRegistry, _domSanitizer, _messageService, _homedecoratorService, _parentEventService, _ownEventService, _integrationService, _sceneService, _webWorkerService) {
49037
+ controllerService, appState, presetsService, screenAnalysis, _iconRegistry, _domSanitizer, _messageService, _homedecoratorService, _parentEventService, _ownEventService, _integrationService, _sceneService, _webWorkerService, _injector) {
49432
49038
  this.appService = appService;
49433
49039
  this.controllerService = controllerService;
49434
49040
  this.appState = appState;
@@ -49443,6 +49049,7 @@ class HomedecoratorComponent {
49443
49049
  this._integrationService = _integrationService;
49444
49050
  this._sceneService = _sceneService;
49445
49051
  this._webWorkerService = _webWorkerService;
49052
+ this._injector = _injector;
49446
49053
  this.generalFilterOrders = [
49447
49054
  { name: 'CATEGORY', order: 1 },
49448
49055
  { name: 'TURNOVER_GROUP', order: 2 },
@@ -49528,6 +49135,7 @@ class HomedecoratorComponent {
49528
49135
  // };
49529
49136
  this._subs = [];
49530
49137
  this._initCommunication = false;
49138
+ ServiceLocator.injector = this._injector;
49531
49139
  this._eventService = _parentEventService || _ownEventService;
49532
49140
  this._webWorkerService.initWorkers();
49533
49141
  }
@@ -49646,7 +49254,7 @@ class HomedecoratorComponent {
49646
49254
  _initConnection() {
49647
49255
  this._homedecoratorService.init(this._settings);
49648
49256
  }
49649
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: HomedecoratorComponent, deps: [{ token: HomedecoratorAppService }, { token: HomedecoratorConnectorService }, { token: AppStateService }, { token: PresetsService }, { token: ScreenSizeAnalysisService }, { token: i4.MatIconRegistry }, { token: i1$1.DomSanitizer }, { token: MessageBusService }, { token: HomedecoratorService }, { token: HomedecoratorAppEventService, optional: true, skipSelf: true }, { token: HomedecoratorAppEventService, optional: true, self: true }, { token: IntegrationService }, { token: SceneService }, { token: WebWorkerService }], target: i0.ɵɵFactoryTarget.Component }); }
49257
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: HomedecoratorComponent, deps: [{ token: HomedecoratorAppService }, { token: HomedecoratorConnectorService }, { token: AppStateService }, { token: PresetsService }, { token: ScreenSizeAnalysisService }, { token: i4.MatIconRegistry }, { token: i1$1.DomSanitizer }, { token: MessageBusService }, { token: HomedecoratorService }, { token: HomedecoratorAppEventService, optional: true, skipSelf: true }, { token: HomedecoratorAppEventService, optional: true, self: true }, { token: IntegrationService }, { token: SceneService }, { token: WebWorkerService }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component }); }
49650
49258
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: HomedecoratorComponent, isStandalone: false, selector: "co-homedecorator", inputs: { generalFilterOrders: "generalFilterOrders", purchaseFilterOrders: "purchaseFilterOrders", logisticsFilterOrders: "logisticsFilterOrders", initCommunication: "initCommunication", projectToLoad: "projectToLoad", settings: "settings" }, host: { listeners: { "document:keyup": "keyup($event)" }, properties: { "class.co-homedecorator": "this.showClass" } }, providers: [
49651
49259
  APPLICATION_SERVICES_PROVIDERS
49652
49260
  ], ngImport: i0, template: `
@@ -49740,7 +49348,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
49740
49348
  type: Optional
49741
49349
  }, {
49742
49350
  type: Self
49743
- }] }, { type: IntegrationService }, { type: SceneService }, { type: WebWorkerService }], propDecorators: { generalFilterOrders: [{
49351
+ }] }, { type: IntegrationService }, { type: SceneService }, { type: WebWorkerService }, { type: i0.Injector }], propDecorators: { generalFilterOrders: [{
49744
49352
  type: Input
49745
49353
  }], purchaseFilterOrders: [{
49746
49354
  type: Input
@@ -52558,11 +52166,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
52558
52166
  }] });
52559
52167
 
52560
52168
  class HomedecoratorModule {
52561
- constructor(_injector) {
52562
- this._injector = _injector;
52563
- ServiceLocator.injector = this._injector;
52564
- }
52565
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: HomedecoratorModule, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.NgModule }); }
52169
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: HomedecoratorModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
52566
52170
  static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.16", ngImport: i0, type: HomedecoratorModule, bootstrap: [HomedecoratorComponent], declarations: [HomedecoratorComponent], imports: [CommonModule,
52567
52171
  ProgressBarModule,
52568
52172
  LoadingOverlayModule,
@@ -52611,7 +52215,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
52611
52215
  ],
52612
52216
  bootstrap: [HomedecoratorComponent]
52613
52217
  }]
52614
- }], ctorParameters: () => [{ type: i0.Injector }] });
52218
+ }] });
52615
52219
 
52616
52220
  class MaterialBuilderComponent {
52617
52221
  set settings(value) {