@2112-lab/central-plant 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/cjs/_virtual/_rollupPluginBabelHelpers.js +432 -1
  2. package/dist/cjs/node_modules/@2112-lab/pathfinder/dist/index.esm.js +1448 -1
  3. package/dist/cjs/node_modules/three/examples/jsm/controls/OrbitControls.js +1853 -1
  4. package/dist/cjs/node_modules/three/examples/jsm/exporters/GLTFExporter.js +3537 -1
  5. package/dist/cjs/node_modules/three/examples/jsm/exporters/OBJExporter.js +305 -1
  6. package/dist/cjs/node_modules/three/examples/jsm/exporters/PLYExporter.js +542 -1
  7. package/dist/cjs/node_modules/three/examples/jsm/exporters/STLExporter.js +218 -1
  8. package/dist/cjs/node_modules/three/examples/jsm/loaders/DRACOLoader.js +683 -1
  9. package/dist/cjs/node_modules/three/examples/jsm/loaders/GLTFLoader.js +4811 -1
  10. package/dist/cjs/node_modules/three/examples/jsm/loaders/RGBELoader.js +480 -1
  11. package/dist/cjs/node_modules/three/examples/jsm/renderers/CSS2DRenderer.js +309 -1
  12. package/dist/cjs/node_modules/three/examples/jsm/utils/BufferGeometryUtils.js +120 -1
  13. package/dist/cjs/src/analysis/analysis.js +560 -1
  14. package/dist/cjs/src/analysis/testing.js +958 -1
  15. package/dist/cjs/src/core/centralPlant.js +1149 -1
  16. package/dist/cjs/src/core/debugLogger.js +175 -1
  17. package/dist/cjs/src/core/mathUtils.js +574 -1
  18. package/dist/cjs/src/core/nameUtils.js +93 -1
  19. package/dist/cjs/src/data/export.js +716 -1
  20. package/dist/cjs/src/data/import.js +380 -1
  21. package/dist/cjs/src/data/numerics.js +522 -1
  22. package/dist/cjs/src/helpers/sceneHelper.js +572 -1
  23. package/dist/cjs/src/index.js +69 -1
  24. package/dist/cjs/src/managers/components/animationManager.js +123 -1
  25. package/dist/cjs/src/managers/components/componentManager.js +332 -1
  26. package/dist/cjs/src/managers/components/pathfindingManager.js +1441 -1
  27. package/dist/cjs/src/managers/controls/TransformControls.js +1063 -1
  28. package/dist/cjs/src/managers/controls/cameraControlsManager.js +79 -1
  29. package/dist/cjs/src/managers/controls/dragDropManager.js +1026 -1
  30. package/dist/cjs/src/managers/controls/keyboardControlsManager.js +395 -1
  31. package/dist/cjs/src/managers/controls/transformControlsManager.js +1807 -1
  32. package/dist/cjs/src/managers/environment/environmentManager.js +714 -1
  33. package/dist/cjs/src/managers/environment/textureConfig.js +229 -1
  34. package/dist/cjs/src/managers/scene/sceneExportManager.js +264 -1
  35. package/dist/cjs/src/managers/scene/sceneInitializationManager.js +346 -1
  36. package/dist/cjs/src/managers/scene/sceneOperationsManager.js +1509 -1
  37. package/dist/cjs/src/managers/scene/sceneTooltipsManager.js +661 -1
  38. package/dist/cjs/src/managers/system/disposalManager.js +444 -1
  39. package/dist/cjs/src/managers/system/hotReloadManager.js +291 -1
  40. package/dist/cjs/src/managers/system/performanceMonitor.js +863 -1
  41. package/dist/cjs/src/rendering/modelPreloader.js +369 -1
  42. package/dist/cjs/src/rendering/rendering2D.js +631 -1
  43. package/dist/cjs/src/rendering/rendering3D.js +685 -1
  44. package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +396 -1
  45. package/dist/esm/node_modules/@2112-lab/pathfinder/dist/index.esm.js +1444 -1
  46. package/dist/esm/node_modules/three/examples/jsm/controls/OrbitControls.js +1849 -1
  47. package/dist/esm/node_modules/three/examples/jsm/exporters/GLTFExporter.js +3533 -1
  48. package/dist/esm/node_modules/three/examples/jsm/exporters/OBJExporter.js +301 -1
  49. package/dist/esm/node_modules/three/examples/jsm/exporters/PLYExporter.js +538 -1
  50. package/dist/esm/node_modules/three/examples/jsm/exporters/STLExporter.js +214 -1
  51. package/dist/esm/node_modules/three/examples/jsm/loaders/DRACOLoader.js +679 -1
  52. package/dist/esm/node_modules/three/examples/jsm/loaders/GLTFLoader.js +4807 -1
  53. package/dist/esm/node_modules/three/examples/jsm/loaders/RGBELoader.js +476 -1
  54. package/dist/esm/node_modules/three/examples/jsm/renderers/CSS2DRenderer.js +304 -1
  55. package/dist/esm/node_modules/three/examples/jsm/utils/BufferGeometryUtils.js +116 -1
  56. package/dist/esm/src/analysis/analysis.js +536 -1
  57. package/dist/esm/src/analysis/testing.js +954 -1
  58. package/dist/esm/src/core/centralPlant.js +1144 -1
  59. package/dist/esm/src/core/debugLogger.js +167 -1
  60. package/dist/esm/src/core/mathUtils.js +570 -1
  61. package/dist/esm/src/core/nameUtils.js +87 -1
  62. package/dist/esm/src/data/export.js +712 -1
  63. package/dist/esm/src/data/import.js +356 -1
  64. package/dist/esm/src/data/numerics.js +518 -1
  65. package/dist/esm/src/helpers/sceneHelper.js +547 -1
  66. package/dist/esm/src/index.js +35 -1
  67. package/dist/esm/src/managers/components/animationManager.js +119 -1
  68. package/dist/esm/src/managers/components/componentManager.js +328 -1
  69. package/dist/esm/src/managers/components/pathfindingManager.js +1417 -1
  70. package/dist/esm/src/managers/controls/TransformControls.js +1057 -1
  71. package/dist/esm/src/managers/controls/cameraControlsManager.js +75 -1
  72. package/dist/esm/src/managers/controls/dragDropManager.js +1002 -1
  73. package/dist/esm/src/managers/controls/keyboardControlsManager.js +371 -1
  74. package/dist/esm/src/managers/controls/transformControlsManager.js +1782 -1
  75. package/dist/esm/src/managers/environment/environmentManager.js +690 -1
  76. package/dist/esm/src/managers/environment/textureConfig.js +202 -1
  77. package/dist/esm/src/managers/scene/sceneExportManager.js +260 -1
  78. package/dist/esm/src/managers/scene/sceneInitializationManager.js +322 -1
  79. package/dist/esm/src/managers/scene/sceneOperationsManager.js +1485 -1
  80. package/dist/esm/src/managers/scene/sceneTooltipsManager.js +637 -1
  81. package/dist/esm/src/managers/system/disposalManager.js +440 -1
  82. package/dist/esm/src/managers/system/hotReloadManager.js +287 -1
  83. package/dist/esm/src/managers/system/performanceMonitor.js +858 -1
  84. package/dist/esm/src/rendering/modelPreloader.js +364 -1
  85. package/dist/esm/src/rendering/rendering2D.js +627 -1
  86. package/dist/esm/src/rendering/rendering3D.js +661 -1
  87. package/package.json +1 -1
