redhotmagma-visualization 1.37.3 → 1.38.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Three/Three3D.js CHANGED
@@ -15,8 +15,6 @@ var _first = _interopRequireDefault(require("lodash/first"));
15
15
 
16
16
  var _findIndex = _interopRequireDefault(require("lodash/findIndex"));
17
17
 
18
- var _get2 = _interopRequireDefault(require("lodash/get"));
19
-
20
18
  var _ThreeBase2 = require("./ThreeBase");
21
19
 
22
20
  var _MTLLoader = _interopRequireDefault(require("./Loaders/MTLLoader"));
@@ -847,16 +845,17 @@ var Three3D = /*#__PURE__*/function (_ThreeBase) {
847
845
  * @param {Vector3|undefined} position The new position
848
846
  * @param {Vector3|undefined} orientation The new orientation of the camera (up vector)
849
847
  * @param {Vector3|undefined} target The new look at point
850
- * @param {{[position]: number, [target]: number, [orientation]: number}} duration The animation duration in ms
848
+ * @param {number|undefined} fov The new fov
849
+ * @param {{[position]: number, [target]: number, [orientation]: number, [fov]: number}} duration The animation duration in ms
851
850
  * @requires TWEEN
852
851
  */
853
852
 
854
853
  }, {
855
854
  key: "moveCamera",
856
- value: function moveCamera(position, orientation, target) {
855
+ value: function moveCamera(position, orientation, target, fov) {
857
856
  var _this4 = this;
858
857
 
859
- var duration = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
858
+ var duration = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
860
859
  this.cleanUpCameraAnimations();
861
860
  var animationDef = new _Deferred.DeferredGroup();
862
861
 
@@ -884,6 +883,14 @@ var Three3D = /*#__PURE__*/function (_ThreeBase) {
884
883
  new _tween["default"].Tween(this.controls.target, this.cameraTweenGroup).to(target, duration.target || 500).easing(_tween["default"].Easing.Quadratic.Out).onComplete(animationDef.createResolver()).start();
885
884
  }
886
885
 
886
+ if (fov) {
887
+ new _tween["default"].Tween(this.camera, this.cameraTweenGroup).to({
888
+ fov: fov
889
+ }, duration.fov || 700).easing(_tween["default"].Easing.Quadratic.Out).onUpdate(function () {
890
+ _this4.camera.updateProjectionMatrix();
891
+ }).start();
892
+ }
893
+
887
894
  animationDef.then(function () {
888
895
  return _this4.stopAnimation("camera");
889
896
  });
@@ -917,19 +924,21 @@ var Three3D = /*#__PURE__*/function (_ThreeBase) {
917
924
  var _this$cameraViews$def = _objectSpread(_objectSpread({}, this.cameraViews["default"]), view),
918
925
  position = _this$cameraViews$def.position,
919
926
  orientation = _this$cameraViews$def.orientation,
920
- target = _this$cameraViews$def.lookat;
927
+ target = _this$cameraViews$def.lookat,
928
+ fov = _this$cameraViews$def.fov;
921
929
 
922
930
  if (animate) {
923
- this.moveCamera(position, orientation, target, duration);
931
+ this.moveCamera(position, orientation, target, fov, duration);
924
932
  } else {
925
- this.setCameraPosition(position, orientation, target);
933
+ this.setCameraPosition(position, orientation, target, fov);
926
934
  }
927
935
  }
928
936
  /**
929
937
  * Sets the camera position and renders the scene if it's not animating
930
938
  * @param {{x: number|undefined, y: number|undefined, z: number|undefined}} position
931
- * @param {{x: number|undefined, y: number|undefined, z: number|undefined}} oritentation
939
+ * @param {{x: number|undefined, y: number|undefined, z: number|undefined}} orientation
932
940
  * @param {{x: number|undefined, y: number|undefined, z: number|undefined}} target
941
+ * @param {number|undefined} fov
933
942
  */
934
943
 
935
944
  }, {
@@ -938,17 +947,23 @@ var Three3D = /*#__PURE__*/function (_ThreeBase) {
938
947
  var position = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
939
948
  y: 30
940
949
  };
941
- var oritentation = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
950
+ var orientation = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
942
951
  var target = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
943
952
  y: 10
944
953
  };
954
+ var fov = arguments.length > 3 ? arguments[3] : undefined;
945
955
 
946
956
  if (!this.camera) {
947
957
  throw new Error("The camera must be available for the setCameraPosition call!");
948
958
  }
949
959
 
950
960
  Object.assign(this.camera.position, position);
951
- Object.assign(this.camera.up, oritentation);
961
+ Object.assign(this.camera.up, orientation);
962
+
963
+ if (fov) {
964
+ this.camera.fov = fov;
965
+ this.camera.updateProjectionMatrix();
966
+ }
952
967
 
953
968
  if (this.controls && this.controls.target) {
954
969
  Object.assign(this.controls.target, target);
@@ -971,7 +986,7 @@ var Three3D = /*#__PURE__*/function (_ThreeBase) {
971
986
  var _getScreenshots = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee9(callback, _ref3) {
972
987
  var _this5 = this;
973
988
 
974
- var viewList, variantList, size, removeTempOverlay, restoreCameraViewOffset, origVariantPath, origPosition, origOrientation, origTarget, origSize, origPixelRatio, restoreOriginalValues, restoreScreenshotSetup, width, height, screenshots, views, viewKeyList, _iterator3, _step3, variant, data, _iterator4, _step4, viewKey, view, _this$cameraViews$def2, position, orientation, target;
989
+ var viewList, variantList, size, removeTempOverlay, restoreCameraViewOffset, origVariantPath, origPosition, origOrientation, origTarget, origSize, origPixelRatio, restoreOriginalValues, restoreScreenshotSetup, width, height, screenshots, views, viewKeyList, _iterator3, _step3, variant, data, _iterator4, _step4, viewKey, view, position, orientation, target, fov;
975
990
 
976
991
  return regeneratorRuntime.wrap(function _callee9$(_context9) {
977
992
  while (1) {
@@ -1053,10 +1068,10 @@ var Three3D = /*#__PURE__*/function (_ThreeBase) {
1053
1068
  case 21:
1054
1069
  restoreScreenshotSetup = _context9.sent;
1055
1070
  // get the size from the size param, or use default values
1056
- width = (0, _get2["default"])(size, "width", 1024);
1057
- height = (0, _get2["default"])(size, "height", 768);
1071
+ width = (size === null || size === void 0 ? void 0 : size.width) || 1024;
1072
+ height = (size === null || size === void 0 ? void 0 : size.height) || 768;
1058
1073
  screenshots = {};
1059
- views = this.cameraViews; // if the viewList option is provided, use it as keys instead of the list of all views
1074
+ views = this.screenshotViews || this.cameraViews; // if the viewList option is provided, use it as keys instead of the list of all views
1060
1075
 
1061
1076
  viewKeyList = viewList instanceof Array && viewList.length > 0 ? viewList : Object.keys(views);
1062
1077
  _iterator3 = _createForOfIteratorHelper(variantList);
@@ -1128,13 +1143,13 @@ var Three3D = /*#__PURE__*/function (_ThreeBase) {
1128
1143
 
1129
1144
  case 55:
1130
1145
  view = views[viewKey];
1131
- _this$cameraViews$def2 = _objectSpread(_objectSpread({}, this.cameraViews["default"]), view), position = _this$cameraViews$def2.position, orientation = _this$cameraViews$def2.orientation, target = _this$cameraViews$def2.lookat; // set the camera to the screenshot size
1146
+ position = view.position, orientation = view.orientation, target = view.lookat, fov = view.fov; // set the camera to the screenshot size
1132
1147
 
1133
1148
  this.renderer.setPixelRatio(1);
1134
1149
  this.renderer.setSize(width, height);
1135
1150
  this.updateCamera(width, height);
1136
1151
  this.camera.clearViewOffset();
1137
- this.setCameraPosition(position, orientation, target);
1152
+ this.setCameraPosition(position, orientation, target, fov);
1138
1153
  this.render();
1139
1154
  data[viewKey] = this.renderer.domElement.toDataURL("image/png");
1140
1155
 
@@ -1283,7 +1298,8 @@ var Three3D = /*#__PURE__*/function (_ThreeBase) {
1283
1298
  });
1284
1299
 
1285
1300
  if (clearTexture) {
1286
- // draw the texture image on the drawing canvas to clear the previous state
1301
+ ctx.clearRect(0, 0, canvas.width, canvas.height); // draw the texture image on the drawing canvas to clear the previous state
1302
+
1287
1303
  ctx.drawImage(originalImage, 0, 0);
1288
1304
  }
1289
1305
 
@@ -1366,9 +1382,9 @@ var Three3D = /*#__PURE__*/function (_ThreeBase) {
1366
1382
  }, {
1367
1383
  key: "setControlsDistanceMinMax",
1368
1384
  value: function setControlsDistanceMinMax() {
1369
- var _this$cameraViews$def3 = this.cameraViews["default"],
1370
- position = _this$cameraViews$def3.position,
1371
- lookat = _this$cameraViews$def3.lookat;
1385
+ var _this$cameraViews$def2 = this.cameraViews["default"],
1386
+ position = _this$cameraViews$def2.position,
1387
+ lookat = _this$cameraViews$def2.lookat;
1372
1388
  var d = position.distanceTo(lookat);
1373
1389
  this.controls.maxDistance = d * MAX_DISTANCE_MULTIPLIER;
1374
1390
  this.controls.minDistance = d * MIN_DISTANCE_MULTIPLIER;
@@ -385,7 +385,20 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
385
385
 
386
386
  _defineProperty(_assertThisInitialized(_this), "dirLightPosition", new _three.Vector3(1, 1, 1).normalize());
387
387
 
388
- _defineProperty(_assertThisInitialized(_this), "cameraPosition", new _three.Vector3(0, 1, 2).normalize());
388
+ _defineProperty(_assertThisInitialized(_this), "defaultCameraPosition", new _three.Vector3(0, 1, 2).normalize());
389
+
390
+ _defineProperty(_assertThisInitialized(_this), "defaultScreenshotPosition", new _three.Vector3(0, 0, 1).normalize());
391
+
392
+ _defineProperty(_assertThisInitialized(_this), "relativeCameraViews", {});
393
+
394
+ _defineProperty(_assertThisInitialized(_this), "relativeScreenshotViews", {});
395
+
396
+ _defineProperty(_assertThisInitialized(_this), "groundObjectNames", [/ground/i]);
397
+
398
+ _defineProperty(_assertThisInitialized(_this), "config", {
399
+ useShadowGround: true,
400
+ removeGroundForScreenshot: true
401
+ });
389
402
 
390
403
  _defineProperty(_assertThisInitialized(_this), "animate", function () {
391
404
  var time = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
@@ -442,6 +455,11 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
442
455
  }
443
456
 
444
457
  _createClass(Three3DScene, [{
458
+ key: "setOptions3D",
459
+ value: function setOptions3D(options) {
460
+ Object.assign(this.config, options);
461
+ }
462
+ }, {
445
463
  key: "createLoadingManager",
446
464
  value: function createLoadingManager() {
447
465
  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
@@ -507,7 +525,7 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
507
525
  key: "createCamera",
508
526
  value: function createCamera() {
509
527
  var camera = new _three.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.01);
510
- camera.position.copy(this.cameraPosition).multiplyScalar(1000);
528
+ camera.position.copy(this.defaultCameraPosition).multiplyScalar(1000);
511
529
  return camera;
512
530
  }
513
531
  }, {
@@ -521,7 +539,6 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
521
539
  value: function createScene() {
522
540
  var scene = new _three.Scene();
523
541
  scene.add(this.createHemiLight());
524
- scene.add(this.createGround());
525
542
  scene.add(this.createDirLight());
526
543
  scene.add(this.sceneContainer);
527
544
  return scene;
@@ -580,7 +597,7 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
580
597
  object.castShadow = true;
581
598
  }
582
599
 
583
- if (object.isLight && object.target) {
600
+ if (object.isLight && object.target && _this2.ground) {
584
601
  object.target = _this2.ground;
585
602
  setLightShadow(object);
586
603
  }
@@ -982,17 +999,57 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
982
999
  modelFileName: modelFileName
983
1000
  };
984
1001
  }
1002
+ }, {
1003
+ key: "loadSceneSync",
1004
+ value: function () {
1005
+ var _loadSceneSync = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee6(resourceList) {
1006
+ var _disableRender, result;
1007
+
1008
+ return regeneratorRuntime.wrap(function _callee6$(_context6) {
1009
+ while (1) {
1010
+ switch (_context6.prev = _context6.next) {
1011
+ case 0:
1012
+ _context6.next = 2;
1013
+ return this._loadScenePromise;
1014
+
1015
+ case 2:
1016
+ _disableRender = this._disableRender;
1017
+ this._disableRender = true;
1018
+ this._loadScenePromise = this.loadScene(resourceList);
1019
+ _context6.next = 7;
1020
+ return this._loadScenePromise;
1021
+
1022
+ case 7:
1023
+ result = _context6.sent;
1024
+ this._disableRender = _disableRender;
1025
+ this.render();
1026
+ return _context6.abrupt("return", result);
1027
+
1028
+ case 11:
1029
+ case "end":
1030
+ return _context6.stop();
1031
+ }
1032
+ }
1033
+ }, _callee6, this);
1034
+ }));
1035
+
1036
+ function loadSceneSync(_x8) {
1037
+ return _loadSceneSync.apply(this, arguments);
1038
+ }
1039
+
1040
+ return loadSceneSync;
1041
+ }()
985
1042
  }, {
986
1043
  key: "loadScene",
987
1044
  value: function () {
988
- var _loadScene = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee6(resourceList) {
1045
+ var _loadScene = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee7(resourceList) {
989
1046
  var _this5 = this;
990
1047
 
991
1048
  var sceneContainer, _diffResourceLists, toBeRemoved, toBeAdded, toBeUpdated, toBeApplied, shouldResetScene, toBeDisposed, triggerLoadEvent, sceneParts, imageLoader, mixer, animations;
992
1049
 
993
- return regeneratorRuntime.wrap(function _callee6$(_context6) {
1050
+ return regeneratorRuntime.wrap(function _callee7$(_context7) {
994
1051
  while (1) {
995
- switch (_context6.prev = _context6.next) {
1052
+ switch (_context7.prev = _context7.next) {
996
1053
  case 0:
997
1054
  sceneContainer = this.sceneContainer;
998
1055
  this.stopAnimation();
@@ -1018,13 +1075,13 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
1018
1075
  });
1019
1076
  triggerLoadEvent = !!(toBeAdded.length || toBeUpdated.length || toBeApplied.length);
1020
1077
  triggerLoadEvent && this.onLoadStart();
1021
- _context6.next = 13;
1078
+ _context7.next = 13;
1022
1079
  return Promise.all(toBeAdded.map(function (item) {
1023
1080
  return _this5.loadSceneContainer(item);
1024
1081
  }));
1025
1082
 
1026
1083
  case 13:
1027
- sceneParts = _context6.sent;
1084
+ sceneParts = _context7.sent;
1028
1085
  sceneParts.forEach(function (_ref10) {
1029
1086
  var scene = _ref10.scene,
1030
1087
  animations = _ref10.animations;
@@ -1043,7 +1100,7 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
1043
1100
  }
1044
1101
  });
1045
1102
  sceneContainer.updateWorldMatrix(true, true);
1046
- _context6.next = 18;
1103
+ _context7.next = 18;
1047
1104
  return Promise.all(toBeUpdated.map(function (item) {
1048
1105
  var itemSrc = getSrc(item);
1049
1106
  var object = findObjectWith(sceneContainer, function (_ref13) {
@@ -1070,7 +1127,7 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
1070
1127
  imageLoader = this.createImageLoader({
1071
1128
  basePath: this._modelBasePath
1072
1129
  });
1073
- _context6.next = 21;
1130
+ _context7.next = 21;
1074
1131
  return Promise.all(toBeApplied.map(function (_ref14) {
1075
1132
  var optionParams = _ref14.params,
1076
1133
  files = _ref14.files;
@@ -1098,10 +1155,11 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
1098
1155
  }));
1099
1156
 
1100
1157
  case 21:
1101
- _context6.next = 23;
1158
+ _context7.next = 23;
1102
1159
  return this.initCustomizableMaterialsIfNeeded();
1103
1160
 
1104
1161
  case 23:
1162
+ this.setupGround();
1105
1163
  this.addLightsIfNeeded(sceneContainer);
1106
1164
  this.fitSceneToCamera();
1107
1165
  this.initCameraViews(this.getCameras(sceneContainer));
@@ -1119,15 +1177,15 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
1119
1177
  this.render();
1120
1178
  }
1121
1179
 
1122
- case 29:
1180
+ case 30:
1123
1181
  case "end":
1124
- return _context6.stop();
1182
+ return _context7.stop();
1125
1183
  }
1126
1184
  }
1127
- }, _callee6, this);
1185
+ }, _callee7, this);
1128
1186
  }));
1129
1187
 
1130
- function loadScene(_x8) {
1188
+ function loadScene(_x9) {
1131
1189
  return _loadScene.apply(this, arguments);
1132
1190
  }
1133
1191
 
@@ -1146,38 +1204,167 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
1146
1204
  return cameras;
1147
1205
  }
1148
1206
  }, {
1149
- key: "initCameraViews",
1150
- value: function initCameraViews(cameras) {
1151
- var box = this.getSceneContainerBox();
1152
- var center = new _three.Vector3();
1153
- box.getCenter(center);
1154
- this.cameraViews["default"] = null;
1155
- this.cameraViews = cameras.reduce(function (views, camera) {
1156
- var position = new _three.Vector3();
1157
- camera.getWorldPosition(position);
1158
- var distance = position.distanceTo(center);
1159
- var dir = new _three.Vector3();
1160
- camera.getWorldDirection(dir);
1161
- var lookat = dir.multiplyScalar(distance).add(position);
1162
- var rotation = new _three.Quaternion();
1163
- camera.getWorldQuaternion(rotation);
1164
-
1165
- var orientation = _three.Object3D.DefaultUp.clone().applyQuaternion(rotation);
1166
-
1167
- return _objectSpread(_objectSpread({}, views), {}, _defineProperty({}, camera.name.toLowerCase(), {
1207
+ key: "setupSceneCameras",
1208
+ value: function setupSceneCameras(cameras, center) {
1209
+ var _iterator4 = _createForOfIteratorHelper(cameras),
1210
+ _step4;
1211
+
1212
+ try {
1213
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
1214
+ var _camera$userData;
1215
+
1216
+ var camera = _step4.value;
1217
+ var position = camera.getWorldPosition(new _three.Vector3());
1218
+ var dir = camera.getWorldDirection(new _three.Vector3());
1219
+ var distance = position.distanceTo(center);
1220
+ var lookat = dir.multiplyScalar(distance).add(position);
1221
+ var rotation = new _three.Quaternion();
1222
+ camera.getWorldQuaternion(rotation);
1223
+
1224
+ var orientation = _three.Object3D.DefaultUp.clone().applyQuaternion(rotation);
1225
+
1226
+ var fov = camera.fov || 45;
1227
+ var cameraView = {
1228
+ position: position,
1229
+ lookat: lookat,
1230
+ orientation: orientation,
1231
+ fov: fov
1232
+ };
1233
+ var cameraName = (_camera$userData = camera.userData) === null || _camera$userData === void 0 ? void 0 : _camera$userData.name;
1234
+
1235
+ if (!cameraName) {
1236
+ continue; // cannot identify, ignore
1237
+ } // map camera views to component names (with the objectName:useFor=component1,component2 name)
1238
+
1239
+
1240
+ var matches = cameraName.match(/:useFor=(([^,]+,?)+)/);
1241
+ var componentIdentifiers = matches && matches[1] && matches[1].split(",");
1242
+
1243
+ if (componentIdentifiers) {
1244
+ var _iterator5 = _createForOfIteratorHelper(componentIdentifiers),
1245
+ _step5;
1246
+
1247
+ try {
1248
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
1249
+ var componentIdentifier = _step5.value;
1250
+ // remove _Orientation suffix added by blender gltf exporter
1251
+ this.cameraViews[componentIdentifier.replace("_Orientation", "")] = cameraView;
1252
+ }
1253
+ } catch (err) {
1254
+ _iterator5.e(err);
1255
+ } finally {
1256
+ _iterator5.f();
1257
+ }
1258
+ } else if (cameraName.startsWith("screenshot_")) {
1259
+ this.screenshotViews[cameraName.replace("screenshot_", "")] = cameraView;
1260
+ } else {
1261
+ this.cameraViews[cameraName] = cameraView;
1262
+ }
1263
+ }
1264
+ } catch (err) {
1265
+ _iterator4.e(err);
1266
+ } finally {
1267
+ _iterator4.f();
1268
+ }
1269
+ }
1270
+ }, {
1271
+ key: "calculateRelativeViews",
1272
+ value: function calculateRelativeViews(viewsObj, center, distance) {
1273
+ var views = {};
1274
+
1275
+ for (var _i3 = 0, _Object$keys = Object.keys(viewsObj); _i3 < _Object$keys.length; _i3++) {
1276
+ var key = _Object$keys[_i3];
1277
+
1278
+ var view = _objectSpread(_objectSpread({}, viewsObj["default"]), viewsObj[key]);
1279
+
1280
+ var position = center.clone().add(view.position.clone().multiplyScalar(distance));
1281
+ var lookat = center.clone().add(view.lookat);
1282
+ views[key] = _objectSpread(_objectSpread({}, view), {}, {
1168
1283
  position: position,
1169
- lookat: lookat,
1170
- orientation: orientation
1171
- }));
1172
- }, {});
1284
+ lookat: lookat
1285
+ });
1286
+ }
1173
1287
 
1174
- if (!this.cameraViews["default"]) {
1175
- this.cameraViews["default"] = {
1176
- position: this.cameraPosition.clone().multiplyScalar(this.controls.maxDistance * 0.75),
1177
- lookat: center.clone(),
1288
+ return views;
1289
+ }
1290
+ }, {
1291
+ key: "setupRelativeCameras",
1292
+ value: function setupRelativeCameras(center) {
1293
+ if (!this.relativeCameraViews["default"]) {
1294
+ this.relativeCameraViews["default"] = {
1295
+ position: this.defaultCameraPosition.clone(),
1296
+ lookat: new _three.Vector3(0, 0, 0),
1178
1297
  orientation: new _three.Vector3(0, 1, 0)
1179
1298
  };
1180
1299
  }
1300
+
1301
+ this.cameraViews = this.calculateRelativeViews(this.relativeCameraViews, center, this.controls.maxDistance * 0.75);
1302
+
1303
+ if (!this.relativeScreenshotViews["default"]) {
1304
+ this.relativeScreenshotViews["default"] = {
1305
+ position: this.defaultScreenshotPosition.clone(),
1306
+ lookat: new _three.Vector3(0, 0, 0),
1307
+ orientation: new _three.Vector3(0, 1, 0)
1308
+ };
1309
+ }
1310
+
1311
+ this.screenshotViews = this.calculateRelativeViews(this.relativeScreenshotViews, center, (this.controls.minDistance + this.controls.maxDistance) * 0.5);
1312
+
1313
+ if (!this._firstCameraInitDone) {
1314
+ this._firstCameraInitDone = true;
1315
+ this.currentCameraView = null;
1316
+ this.jumpToView("default", false);
1317
+ }
1318
+ }
1319
+ }, {
1320
+ key: "initCameraViews",
1321
+ value: function initCameraViews(cameras) {
1322
+ var _this$sceneContainer, _this$sceneContainer$;
1323
+
1324
+ if (!((_this$sceneContainer = this.sceneContainer) !== null && _this$sceneContainer !== void 0 && (_this$sceneContainer$ = _this$sceneContainer.children) !== null && _this$sceneContainer$ !== void 0 && _this$sceneContainer$.length)) {
1325
+ return;
1326
+ }
1327
+
1328
+ if (!this.controls) {
1329
+ return;
1330
+ }
1331
+
1332
+ var box = this.getSceneContainerBox();
1333
+ var center = box.getCenter(new _three.Vector3());
1334
+ this.setupRelativeCameras(center);
1335
+ this.setupSceneCameras(cameras, center);
1336
+ }
1337
+ }, {
1338
+ key: "jumpToView",
1339
+ value: function jumpToView(viewName) {
1340
+ var animate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
1341
+ var duration = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
1342
+
1343
+ if (!this.cameraViews[viewName]) {
1344
+ viewName = "default";
1345
+ }
1346
+
1347
+ if (this.currentCameraView === viewName) {
1348
+ return;
1349
+ }
1350
+
1351
+ this.currentCameraView = viewName;
1352
+ var view = this.cameraViews[viewName];
1353
+
1354
+ if (!view) {
1355
+ return;
1356
+ }
1357
+
1358
+ var position = view.position,
1359
+ orientation = view.orientation,
1360
+ target = view.lookat,
1361
+ fov = view.fov;
1362
+
1363
+ if (animate) {
1364
+ this.moveCamera(position, orientation, target, fov, duration);
1365
+ } else {
1366
+ this.setCameraPosition(position, orientation, target, fov);
1367
+ }
1181
1368
  }
1182
1369
  }, {
1183
1370
  key: "resetScene",
@@ -1189,15 +1376,71 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
1189
1376
  this._customizableMaterialKeys.length = 0;
1190
1377
  this._customizableMaterials.length = 0;
1191
1378
  }
1379
+ }, {
1380
+ key: "isGroundObject",
1381
+ value: function isGroundObject(object) {
1382
+ return this.groundObjectNames.some(function (pattern) {
1383
+ var _object$material;
1384
+
1385
+ return pattern.test(object.name) || pattern.test((_object$material = object.material) === null || _object$material === void 0 ? void 0 : _object$material.name);
1386
+ });
1387
+ }
1388
+ }, {
1389
+ key: "findGroundObject",
1390
+ value: function findGroundObject() {
1391
+ var root = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.sceneContainer;
1392
+
1393
+ var _iterator6 = _createForOfIteratorHelper(root.children),
1394
+ _step6;
1395
+
1396
+ try {
1397
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
1398
+ var object = _step6.value;
1399
+
1400
+ if (this.isGroundObject(object)) {
1401
+ return object;
1402
+ }
1403
+
1404
+ var ground = this.findGroundObject(object);
1405
+
1406
+ if (ground) {
1407
+ return ground;
1408
+ }
1409
+ }
1410
+ } catch (err) {
1411
+ _iterator6.e(err);
1412
+ } finally {
1413
+ _iterator6.f();
1414
+ }
1415
+
1416
+ return null;
1417
+ }
1418
+ }, {
1419
+ key: "setupGround",
1420
+ value: function setupGround() {
1421
+ this.sceneGround = this.findGroundObject();
1422
+
1423
+ if (this.sceneGround && this.ground) {
1424
+ this.scene.remove(this.ground);
1425
+ this.ground = null;
1426
+ } else if (!this.sceneGround && this.config.useShadowGround) {
1427
+ this.scene.add(this.createGround());
1428
+ }
1429
+ }
1192
1430
  }, {
1193
1431
  key: "getSceneContainerBox",
1194
1432
  value: function getSceneContainerBox() {
1433
+ var _this$sceneGround;
1434
+
1435
+ var groundParent = (_this$sceneGround = this.sceneGround) === null || _this$sceneGround === void 0 ? void 0 : _this$sceneGround.parent;
1436
+ groundParent === null || groundParent === void 0 ? void 0 : groundParent.remove(this.sceneGround);
1195
1437
  var box = new _three.Box3();
1196
1438
  this.sceneContainer.traverse(function (object) {
1197
1439
  if (object.isMesh) {
1198
1440
  box.expandByObject(object);
1199
1441
  }
1200
1442
  });
1443
+ groundParent === null || groundParent === void 0 ? void 0 : groundParent.add(this.sceneGround);
1201
1444
  return box;
1202
1445
  }
1203
1446
  }, {
@@ -1307,33 +1550,33 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
1307
1550
  }, {
1308
1551
  key: "update",
1309
1552
  value: function () {
1310
- var _update = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee7(configuration) {
1553
+ var _update = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee8(configuration) {
1311
1554
  var sceneData;
1312
- return regeneratorRuntime.wrap(function _callee7$(_context7) {
1555
+ return regeneratorRuntime.wrap(function _callee8$(_context8) {
1313
1556
  while (1) {
1314
- switch (_context7.prev = _context7.next) {
1557
+ switch (_context8.prev = _context8.next) {
1315
1558
  case 0:
1316
1559
  this._configuration = configuration;
1317
1560
  sceneData = (0, _get["default"])(configuration, "visualizationData.sceneData", false) || (0, _get["default"])(configuration, "visualizationData.designViews[0].models.".concat(this._materialVariantPath), false);
1318
- _context7.t0 = sceneData;
1561
+ _context8.t0 = sceneData;
1319
1562
 
1320
- if (!_context7.t0) {
1321
- _context7.next = 6;
1563
+ if (!_context8.t0) {
1564
+ _context8.next = 6;
1322
1565
  break;
1323
1566
  }
1324
1567
 
1325
- _context7.next = 6;
1326
- return this.loadScene(sceneData);
1568
+ _context8.next = 6;
1569
+ return this.loadSceneSync(sceneData);
1327
1570
 
1328
1571
  case 6:
1329
1572
  case "end":
1330
- return _context7.stop();
1573
+ return _context8.stop();
1331
1574
  }
1332
1575
  }
1333
- }, _callee7, this);
1576
+ }, _callee8, this);
1334
1577
  }));
1335
1578
 
1336
- function update(_x9) {
1579
+ function update(_x10) {
1337
1580
  return _update.apply(this, arguments);
1338
1581
  }
1339
1582
 
@@ -1342,29 +1585,29 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
1342
1585
  }, {
1343
1586
  key: "updateMaterial",
1344
1587
  value: function () {
1345
- var _updateMaterial = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee8() {
1588
+ var _updateMaterial = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee9() {
1346
1589
  var sceneData;
1347
- return regeneratorRuntime.wrap(function _callee8$(_context8) {
1590
+ return regeneratorRuntime.wrap(function _callee9$(_context9) {
1348
1591
  while (1) {
1349
- switch (_context8.prev = _context8.next) {
1592
+ switch (_context9.prev = _context9.next) {
1350
1593
  case 0:
1351
1594
  sceneData = (0, _get["default"])(this._designAreaList, "[0].designView.models.".concat(this._materialVariantPath)) || (0, _get["default"])(this._configuration, "visualizationData.designViews[0].models.".concat(this._materialVariantPath)) || false;
1352
- _context8.t0 = sceneData;
1595
+ _context9.t0 = sceneData;
1353
1596
 
1354
- if (!_context8.t0) {
1355
- _context8.next = 5;
1597
+ if (!_context9.t0) {
1598
+ _context9.next = 5;
1356
1599
  break;
1357
1600
  }
1358
1601
 
1359
- _context8.next = 5;
1360
- return this.loadScene(sceneData);
1602
+ _context9.next = 5;
1603
+ return this.loadSceneSync(sceneData);
1361
1604
 
1362
1605
  case 5:
1363
1606
  case "end":
1364
- return _context8.stop();
1607
+ return _context9.stop();
1365
1608
  }
1366
1609
  }
1367
- }, _callee8, this);
1610
+ }, _callee9, this);
1368
1611
  }));
1369
1612
 
1370
1613
  function updateMaterial() {
@@ -1376,33 +1619,33 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
1376
1619
  }, {
1377
1620
  key: "updateDesignAreaList",
1378
1621
  value: function () {
1379
- var _updateDesignAreaList = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee9(designAreaList) {
1622
+ var _updateDesignAreaList = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee10(designAreaList) {
1380
1623
  var sceneData;
1381
- return regeneratorRuntime.wrap(function _callee9$(_context9) {
1624
+ return regeneratorRuntime.wrap(function _callee10$(_context10) {
1382
1625
  while (1) {
1383
- switch (_context9.prev = _context9.next) {
1626
+ switch (_context10.prev = _context10.next) {
1384
1627
  case 0:
1385
1628
  this._designAreaList = designAreaList;
1386
1629
  sceneData = (0, _get["default"])(designAreaList, "[0].designView.models.".concat(this._materialVariantPath));
1387
- _context9.t0 = sceneData;
1630
+ _context10.t0 = sceneData;
1388
1631
 
1389
- if (!_context9.t0) {
1390
- _context9.next = 6;
1632
+ if (!_context10.t0) {
1633
+ _context10.next = 6;
1391
1634
  break;
1392
1635
  }
1393
1636
 
1394
- _context9.next = 6;
1395
- return this.loadScene(sceneData);
1637
+ _context10.next = 6;
1638
+ return this.loadSceneSync(sceneData);
1396
1639
 
1397
1640
  case 6:
1398
1641
  case "end":
1399
- return _context9.stop();
1642
+ return _context10.stop();
1400
1643
  }
1401
1644
  }
1402
- }, _callee9, this);
1645
+ }, _callee10, this);
1403
1646
  }));
1404
1647
 
1405
- function updateDesignAreaList(_x10) {
1648
+ function updateDesignAreaList(_x11) {
1406
1649
  return _updateDesignAreaList.apply(this, arguments);
1407
1650
  }
1408
1651
 
@@ -1416,13 +1659,17 @@ var Three3DScene = /*#__PURE__*/function (_Three3D) {
1416
1659
  }, {
1417
1660
  key: "setupScreenshots",
1418
1661
  value: function setupScreenshots() {
1419
- var _this6 = this;
1662
+ var ground = this.ground || this.sceneGround;
1420
1663
 
1421
- var groundVisibility = this.ground.visible;
1422
- this.ground.visible = false;
1423
- return function () {
1424
- _this6.ground.visible = groundVisibility;
1425
- };
1664
+ if (ground && this.config.removeGroundForScreenshot) {
1665
+ var groundVisibility = ground.visible;
1666
+ ground.visible = false;
1667
+ return function () {
1668
+ ground.visible = groundVisibility;
1669
+ };
1670
+ }
1671
+
1672
+ return function () {};
1426
1673
  }
1427
1674
  }]);
1428
1675
 
@@ -514,6 +514,10 @@ var ThreeBase = /*#__PURE__*/function (_VisualizationInterfa) {
514
514
  }, {
515
515
  key: "render",
516
516
  value: function render() {
517
+ if (this._disableRender) {
518
+ return;
519
+ }
520
+
517
521
  this.renderer && this.renderer.render(this.scene, this.camera);
518
522
  }
519
523
  }, {
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "redhotmagma-visualization",
3
- "version": "1.37.3",
3
+ "version": "1.38.1",
4
4
  "license": "UNLICENSED",
5
5
  "private": false,
6
6
  "main": "./index.js",
7
7
  "dependencies": {
8
8
  "@babel/polyfill": "^7.12.1",
9
- "@configuratorware/scripts": "1.37.3",
9
+ "@configuratorware/scripts": "1.38.1",
10
10
  "@tweenjs/tween.js": "^17.6.0",
11
11
  "console-polyfill": "^0.3.0",
12
12
  "css-element-queries": "^1.2.3",
@@ -13,7 +13,6 @@ import {
13
13
  import TWEEN from "@tweenjs/tween.js";
14
14
  import first from "lodash/first";
15
15
  import findIndex from "lodash/findIndex";
16
- import get from "lodash/get";
17
16
 
18
17
  import { ThreeBase, onProgress } from "./ThreeBase";
19
18
  import MTLLoader from "./Loaders/MTLLoader";
@@ -465,10 +464,11 @@ export class Three3D extends ThreeBase {
465
464
  * @param {Vector3|undefined} position The new position
466
465
  * @param {Vector3|undefined} orientation The new orientation of the camera (up vector)
467
466
  * @param {Vector3|undefined} target The new look at point
468
- * @param {{[position]: number, [target]: number, [orientation]: number}} duration The animation duration in ms
467
+ * @param {number|undefined} fov The new fov
468
+ * @param {{[position]: number, [target]: number, [orientation]: number, [fov]: number}} duration The animation duration in ms
469
469
  * @requires TWEEN
470
470
  */
471
- moveCamera(position, orientation, target, duration = {}) {
471
+ moveCamera(position, orientation, target, fov, duration = {}) {
472
472
  this.cleanUpCameraAnimations();
473
473
 
474
474
  const animationDef = new DeferredGroup();
@@ -505,6 +505,15 @@ export class Three3D extends ThreeBase {
505
505
  .onComplete(animationDef.createResolver())
506
506
  .start();
507
507
  }
508
+ if (fov) {
509
+ new TWEEN.Tween(this.camera, this.cameraTweenGroup)
510
+ .to({ fov }, duration.fov || 700)
511
+ .easing(TWEEN.Easing.Quadratic.Out)
512
+ .onUpdate(() => {
513
+ this.camera.updateProjectionMatrix();
514
+ })
515
+ .start();
516
+ }
508
517
  animationDef.then(() => this.stopAnimation("camera"));
509
518
  this.startAnimation("camera");
510
519
  }
@@ -527,30 +536,35 @@ export class Three3D extends ThreeBase {
527
536
  console.error(`Camera view does not exist: ${viewNameSafe}`);
528
537
  return;
529
538
  }
530
- const { position, orientation, lookat: target } = {
539
+ const { position, orientation, lookat: target, fov } = {
531
540
  ...this.cameraViews.default,
532
541
  ...view,
533
542
  };
534
543
 
535
544
  if (animate) {
536
- this.moveCamera(position, orientation, target, duration);
545
+ this.moveCamera(position, orientation, target, fov, duration);
537
546
  } else {
538
- this.setCameraPosition(position, orientation, target);
547
+ this.setCameraPosition(position, orientation, target, fov);
539
548
  }
540
549
  }
541
550
 
542
551
  /**
543
552
  * Sets the camera position and renders the scene if it's not animating
544
553
  * @param {{x: number|undefined, y: number|undefined, z: number|undefined}} position
545
- * @param {{x: number|undefined, y: number|undefined, z: number|undefined}} oritentation
554
+ * @param {{x: number|undefined, y: number|undefined, z: number|undefined}} orientation
546
555
  * @param {{x: number|undefined, y: number|undefined, z: number|undefined}} target
556
+ * @param {number|undefined} fov
547
557
  */
548
- setCameraPosition(position = { y: 30 }, oritentation = {}, target = { y: 10 }) {
558
+ setCameraPosition(position = { y: 30 }, orientation = {}, target = { y: 10 }, fov) {
549
559
  if (!this.camera) {
550
560
  throw new Error("The camera must be available for the setCameraPosition call!");
551
561
  }
552
562
  Object.assign(this.camera.position, position);
553
- Object.assign(this.camera.up, oritentation);
563
+ Object.assign(this.camera.up, orientation);
564
+ if (fov) {
565
+ this.camera.fov = fov;
566
+ this.camera.updateProjectionMatrix();
567
+ }
554
568
  if (this.controls && this.controls.target) {
555
569
  Object.assign(this.controls.target, target);
556
570
  if (!this.isAnimating()) {
@@ -601,11 +615,11 @@ export class Three3D extends ThreeBase {
601
615
  const restoreScreenshotSetup = await this.setupScreenshots();
602
616
 
603
617
  // get the size from the size param, or use default values
604
- const width = get(size, "width", 1024);
605
- const height = get(size, "height", 768);
618
+ const width = size?.width || 1024;
619
+ const height = size?.height || 768;
606
620
 
607
621
  const screenshots = {};
608
- const views = this.cameraViews;
622
+ const views = this.screenshotViews || this.cameraViews;
609
623
  // if the viewList option is provided, use it as keys instead of the list of all views
610
624
  const viewKeyList =
611
625
  viewList instanceof Array && viewList.length > 0 ? viewList : Object.keys(views);
@@ -631,17 +645,14 @@ export class Three3D extends ThreeBase {
631
645
  }
632
646
 
633
647
  const view = views[viewKey];
634
- const { position, orientation, lookat: target } = {
635
- ...this.cameraViews.default,
636
- ...view,
637
- };
648
+ const { position, orientation, lookat: target, fov } = view;
638
649
  // set the camera to the screenshot size
639
650
  this.renderer.setPixelRatio(1);
640
651
  this.renderer.setSize(width, height);
641
652
  this.updateCamera(width, height);
642
653
  this.camera.clearViewOffset();
643
654
 
644
- this.setCameraPosition(position, orientation, target);
655
+ this.setCameraPosition(position, orientation, target, fov);
645
656
  this.render();
646
657
 
647
658
  data[viewKey] = this.renderer.domElement.toDataURL("image/png");
@@ -702,6 +713,7 @@ export class Three3D extends ThreeBase {
702
713
  const getTextureBuilder = createTextureBuilder(originalImage, { scaling });
703
714
 
704
715
  if (clearTexture) {
716
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
705
717
  // draw the texture image on the drawing canvas to clear the previous state
706
718
  ctx.drawImage(originalImage, 0, 0);
707
719
  }
@@ -271,13 +271,29 @@ export class Three3DScene extends Three3D {
271
271
  defaultCamera = null;
272
272
 
273
273
  dirLightPosition = new Vector3(1, 1, 1).normalize();
274
- cameraPosition = new Vector3(0, 1, 2).normalize();
274
+
275
+ defaultCameraPosition = new Vector3(0, 1, 2).normalize();
276
+ defaultScreenshotPosition = new Vector3(0, 0, 1).normalize();
277
+
278
+ relativeCameraViews = {};
279
+ relativeScreenshotViews = {};
280
+
281
+ groundObjectNames = [/ground/i];
282
+
283
+ config = {
284
+ useShadowGround: true,
285
+ removeGroundForScreenshot: true,
286
+ };
275
287
 
276
288
  constructor(cfg = {}) {
277
289
  super(cfg);
278
290
  cfg.modelBasePath ? (this._modelBasePath = cfg.modelBasePath) : (this._modelBasePath = "");
279
291
  }
280
292
 
293
+ setOptions3D(options) {
294
+ Object.assign(this.config, options);
295
+ }
296
+
281
297
  createLoadingManager(options = {}) {
282
298
  const { basePath = "", resourcePath = "/" } = options;
283
299
 
@@ -332,7 +348,7 @@ export class Three3DScene extends Three3D {
332
348
 
333
349
  createCamera() {
334
350
  const camera = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.01);
335
- camera.position.copy(this.cameraPosition).multiplyScalar(1000);
351
+ camera.position.copy(this.defaultCameraPosition).multiplyScalar(1000);
336
352
  return camera;
337
353
  }
338
354
 
@@ -343,7 +359,6 @@ export class Three3DScene extends Three3D {
343
359
  createScene() {
344
360
  const scene = new Scene();
345
361
  scene.add(this.createHemiLight());
346
- scene.add(this.createGround());
347
362
  scene.add(this.createDirLight());
348
363
  scene.add(this.sceneContainer);
349
364
  return scene;
@@ -394,7 +409,7 @@ export class Three3DScene extends Three3D {
394
409
  if (object.isMesh) {
395
410
  object.castShadow = true;
396
411
  }
397
- if (object.isLight && object.target) {
412
+ if (object.isLight && object.target && this.ground) {
398
413
  object.target = this.ground;
399
414
  setLightShadow(object);
400
415
  }
@@ -639,6 +654,22 @@ export class Three3DScene extends Three3D {
639
654
  };
640
655
  }
641
656
 
657
+ async loadSceneSync(resourceList) {
658
+ // fix LoadFinished event by trapping the loadScene calls to finish the current one before starting the next one
659
+ await this._loadScenePromise;
660
+
661
+ const { _disableRender } = this;
662
+ this._disableRender = true;
663
+
664
+ this._loadScenePromise = this.loadScene(resourceList);
665
+ const result = await this._loadScenePromise;
666
+
667
+ this._disableRender = _disableRender;
668
+ this.render();
669
+
670
+ return result;
671
+ }
672
+
642
673
  async loadScene(resourceList) {
643
674
  const { sceneContainer } = this;
644
675
 
@@ -740,6 +771,8 @@ export class Three3DScene extends Three3D {
740
771
 
741
772
  await this.initCustomizableMaterialsIfNeeded();
742
773
 
774
+ this.setupGround();
775
+
743
776
  this.addLightsIfNeeded(sceneContainer);
744
777
 
745
778
  this.fitSceneToCamera();
@@ -772,42 +805,136 @@ export class Three3DScene extends Three3D {
772
805
  return cameras;
773
806
  }
774
807
 
775
- initCameraViews(cameras) {
776
- const box = this.getSceneContainerBox();
777
- const center = new Vector3();
778
- box.getCenter(center);
779
-
780
- this.cameraViews.default = null;
781
-
782
- this.cameraViews = cameras.reduce((views, camera) => {
783
- const position = new Vector3();
784
- camera.getWorldPosition(position);
785
-
808
+ setupSceneCameras(cameras, center) {
809
+ for (const camera of cameras) {
810
+ const position = camera.getWorldPosition(new Vector3());
811
+ const dir = camera.getWorldDirection(new Vector3());
786
812
  const distance = position.distanceTo(center);
787
- const dir = new Vector3();
788
- camera.getWorldDirection(dir);
789
813
  const lookat = dir.multiplyScalar(distance).add(position);
790
814
 
791
815
  const rotation = new Quaternion();
792
816
  camera.getWorldQuaternion(rotation);
793
-
794
817
  const orientation = Object3D.DefaultUp.clone().applyQuaternion(rotation);
795
- return {
796
- ...views,
797
- [camera.name.toLowerCase()]: {
798
- position,
799
- lookat,
800
- orientation,
801
- },
818
+
819
+ const fov = camera.fov || 45;
820
+
821
+ const cameraView = {
822
+ position,
823
+ lookat,
824
+ orientation,
825
+ fov,
826
+ };
827
+
828
+ const cameraName = camera.userData?.name;
829
+ if (!cameraName) {
830
+ continue; // cannot identify, ignore
831
+ }
832
+ // map camera views to component names (with the objectName:useFor=component1,component2 name)
833
+ const matches = cameraName.match(/:useFor=(([^,]+,?)+)/);
834
+ const componentIdentifiers = matches && matches[1] && matches[1].split(",");
835
+ if (componentIdentifiers) {
836
+ for (const componentIdentifier of componentIdentifiers) {
837
+ // remove _Orientation suffix added by blender gltf exporter
838
+ this.cameraViews[componentIdentifier.replace("_Orientation", "")] = cameraView;
839
+ }
840
+ } else if (cameraName.startsWith("screenshot_")) {
841
+ this.screenshotViews[cameraName.replace("screenshot_", "")] = cameraView;
842
+ } else {
843
+ this.cameraViews[cameraName] = cameraView;
844
+ }
845
+ }
846
+ }
847
+
848
+ calculateRelativeViews(viewsObj, center, distance) {
849
+ const views = {};
850
+ for (const key of Object.keys(viewsObj)) {
851
+ const view = {
852
+ ...viewsObj.default,
853
+ ...viewsObj[key],
854
+ };
855
+ const position = center.clone().add(view.position.clone().multiplyScalar(distance));
856
+ const lookat = center.clone().add(view.lookat);
857
+ views[key] = {
858
+ ...view,
859
+ position,
860
+ lookat,
861
+ };
862
+ }
863
+ return views;
864
+ }
865
+
866
+ setupRelativeCameras(center) {
867
+ if (!this.relativeCameraViews.default) {
868
+ this.relativeCameraViews.default = {
869
+ position: this.defaultCameraPosition.clone(),
870
+ lookat: new Vector3(0, 0, 0),
871
+ orientation: new Vector3(0, 1, 0),
802
872
  };
803
- }, {});
804
- if (!this.cameraViews.default) {
805
- this.cameraViews.default = {
806
- position: this.cameraPosition.clone().multiplyScalar(this.controls.maxDistance * 0.75),
807
- lookat: center.clone(),
873
+ }
874
+ this.cameraViews = this.calculateRelativeViews(
875
+ this.relativeCameraViews,
876
+ center,
877
+ this.controls.maxDistance * 0.75
878
+ );
879
+
880
+ if (!this.relativeScreenshotViews.default) {
881
+ this.relativeScreenshotViews.default = {
882
+ position: this.defaultScreenshotPosition.clone(),
883
+ lookat: new Vector3(0, 0, 0),
808
884
  orientation: new Vector3(0, 1, 0),
809
885
  };
810
886
  }
887
+
888
+ this.screenshotViews = this.calculateRelativeViews(
889
+ this.relativeScreenshotViews,
890
+ center,
891
+ (this.controls.minDistance + this.controls.maxDistance) * 0.5
892
+ );
893
+
894
+ if (!this._firstCameraInitDone) {
895
+ this._firstCameraInitDone = true;
896
+ this.currentCameraView = null;
897
+ this.jumpToView("default", false);
898
+ }
899
+ }
900
+
901
+ initCameraViews(cameras) {
902
+ if (!this.sceneContainer?.children?.length) {
903
+ return;
904
+ }
905
+ if (!this.controls) {
906
+ return;
907
+ }
908
+
909
+ const box = this.getSceneContainerBox();
910
+ const center = box.getCenter(new Vector3());
911
+
912
+ this.setupRelativeCameras(center);
913
+ this.setupSceneCameras(cameras, center);
914
+ }
915
+
916
+ jumpToView(viewName, animate = true, duration = {}) {
917
+ if (!this.cameraViews[viewName]) {
918
+ viewName = "default";
919
+ }
920
+ if (this.currentCameraView === viewName) {
921
+ return;
922
+ }
923
+
924
+ this.currentCameraView = viewName;
925
+ const view = this.cameraViews[viewName];
926
+
927
+ if (!view) {
928
+ return;
929
+ }
930
+
931
+ const { position, orientation, lookat: target, fov } = view;
932
+
933
+ if (animate) {
934
+ this.moveCamera(position, orientation, target, fov, duration);
935
+ } else {
936
+ this.setCameraPosition(position, orientation, target, fov);
937
+ }
811
938
  }
812
939
 
813
940
  resetScene() {
@@ -819,13 +946,45 @@ export class Three3DScene extends Three3D {
819
946
  this._customizableMaterials.length = 0;
820
947
  }
821
948
 
949
+ isGroundObject(object) {
950
+ return this.groundObjectNames.some(
951
+ pattern => pattern.test(object.name) || pattern.test(object.material?.name)
952
+ );
953
+ }
954
+
955
+ findGroundObject(root = this.sceneContainer) {
956
+ for (const object of root.children) {
957
+ if (this.isGroundObject(object)) {
958
+ return object;
959
+ }
960
+ const ground = this.findGroundObject(object);
961
+ if (ground) {
962
+ return ground;
963
+ }
964
+ }
965
+ return null;
966
+ }
967
+
968
+ setupGround() {
969
+ this.sceneGround = this.findGroundObject();
970
+ if (this.sceneGround && this.ground) {
971
+ this.scene.remove(this.ground);
972
+ this.ground = null;
973
+ } else if (!this.sceneGround && this.config.useShadowGround) {
974
+ this.scene.add(this.createGround());
975
+ }
976
+ }
977
+
822
978
  getSceneContainerBox() {
979
+ const groundParent = this.sceneGround?.parent;
980
+ groundParent?.remove(this.sceneGround);
823
981
  const box = new Box3();
824
982
  this.sceneContainer.traverse(object => {
825
983
  if (object.isMesh) {
826
984
  box.expandByObject(object);
827
985
  }
828
986
  });
987
+ groundParent?.add(this.sceneGround);
829
988
  return box;
830
989
  }
831
990
 
@@ -948,7 +1107,7 @@ export class Three3DScene extends Three3D {
948
1107
  `visualizationData.designViews[0].models.${this._materialVariantPath}`,
949
1108
  false
950
1109
  );
951
- sceneData && (await this.loadScene(sceneData));
1110
+ sceneData && (await this.loadSceneSync(sceneData));
952
1111
  }
953
1112
 
954
1113
  async updateMaterial() {
@@ -959,13 +1118,13 @@ export class Three3DScene extends Three3D {
959
1118
  `visualizationData.designViews[0].models.${this._materialVariantPath}`
960
1119
  ) ||
961
1120
  false;
962
- sceneData && (await this.loadScene(sceneData));
1121
+ sceneData && (await this.loadSceneSync(sceneData));
963
1122
  }
964
1123
 
965
1124
  async updateDesignAreaList(designAreaList) {
966
1125
  this._designAreaList = designAreaList;
967
1126
  const sceneData = get(designAreaList, `[0].designView.models.${this._materialVariantPath}`);
968
- sceneData && (await this.loadScene(sceneData));
1127
+ sceneData && (await this.loadSceneSync(sceneData));
969
1128
  }
970
1129
 
971
1130
  exportGLTF() {
@@ -992,10 +1151,14 @@ export class Three3DScene extends Three3D {
992
1151
  };
993
1152
 
994
1153
  setupScreenshots() {
995
- const groundVisibility = this.ground.visible;
996
- this.ground.visible = false;
997
- return () => {
998
- this.ground.visible = groundVisibility;
999
- };
1154
+ const ground = this.ground || this.sceneGround;
1155
+ if (ground && this.config.removeGroundForScreenshot) {
1156
+ const groundVisibility = ground.visible;
1157
+ ground.visible = false;
1158
+ return () => {
1159
+ ground.visible = groundVisibility;
1160
+ };
1161
+ }
1162
+ return () => {};
1000
1163
  }
1001
1164
  }
@@ -294,6 +294,9 @@ export class ThreeBase extends VisualizationInterface {
294
294
  endAnimation = () => this.cameraTweenGroup.getAll().forEach(item => item.end());
295
295
 
296
296
  render() {
297
+ if (this._disableRender) {
298
+ return;
299
+ }
297
300
  this.renderer && this.renderer.render(this.scene, this.camera);
298
301
  }
299
302