@@ -1 +1,661 @@
1
- "use strict";Object.defineProperty(exports,"t",{value:!0});var t=require("../../../_virtual/_rollupPluginBabelHelpers.js"),i=require("../../../node_modules/three/examples/jsm/renderers/CSS2DRenderer.js");function e(t){if(t&&t.t)return t;var i=Object.create(null);return t&&Object.keys(t).forEach(function(e){if("default"!==e){var n=Object.getOwnPropertyDescriptor(t,e);Object.defineProperty(i,e,n.get?n:{enumerable:!0,get:function(){return t[e]}})}}),i.default=t,Object.freeze(i)}var n=e(require("three")),o=function(t){for(var i,e=arguments.length,n=new Array(e>1?e-1:0),o=1;o<e;o++)n[o-1]=arguments[o];return(i=console).log.apply(i,["🔍 [Tooltips] ".concat(t)].concat(n))},s=function(t){for(var i,e=arguments.length,n=new Array(e>1?e-1:0),o=1;o<e;o++)n[o-1]=arguments[o];return(i=console).log.apply(i,["ℹ️ [Tooltips] ".concat(t)].concat(n))},r=function(t){for(var i,e=arguments.length,n=new Array(e>1?e-1:0),o=1;o<e;o++)n[o-1]=arguments[o];return(i=console).warn.apply(i,["⚠️ [Tooltips] ".concat(t)].concat(n))},a=function(t){for(var i,e=arguments.length,n=new Array(e>1?e-1:0),o=1;o<e;o++)n[o-1]=arguments[o];return(i=console).error.apply(i,["❌ [Tooltips] ".concat(t)].concat(n))},l=function(){return t.createClass(function i(e,n,o){var s=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null;t.classCallCheck(this,i),this.container=e,this.camera=n,this.scene=o,this.transformControlsManager=s,this.tooltipTemplate='\n<div class="component-tooltip" style="\n background-color: rgba(255, 255, 255, 0.95); \n color: #333333; \n border-radius: 8px; \n padding: 12px; \n width: 250px; \n font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n border: 1px solid rgba(0, 0, 0, 0.1);\n user-select: none;\n pointer-events: auto;\n font-size: 13px;\n line-height: 1.4;\n transform: translate(-50%, -100%);\n margin-top: 0px;\n margin-left: 0px;\n position: relative;\n z-index: 1000;\n">\n <div class="tooltip-header" style="\n font-weight: 600; \n padding-bottom: 8px; \n border-bottom: 1px solid rgba(0, 0, 0, 0.1); \n margin-bottom: 8px;\n font-size: 14px;\n color: #2c3e50;\n ">Component Name</div>\n <div class="tooltip-body">\n <div class="tooltip-type" style="\n font-size: 12px;\n color: #666;\n margin-bottom: 8px;\n font-style: italic;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n "></div>\n <div class="tooltip-attributes">\n \x3c!-- Dynamic attributes will be inserted here --\x3e\n </div>\n <div class="tooltip-row tooltip-actions" style="display: flex; align-items: center; justify-content: space-between; margin-top: 12px; padding-top: 8px; border-top: 1px solid rgba(0, 0, 0, 0.1);">\n <div class="tooltip-key" style="flex: 1; color: #555555; font-size: 12px;">Add:</div>\n <div class="tooltip-dropdown-container" style="flex: 1; text-align: center;">\n <select class="tooltip-dropdown" style="\n background-color: #f8f9fa;\n color: #333333;\n border: 1px solid #ddd;\n padding: 4px 8px;\n border-radius: 4px;\n width: 100%;\n cursor: pointer;\n pointer-events: auto;\n font-size: 12px;\n ">\n <option value="" disabled selected>Select...</option>\n <option value="gateway">Gateway</option>\n <option value="connector">Connector</option>\n </select>\n </div>\n </div>\n </div>\n</div>\n',this.tooltipRenderer=null,this.selectedMesh=null,this.tooltipParent=null,this.tooltipObject=null,this.init()},[{key:"init",value:function(){this.tooltipRenderer=new i.CSS2DRenderer,this.tooltipRenderer.setSize(this.container.clientWidth,this.container.clientHeight),this.tooltipRenderer.domElement.style.position="absolute",this.tooltipRenderer.domElement.style.top="0",this.tooltipRenderer.domElement.style.left="0",this.tooltipRenderer.domElement.style.overflow="visible",this.tooltipRenderer.domElement.style.pointerEvents="none",this.tooltipRenderer.domElement.style.zIndex="100",this.container.appendChild(this.tooltipRenderer.domElement)}},{key:"resize",value:function(){this.tooltipRenderer&&this.tooltipRenderer.setSize(this.container.clientWidth,this.container.clientHeight)}},{key:"setTransformControlsManager",value:function(t){this.transformControlsManager=t,s("Transform controls manager set for tooltips"),this.transformControlsManager&&this.setupTransformControlsEvents(),this.tooltipObject&&this.updateTooltipForTransform()}},{key:"setupTransformControlsEvents",value:function(){var t=this;this.transformControlsManager&&this.transformControlsManager.on({onTransform:function(i){i===t.selectedMesh&&t.tooltipObject&&t.updateTooltipForTransform()},onTransformEnd:function(i){i===t.selectedMesh&&t.tooltipObject&&t.updateTooltipForTransform()}})}},{key:"setSelectedMesh",value:function(){var t,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;this.selectedMesh!==i&&(s("Setting selected mesh:",i?i.uuid:"none"),this.clearTooltip(),this.selectedMesh=i,i&&null!==(t=i.userData)&&void 0!==t&&null!==(t=t.component)&&void 0!==t&&t.attributes?(s("Mesh has component attributes, showing tooltip"),this.showTooltip()):i&&(r("Mesh does not have required component data for tooltip:",i),i.userData&&o("Available userData:",i.userData)))}},{key:"render",value:function(){if(this.tooltipRenderer&&this.camera&&this.scene)try{this.tooltipRenderer.render(this.scene,this.camera)}catch(t){a("Error rendering tooltips:",t)}}},{key:"dispose",value:function(){this.clearTooltip(),this.transformControlsManager&&(this.transformControlsManager=null),this.tooltipRenderer&&this.tooltipRenderer.domElement&&this.tooltipRenderer.domElement.parentNode&&this.tooltipRenderer.domElement.parentNode.removeChild(this.tooltipRenderer.domElement),this.tooltipRenderer=null,this.selectedMesh=null,this.container=null,this.camera=null,this.scene=null}},{key:"showTooltip",value:function(){try{if(!this.selectedMesh||!this.selectedMesh.userData||!this.selectedMesh.userData.component)return void r("Cannot show tooltip, missing data in selectedMesh");s("Showing tooltip for:",this.selectedMesh.uuid);var t=this.selectedMesh.userData.component;if(!t.attributes)return void r("Component has no attributes:",t);var e=t.attributes,n=document.createElement("div");n.innerHTML=this.tooltipTemplate.trim();var l=n.firstElementChild||n.firstChild;o("showTooltip this.selectedMesh:",this.selectedMesh),o("showTooltip meshComponentData:",t);var h=l.querySelector(".tooltip-header");h&&(this.selectedMesh.name&&""!==this.selectedMesh.name?h.textContent=this.selectedMesh.name:h.textContent=this.selectedMesh.userData.originalUuid||this.selectedMesh.userData.uuid||"Unknown Component");var u=l.querySelector(".tooltip-type");u&&t.type&&(u.textContent=t.type);var c=l.querySelector(".tooltip-attributes");if(c&&e&&Object.keys(e).length>0){c.innerHTML="",Object.keys(e).forEach(function(t){var i=e[t],n=document.createElement("div");n.className="tooltip-row",n.style.display="flex",n.style.alignItems="center",n.style.justifyContent="space-between",n.style.marginBottom="5px";var o=document.createElement("div");o.className="tooltip-key",o.style.flex="1",o.style.color="#555555",o.textContent="".concat(i.key||t,":");var s=document.createElement("div");s.className="tooltip-value",s.style.flex="1",s.style.textAlign="center",s.style.color="#000000";var r=i.value||"0";i.unit&&(r+=" ".concat(i.unit)),s.textContent=r,n.appendChild(o),n.appendChild(s),c.appendChild(n)});var d=l.querySelector(".tooltip-dropdown");d&&d.addEventListener("change",function(t){t.stopPropagation();var i=t.target.value;s("Add option selected: ".concat(i)),"gateway"===i?s("Adding Gateway"):"connector"===i&&s("Adding Connector"),t.target.selectedIndex=0})}var p=new i.CSS2DObject(l);this.tooltipParent=this.selectedMesh,this.tooltipObject=p;var v=this.calculateTooltipPosition();p.position.set(v.x,v.y,v.z),p.userData={isTooltip:!0},this.selectedMesh.add(p),s("Tooltip positioned at:",v)}catch(t){a("Error showing tooltip:",t)}}},{key:"updateTooltip",value:function(){if(this.tooltipParent&&this.tooltipObject){var t=this.calculateTooltipPosition();this.tooltipObject.position.set(t.x,t.y,t.z)}}},{key:"updateTooltipForTransform",value:function(){if(this.tooltipObject&&this.selectedMesh){var t=this.calculateTooltipPosition();this.tooltipObject.position.set(t.x,t.y,t.z),o("Tooltip position updated for transform")}}},{key:"getObjectBoundingBox",value:function(t){return(new n.Box3).setFromObject(t)}},{key:"calculateOptimalTooltipOffset",value:function(){if(!this.camera||!this.selectedMesh)return 1.5;var t=new n.Vector3;this.selectedMesh.getWorldPosition(t);var i=new n.Vector3;this.camera.getWorldPosition(i);return 1}},{key:"calculateTooltipPosition",value:function(){var t=this.getObjectBoundingBox(this.selectedMesh),i=this.findClosestBoundingBoxCorner(t),e=new n.Vector3;this.selectedMesh.getWorldPosition(e);var o=i.clone().sub(e),a=this.calculatePixelBasedOffset(o,e),l={x:o.x+a.x,y:o.y+a.y,z:o.z+a.z};if(this.transformControlsManager&&this.transformControlsManager.selectedObject===this.selectedMesh)try{var h=this.transformControlsManager.getWorldTransformData();if(h&&h.position)return s("Using transform controls position for tooltip at closest corner"),{x:o.x+a.x,y:o.y+a.y,z:o.z+a.z}}catch(t){r("Error getting transform controls position:",t)}return s("Positioning tooltip at closest corner to origin:",l),l}},{key:"calculatePixelBasedOffset",value:function(t,i){if(!this.camera)return{x:0,y:0,z:0};var e=250;if(this.tooltipObject&&this.tooltipObject.element){var s=this.tooltipObject.element;if(s.offsetWidth>0)e=s.offsetWidth;else{var r=document.createElement("div");r.style.position="absolute",r.style.visibility="hidden",r.style.top="-9999px",document.body.appendChild(r),r.appendChild(s),e=s.offsetWidth||250,document.body.removeChild(r)}}var a=e/2,l=i.clone().add(t),h=new n.Vector3;this.camera.getWorldPosition(h);var u=new n.Vector3;this.camera.getWorldDirection(u);var c=this.isPositionOnRightSideOfCameraMidline(l,h,u),d=l.distanceTo(h),p=0;if(this.camera.isPerspectiveCamera){var v=this.camera.fov*Math.PI/180,f=Math.tan(v/2)*d*this.camera.aspect;p=a/this.container.clientWidth*(2*f)}else if(this.camera.isOrthographicCamera){var m=(this.camera.right-this.camera.left)/2;p=a/this.container.clientWidth*(2*m)}var y=new n.Vector3;this.camera.getWorldDirection(y),y.cross(this.camera.up).normalize();var g=c?-1:1,w=y.multiplyScalar(p*g);return o("Tooltip pixel offset calculated:",{tooltipWidth:e,halfTooltipWidth:a,distanceToCamera:d,screenSpaceOffset:p,isOnRightSide:c,offsetDirection:g,worldOffset:w}),{x:w.x,y:0,z:w.z}}},{key:"findClosestBoundingBoxCorner",value:function(t){var i=t.min,e=t.max,o=[new n.Vector3(i.x,i.y,i.z),new n.Vector3(e.x,i.y,i.z),new n.Vector3(i.x,e.y,i.z),new n.Vector3(e.x,e.y,i.z),new n.Vector3(i.x,i.y,e.z),new n.Vector3(e.x,i.y,e.z),new n.Vector3(i.x,e.y,e.z),new n.Vector3(e.x,e.y,e.z)];return this.findCornerClosestToCameraVerticalMidline(o)}},{key:"findCornerClosestToCameraVerticalMidline",value:function(t){if(!this.camera)return r("No camera available, using first corner"),t[0];var i=new n.Vector3;this.camera.getWorldPosition(i);var e=new n.Vector3;this.camera.getWorldDirection(e);for(var s=t[0],a=this.getDistanceToVerticalMidline(t[0],i,e),l=1;l<t.length;l++){var h=this.getDistanceToVerticalMidline(t[l],i,e);h<a&&(a=h,s=t[l])}return o("Closest corner to camera vertical midline:",s,"Distance:",a),s}},{key:"getDistanceToVerticalMidline",value:function(t,i,e){var n=t.clone().sub(i),o=n.dot(e),s=e.clone().multiplyScalar(o);return n.clone().sub(s).length()}},{key:"clearTooltip",value:function(){this.tooltipParent&&this.tooltipObject&&(this.tooltipParent.remove(this.tooltipObject),this.tooltipParent=null,this.tooltipObject=null)}},{key:"handleSceneClick",value:function(t,i){this.clearTooltip(),this.selectedMesh=null}},{key:"isSelectableComponent",value:function(t){var i,e;return!!(t&&t.userData&&t.userData.component)||!(!t||!(null!==(i=t.userData)&&void 0!==i&&i.isPipeSegment||null!==(e=t.userData)&&void 0!==e&&e.isPipeJunction))}},{key:"isPositionOnRightSideOfCameraMidline",value:function(t,i,e){var o=new n.Vector3;return this.camera.getWorldDirection(o),o.cross(this.camera.up).normalize(),t.clone().sub(i).dot(o)>0}}])}();exports.SceneTooltipsManager=l;
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _rollupPluginBabelHelpers = require('../../../_virtual/_rollupPluginBabelHelpers.js');
6
+ var CSS2DRenderer = require('../../../node_modules/three/examples/jsm/renderers/CSS2DRenderer.js');
7
+ var THREE = require('three');
8
+
9
+ function _interopNamespace(e) {
10
+ if (e && e.__esModule) return e;
11
+ var n = Object.create(null);
12
+ if (e) {
13
+ Object.keys(e).forEach(function (k) {
14
+ if (k !== 'default') {
15
+ var d = Object.getOwnPropertyDescriptor(e, k);
16
+ Object.defineProperty(n, k, d.get ? d : {
17
+ enumerable: true,
18
+ get: function () { return e[k]; }
19
+ });
20
+ }
21
+ });
22
+ }
23
+ n["default"] = e;
24
+ return Object.freeze(n);
25
+ }
26
+
27
+ var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
28
+
29
+ // Add a simple debug logger for tooltip events
30
+ var tooltipLogger = {
31
+ debug: function debug(message) {
32
+ var _console;
33
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
34
+ args[_key - 1] = arguments[_key];
35
+ }
36
+ return (_console = console).log.apply(_console, ["\uD83D\uDD0D [Tooltips] ".concat(message)].concat(args));
37
+ },
38
+ info: function info(message) {
39
+ var _console2;
40
+ for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
41
+ args[_key2 - 1] = arguments[_key2];
42
+ }
43
+ return (_console2 = console).log.apply(_console2, ["\u2139\uFE0F [Tooltips] ".concat(message)].concat(args));
44
+ },
45
+ warn: function warn(message) {
46
+ var _console3;
47
+ for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
48
+ args[_key3 - 1] = arguments[_key3];
49
+ }
50
+ return (_console3 = console).warn.apply(_console3, ["\u26A0\uFE0F [Tooltips] ".concat(message)].concat(args));
51
+ },
52
+ error: function error(message) {
53
+ var _console4;
54
+ for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
55
+ args[_key4 - 1] = arguments[_key4];
56
+ }
57
+ return (_console4 = console).error.apply(_console4, ["\u274C [Tooltips] ".concat(message)].concat(args));
58
+ }
59
+ };
60
+
61
+ // Inline tooltip template instead of importing from a file
62
+ var tooltipTemplate = "\n<div class=\"component-tooltip\" style=\"\n background-color: rgba(255, 255, 255, 0.95); \n color: #333333; \n border-radius: 8px; \n padding: 12px; \n width: 250px; \n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n border: 1px solid rgba(0, 0, 0, 0.1);\n user-select: none;\n pointer-events: auto;\n font-size: 13px;\n line-height: 1.4;\n transform: translate(-50%, -100%);\n margin-top: 0px;\n margin-left: 0px;\n position: relative;\n z-index: 1000;\n\">\n <div class=\"tooltip-header\" style=\"\n font-weight: 600; \n padding-bottom: 8px; \n border-bottom: 1px solid rgba(0, 0, 0, 0.1); \n margin-bottom: 8px;\n font-size: 14px;\n color: #2c3e50;\n \">Component Name</div>\n <div class=\"tooltip-body\">\n <div class=\"tooltip-type\" style=\"\n font-size: 12px;\n color: #666;\n margin-bottom: 8px;\n font-style: italic;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n \"></div>\n <div class=\"tooltip-attributes\">\n <!-- Dynamic attributes will be inserted here -->\n </div>\n <div class=\"tooltip-row tooltip-actions\" style=\"display: flex; align-items: center; justify-content: space-between; margin-top: 12px; padding-top: 8px; border-top: 1px solid rgba(0, 0, 0, 0.1);\">\n <div class=\"tooltip-key\" style=\"flex: 1; color: #555555; font-size: 12px;\">Add:</div>\n <div class=\"tooltip-dropdown-container\" style=\"flex: 1; text-align: center;\">\n <select class=\"tooltip-dropdown\" style=\"\n background-color: #f8f9fa;\n color: #333333;\n border: 1px solid #ddd;\n padding: 4px 8px;\n border-radius: 4px;\n width: 100%;\n cursor: pointer;\n pointer-events: auto;\n font-size: 12px;\n \">\n <option value=\"\" disabled selected>Select...</option>\n <option value=\"gateway\">Gateway</option>\n <option value=\"connector\">Connector</option>\n </select>\n </div>\n </div>\n </div>\n</div>\n";
63
+ var SceneTooltipsManager = /*#__PURE__*/function () {
64
+ function SceneTooltipsManager(container, camera, scene) {
65
+ var transformControlsManager = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
66
+ _rollupPluginBabelHelpers.classCallCheck(this, SceneTooltipsManager);
67
+ this.container = container;
68
+ this.camera = camera;
69
+ this.scene = scene;
70
+ this.transformControlsManager = transformControlsManager;
71
+ this.tooltipTemplate = tooltipTemplate;
72
+ this.tooltipRenderer = null;
73
+ this.selectedMesh = null;
74
+ this.tooltipParent = null;
75
+ this.tooltipObject = null;
76
+ this.init();
77
+ }
78
+ return _rollupPluginBabelHelpers.createClass(SceneTooltipsManager, [{
79
+ key: "init",
80
+ value: function init() {
81
+ // Create the CSS2D renderer for the tooltips
82
+ this.tooltipRenderer = new CSS2DRenderer.CSS2DRenderer();
83
+ this.tooltipRenderer.setSize(this.container.clientWidth, this.container.clientHeight);
84
+ this.tooltipRenderer.domElement.style.position = 'absolute';
85
+ this.tooltipRenderer.domElement.style.top = '0';
86
+ this.tooltipRenderer.domElement.style.left = '0';
87
+ this.tooltipRenderer.domElement.style.overflow = 'visible';
88
+ // Use 'none' for the renderer to allow camera controls to work
89
+ this.tooltipRenderer.domElement.style.pointerEvents = 'none';
90
+ this.tooltipRenderer.domElement.style.zIndex = '100'; // Ensure tooltips appear on top
91
+ this.container.appendChild(this.tooltipRenderer.domElement);
92
+ }
93
+ }, {
94
+ key: "resize",
95
+ value: function resize() {
96
+ if (this.tooltipRenderer) {
97
+ this.tooltipRenderer.setSize(this.container.clientWidth, this.container.clientHeight);
98
+ }
99
+ }
100
+ }, {
101
+ key: "setTransformControlsManager",
102
+ value: function setTransformControlsManager(transformControlsManager) {
103
+ this.transformControlsManager = transformControlsManager;
104
+ tooltipLogger.info('Transform controls manager set for tooltips');
105
+
106
+ // Set up event listeners for transform controls
107
+ if (this.transformControlsManager) {
108
+ this.setupTransformControlsEvents();
109
+ }
110
+
111
+ // Update existing tooltip position if one is shown
112
+ if (this.tooltipObject) {
113
+ this.updateTooltipForTransform();
114
+ }
115
+ }
116
+ }, {
117
+ key: "setupTransformControlsEvents",
118
+ value: function setupTransformControlsEvents() {
119
+ var _this = this;
120
+ if (!this.transformControlsManager) return;
121
+
122
+ // Listen for transform events to update tooltip position
123
+ this.transformControlsManager.on({
124
+ onTransform: function onTransform(object) {
125
+ // Update tooltip position during transformation
126
+ if (object === _this.selectedMesh && _this.tooltipObject) {
127
+ _this.updateTooltipForTransform();
128
+ }
129
+ },
130
+ onTransformEnd: function onTransformEnd(object) {
131
+ // Final position update after transformation
132
+ if (object === _this.selectedMesh && _this.tooltipObject) {
133
+ _this.updateTooltipForTransform();
134
+ }
135
+ }
136
+ });
137
+ }
138
+ }, {
139
+ key: "setSelectedMesh",
140
+ value: function setSelectedMesh() {
141
+ var _mesh$userData;
142
+ var mesh = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
143
+ if (this.selectedMesh === mesh) return;
144
+ tooltipLogger.info('Setting selected mesh:', mesh ? mesh.uuid : 'none');
145
+ this.clearTooltip();
146
+ this.selectedMesh = mesh;
147
+ if (mesh && (_mesh$userData = mesh.userData) !== null && _mesh$userData !== void 0 && (_mesh$userData = _mesh$userData.component) !== null && _mesh$userData !== void 0 && _mesh$userData.attributes) {
148
+ tooltipLogger.info('Mesh has component attributes, showing tooltip');
149
+ this.showTooltip();
150
+ } else if (mesh) {
151
+ tooltipLogger.warn('Mesh does not have required component data for tooltip:', mesh);
152
+ if (mesh.userData) {
153
+ tooltipLogger.debug('Available userData:', mesh.userData);
154
+ }
155
+ }
156
+ }
157
+ }, {
158
+ key: "render",
159
+ value: function render() {
160
+ if (this.tooltipRenderer && this.camera && this.scene) {
161
+ try {
162
+ this.tooltipRenderer.render(this.scene, this.camera);
163
+ } catch (error) {
164
+ tooltipLogger.error('Error rendering tooltips:', error);
165
+ }
166
+ }
167
+ }
168
+
169
+ // This method should be called when disposing the manager
170
+ }, {
171
+ key: "dispose",
172
+ value: function dispose() {
173
+ this.clearTooltip();
174
+
175
+ // Clean up transform controls event listeners
176
+ if (this.transformControlsManager) {
177
+ // Note: The transform controls manager doesn't have a removeEventListener method
178
+ // so we'll just remove our reference
179
+ this.transformControlsManager = null;
180
+ }
181
+ if (this.tooltipRenderer && this.tooltipRenderer.domElement && this.tooltipRenderer.domElement.parentNode) {
182
+ this.tooltipRenderer.domElement.parentNode.removeChild(this.tooltipRenderer.domElement);
183
+ }
184
+ this.tooltipRenderer = null;
185
+ this.selectedMesh = null;
186
+ this.container = null;
187
+ this.camera = null;
188
+ this.scene = null;
189
+ }
190
+ }, {
191
+ key: "showTooltip",
192
+ value: function showTooltip() {
193
+ try {
194
+ if (!this.selectedMesh || !this.selectedMesh.userData || !this.selectedMesh.userData.component) {
195
+ tooltipLogger.warn('Cannot show tooltip, missing data in selectedMesh');
196
+ return;
197
+ }
198
+ console.log("showTooltip this.selectedMesh:", this.selectedMesh);
199
+ tooltipLogger.info('Showing tooltip for:', this.selectedMesh.uuid);
200
+ var meshComponentData = this.selectedMesh.userData.component;
201
+ if (!meshComponentData.attributes) {
202
+ tooltipLogger.warn('Component has no attributes:', meshComponentData);
203
+ return;
204
+ }
205
+ var meshAttributes = meshComponentData.attributes;
206
+
207
+ // Clone the loaded template
208
+ var tooltipDiv = document.createElement('div');
209
+ tooltipDiv.innerHTML = this.tooltipTemplate.trim(); // Use the template string
210
+ var tooltipElement = tooltipDiv.firstElementChild || tooltipDiv.firstChild;
211
+ tooltipLogger.debug("showTooltip this.selectedMesh:", this.selectedMesh);
212
+ tooltipLogger.debug("showTooltip meshComponentData:", meshComponentData);
213
+
214
+ // Update the tooltip header with object name or ID
215
+ var headerElement = tooltipElement.querySelector('.tooltip-header');
216
+ if (headerElement) {
217
+ // Use a more user-friendly display name
218
+ if (this.selectedMesh.name && this.selectedMesh.name !== "") {
219
+ headerElement.textContent = this.selectedMesh.name;
220
+ } else {
221
+ headerElement.textContent = this.selectedMesh.userData.originalUuid || this.selectedMesh.userData.uuid || "Unknown Component";
222
+ }
223
+ }
224
+
225
+ // Add component type if available
226
+ var typeElement = tooltipElement.querySelector('.tooltip-type');
227
+ if (typeElement && meshComponentData.type) {
228
+ typeElement.textContent = meshComponentData.type;
229
+ }
230
+
231
+ // Populate all attributes
232
+ var attributesContainer = tooltipElement.querySelector('.tooltip-attributes');
233
+ if (attributesContainer && meshAttributes && Object.keys(meshAttributes).length > 0) {
234
+ // First clear any existing content
235
+ attributesContainer.innerHTML = '';
236
+
237
+ // Add each attribute as a row
238
+ var attrKeys = Object.keys(meshAttributes);
239
+ attrKeys.forEach(function (key) {
240
+ var attr = meshAttributes[key];
241
+
242
+ // Create attribute row
243
+ var rowDiv = document.createElement('div');
244
+ rowDiv.className = 'tooltip-row';
245
+ rowDiv.style.display = 'flex';
246
+ rowDiv.style.alignItems = 'center';
247
+ rowDiv.style.justifyContent = 'space-between';
248
+ rowDiv.style.marginBottom = '5px';
249
+
250
+ // Create key div
251
+ var keyDiv = document.createElement('div');
252
+ keyDiv.className = 'tooltip-key';
253
+ keyDiv.style.flex = '1';
254
+ keyDiv.style.color = '#555555';
255
+ keyDiv.textContent = "".concat(attr.key || key, ":");
256
+
257
+ // Create value div
258
+ var valueDiv = document.createElement('div');
259
+ valueDiv.className = 'tooltip-value';
260
+ valueDiv.style.flex = '1';
261
+ valueDiv.style.textAlign = 'center';
262
+ valueDiv.style.color = '#000000';
263
+
264
+ // Format the value with unit if available
265
+ var displayValue = attr.value || '0';
266
+ if (attr.unit) {
267
+ displayValue += " ".concat(attr.unit);
268
+ }
269
+ valueDiv.textContent = displayValue;
270
+
271
+ // Append to row
272
+ rowDiv.appendChild(keyDiv);
273
+ rowDiv.appendChild(valueDiv);
274
+
275
+ // Append row to container
276
+ attributesContainer.appendChild(rowDiv);
277
+ });
278
+
279
+ // Set up dropdown event handler
280
+ var dropdown = tooltipElement.querySelector('.tooltip-dropdown');
281
+ if (dropdown) {
282
+ dropdown.addEventListener('change', function (event) {
283
+ event.stopPropagation(); // Prevent event from bubbling up to the scene
284
+ var selectedValue = event.target.value;
285
+ tooltipLogger.info("Add option selected: ".concat(selectedValue));
286
+
287
+ // Handle the dropdown selection (add Gateway or Connector)
288
+ if (selectedValue === 'gateway') {
289
+ tooltipLogger.info('Adding Gateway');
290
+ // Add your gateway creation logic here
291
+ } else if (selectedValue === 'connector') {
292
+ tooltipLogger.info('Adding Connector');
293
+ // Add your connector creation logic here
294
+ }
295
+
296
+ // Reset dropdown to default "Select..." option after use
297
+ event.target.selectedIndex = 0;
298
+ });
299
+ }
300
+ }
301
+
302
+ // Add the tooltip as a CSS2DObject with proper positioning
303
+ var label = new CSS2DRenderer.CSS2DObject(tooltipElement);
304
+
305
+ // Store references first so calculatePixelBasedOffset can access them
306
+ this.tooltipParent = this.selectedMesh;
307
+ this.tooltipObject = label;
308
+
309
+ // Calculate tooltip position with pixel-based offset (now that tooltip object exists)
310
+ var tooltipPosition = this.calculateTooltipPosition();
311
+
312
+ // Set the position
313
+ label.position.set(tooltipPosition.x, tooltipPosition.y, tooltipPosition.z);
314
+
315
+ // Ensure the CSS2DObject renders properly
316
+ label.userData = {
317
+ isTooltip: true
318
+ };
319
+
320
+ // For CSS2DRenderer, we want the tooltip to be positioned correctly
321
+ // The CSS transform in the template will center it horizontally and position it above the anchor point
322
+
323
+ // Add the label to the mesh (this makes it follow the mesh's transformations)
324
+ this.selectedMesh.add(label);
325
+ tooltipLogger.info('Tooltip positioned at:', tooltipPosition);
326
+ } catch (error) {
327
+ tooltipLogger.error('Error showing tooltip:', error);
328
+ }
329
+ }
330
+ }, {
331
+ key: "updateTooltip",
332
+ value: function updateTooltip() {
333
+ if (this.tooltipParent && this.tooltipObject) {
334
+ // Update position when object is transformed
335
+ var newPosition = this.calculateTooltipPosition();
336
+ this.tooltipObject.position.set(newPosition.x, newPosition.y, newPosition.z);
337
+ }
338
+ }
339
+ }, {
340
+ key: "updateTooltipForTransform",
341
+ value: function updateTooltipForTransform() {
342
+ // This method is called when transform controls move the object
343
+ if (this.tooltipObject && this.selectedMesh) {
344
+ var newPosition = this.calculateTooltipPosition();
345
+ this.tooltipObject.position.set(newPosition.x, newPosition.y, newPosition.z);
346
+ tooltipLogger.debug('Tooltip position updated for transform');
347
+ }
348
+ }
349
+ }, {
350
+ key: "getObjectBoundingBox",
351
+ value: function getObjectBoundingBox(object) {
352
+ // Calculate bounding box for the object
353
+ var box = new THREE__namespace.Box3().setFromObject(object);
354
+ return box;
355
+ }
356
+ }, {
357
+ key: "calculateOptimalTooltipOffset",
358
+ value: function calculateOptimalTooltipOffset() {
359
+ // Calculate offset based on camera distance for consistent visual appearance
360
+ if (!this.camera || !this.selectedMesh) {
361
+ return 1.5; // Default offset
362
+ }
363
+ var meshWorldPosition = new THREE__namespace.Vector3();
364
+ this.selectedMesh.getWorldPosition(meshWorldPosition);
365
+ var cameraWorldPosition = new THREE__namespace.Vector3();
366
+ this.camera.getWorldPosition(cameraWorldPosition);
367
+ var baseOffset = 1.0;
368
+ return baseOffset;
369
+ }
370
+
371
+ /**
372
+ * Calculates the optimal position for tooltip placement
373
+ *
374
+ * This method determines tooltip positioning through several steps:
375
+ * 1. Finds the closest corner of the mesh's bounding box to the camera's vertical midline
376
+ * 2. Converts this corner from world space to local space relative to the mesh
377
+ * 3. Applies a pixel-based horizontal offset to prevent tooltip from overlapping the mesh
378
+ * 4. The offset direction depends on which side of camera midline the tooltip is on
379
+ * 5. If transform controls are active, considers their position for more accurate placement
380
+ *
381
+ * The positioning algorithm aims to:
382
+ * - Keep tooltips visible and readable
383
+ * - Prevent obstruction of the mesh being described
384
+ * - Maintain consistent visual appearance across different camera distances
385
+ * - Adapt to camera perspective and orientation changes
386
+ *
387
+ * Known Issues:
388
+ * - Sometimes tooltips still obscure the mesh despite positioning logic
389
+ * - The root cause of this obstruction is currently unknown and needs investigation (this issue on hold)
390
+ * - May be related to CSS transform calculations or screen-space projection accuracy
391
+ *
392
+ * @returns {Object} Position coordinates {x, y, z} in local space relative to the mesh
393
+ */
394
+ }, {
395
+ key: "calculateTooltipPosition",
396
+ value: function calculateTooltipPosition() {
397
+ // Get bounding box of the selected mesh for better positioning
398
+ var boundingBox = this.getObjectBoundingBox(this.selectedMesh);
399
+
400
+ // Find the closest corner of the bounding box to world origin (0, 0, 0)
401
+ var closestCorner = this.findClosestBoundingBoxCorner(boundingBox);
402
+
403
+ // Get mesh world position to convert from world space to local space
404
+ var meshWorldPosition = new THREE__namespace.Vector3();
405
+ this.selectedMesh.getWorldPosition(meshWorldPosition);
406
+
407
+ // Convert closest corner from world space to local space relative to mesh
408
+ var localCornerPosition = closestCorner.clone().sub(meshWorldPosition);
409
+
410
+ // Calculate 2D pixel offset for tooltip positioning
411
+ var pixelOffset = this.calculatePixelBasedOffset(localCornerPosition, meshWorldPosition);
412
+
413
+ // Add a small offset above the corner for better visibility, plus pixel-based offset
414
+ var tooltipPosition = {
415
+ x: localCornerPosition.x + pixelOffset.x,
416
+ y: localCornerPosition.y + pixelOffset.y,
417
+ z: localCornerPosition.z + pixelOffset.z
418
+ };
419
+
420
+ // If transform controls are available and have a selected object
421
+ if (this.transformControlsManager && this.transformControlsManager.selectedObject === this.selectedMesh) {
422
+ try {
423
+ // Get world transform data from transform controls
424
+ var worldTransform = this.transformControlsManager.getWorldTransformData();
425
+ if (worldTransform && worldTransform.position) {
426
+ tooltipLogger.info('Using transform controls position for tooltip at closest corner');
427
+ return {
428
+ x: localCornerPosition.x + pixelOffset.x,
429
+ y: localCornerPosition.y + pixelOffset.y,
430
+ z: localCornerPosition.z + pixelOffset.z
431
+ };
432
+ }
433
+ } catch (error) {
434
+ tooltipLogger.warn('Error getting transform controls position:', error);
435
+ }
436
+ }
437
+ tooltipLogger.info('Positioning tooltip at closest corner to origin:', tooltipPosition);
438
+ return tooltipPosition;
439
+ }
440
+ }, {
441
+ key: "calculatePixelBasedOffset",
442
+ value: function calculatePixelBasedOffset(localCornerPosition, meshWorldPosition) {
443
+ if (!this.camera) {
444
+ return {
445
+ x: 0,
446
+ y: 0,
447
+ z: 0
448
+ };
449
+ }
450
+
451
+ // Get tooltip width - use the template width or measure if tooltip exists
452
+ var tooltipWidth = 250; // Default from template
453
+
454
+ if (this.tooltipObject && this.tooltipObject.element) {
455
+ // Force a layout update to get accurate measurements
456
+ var element = this.tooltipObject.element;
457
+ if (element.offsetWidth > 0) {
458
+ tooltipWidth = element.offsetWidth;
459
+ } else {
460
+ // If not yet measured, temporarily add to DOM to measure
461
+ var tempParent = document.createElement('div');
462
+ tempParent.style.position = 'absolute';
463
+ tempParent.style.visibility = 'hidden';
464
+ tempParent.style.top = '-9999px';
465
+ document.body.appendChild(tempParent);
466
+ tempParent.appendChild(element);
467
+ tooltipWidth = element.offsetWidth || 250;
468
+
469
+ // Remove from temp parent
470
+ document.body.removeChild(tempParent);
471
+ }
472
+ }
473
+ var halfTooltipWidth = tooltipWidth / 2;
474
+
475
+ // Calculate world position for the tooltip anchor point
476
+ var worldAnchorPosition = meshWorldPosition.clone().add(localCornerPosition);
477
+
478
+ // Get camera position and direction
479
+ var cameraPosition = new THREE__namespace.Vector3();
480
+ this.camera.getWorldPosition(cameraPosition);
481
+ var cameraDirection = new THREE__namespace.Vector3();
482
+ this.camera.getWorldDirection(cameraDirection);
483
+
484
+ // Determine which side of the camera midline the tooltip is on
485
+ var isOnRightSide = this.isPositionOnRightSideOfCameraMidline(worldAnchorPosition, cameraPosition, cameraDirection);
486
+
487
+ // Calculate distance to camera for scaling the offset
488
+ var distanceToCamera = worldAnchorPosition.distanceTo(cameraPosition);
489
+
490
+ // Calculate screen-space offset magnitude using camera projection
491
+ var screenSpaceOffset = 0;
492
+ if (this.camera.isPerspectiveCamera) {
493
+ // Convert pixel offset to world space based on camera distance and FOV
494
+ var fov = this.camera.fov * Math.PI / 180; // Convert to radians
495
+ var halfHeight = Math.tan(fov / 2) * distanceToCamera;
496
+ var halfWidth = halfHeight * this.camera.aspect;
497
+
498
+ // Convert pixel offset to world space
499
+ screenSpaceOffset = halfTooltipWidth / this.container.clientWidth * (halfWidth * 2);
500
+ } else if (this.camera.isOrthographicCamera) {
501
+ // For orthographic cameras, use the zoom factor
502
+ var _halfWidth = (this.camera.right - this.camera.left) / 2;
503
+ screenSpaceOffset = halfTooltipWidth / this.container.clientWidth * (_halfWidth * 2);
504
+ }
505
+
506
+ // Get camera's right vector for horizontal offset
507
+ var cameraRight = new THREE__namespace.Vector3();
508
+ this.camera.getWorldDirection(cameraRight);
509
+ cameraRight.cross(this.camera.up).normalize();
510
+
511
+ // Apply offset direction: left if on right side, right if on left side
512
+ var offsetDirection = isOnRightSide ? -1 : 1;
513
+ var worldOffset = cameraRight.multiplyScalar(screenSpaceOffset * offsetDirection);
514
+ tooltipLogger.debug('Tooltip pixel offset calculated:', {
515
+ tooltipWidth: tooltipWidth,
516
+ halfTooltipWidth: halfTooltipWidth,
517
+ distanceToCamera: distanceToCamera,
518
+ screenSpaceOffset: screenSpaceOffset,
519
+ isOnRightSide: isOnRightSide,
520
+ offsetDirection: offsetDirection,
521
+ worldOffset: worldOffset
522
+ });
523
+ return {
524
+ x: worldOffset.x,
525
+ y: 0,
526
+ // No vertical offset - only move horizontally
527
+ z: worldOffset.z
528
+ };
529
+ }
530
+ }, {
531
+ key: "findClosestBoundingBoxCorner",
532
+ value: function findClosestBoundingBoxCorner(boundingBox) {
533
+ // Get the 8 corners of the bounding box in world space
534
+ var min = boundingBox.min;
535
+ var max = boundingBox.max;
536
+
537
+ // Define all 8 corners of the bounding box
538
+ var corners = [new THREE__namespace.Vector3(min.x, min.y, min.z),
539
+ // Bottom-front-left
540
+ new THREE__namespace.Vector3(max.x, min.y, min.z),
541
+ // Bottom-front-right
542
+ new THREE__namespace.Vector3(min.x, max.y, min.z),
543
+ // Top-front-left
544
+ new THREE__namespace.Vector3(max.x, max.y, min.z),
545
+ // Top-front-right
546
+ new THREE__namespace.Vector3(min.x, min.y, max.z),
547
+ // Bottom-back-left
548
+ new THREE__namespace.Vector3(max.x, min.y, max.z),
549
+ // Bottom-back-right
550
+ new THREE__namespace.Vector3(min.x, max.y, max.z),
551
+ // Top-back-left
552
+ new THREE__namespace.Vector3(max.x, max.y, max.z) // Top-back-right
553
+ ];
554
+
555
+ // Find the corner closest to the camera's vertical midline
556
+ return this.findCornerClosestToCameraVerticalMidline(corners);
557
+ }
558
+ }, {
559
+ key: "findCornerClosestToCameraVerticalMidline",
560
+ value: function findCornerClosestToCameraVerticalMidline(corners) {
561
+ if (!this.camera) {
562
+ tooltipLogger.warn('No camera available, using first corner');
563
+ return corners[0];
564
+ }
565
+
566
+ // Get camera position and direction
567
+ var cameraPosition = new THREE__namespace.Vector3();
568
+ this.camera.getWorldPosition(cameraPosition);
569
+ var cameraDirection = new THREE__namespace.Vector3();
570
+ this.camera.getWorldDirection(cameraDirection);
571
+
572
+ // Calculate the camera's vertical midline plane
573
+ // The midline is a line extending from the camera in the forward direction
574
+ // We need to find which corner has the smallest perpendicular distance to this line
575
+
576
+ var closestCorner = corners[0];
577
+ var smallestDistance = this.getDistanceToVerticalMidline(corners[0], cameraPosition, cameraDirection);
578
+ for (var i = 1; i < corners.length; i++) {
579
+ var distance = this.getDistanceToVerticalMidline(corners[i], cameraPosition, cameraDirection);
580
+ if (distance < smallestDistance) {
581
+ smallestDistance = distance;
582
+ closestCorner = corners[i];
583
+ }
584
+ }
585
+ tooltipLogger.debug('Closest corner to camera vertical midline:', closestCorner, 'Distance:', smallestDistance);
586
+ return closestCorner;
587
+ }
588
+ }, {
589
+ key: "getDistanceToVerticalMidline",
590
+ value: function getDistanceToVerticalMidline(point, cameraPosition, cameraDirection) {
591
+ // Calculate the perpendicular distance from a point to the camera's vertical midline
592
+ // The vertical midline is the line extending from the camera in the forward direction
593
+
594
+ // Vector from camera to the point
595
+ var cameraToPoint = point.clone().sub(cameraPosition);
596
+
597
+ // Project this vector onto the camera direction to get the component along the midline
598
+ var projectionLength = cameraToPoint.dot(cameraDirection);
599
+ var projectionVector = cameraDirection.clone().multiplyScalar(projectionLength);
600
+
601
+ // The perpendicular component is the remainder
602
+ var perpendicularVector = cameraToPoint.clone().sub(projectionVector);
603
+
604
+ // Return the magnitude of the perpendicular component
605
+ return perpendicularVector.length();
606
+ }
607
+ }, {
608
+ key: "clearTooltip",
609
+ value: function clearTooltip() {
610
+ if (this.tooltipParent && this.tooltipObject) {
611
+ this.tooltipParent.remove(this.tooltipObject);
612
+ this.tooltipParent = null;
613
+ this.tooltipObject = null;
614
+ }
615
+ }
616
+
617
+ // Method to handle scene interaction when clicking away from objects (single clicks now clear tooltips)
618
+ }, {
619
+ key: "handleSceneClick",
620
+ value: function handleSceneClick(raycaster, camera) {
621
+ // If no intersection found, clear tooltip
622
+ this.clearTooltip();
623
+ this.selectedMesh = null;
624
+ }
625
+
626
+ // Method to check if an object is a selectable component
627
+ }, {
628
+ key: "isSelectableComponent",
629
+ value: function isSelectableComponent(object) {
630
+ var _object$userData, _object$userData2;
631
+ // Check if the object has component data
632
+ if (object && object.userData && object.userData.component) {
633
+ return true;
634
+ }
635
+
636
+ // Check if the object is a pipe segment or junction
637
+ if (object && ((_object$userData = object.userData) !== null && _object$userData !== void 0 && _object$userData.isPipeSegment || (_object$userData2 = object.userData) !== null && _object$userData2 !== void 0 && _object$userData2.isPipeJunction)) {
638
+ return true;
639
+ }
640
+ return false;
641
+ }
642
+ }, {
643
+ key: "isPositionOnRightSideOfCameraMidline",
644
+ value: function isPositionOnRightSideOfCameraMidline(worldPosition, cameraPosition, cameraDirection) {
645
+ // Get camera's right vector (camera's local X-axis)
646
+ var cameraRight = new THREE__namespace.Vector3();
647
+ this.camera.getWorldDirection(cameraRight);
648
+ cameraRight.cross(this.camera.up).normalize();
649
+
650
+ // Vector from camera to the position
651
+ var cameraToPosition = worldPosition.clone().sub(cameraPosition);
652
+
653
+ // Project this vector onto the camera's right vector
654
+ // Positive dot product means it's on the right side, negative means left side
655
+ var rightComponent = cameraToPosition.dot(cameraRight);
656
+ return rightComponent > 0;
657
+ }
658
+ }]);
659
+ }();
660
+
661
+ exports.SceneTooltipsManager = SceneTooltipsManager;