force-3d-graph 1.0.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,11 @@
1
- (function(C,d){typeof exports=="object"&&typeof module<"u"?d(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],d):(C=typeof globalThis<"u"?globalThis:C||self,d(C.ForceGraph3D={},C.THREE))})(this,function(C,d){"use strict";var wt=Object.defineProperty;var Ct=(C,d,j)=>d in C?wt(C,d,{enumerable:!0,configurable:!0,writable:!0,value:j}):C[d]=j;var r=(C,d,j)=>Ct(C,typeof d!="symbol"?d+"":d,j);function j(c){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(c){for(const s in c)if(s!=="default"){const t=Object.getOwnPropertyDescriptor(c,s);Object.defineProperty(e,s,t.get?t:{enumerable:!0,get:()=>c[s]})}}return e.default=c,Object.freeze(e)}const u=j(d),O={backgroundColor:657930,cameraPosition:{x:0,y:0,z:80},cameraFov:75,repulsionStrength:100,attractionStrength:.01,damping:.9,useBarnesHut:!1,barnesHutTheta:.5,defaultNodeColor:4886754,nodeRadius:2,nodeSegments:32,enableLOD:!0,lodDistances:[50,100,200],lodSegments:[32,16,8],edgeColor:8947848,edgeOpacity:.4,enableEdgeCulling:!0,showPanel:!0,showSearch:!0,searchPlaceholder:"Search nodes or relationships...",targetFPS:60,maxVisibleNodes:1e4};var D=(c=>(c[c.HIGH=0]="HIGH",c[c.MEDIUM=1]="MEDIUM",c[c.LOW=2]="LOW",c))(D||{});function Fe(){const c=document.createElement("div");return c.id="force-graph-3d-container",c.style.cssText=`
1
+ (function(N,g){typeof exports=="object"&&typeof module<"u"?g(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],g):(N=typeof globalThis<"u"?globalThis:N||self,g(N.ForceGraph3D={},N.THREE))})(this,function(N,g){"use strict";var St=Object.defineProperty;var zt=(N,g,R)=>g in N?St(N,g,{enumerable:!0,configurable:!0,writable:!0,value:R}):N[g]=R;var l=(N,g,R)=>zt(N,typeof g!="symbol"?g+"":g,R);function R(h){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(h){for(const s in h)if(s!=="default"){const t=Object.getOwnPropertyDescriptor(h,s);Object.defineProperty(e,s,t.get?t:{enumerable:!0,get:()=>h[s]})}}return e.default=h,Object.freeze(e)}const y=R(g),P={backgroundColor:657930,cameraPosition:{x:0,y:0,z:80},cameraFov:75,repulsionStrength:100,attractionStrength:.01,damping:.9,useBarnesHut:!1,barnesHutTheta:.5,defaultNodeColor:4886754,nodeRadius:2,nodeSegments:32,enableLOD:!0,lodDistances:[50,100,200],lodSegments:[32,16,8],edgeColor:8947848,edgeOpacity:.4,enableEdgeCulling:!0,showPanel:!0,showSearch:!0,searchPlaceholder:"Search nodes or relationships...",initialViewMode:"3d",showViewToggle:!0,targetFPS:60,maxVisibleNodes:1e4};var H=(h=>(h[h.HIGH=0]="HIGH",h[h.MEDIUM=1]="MEDIUM",h[h.LOW=2]="LOW",h))(H||{});function Ie(){const h=document.createElement("div");return h.id="force-graph-3d-container",h.style.cssText=`
2
2
  width: 100%;
3
3
  height: 100%;
4
4
  position: absolute;
5
5
  top: 0;
6
6
  left: 0;
7
7
  overflow: hidden;
8
- `,document.body.appendChild(c),c}function Te(c){return c&&c instanceof HTMLElement?c:(console.warn("[ForceGraph3D] No container provided, creating one automatically"),Fe())}function le(c){const e=c.getBoundingClientRect();return{width:e.width||window.innerWidth,height:e.height||window.innerHeight}}function Q(c){if(!c||typeof c!="object")return console.warn("[ForceGraph3D] Invalid node: must be an object"),!1;const e=c;return typeof e.id!="string"||e.id.trim()===""?(console.warn("[ForceGraph3D] Invalid node: id must be a non-empty string"),!1):typeof e.label!="string"?(console.warn("[ForceGraph3D] Invalid node: label must be a string"),!1):e.color!==void 0&&typeof e.color!="number"?(console.warn("[ForceGraph3D] Invalid node: color must be a number (hex)"),!1):e.position!==void 0&&!De(e.position)?(console.warn("[ForceGraph3D] Invalid node: position must have x, y, z numbers"),!1):!0}function J(c){if(!c||typeof c!="object")return console.warn("[ForceGraph3D] Invalid edge: must be an object"),!1;const e=c;return typeof e.source!="string"||e.source.trim()===""?(console.warn("[ForceGraph3D] Invalid edge: source must be a non-empty string"),!1):typeof e.target!="string"||e.target.trim()===""?(console.warn("[ForceGraph3D] Invalid edge: target must be a non-empty string"),!1):!0}function je(c){return typeof c!="string"||c.trim()===""?(console.warn("[ForceGraph3D] Invalid node ID: must be a non-empty string"),!1):!0}function De(c){if(!c||typeof c!="object")return!1;const e=c;return typeof e.x=="number"&&typeof e.y=="number"&&typeof e.z=="number"}function k(c,e){return c===e?`${c}-${e}`:c<e?`${c}-${e}`:`${e}-${c}`}const ce={type:"change"},ee={type:"start"},he={type:"end"},B=new d.Ray,de=new d.Plane,Ae=Math.cos(70*d.MathUtils.DEG2RAD);class Re extends d.EventDispatcher{constructor(e,s){super(),this.object=e,this.domElement=s,this.domElement.style.touchAction="none",this.enabled=!0,this.target=new d.Vector3,this.cursor=new d.Vector3,this.minDistance=0,this.maxDistance=1/0,this.minZoom=0,this.maxZoom=1/0,this.minTargetRadius=0,this.maxTargetRadius=1/0,this.minPolarAngle=0,this.maxPolarAngle=Math.PI,this.minAzimuthAngle=-1/0,this.maxAzimuthAngle=1/0,this.enableDamping=!1,this.dampingFactor=.05,this.enableZoom=!0,this.zoomSpeed=1,this.enableRotate=!0,this.rotateSpeed=1,this.enablePan=!0,this.panSpeed=1,this.screenSpacePanning=!0,this.keyPanSpeed=7,this.zoomToCursor=!1,this.autoRotate=!1,this.autoRotateSpeed=2,this.keys={LEFT:"ArrowLeft",UP:"ArrowUp",RIGHT:"ArrowRight",BOTTOM:"ArrowDown"},this.mouseButtons={LEFT:d.MOUSE.ROTATE,MIDDLE:d.MOUSE.DOLLY,RIGHT:d.MOUSE.PAN},this.touches={ONE:d.TOUCH.ROTATE,TWO:d.TOUCH.DOLLY_PAN},this.target0=this.target.clone(),this.position0=this.object.position.clone(),this.zoom0=this.object.zoom,this._domElementKeyEvents=null,this.getPolarAngle=function(){return l.phi},this.getAzimuthalAngle=function(){return l.theta},this.getDistance=function(){return this.object.position.distanceTo(this.target)},this.listenToKeyEvents=function(n){n.addEventListener("keydown",ae),this._domElementKeyEvents=n},this.stopListenToKeyEvents=function(){this._domElementKeyEvents.removeEventListener("keydown",ae),this._domElementKeyEvents=null},this.saveState=function(){t.target0.copy(t.target),t.position0.copy(t.object.position),t.zoom0=t.object.zoom},this.reset=function(){t.target.copy(t.target0),t.object.position.copy(t.position0),t.object.zoom=t.zoom0,t.object.updateProjectionMatrix(),t.dispatchEvent(ce),t.update(),o=i.NONE},this.update=function(){const n=new d.Vector3,h=new d.Quaternion().setFromUnitVectors(e.up,new d.Vector3(0,1,0)),f=h.clone().invert(),v=new d.Vector3,E=new d.Quaternion,F=new d.Vector3,z=2*Math.PI;return function(Mt=null){const Ie=t.object.position;n.copy(Ie).sub(t.target),n.applyQuaternion(h),l.setFromVector3(n),t.autoRotate&&o===i.NONE&&K(st(Mt)),t.enableDamping?(l.theta+=p.theta*t.dampingFactor,l.phi+=p.phi*t.dampingFactor):(l.theta+=p.theta,l.phi+=p.phi);let P=t.minAzimuthAngle,L=t.maxAzimuthAngle;isFinite(P)&&isFinite(L)&&(P<-Math.PI?P+=z:P>Math.PI&&(P-=z),L<-Math.PI?L+=z:L>Math.PI&&(L-=z),P<=L?l.theta=Math.max(P,Math.min(L,l.theta)):l.theta=l.theta>(P+L)/2?Math.max(P,l.theta):Math.min(L,l.theta)),l.phi=Math.max(t.minPolarAngle,Math.min(t.maxPolarAngle,l.phi)),l.makeSafe(),t.enableDamping===!0?t.target.addScaledVector(m,t.dampingFactor):t.target.add(m),t.target.sub(t.cursor),t.target.clampLength(t.minTargetRadius,t.maxTargetRadius),t.target.add(t.cursor),t.zoomToCursor&&_||t.object.isOrthographicCamera?l.radius=oe(l.radius):l.radius=oe(l.radius*g),n.setFromSpherical(l),n.applyQuaternion(f),Ie.copy(t.target).add(n),t.object.lookAt(t.target),t.enableDamping===!0?(p.theta*=1-t.dampingFactor,p.phi*=1-t.dampingFactor,m.multiplyScalar(1-t.dampingFactor)):(p.set(0,0,0),m.set(0,0,0));let re=!1;if(t.zoomToCursor&&_){let Y=null;if(t.object.isPerspectiveCamera){const V=n.length();Y=oe(V*g);const Z=V-Y;t.object.position.addScaledVector(me,Z),t.object.updateMatrixWorld()}else if(t.object.isOrthographicCamera){const V=new d.Vector3(I.x,I.y,0);V.unproject(t.object),t.object.zoom=Math.max(t.minZoom,Math.min(t.maxZoom,t.object.zoom/g)),t.object.updateProjectionMatrix(),re=!0;const Z=new d.Vector3(I.x,I.y,0);Z.unproject(t.object),t.object.position.sub(Z).add(V),t.object.updateMatrixWorld(),Y=n.length()}else console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."),t.zoomToCursor=!1;Y!==null&&(this.screenSpacePanning?t.target.set(0,0,-1).transformDirection(t.object.matrix).multiplyScalar(Y).add(t.object.position):(B.origin.copy(t.object.position),B.direction.set(0,0,-1).transformDirection(t.object.matrix),Math.abs(t.object.up.dot(B.direction))<Ae?e.lookAt(t.target):(de.setFromNormalAndCoplanarPoint(t.object.up,t.target),B.intersectPlane(de,t.target))))}else t.object.isOrthographicCamera&&(t.object.zoom=Math.max(t.minZoom,Math.min(t.maxZoom,t.object.zoom/g)),t.object.updateProjectionMatrix(),re=!0);return g=1,_=!1,re||v.distanceToSquared(t.object.position)>a||8*(1-E.dot(t.object.quaternion))>a||F.distanceToSquared(t.target)>0?(t.dispatchEvent(ce),v.copy(t.object.position),E.copy(t.object.quaternion),F.copy(t.target),!0):!1}}(),this.dispose=function(){t.domElement.removeEventListener("contextmenu",Le),t.domElement.removeEventListener("pointerdown",ze),t.domElement.removeEventListener("pointercancel",G),t.domElement.removeEventListener("wheel",Oe),t.domElement.removeEventListener("pointermove",ne),t.domElement.removeEventListener("pointerup",G),t._domElementKeyEvents!==null&&(t._domElementKeyEvents.removeEventListener("keydown",ae),t._domElementKeyEvents=null)};const t=this,i={NONE:-1,ROTATE:0,DOLLY:1,PAN:2,TOUCH_ROTATE:3,TOUCH_PAN:4,TOUCH_DOLLY_PAN:5,TOUCH_DOLLY_ROTATE:6};let o=i.NONE;const a=1e-6,l=new d.Spherical,p=new d.Spherical;let g=1;const m=new d.Vector3,x=new d.Vector2,M=new d.Vector2,b=new d.Vector2,y=new d.Vector2,w=new d.Vector2,N=new d.Vector2,A=new d.Vector2,R=new d.Vector2,T=new d.Vector2,me=new d.Vector3,I=new d.Vector2;let _=!1;const S=[],X={};let te=!1;function st(n){return n!==null?2*Math.PI/60*t.autoRotateSpeed*n:2*Math.PI/60/60*t.autoRotateSpeed}function q(n){const h=Math.abs(n*.01);return Math.pow(.95,t.zoomSpeed*h)}function K(n){p.theta-=n}function W(n){p.phi-=n}const fe=function(){const n=new d.Vector3;return function(f,v){n.setFromMatrixColumn(v,0),n.multiplyScalar(-f),m.add(n)}}(),ye=function(){const n=new d.Vector3;return function(f,v){t.screenSpacePanning===!0?n.setFromMatrixColumn(v,1):(n.setFromMatrixColumn(v,0),n.crossVectors(t.object.up,n)),n.multiplyScalar(f),m.add(n)}}(),H=function(){const n=new d.Vector3;return function(f,v){const E=t.domElement;if(t.object.isPerspectiveCamera){const F=t.object.position;n.copy(F).sub(t.target);let z=n.length();z*=Math.tan(t.object.fov/2*Math.PI/180),fe(2*f*z/E.clientHeight,t.object.matrix),ye(2*v*z/E.clientHeight,t.object.matrix)}else t.object.isOrthographicCamera?(fe(f*(t.object.right-t.object.left)/t.object.zoom/E.clientWidth,t.object.matrix),ye(v*(t.object.top-t.object.bottom)/t.object.zoom/E.clientHeight,t.object.matrix)):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."),t.enablePan=!1)}}();function se(n){t.object.isPerspectiveCamera||t.object.isOrthographicCamera?g/=n:(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),t.enableZoom=!1)}function be(n){t.object.isPerspectiveCamera||t.object.isOrthographicCamera?g*=n:(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),t.enableZoom=!1)}function ie(n,h){if(!t.zoomToCursor)return;_=!0;const f=t.domElement.getBoundingClientRect(),v=n-f.left,E=h-f.top,F=f.width,z=f.height;I.x=v/F*2-1,I.y=-(E/z)*2+1,me.set(I.x,I.y,1).unproject(t.object).sub(t.object.position).normalize()}function oe(n){return Math.max(t.minDistance,Math.min(t.maxDistance,n))}function xe(n){x.set(n.clientX,n.clientY)}function it(n){ie(n.clientX,n.clientX),A.set(n.clientX,n.clientY)}function ve(n){y.set(n.clientX,n.clientY)}function ot(n){M.set(n.clientX,n.clientY),b.subVectors(M,x).multiplyScalar(t.rotateSpeed);const h=t.domElement;K(2*Math.PI*b.x/h.clientHeight),W(2*Math.PI*b.y/h.clientHeight),x.copy(M),t.update()}function nt(n){R.set(n.clientX,n.clientY),T.subVectors(R,A),T.y>0?se(q(T.y)):T.y<0&&be(q(T.y)),A.copy(R),t.update()}function at(n){w.set(n.clientX,n.clientY),N.subVectors(w,y).multiplyScalar(t.panSpeed),H(N.x,N.y),y.copy(w),t.update()}function rt(n){ie(n.clientX,n.clientY),n.deltaY<0?be(q(n.deltaY)):n.deltaY>0&&se(q(n.deltaY)),t.update()}function lt(n){let h=!1;switch(n.code){case t.keys.UP:n.ctrlKey||n.metaKey||n.shiftKey?W(2*Math.PI*t.rotateSpeed/t.domElement.clientHeight):H(0,t.keyPanSpeed),h=!0;break;case t.keys.BOTTOM:n.ctrlKey||n.metaKey||n.shiftKey?W(-2*Math.PI*t.rotateSpeed/t.domElement.clientHeight):H(0,-t.keyPanSpeed),h=!0;break;case t.keys.LEFT:n.ctrlKey||n.metaKey||n.shiftKey?K(2*Math.PI*t.rotateSpeed/t.domElement.clientHeight):H(t.keyPanSpeed,0),h=!0;break;case t.keys.RIGHT:n.ctrlKey||n.metaKey||n.shiftKey?K(-2*Math.PI*t.rotateSpeed/t.domElement.clientHeight):H(-t.keyPanSpeed,0),h=!0;break}h&&(n.preventDefault(),t.update())}function Me(n){if(S.length===1)x.set(n.pageX,n.pageY);else{const h=$(n),f=.5*(n.pageX+h.x),v=.5*(n.pageY+h.y);x.set(f,v)}}function we(n){if(S.length===1)y.set(n.pageX,n.pageY);else{const h=$(n),f=.5*(n.pageX+h.x),v=.5*(n.pageY+h.y);y.set(f,v)}}function Ce(n){const h=$(n),f=n.pageX-h.x,v=n.pageY-h.y,E=Math.sqrt(f*f+v*v);A.set(0,E)}function ct(n){t.enableZoom&&Ce(n),t.enablePan&&we(n)}function ht(n){t.enableZoom&&Ce(n),t.enableRotate&&Me(n)}function Ee(n){if(S.length==1)M.set(n.pageX,n.pageY);else{const f=$(n),v=.5*(n.pageX+f.x),E=.5*(n.pageY+f.y);M.set(v,E)}b.subVectors(M,x).multiplyScalar(t.rotateSpeed);const h=t.domElement;K(2*Math.PI*b.x/h.clientHeight),W(2*Math.PI*b.y/h.clientHeight),x.copy(M)}function Se(n){if(S.length===1)w.set(n.pageX,n.pageY);else{const h=$(n),f=.5*(n.pageX+h.x),v=.5*(n.pageY+h.y);w.set(f,v)}N.subVectors(w,y).multiplyScalar(t.panSpeed),H(N.x,N.y),y.copy(w)}function Ne(n){const h=$(n),f=n.pageX-h.x,v=n.pageY-h.y,E=Math.sqrt(f*f+v*v);R.set(0,E),T.set(0,Math.pow(R.y/A.y,t.zoomSpeed)),se(T.y),A.copy(R);const F=(n.pageX+h.x)*.5,z=(n.pageY+h.y)*.5;ie(F,z)}function dt(n){t.enableZoom&&Ne(n),t.enablePan&&Se(n)}function pt(n){t.enableZoom&&Ne(n),t.enableRotate&&Ee(n)}function ze(n){t.enabled!==!1&&(S.length===0&&(t.domElement.setPointerCapture(n.pointerId),t.domElement.addEventListener("pointermove",ne),t.domElement.addEventListener("pointerup",G)),xt(n),n.pointerType==="touch"?yt(n):ut(n))}function ne(n){t.enabled!==!1&&(n.pointerType==="touch"?bt(n):gt(n))}function G(n){vt(n),S.length===0&&(t.domElement.releasePointerCapture(n.pointerId),t.domElement.removeEventListener("pointermove",ne),t.domElement.removeEventListener("pointerup",G)),t.dispatchEvent(he),o=i.NONE}function ut(n){let h;switch(n.button){case 0:h=t.mouseButtons.LEFT;break;case 1:h=t.mouseButtons.MIDDLE;break;case 2:h=t.mouseButtons.RIGHT;break;default:h=-1}switch(h){case d.MOUSE.DOLLY:if(t.enableZoom===!1)return;it(n),o=i.DOLLY;break;case d.MOUSE.ROTATE:if(n.ctrlKey||n.metaKey||n.shiftKey){if(t.enablePan===!1)return;ve(n),o=i.PAN}else{if(t.enableRotate===!1)return;xe(n),o=i.ROTATE}break;case d.MOUSE.PAN:if(n.ctrlKey||n.metaKey||n.shiftKey){if(t.enableRotate===!1)return;xe(n),o=i.ROTATE}else{if(t.enablePan===!1)return;ve(n),o=i.PAN}break;default:o=i.NONE}o!==i.NONE&&t.dispatchEvent(ee)}function gt(n){switch(o){case i.ROTATE:if(t.enableRotate===!1)return;ot(n);break;case i.DOLLY:if(t.enableZoom===!1)return;nt(n);break;case i.PAN:if(t.enablePan===!1)return;at(n);break}}function Oe(n){t.enabled===!1||t.enableZoom===!1||o!==i.NONE||(n.preventDefault(),t.dispatchEvent(ee),rt(mt(n)),t.dispatchEvent(he))}function mt(n){const h=n.deltaMode,f={clientX:n.clientX,clientY:n.clientY,deltaY:n.deltaY};switch(h){case 1:f.deltaY*=16;break;case 2:f.deltaY*=100;break}return n.ctrlKey&&!te&&(f.deltaY*=10),f}function ft(n){n.key==="Control"&&(te=!0,document.addEventListener("keyup",Pe,{passive:!0,capture:!0}))}function Pe(n){n.key==="Control"&&(te=!1,document.removeEventListener("keyup",Pe,{passive:!0,capture:!0}))}function ae(n){t.enabled===!1||t.enablePan===!1||lt(n)}function yt(n){switch(ke(n),S.length){case 1:switch(t.touches.ONE){case d.TOUCH.ROTATE:if(t.enableRotate===!1)return;Me(n),o=i.TOUCH_ROTATE;break;case d.TOUCH.PAN:if(t.enablePan===!1)return;we(n),o=i.TOUCH_PAN;break;default:o=i.NONE}break;case 2:switch(t.touches.TWO){case d.TOUCH.DOLLY_PAN:if(t.enableZoom===!1&&t.enablePan===!1)return;ct(n),o=i.TOUCH_DOLLY_PAN;break;case d.TOUCH.DOLLY_ROTATE:if(t.enableZoom===!1&&t.enableRotate===!1)return;ht(n),o=i.TOUCH_DOLLY_ROTATE;break;default:o=i.NONE}break;default:o=i.NONE}o!==i.NONE&&t.dispatchEvent(ee)}function bt(n){switch(ke(n),o){case i.TOUCH_ROTATE:if(t.enableRotate===!1)return;Ee(n),t.update();break;case i.TOUCH_PAN:if(t.enablePan===!1)return;Se(n),t.update();break;case i.TOUCH_DOLLY_PAN:if(t.enableZoom===!1&&t.enablePan===!1)return;dt(n),t.update();break;case i.TOUCH_DOLLY_ROTATE:if(t.enableZoom===!1&&t.enableRotate===!1)return;pt(n),t.update();break;default:o=i.NONE}}function Le(n){t.enabled!==!1&&n.preventDefault()}function xt(n){S.push(n.pointerId)}function vt(n){delete X[n.pointerId];for(let h=0;h<S.length;h++)if(S[h]==n.pointerId){S.splice(h,1);return}}function ke(n){let h=X[n.pointerId];h===void 0&&(h=new d.Vector2,X[n.pointerId]=h),h.set(n.pageX,n.pageY)}function $(n){const h=n.pointerId===S[0]?S[1]:S[0];return X[h]}t.domElement.addEventListener("contextmenu",Le),t.domElement.addEventListener("pointerdown",ze),t.domElement.addEventListener("pointercancel",G),t.domElement.addEventListener("wheel",Oe,{passive:!1}),document.addEventListener("keydown",ft,{passive:!0,capture:!0}),this.update()}}class He{constructor(e,s){r(this,"scene");r(this,"camera");r(this,"renderer");r(this,"controls");r(this,"container");r(this,"resizeHandler");this.container=e,this.scene=new u.Scene,this.scene.background=new u.Color(s.backgroundColor??657930);const{width:t,height:i}=le(e),o=s.cameraFov??75;this.camera=new u.PerspectiveCamera(o,t/i,.1,2e3);const a=s.cameraPosition??{x:0,y:0,z:80};this.camera.position.set(a.x,a.y,a.z),this.renderer=new u.WebGLRenderer({antialias:!0,alpha:!0,powerPreference:"high-performance"}),this.renderer.setSize(t,i),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2)),this.renderer.toneMapping=u.ACESFilmicToneMapping,this.renderer.toneMappingExposure=1,this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=u.PCFSoftShadowMap,e.appendChild(this.renderer.domElement),this.controls=new Re(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.controls.dampingFactor=.05,this.controls.rotateSpeed=.8,this.controls.zoomSpeed=1.2,this.controls.minDistance=10,this.controls.maxDistance=500,this.setupLighting(),this.resizeHandler=this.onWindowResize.bind(this),window.addEventListener("resize",this.resizeHandler)}setupLighting(){const e=new u.AmbientLight(16777215,.4);this.scene.add(e);const s=new u.DirectionalLight(16777215,.9);s.position.set(50,60,40),s.castShadow=!0,s.shadow.mapSize.width=1024,s.shadow.mapSize.height=1024,this.scene.add(s);const t=new u.DirectionalLight(16773344,.4);t.position.set(-50,30,-40),this.scene.add(t);const i=new u.DirectionalLight(16777215,.3);i.position.set(0,-30,-50),this.scene.add(i);const o=new u.PointLight(16750950,.5,150);o.position.set(40,20,40),this.scene.add(o);const a=new u.PointLight(16764057,.4,150);a.position.set(-40,-20,40),this.scene.add(a);const l=new u.PointLight(6724095,.2,100);l.position.set(0,40,-40),this.scene.add(l)}onWindowResize(){const{width:e,height:s}=le(this.container);this.camera.aspect=e/s,this.camera.updateProjectionMatrix(),this.renderer.setSize(e,s)}add(e){this.scene.add(e)}remove(e){this.scene.remove(e)}render(){this.controls.update(),this.renderer.render(this.scene,this.camera)}getCameraPosition(){return{x:this.camera.position.x,y:this.camera.position.y,z:this.camera.position.z}}getCameraDirection(){const e=new u.Vector3;return this.camera.getWorldDirection(e),e}dispose(){for(window.removeEventListener("resize",this.resizeHandler),this.controls.dispose(),this.renderer.dispose(),this.renderer.domElement.parentNode&&this.renderer.domElement.parentNode.removeChild(this.renderer.domElement);this.scene.children.length>0;){const e=this.scene.children[0];this.scene.remove(e)}}}class $e{constructor(e,s){r(this,"sceneManager");r(this,"nodeFactory");r(this,"nodes",new Map);r(this,"nodeObjects",new Map);this.sceneManager=e,this.nodeFactory=s}hasNode(e){return this.nodes.has(e)}addNode(e,s=0){if(!Q(e))return!1;if(this.nodes.has(e.id))return console.warn(`[ForceGraph3D] Node with id "${e.id}" already exists`),!1;const t=e.position??{x:(Math.random()-.5)*50,y:(Math.random()-.5)*50,z:(Math.random()-.5)*50},i={...e,position:t,velocity:{x:0,y:0,z:0},mass:1},o=this.nodeFactory.createNode({...e,position:t},s);return this.sceneManager.add(o.group),this.nodes.set(e.id,i),this.nodeObjects.set(e.id,o),!0}removeNode(e){const s=this.nodes.get(e),t=this.nodeObjects.get(e);return!s||!t?!1:(this.sceneManager.remove(t.group),this.nodeFactory.disposeNode(t),this.nodes.delete(e),this.nodeObjects.delete(e),!0)}updateNode(e,s){const t=this.nodes.get(e),i=this.nodeObjects.get(e);return!t||!i?(console.warn(`[ForceGraph3D] Node "${e}" not found`),!1):(s.label!==void 0&&(t.label=s.label,this.nodeFactory.updateNodeLabel(i,s.label)),s.color!==void 0&&(t.color=s.color,this.nodeFactory.updateNodeColor(i,s.color)),Object.keys(s).forEach(o=>{o!=="id"&&o!=="label"&&o!=="color"&&o!=="position"&&(t[o]=s[o])}),!0)}updateNodePosition(e,s){const t=this.nodes.get(e),i=this.nodeObjects.get(e);t&&i&&(t.position=s,i.group.position.set(s.x,s.y,s.z))}updateNodeLOD(e,s){const t=this.nodeObjects.get(e);t&&this.nodeFactory.updateNodeLOD(t,s)}getNode(e){return this.nodes.get(e)}getNodeObject(e){return this.nodeObjects.get(e)}getAllNodes(){return this.nodes}getAllNodeObjects(){const e=[];return this.nodeObjects.forEach(s=>{e.push(s.group)}),e}getAllSpheres(){const e=[];return this.nodeObjects.forEach(s=>{e.push(s.sphere)}),e}getNodeCount(){return this.nodes.size}clear(){this.nodes.forEach((e,s)=>{this.removeNode(s)})}dispose(){this.clear()}}class Ke{constructor(e,s,t){r(this,"sceneManager");r(this,"nodeManager");r(this,"edgeFactory");r(this,"edges",[]);r(this,"edgeObjects",[]);r(this,"edgeKeySet",new Set);r(this,"highlightedEdgeKey",null);this.sceneManager=e,this.nodeManager=s,this.edgeFactory=t}hasEdge(e,s){const t=k(e,s);return this.edgeKeySet.has(t)}addEdge(e){if(!J(e))return!1;if(!this.nodeManager.hasNode(e.source))return console.warn(`[ForceGraph3D] Source node "${e.source}" does not exist`),!1;if(!this.nodeManager.hasNode(e.target))return console.warn(`[ForceGraph3D] Target node "${e.target}" does not exist`),!1;const s=k(e.source,e.target);if(this.edgeKeySet.has(s))return console.warn(`[ForceGraph3D] Edge "${e.source}" -> "${e.target}" already exists`),!1;const t=this.nodeManager.getNode(e.source),i=this.nodeManager.getNode(e.target),o=this.edgeFactory.createEdge(e,t,i,t.position,i.position);return this.sceneManager.add(o.line),this.edges.push(e),this.edgeObjects.push(o),this.edgeKeySet.add(s),!0}removeEdge(e,s){const t=k(e,s);if(!this.edgeKeySet.has(t))return!1;const i=this.edges.findIndex(a=>k(a.source,a.target)===t);if(i===-1)return!1;const o=this.edgeObjects[i];return this.sceneManager.remove(o.line),this.edgeFactory.disposeEdge(o),this.edges.splice(i,1),this.edgeObjects.splice(i,1),this.edgeKeySet.delete(t),this.highlightedEdgeKey===t&&(this.highlightedEdgeKey=null),!0}highlightEdge(e,s){const t=k(e,s);this.highlightedEdgeKey&&this.highlightedEdgeKey!==t&&this.unhighlightCurrentEdge();const i=this.edges.findIndex(o=>k(o.source,o.target)===t);i!==-1&&(this.edgeFactory.highlightEdge(this.edgeObjects[i]),this.highlightedEdgeKey=t)}unhighlightCurrentEdge(){if(!this.highlightedEdgeKey)return;const e=this.edges.findIndex(s=>k(s.source,s.target)===this.highlightedEdgeKey);e!==-1&&this.edgeFactory.unhighlightEdge(this.edgeObjects[e]),this.highlightedEdgeKey=null}removeEdgesForNode(e){const s=[];this.edges.forEach(t=>{(t.source===e||t.target===e)&&s.push({source:t.source,target:t.target})}),s.forEach(t=>{this.removeEdge(t.source,t.target)})}getEdgesForNode(e){return this.edges.filter(s=>s.source===e||s.target===e)}getNeighborIds(e){const s=[];return this.edges.forEach(t=>{t.source===e?s.push(t.target):t.target===e&&s.push(t.source)}),[...new Set(s)]}updateEdgePositions(){this.edgeObjects.forEach((e,s)=>{const t=this.edges[s],i=this.nodeManager.getNode(t.source),o=this.nodeManager.getNode(t.target);i&&o&&this.edgeFactory.updateEdgePositions(e,i.position,o.position)})}getAllEdges(){return this.edges}getAllEdgeLines(){return this.edgeObjects.map(e=>e.line)}getEdgeCount(){return this.edges.length}clear(){this.edgeObjects.forEach(e=>{this.sceneManager.remove(e.line),this.edgeFactory.disposeEdge(e)}),this.edges=[],this.edgeObjects=[],this.edgeKeySet.clear(),this.highlightedEdgeKey=null}dispose(){this.clear()}}class pe{constructor(e,s,t={}){r(this,"nodes");r(this,"edges");r(this,"repulsionStrength");r(this,"attractionStrength");r(this,"damping");r(this,"useBarnesHut");r(this,"barnesHutTheta");r(this,"alpha",1);r(this,"alphaDecay",.0228);r(this,"alphaMin",.001);r(this,"alphaTarget",0);this.nodes=e,this.edges=s,this.repulsionStrength=t.repulsionStrength??100,this.attractionStrength=t.attractionStrength??.01,this.damping=t.damping??.9,this.useBarnesHut=t.useBarnesHut??!1,this.barnesHutTheta=t.barnesHutTheta??.5}simulate(){if(this.alpha<this.alphaMin)return;const e=this.nodes.size;(this.useBarnesHut||e>=1e3)&&e>=100?this.calculateRepulsionBarnesHut():this.calculateRepulsionBruteForce(),this.calculateAttraction(),this.applyForces(),this.alpha+=(this.alphaTarget-this.alpha)*this.alphaDecay}calculateRepulsionBruteForce(){const e=Array.from(this.nodes.values()),s=e.length;for(let t=0;t<s;t++){const i=e[t];for(let o=t+1;o<s;o++){const a=e[o],l=a.position.x-i.position.x,p=a.position.y-i.position.y,g=a.position.z-i.position.z;let m=l*l+p*p+g*g;m<.01&&(m=.01);const x=Math.sqrt(m),M=this.repulsionStrength*this.alpha/m,b=l/x*M,y=p/x*M,w=g/x*M;i.velocity.x-=b/i.mass,i.velocity.y-=y/i.mass,i.velocity.z-=w/i.mass,a.velocity.x+=b/a.mass,a.velocity.y+=y/a.mass,a.velocity.z+=w/a.mass}}}calculateRepulsionBarnesHut(){const e=Array.from(this.nodes.values()),s=new Ge(e);for(const t of e)this.calculateForceFromOctree(t,s.root)}calculateForceFromOctree(e,s){if(s.isLeaf){s.node&&s.node.id!==e.id&&this.applyRepulsionBetween(e,s.node);return}if(s.mass===0)return;const t=s.centerOfMass.x-e.position.x,i=s.centerOfMass.y-e.position.y,o=s.centerOfMass.z-e.position.z,a=Math.sqrt(t*t+i*i+o*o);if(s.size/a<this.barnesHutTheta){const l=Math.max(a*a,.01),p=this.repulsionStrength*this.alpha*s.mass/l;e.velocity.x-=t/a*p/e.mass,e.velocity.y-=i/a*p/e.mass,e.velocity.z-=o/a*p/e.mass}else for(const l of s.children)l&&this.calculateForceFromOctree(e,l)}applyRepulsionBetween(e,s){const t=s.position.x-e.position.x,i=s.position.y-e.position.y,o=s.position.z-e.position.z;let a=t*t+i*i+o*o;a<.01&&(a=.01);const l=Math.sqrt(a),p=this.repulsionStrength*this.alpha/a;e.velocity.x-=t/l*p/e.mass,e.velocity.y-=i/l*p/e.mass,e.velocity.z-=o/l*p/e.mass}calculateAttraction(){for(const e of this.edges){const s=this.nodes.get(e.source),t=this.nodes.get(e.target);if(!s||!t)continue;const i=t.position.x-s.position.x,o=t.position.y-s.position.y,a=t.position.z-s.position.z,l=Math.sqrt(i*i+o*o+a*a);if(l<.01)continue;const g=(l-15)*this.attractionStrength*this.alpha,m=i/l*g,x=o/l*g,M=a/l*g;s.velocity.x+=m/s.mass,s.velocity.y+=x/s.mass,s.velocity.z+=M/s.mass,t.velocity.x-=m/t.mass,t.velocity.y-=x/t.mass,t.velocity.z-=M/t.mass}}applyForces(){for(const e of this.nodes.values())e.velocity.x*=this.damping,e.velocity.y*=this.damping,e.velocity.z*=this.damping,e.position.x+=e.velocity.x,e.position.y+=e.velocity.y,e.position.z+=e.velocity.z}setEdges(e){this.edges=e}restart(){this.alpha=1}getAlpha(){return this.alpha}setPhysicsParams(e){e.repulsionStrength!==void 0&&(this.repulsionStrength=e.repulsionStrength),e.attractionStrength!==void 0&&(this.attractionStrength=e.attractionStrength),e.damping!==void 0&&(this.damping=e.damping)}}class Ge{constructor(e){r(this,"root");const s=this.calculateBounds(e);this.root=this.buildTree(e,s)}calculateBounds(e){if(e.length===0)return{min:{x:-100,y:-100,z:-100},max:{x:100,y:100,z:100}};const s={x:1/0,y:1/0,z:1/0},t={x:-1/0,y:-1/0,z:-1/0};for(const o of e)s.x=Math.min(s.x,o.position.x),s.y=Math.min(s.y,o.position.y),s.z=Math.min(s.z,o.position.z),t.x=Math.max(t.x,o.position.x),t.y=Math.max(t.y,o.position.y),t.z=Math.max(t.z,o.position.z);const i=10;return s.x-=i,s.y-=i,s.z-=i,t.x+=i,t.y+=i,t.z+=i,{min:s,max:t}}buildTree(e,s,t=0){const i=Math.max(s.max.x-s.min.x,s.max.y-s.min.y,s.max.z-s.min.z);if(e.length===0)return{bounds:s,size:i,centerOfMass:{x:0,y:0,z:0},mass:0,isLeaf:!0,node:null,children:[]};if(e.length===1||t>20){let b=0;const y={x:0,y:0,z:0};for(const w of e)b+=w.mass,y.x+=w.position.x*w.mass,y.y+=w.position.y*w.mass,y.z+=w.position.z*w.mass;return b>0&&(y.x/=b,y.y/=b,y.z/=b),{bounds:s,size:i,centerOfMass:y,mass:b,isLeaf:!0,node:e[0],children:[]}}const o=(s.min.x+s.max.x)/2,a=(s.min.y+s.max.y)/2,l=(s.min.z+s.max.z)/2,p=[[],[],[],[],[],[],[],[]];for(const b of e){const y=(b.position.x>=o?1:0)+(b.position.y>=a?2:0)+(b.position.z>=l?4:0);p[y].push(b)}const g=[{min:{x:s.min.x,y:s.min.y,z:s.min.z},max:{x:o,y:a,z:l}},{min:{x:o,y:s.min.y,z:s.min.z},max:{x:s.max.x,y:a,z:l}},{min:{x:s.min.x,y:a,z:s.min.z},max:{x:o,y:s.max.y,z:l}},{min:{x:o,y:a,z:s.min.z},max:{x:s.max.x,y:s.max.y,z:l}},{min:{x:s.min.x,y:s.min.y,z:l},max:{x:o,y:a,z:s.max.z}},{min:{x:o,y:s.min.y,z:l},max:{x:s.max.x,y:a,z:s.max.z}},{min:{x:s.min.x,y:a,z:l},max:{x:o,y:s.max.y,z:s.max.z}},{min:{x:o,y:a,z:l},max:{x:s.max.x,y:s.max.y,z:s.max.z}}],m=[];let x=0;const M={x:0,y:0,z:0};for(let b=0;b<8;b++)if(p[b].length>0){const y=this.buildTree(p[b],g[b],t+1);m.push(y),x+=y.mass,M.x+=y.centerOfMass.x*y.mass,M.y+=y.centerOfMass.y*y.mass,M.z+=y.centerOfMass.z*y.mass}else m.push(null);return x>0&&(M.x/=x,M.y/=x,M.z/=x),{bounds:s,size:i,centerOfMass:M,mass:x,isLeaf:!1,node:null,children:m}}}class Ye{constructor(e,s,t,i=60){r(this,"sceneManager");r(this,"animationId",null);r(this,"isRunning",!1);r(this,"frameInterval");r(this,"lastFrameTime",0);r(this,"onSimulate");r(this,"onRender");r(this,"frameCount",0);r(this,"fpsStartTime",0);r(this,"currentFPS",60);r(this,"animate",()=>{if(!this.isRunning)return;this.animationId=requestAnimationFrame(this.animate);const e=performance.now(),s=e-this.lastFrameTime;if(s<this.frameInterval)return;this.lastFrameTime=e-s%this.frameInterval,this.frameCount++;const t=e-this.fpsStartTime;t>=1e3&&(this.currentFPS=this.frameCount/(t/1e3),this.frameCount=0,this.fpsStartTime=e),this.onSimulate(),this.onRender(),this.sceneManager.render()});this.sceneManager=e,this.onSimulate=s,this.onRender=t,this.frameInterval=1e3/i}start(){this.isRunning||(this.isRunning=!0,this.lastFrameTime=performance.now(),this.fpsStartTime=performance.now(),this.frameCount=0,this.animate())}stop(){this.isRunning=!1,this.animationId!==null&&(cancelAnimationFrame(this.animationId),this.animationId=null)}getFPS(){return Math.round(this.currentFPS)}setTargetFPS(e){this.frameInterval=1e3/e}isAnimating(){return this.isRunning}dispose(){this.stop()}}class Ve{constructor(){r(this,"envMap",null);r(this,"materialCache",new Map);r(this,"COLORS",[16777215,16750950,16764057,16772829,16746564]);this.createEnvironmentMap()}createEnvironmentMap(){const s=[],t=[{colors:["#1a1a2e","#16213e","#0f3460"]},{colors:["#2d1f1f","#1a1a1a","#0f0f0f"]},{colors:["#1f2d2d","#1a1a2e","#101020"]},{colors:["#0a0a0a","#050505","#000000"]},{colors:["#1a1a2e","#0f1a2a","#0a0a15"]},{colors:["#2d1a1a","#1a0a0a","#0f0505"]}];for(const i of t){const o=document.createElement("canvas");o.width=256,o.height=256;const a=o.getContext("2d"),l=a.createRadialGradient(256/2,256/2,0,256/2,256/2,256*.8);l.addColorStop(0,i.colors[0]),l.addColorStop(.5,i.colors[1]),l.addColorStop(1,i.colors[2]),a.fillStyle=l,a.fillRect(0,0,256,256);const p=a.getImageData(0,0,256,256);for(let g=0;g<p.data.length;g+=4){const m=(Math.random()-.5)*5;p.data[g]=Math.min(255,Math.max(0,p.data[g]+m)),p.data[g+1]=Math.min(255,Math.max(0,p.data[g+1]+m)),p.data[g+2]=Math.min(255,Math.max(0,p.data[g+2]+m))}a.putImageData(p,0,0),s.push(o)}this.envMap=new u.CubeTexture(s.map(i=>{const o=new Image;return o.src=i.toDataURL(),o})),this.envMap.needsUpdate=!0}getRandomColor(){return this.COLORS[Math.floor(Math.random()*this.COLORS.length)]}createGlassMaterial(e){const t="glass-single";if(this.materialCache.has(t))return this.materialCache.get(t).clone();const i=new u.Color(16750950),o=new u.ShaderMaterial({uniforms:{uColor:{value:i},uEnvMap:{value:this.envMap},uGlowColor:{value:new u.Color(16777215)},uGlowIntensity:{value:.8},uReflectivity:{value:.4},uFresnelPower:{value:2.5}},vertexShader:`
8
+ `,document.body.appendChild(h),h}function De(h){return h&&h instanceof HTMLElement?h:(console.warn("[ForceGraph3D] No container provided, creating one automatically"),Ie())}function ce(h){const e=h.getBoundingClientRect();return{width:e.width||window.innerWidth,height:e.height||window.innerHeight}}function J(h){if(!h||typeof h!="object")return console.warn("[ForceGraph3D] Invalid node: must be an object"),!1;const e=h;return typeof e.id!="string"||e.id.trim()===""?(console.warn("[ForceGraph3D] Invalid node: id must be a non-empty string"),!1):typeof e.label!="string"?(console.warn("[ForceGraph3D] Invalid node: label must be a string"),!1):e.color!==void 0&&typeof e.color!="number"?(console.warn("[ForceGraph3D] Invalid node: color must be a number (hex)"),!1):e.position!==void 0&&!Ae(e.position)?(console.warn("[ForceGraph3D] Invalid node: position must have x, y, z numbers"),!1):!0}function ee(h){if(!h||typeof h!="object")return console.warn("[ForceGraph3D] Invalid edge: must be an object"),!1;const e=h;return typeof e.source!="string"||e.source.trim()===""?(console.warn("[ForceGraph3D] Invalid edge: source must be a non-empty string"),!1):typeof e.target!="string"||e.target.trim()===""?(console.warn("[ForceGraph3D] Invalid edge: target must be a non-empty string"),!1):!0}function Fe(h){return typeof h!="string"||h.trim()===""?(console.warn("[ForceGraph3D] Invalid node ID: must be a non-empty string"),!1):!0}function Ae(h){if(!h||typeof h!="object")return!1;const e=h;return typeof e.x=="number"&&typeof e.y=="number"&&typeof e.z=="number"}function D(h,e){return h===e?`${h}-${e}`:h<e?`${h}-${e}`:`${e}-${h}`}const he={type:"change"},te={type:"start"},de={type:"end"},X=new g.Ray,pe=new g.Plane,je=Math.cos(70*g.MathUtils.DEG2RAD);class Re extends g.EventDispatcher{constructor(e,s){super(),this.object=e,this.domElement=s,this.domElement.style.touchAction="none",this.enabled=!0,this.target=new g.Vector3,this.cursor=new g.Vector3,this.minDistance=0,this.maxDistance=1/0,this.minZoom=0,this.maxZoom=1/0,this.minTargetRadius=0,this.maxTargetRadius=1/0,this.minPolarAngle=0,this.maxPolarAngle=Math.PI,this.minAzimuthAngle=-1/0,this.maxAzimuthAngle=1/0,this.enableDamping=!1,this.dampingFactor=.05,this.enableZoom=!0,this.zoomSpeed=1,this.enableRotate=!0,this.rotateSpeed=1,this.enablePan=!0,this.panSpeed=1,this.screenSpacePanning=!0,this.keyPanSpeed=7,this.zoomToCursor=!1,this.autoRotate=!1,this.autoRotateSpeed=2,this.keys={LEFT:"ArrowLeft",UP:"ArrowUp",RIGHT:"ArrowRight",BOTTOM:"ArrowDown"},this.mouseButtons={LEFT:g.MOUSE.ROTATE,MIDDLE:g.MOUSE.DOLLY,RIGHT:g.MOUSE.PAN},this.touches={ONE:g.TOUCH.ROTATE,TWO:g.TOUCH.DOLLY_PAN},this.target0=this.target.clone(),this.position0=this.object.position.clone(),this.zoom0=this.object.zoom,this._domElementKeyEvents=null,this.getPolarAngle=function(){return r.phi},this.getAzimuthalAngle=function(){return r.theta},this.getDistance=function(){return this.object.position.distanceTo(this.target)},this.listenToKeyEvents=function(n){n.addEventListener("keydown",re),this._domElementKeyEvents=n},this.stopListenToKeyEvents=function(){this._domElementKeyEvents.removeEventListener("keydown",re),this._domElementKeyEvents=null},this.saveState=function(){t.target0.copy(t.target),t.position0.copy(t.object.position),t.zoom0=t.object.zoom},this.reset=function(){t.target.copy(t.target0),t.object.position.copy(t.position0),t.object.zoom=t.zoom0,t.object.updateProjectionMatrix(),t.dispatchEvent(he),t.update(),i=o.NONE},this.update=function(){const n=new g.Vector3,p=new g.Quaternion().setFromUnitVectors(e.up,new g.Vector3(0,1,0)),v=p.clone().invert(),C=new g.Vector3,S=new g.Quaternion,A=new g.Vector3,k=2*Math.PI;return function(Nt=null){const Le=t.object.position;n.copy(Le).sub(t.target),n.applyQuaternion(p),r.setFromVector3(n),t.autoRotate&&i===o.NONE&&B(at(Nt)),t.enableDamping?(r.theta+=c.theta*t.dampingFactor,r.phi+=c.phi*t.dampingFactor):(r.theta+=c.theta,r.phi+=c.phi);let L=t.minAzimuthAngle,I=t.maxAzimuthAngle;isFinite(L)&&isFinite(I)&&(L<-Math.PI?L+=k:L>Math.PI&&(L-=k),I<-Math.PI?I+=k:I>Math.PI&&(I-=k),L<=I?r.theta=Math.max(L,Math.min(I,r.theta)):r.theta=r.theta>(L+I)/2?Math.max(L,r.theta):Math.min(I,r.theta)),r.phi=Math.max(t.minPolarAngle,Math.min(t.maxPolarAngle,r.phi)),r.makeSafe(),t.enableDamping===!0?t.target.addScaledVector(u,t.dampingFactor):t.target.add(u),t.target.sub(t.cursor),t.target.clampLength(t.minTargetRadius,t.maxTargetRadius),t.target.add(t.cursor),t.zoomToCursor&&j||t.object.isOrthographicCamera?r.radius=ne(r.radius):r.radius=ne(r.radius*d),n.setFromSpherical(r),n.applyQuaternion(v),Le.copy(t.target).add(n),t.object.lookAt(t.target),t.enableDamping===!0?(c.theta*=1-t.dampingFactor,c.phi*=1-t.dampingFactor,u.multiplyScalar(1-t.dampingFactor)):(c.set(0,0,0),u.set(0,0,0));let le=!1;if(t.zoomToCursor&&j){let K=null;if(t.object.isPerspectiveCamera){const U=n.length();K=ne(U*d);const Q=U-K;t.object.position.addScaledVector(Y,Q),t.object.updateMatrixWorld()}else if(t.object.isOrthographicCamera){const U=new g.Vector3(O.x,O.y,0);U.unproject(t.object),t.object.zoom=Math.max(t.minZoom,Math.min(t.maxZoom,t.object.zoom/d)),t.object.updateProjectionMatrix(),le=!0;const Q=new g.Vector3(O.x,O.y,0);Q.unproject(t.object),t.object.position.sub(Q).add(U),t.object.updateMatrixWorld(),K=n.length()}else console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."),t.zoomToCursor=!1;K!==null&&(this.screenSpacePanning?t.target.set(0,0,-1).transformDirection(t.object.matrix).multiplyScalar(K).add(t.object.position):(X.origin.copy(t.object.position),X.direction.set(0,0,-1).transformDirection(t.object.matrix),Math.abs(t.object.up.dot(X.direction))<je?e.lookAt(t.target):(pe.setFromNormalAndCoplanarPoint(t.object.up,t.target),X.intersectPlane(pe,t.target))))}else t.object.isOrthographicCamera&&(t.object.zoom=Math.max(t.minZoom,Math.min(t.maxZoom,t.object.zoom/d)),t.object.updateProjectionMatrix(),le=!0);return d=1,j=!1,le||C.distanceToSquared(t.object.position)>a||8*(1-S.dot(t.object.quaternion))>a||A.distanceToSquared(t.target)>0?(t.dispatchEvent(he),C.copy(t.object.position),S.copy(t.object.quaternion),A.copy(t.target),!0):!1}}(),this.dispose=function(){t.domElement.removeEventListener("contextmenu",Oe),t.domElement.removeEventListener("pointerdown",ze),t.domElement.removeEventListener("pointercancel",V),t.domElement.removeEventListener("wheel",ke),t.domElement.removeEventListener("pointermove",ae),t.domElement.removeEventListener("pointerup",V),t._domElementKeyEvents!==null&&(t._domElementKeyEvents.removeEventListener("keydown",re),t._domElementKeyEvents=null)};const t=this,o={NONE:-1,ROTATE:0,DOLLY:1,PAN:2,TOUCH_ROTATE:3,TOUCH_PAN:4,TOUCH_DOLLY_PAN:5,TOUCH_DOLLY_ROTATE:6};let i=o.NONE;const a=1e-6,r=new g.Spherical,c=new g.Spherical;let d=1;const u=new g.Vector3,f=new g.Vector2,x=new g.Vector2,m=new g.Vector2,b=new g.Vector2,M=new g.Vector2,w=new g.Vector2,z=new g.Vector2,F=new g.Vector2,T=new g.Vector2,Y=new g.Vector3,O=new g.Vector2;let j=!1;const E=[],q={};let se=!1;function at(n){return n!==null?2*Math.PI/60*t.autoRotateSpeed*n:2*Math.PI/60/60*t.autoRotateSpeed}function W(n){const p=Math.abs(n*.01);return Math.pow(.95,t.zoomSpeed*p)}function B(n){c.theta-=n}function Z(n){c.phi-=n}const me=function(){const n=new g.Vector3;return function(v,C){n.setFromMatrixColumn(C,0),n.multiplyScalar(-v),u.add(n)}}(),ye=function(){const n=new g.Vector3;return function(v,C){t.screenSpacePanning===!0?n.setFromMatrixColumn(C,1):(n.setFromMatrixColumn(C,0),n.crossVectors(t.object.up,n)),n.multiplyScalar(v),u.add(n)}}(),$=function(){const n=new g.Vector3;return function(v,C){const S=t.domElement;if(t.object.isPerspectiveCamera){const A=t.object.position;n.copy(A).sub(t.target);let k=n.length();k*=Math.tan(t.object.fov/2*Math.PI/180),me(2*v*k/S.clientHeight,t.object.matrix),ye(2*C*k/S.clientHeight,t.object.matrix)}else t.object.isOrthographicCamera?(me(v*(t.object.right-t.object.left)/t.object.zoom/S.clientWidth,t.object.matrix),ye(C*(t.object.top-t.object.bottom)/t.object.zoom/S.clientHeight,t.object.matrix)):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."),t.enablePan=!1)}}();function ie(n){t.object.isPerspectiveCamera||t.object.isOrthographicCamera?d/=n:(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),t.enableZoom=!1)}function xe(n){t.object.isPerspectiveCamera||t.object.isOrthographicCamera?d*=n:(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),t.enableZoom=!1)}function oe(n,p){if(!t.zoomToCursor)return;j=!0;const v=t.domElement.getBoundingClientRect(),C=n-v.left,S=p-v.top,A=v.width,k=v.height;O.x=C/A*2-1,O.y=-(S/k)*2+1,Y.set(O.x,O.y,1).unproject(t.object).sub(t.object.position).normalize()}function ne(n){return Math.max(t.minDistance,Math.min(t.maxDistance,n))}function be(n){f.set(n.clientX,n.clientY)}function rt(n){oe(n.clientX,n.clientX),z.set(n.clientX,n.clientY)}function ve(n){b.set(n.clientX,n.clientY)}function lt(n){x.set(n.clientX,n.clientY),m.subVectors(x,f).multiplyScalar(t.rotateSpeed);const p=t.domElement;B(2*Math.PI*m.x/p.clientHeight),Z(2*Math.PI*m.y/p.clientHeight),f.copy(x),t.update()}function ct(n){F.set(n.clientX,n.clientY),T.subVectors(F,z),T.y>0?ie(W(T.y)):T.y<0&&xe(W(T.y)),z.copy(F),t.update()}function ht(n){M.set(n.clientX,n.clientY),w.subVectors(M,b).multiplyScalar(t.panSpeed),$(w.x,w.y),b.copy(M),t.update()}function dt(n){oe(n.clientX,n.clientY),n.deltaY<0?xe(W(n.deltaY)):n.deltaY>0&&ie(W(n.deltaY)),t.update()}function pt(n){let p=!1;switch(n.code){case t.keys.UP:n.ctrlKey||n.metaKey||n.shiftKey?Z(2*Math.PI*t.rotateSpeed/t.domElement.clientHeight):$(0,t.keyPanSpeed),p=!0;break;case t.keys.BOTTOM:n.ctrlKey||n.metaKey||n.shiftKey?Z(-2*Math.PI*t.rotateSpeed/t.domElement.clientHeight):$(0,-t.keyPanSpeed),p=!0;break;case t.keys.LEFT:n.ctrlKey||n.metaKey||n.shiftKey?B(2*Math.PI*t.rotateSpeed/t.domElement.clientHeight):$(t.keyPanSpeed,0),p=!0;break;case t.keys.RIGHT:n.ctrlKey||n.metaKey||n.shiftKey?B(-2*Math.PI*t.rotateSpeed/t.domElement.clientHeight):$(-t.keyPanSpeed,0),p=!0;break}p&&(n.preventDefault(),t.update())}function Me(n){if(E.length===1)f.set(n.pageX,n.pageY);else{const p=G(n),v=.5*(n.pageX+p.x),C=.5*(n.pageY+p.y);f.set(v,C)}}function we(n){if(E.length===1)b.set(n.pageX,n.pageY);else{const p=G(n),v=.5*(n.pageX+p.x),C=.5*(n.pageY+p.y);b.set(v,C)}}function Ce(n){const p=G(n),v=n.pageX-p.x,C=n.pageY-p.y,S=Math.sqrt(v*v+C*C);z.set(0,S)}function gt(n){t.enableZoom&&Ce(n),t.enablePan&&we(n)}function ut(n){t.enableZoom&&Ce(n),t.enableRotate&&Me(n)}function Ee(n){if(E.length==1)x.set(n.pageX,n.pageY);else{const v=G(n),C=.5*(n.pageX+v.x),S=.5*(n.pageY+v.y);x.set(C,S)}m.subVectors(x,f).multiplyScalar(t.rotateSpeed);const p=t.domElement;B(2*Math.PI*m.x/p.clientHeight),Z(2*Math.PI*m.y/p.clientHeight),f.copy(x)}function Ne(n){if(E.length===1)M.set(n.pageX,n.pageY);else{const p=G(n),v=.5*(n.pageX+p.x),C=.5*(n.pageY+p.y);M.set(v,C)}w.subVectors(M,b).multiplyScalar(t.panSpeed),$(w.x,w.y),b.copy(M)}function Se(n){const p=G(n),v=n.pageX-p.x,C=n.pageY-p.y,S=Math.sqrt(v*v+C*C);F.set(0,S),T.set(0,Math.pow(F.y/z.y,t.zoomSpeed)),ie(T.y),z.copy(F);const A=(n.pageX+p.x)*.5,k=(n.pageY+p.y)*.5;oe(A,k)}function ft(n){t.enableZoom&&Se(n),t.enablePan&&Ne(n)}function mt(n){t.enableZoom&&Se(n),t.enableRotate&&Ee(n)}function ze(n){t.enabled!==!1&&(E.length===0&&(t.domElement.setPointerCapture(n.pointerId),t.domElement.addEventListener("pointermove",ae),t.domElement.addEventListener("pointerup",V)),Ct(n),n.pointerType==="touch"?Mt(n):yt(n))}function ae(n){t.enabled!==!1&&(n.pointerType==="touch"?wt(n):xt(n))}function V(n){Et(n),E.length===0&&(t.domElement.releasePointerCapture(n.pointerId),t.domElement.removeEventListener("pointermove",ae),t.domElement.removeEventListener("pointerup",V)),t.dispatchEvent(de),i=o.NONE}function yt(n){let p;switch(n.button){case 0:p=t.mouseButtons.LEFT;break;case 1:p=t.mouseButtons.MIDDLE;break;case 2:p=t.mouseButtons.RIGHT;break;default:p=-1}switch(p){case g.MOUSE.DOLLY:if(t.enableZoom===!1)return;rt(n),i=o.DOLLY;break;case g.MOUSE.ROTATE:if(n.ctrlKey||n.metaKey||n.shiftKey){if(t.enablePan===!1)return;ve(n),i=o.PAN}else{if(t.enableRotate===!1)return;be(n),i=o.ROTATE}break;case g.MOUSE.PAN:if(n.ctrlKey||n.metaKey||n.shiftKey){if(t.enableRotate===!1)return;be(n),i=o.ROTATE}else{if(t.enablePan===!1)return;ve(n),i=o.PAN}break;default:i=o.NONE}i!==o.NONE&&t.dispatchEvent(te)}function xt(n){switch(i){case o.ROTATE:if(t.enableRotate===!1)return;lt(n);break;case o.DOLLY:if(t.enableZoom===!1)return;ct(n);break;case o.PAN:if(t.enablePan===!1)return;ht(n);break}}function ke(n){t.enabled===!1||t.enableZoom===!1||i!==o.NONE||(n.preventDefault(),t.dispatchEvent(te),dt(bt(n)),t.dispatchEvent(de))}function bt(n){const p=n.deltaMode,v={clientX:n.clientX,clientY:n.clientY,deltaY:n.deltaY};switch(p){case 1:v.deltaY*=16;break;case 2:v.deltaY*=100;break}return n.ctrlKey&&!se&&(v.deltaY*=10),v}function vt(n){n.key==="Control"&&(se=!0,document.addEventListener("keyup",Pe,{passive:!0,capture:!0}))}function Pe(n){n.key==="Control"&&(se=!1,document.removeEventListener("keyup",Pe,{passive:!0,capture:!0}))}function re(n){t.enabled===!1||t.enablePan===!1||pt(n)}function Mt(n){switch(Te(n),E.length){case 1:switch(t.touches.ONE){case g.TOUCH.ROTATE:if(t.enableRotate===!1)return;Me(n),i=o.TOUCH_ROTATE;break;case g.TOUCH.PAN:if(t.enablePan===!1)return;we(n),i=o.TOUCH_PAN;break;default:i=o.NONE}break;case 2:switch(t.touches.TWO){case g.TOUCH.DOLLY_PAN:if(t.enableZoom===!1&&t.enablePan===!1)return;gt(n),i=o.TOUCH_DOLLY_PAN;break;case g.TOUCH.DOLLY_ROTATE:if(t.enableZoom===!1&&t.enableRotate===!1)return;ut(n),i=o.TOUCH_DOLLY_ROTATE;break;default:i=o.NONE}break;default:i=o.NONE}i!==o.NONE&&t.dispatchEvent(te)}function wt(n){switch(Te(n),i){case o.TOUCH_ROTATE:if(t.enableRotate===!1)return;Ee(n),t.update();break;case o.TOUCH_PAN:if(t.enablePan===!1)return;Ne(n),t.update();break;case o.TOUCH_DOLLY_PAN:if(t.enableZoom===!1&&t.enablePan===!1)return;ft(n),t.update();break;case o.TOUCH_DOLLY_ROTATE:if(t.enableZoom===!1&&t.enableRotate===!1)return;mt(n),t.update();break;default:i=o.NONE}}function Oe(n){t.enabled!==!1&&n.preventDefault()}function Ct(n){E.push(n.pointerId)}function Et(n){delete q[n.pointerId];for(let p=0;p<E.length;p++)if(E[p]==n.pointerId){E.splice(p,1);return}}function Te(n){let p=q[n.pointerId];p===void 0&&(p=new g.Vector2,q[n.pointerId]=p),p.set(n.pageX,n.pageY)}function G(n){const p=n.pointerId===E[0]?E[1]:E[0];return q[p]}t.domElement.addEventListener("contextmenu",Oe),t.domElement.addEventListener("pointerdown",ze),t.domElement.addEventListener("pointercancel",V),t.domElement.addEventListener("wheel",ke,{passive:!1}),document.addEventListener("keydown",vt,{passive:!0,capture:!0}),this.update()}}class He{constructor(e,s){l(this,"scene");l(this,"camera");l(this,"renderer");l(this,"controls");l(this,"container");l(this,"resizeHandler");this.container=e,this.scene=new y.Scene,this.scene.background=new y.Color(s.backgroundColor??657930);const{width:t,height:o}=ce(e),i=s.cameraFov??75;this.camera=new y.PerspectiveCamera(i,t/o,.1,2e3);const a=s.cameraPosition??{x:0,y:0,z:80};this.camera.position.set(a.x,a.y,a.z),this.renderer=new y.WebGLRenderer({antialias:!0,alpha:!0,powerPreference:"high-performance"}),this.renderer.setSize(t,o),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2)),this.renderer.toneMapping=y.ACESFilmicToneMapping,this.renderer.toneMappingExposure=1,this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=y.PCFSoftShadowMap,e.appendChild(this.renderer.domElement),this.controls=new Re(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.controls.dampingFactor=.05,this.controls.rotateSpeed=.8,this.controls.zoomSpeed=1.2,this.controls.minDistance=10,this.controls.maxDistance=500,this.setupLighting(),this.resizeHandler=this.onWindowResize.bind(this),window.addEventListener("resize",this.resizeHandler)}setupLighting(){const e=new y.AmbientLight(16777215,.4);this.scene.add(e);const s=new y.DirectionalLight(16777215,.9);s.position.set(50,60,40),s.castShadow=!0,s.shadow.mapSize.width=1024,s.shadow.mapSize.height=1024,this.scene.add(s);const t=new y.DirectionalLight(16773344,.4);t.position.set(-50,30,-40),this.scene.add(t);const o=new y.DirectionalLight(16777215,.3);o.position.set(0,-30,-50),this.scene.add(o);const i=new y.PointLight(16750950,.5,150);i.position.set(40,20,40),this.scene.add(i);const a=new y.PointLight(16764057,.4,150);a.position.set(-40,-20,40),this.scene.add(a);const r=new y.PointLight(6724095,.2,100);r.position.set(0,40,-40),this.scene.add(r)}onWindowResize(){const{width:e,height:s}=ce(this.container);this.camera.aspect=e/s,this.camera.updateProjectionMatrix(),this.renderer.setSize(e,s)}add(e){this.scene.add(e)}remove(e){this.scene.remove(e)}render(){this.controls.update(),this.renderer.render(this.scene,this.camera)}getCameraPosition(){return{x:this.camera.position.x,y:this.camera.position.y,z:this.camera.position.z}}getCameraDirection(){const e=new y.Vector3;return this.camera.getWorldDirection(e),e}dispose(){for(window.removeEventListener("resize",this.resizeHandler),this.controls.dispose(),this.renderer.dispose(),this.renderer.domElement.parentNode&&this.renderer.domElement.parentNode.removeChild(this.renderer.domElement);this.scene.children.length>0;){const e=this.scene.children[0];this.scene.remove(e)}}}class $e{constructor(e,s){l(this,"sceneManager");l(this,"nodeFactory");l(this,"nodes",new Map);l(this,"nodeObjects",new Map);this.sceneManager=e,this.nodeFactory=s}hasNode(e){return this.nodes.has(e)}addNode(e,s=0){if(!J(e))return!1;if(this.nodes.has(e.id))return console.warn(`[ForceGraph3D] Node with id "${e.id}" already exists`),!1;const t=e.position??{x:(Math.random()-.5)*50,y:(Math.random()-.5)*50,z:(Math.random()-.5)*50},o={...e,position:t,velocity:{x:0,y:0,z:0},mass:1},i=this.nodeFactory.createNode({...e,position:t},s);return this.sceneManager.add(i.group),this.nodes.set(e.id,o),this.nodeObjects.set(e.id,i),!0}removeNode(e){const s=this.nodes.get(e),t=this.nodeObjects.get(e);return!s||!t?!1:(this.sceneManager.remove(t.group),this.nodeFactory.disposeNode(t),this.nodes.delete(e),this.nodeObjects.delete(e),!0)}updateNode(e,s){const t=this.nodes.get(e),o=this.nodeObjects.get(e);return!t||!o?(console.warn(`[ForceGraph3D] Node "${e}" not found`),!1):(s.label!==void 0&&(t.label=s.label,this.nodeFactory.updateNodeLabel(o,s.label)),s.color!==void 0&&(t.color=s.color,this.nodeFactory.updateNodeColor(o,s.color)),Object.keys(s).forEach(i=>{i!=="id"&&i!=="label"&&i!=="color"&&i!=="position"&&(t[i]=s[i])}),!0)}updateNodePosition(e,s){const t=this.nodes.get(e),o=this.nodeObjects.get(e);t&&o&&(t.position=s,o.group.position.set(s.x,s.y,s.z))}updateNodeLOD(e,s){const t=this.nodeObjects.get(e);t&&this.nodeFactory.updateNodeLOD(t,s)}getNode(e){return this.nodes.get(e)}getNodeObject(e){return this.nodeObjects.get(e)}getAllNodes(){return this.nodes}getAllNodeObjects(){const e=[];return this.nodeObjects.forEach(s=>{e.push(s.group)}),e}getAllSpheres(){const e=[];return this.nodeObjects.forEach(s=>{e.push(s.sphere)}),e}getNodeCount(){return this.nodes.size}clear(){this.nodes.forEach((e,s)=>{this.removeNode(s)})}dispose(){this.clear()}}class Ge{constructor(e,s,t){l(this,"sceneManager");l(this,"nodeManager");l(this,"edgeFactory");l(this,"edges",[]);l(this,"edgeObjects",[]);l(this,"edgeKeySet",new Set);l(this,"highlightedEdgeKey",null);this.sceneManager=e,this.nodeManager=s,this.edgeFactory=t}hasEdge(e,s){const t=D(e,s);return this.edgeKeySet.has(t)}addEdge(e){if(!ee(e))return!1;if(!this.nodeManager.hasNode(e.source))return console.warn(`[ForceGraph3D] Source node "${e.source}" does not exist`),!1;if(!this.nodeManager.hasNode(e.target))return console.warn(`[ForceGraph3D] Target node "${e.target}" does not exist`),!1;const s=D(e.source,e.target);if(this.edgeKeySet.has(s))return console.warn(`[ForceGraph3D] Edge "${e.source}" -> "${e.target}" already exists`),!1;const t=this.nodeManager.getNode(e.source),o=this.nodeManager.getNode(e.target),i=this.edgeFactory.createEdge(e,t,o,t.position,o.position);return this.sceneManager.add(i.line),this.edges.push(e),this.edgeObjects.push(i),this.edgeKeySet.add(s),!0}removeEdge(e,s){const t=D(e,s);if(!this.edgeKeySet.has(t))return!1;const o=this.edges.findIndex(a=>D(a.source,a.target)===t);if(o===-1)return!1;const i=this.edgeObjects[o];return this.sceneManager.remove(i.line),this.edgeFactory.disposeEdge(i),this.edges.splice(o,1),this.edgeObjects.splice(o,1),this.edgeKeySet.delete(t),this.highlightedEdgeKey===t&&(this.highlightedEdgeKey=null),!0}highlightEdge(e,s){const t=D(e,s);this.highlightedEdgeKey&&this.highlightedEdgeKey!==t&&this.unhighlightCurrentEdge();const o=this.edges.findIndex(i=>D(i.source,i.target)===t);o!==-1&&(this.edgeFactory.highlightEdge(this.edgeObjects[o]),this.highlightedEdgeKey=t)}unhighlightCurrentEdge(){if(!this.highlightedEdgeKey)return;const e=this.edges.findIndex(s=>D(s.source,s.target)===this.highlightedEdgeKey);e!==-1&&this.edgeFactory.unhighlightEdge(this.edgeObjects[e]),this.highlightedEdgeKey=null}removeEdgesForNode(e){const s=[];this.edges.forEach(t=>{(t.source===e||t.target===e)&&s.push({source:t.source,target:t.target})}),s.forEach(t=>{this.removeEdge(t.source,t.target)})}getEdgesForNode(e){return this.edges.filter(s=>s.source===e||s.target===e)}getNeighborIds(e){const s=[];return this.edges.forEach(t=>{t.source===e?s.push(t.target):t.target===e&&s.push(t.source)}),[...new Set(s)]}updateEdgePositions(){this.edgeObjects.forEach((e,s)=>{const t=this.edges[s],o=this.nodeManager.getNode(t.source),i=this.nodeManager.getNode(t.target);o&&i&&this.edgeFactory.updateEdgePositions(e,o.position,i.position)})}getAllEdges(){return this.edges}getAllEdgeLines(){return this.edgeObjects.map(e=>e.line)}getEdgeCount(){return this.edges.length}clear(){this.edgeObjects.forEach(e=>{this.sceneManager.remove(e.line),this.edgeFactory.disposeEdge(e)}),this.edges=[],this.edgeObjects=[],this.edgeKeySet.clear(),this.highlightedEdgeKey=null}dispose(){this.clear()}}class ge{constructor(e,s,t={}){l(this,"nodes");l(this,"edges");l(this,"repulsionStrength");l(this,"attractionStrength");l(this,"damping");l(this,"useBarnesHut");l(this,"barnesHutTheta");l(this,"alpha",1);l(this,"alphaDecay",.0228);l(this,"alphaMin",.001);l(this,"alphaTarget",0);this.nodes=e,this.edges=s,this.repulsionStrength=t.repulsionStrength??100,this.attractionStrength=t.attractionStrength??.01,this.damping=t.damping??.9,this.useBarnesHut=t.useBarnesHut??!1,this.barnesHutTheta=t.barnesHutTheta??.5}simulate(){if(this.alpha<this.alphaMin)return;const e=this.nodes.size;(this.useBarnesHut||e>=1e3)&&e>=100?this.calculateRepulsionBarnesHut():this.calculateRepulsionBruteForce(),this.calculateAttraction(),this.applyForces(),this.alpha+=(this.alphaTarget-this.alpha)*this.alphaDecay}calculateRepulsionBruteForce(){const e=Array.from(this.nodes.values()),s=e.length;for(let t=0;t<s;t++){const o=e[t];for(let i=t+1;i<s;i++){const a=e[i],r=a.position.x-o.position.x,c=a.position.y-o.position.y,d=a.position.z-o.position.z;let u=r*r+c*c+d*d;u<.01&&(u=.01);const f=Math.sqrt(u),x=this.repulsionStrength*this.alpha/u,m=r/f*x,b=c/f*x,M=d/f*x;o.velocity.x-=m/o.mass,o.velocity.y-=b/o.mass,o.velocity.z-=M/o.mass,a.velocity.x+=m/a.mass,a.velocity.y+=b/a.mass,a.velocity.z+=M/a.mass}}}calculateRepulsionBarnesHut(){const e=Array.from(this.nodes.values()),s=new Ye(e);for(const t of e)this.calculateForceFromOctree(t,s.root)}calculateForceFromOctree(e,s){if(s.isLeaf){s.node&&s.node.id!==e.id&&this.applyRepulsionBetween(e,s.node);return}if(s.mass===0)return;const t=s.centerOfMass.x-e.position.x,o=s.centerOfMass.y-e.position.y,i=s.centerOfMass.z-e.position.z,a=Math.sqrt(t*t+o*o+i*i);if(s.size/a<this.barnesHutTheta){const r=Math.max(a*a,.01),c=this.repulsionStrength*this.alpha*s.mass/r;e.velocity.x-=t/a*c/e.mass,e.velocity.y-=o/a*c/e.mass,e.velocity.z-=i/a*c/e.mass}else for(const r of s.children)r&&this.calculateForceFromOctree(e,r)}applyRepulsionBetween(e,s){const t=s.position.x-e.position.x,o=s.position.y-e.position.y,i=s.position.z-e.position.z;let a=t*t+o*o+i*i;a<.01&&(a=.01);const r=Math.sqrt(a),c=this.repulsionStrength*this.alpha/a;e.velocity.x-=t/r*c/e.mass,e.velocity.y-=o/r*c/e.mass,e.velocity.z-=i/r*c/e.mass}calculateAttraction(){for(const e of this.edges){const s=this.nodes.get(e.source),t=this.nodes.get(e.target);if(!s||!t)continue;const o=t.position.x-s.position.x,i=t.position.y-s.position.y,a=t.position.z-s.position.z,r=Math.sqrt(o*o+i*i+a*a);if(r<.01)continue;const d=(r-15)*this.attractionStrength*this.alpha,u=o/r*d,f=i/r*d,x=a/r*d;s.velocity.x+=u/s.mass,s.velocity.y+=f/s.mass,s.velocity.z+=x/s.mass,t.velocity.x-=u/t.mass,t.velocity.y-=f/t.mass,t.velocity.z-=x/t.mass}}applyForces(){for(const e of this.nodes.values())e.velocity.x*=this.damping,e.velocity.y*=this.damping,e.velocity.z*=this.damping,e.position.x+=e.velocity.x,e.position.y+=e.velocity.y,e.position.z+=e.velocity.z}setEdges(e){this.edges=e}restart(){this.alpha=1}getAlpha(){return this.alpha}setPhysicsParams(e){e.repulsionStrength!==void 0&&(this.repulsionStrength=e.repulsionStrength),e.attractionStrength!==void 0&&(this.attractionStrength=e.attractionStrength),e.damping!==void 0&&(this.damping=e.damping)}}class Ye{constructor(e){l(this,"root");const s=this.calculateBounds(e);this.root=this.buildTree(e,s)}calculateBounds(e){if(e.length===0)return{min:{x:-100,y:-100,z:-100},max:{x:100,y:100,z:100}};const s={x:1/0,y:1/0,z:1/0},t={x:-1/0,y:-1/0,z:-1/0};for(const i of e)s.x=Math.min(s.x,i.position.x),s.y=Math.min(s.y,i.position.y),s.z=Math.min(s.z,i.position.z),t.x=Math.max(t.x,i.position.x),t.y=Math.max(t.y,i.position.y),t.z=Math.max(t.z,i.position.z);const o=10;return s.x-=o,s.y-=o,s.z-=o,t.x+=o,t.y+=o,t.z+=o,{min:s,max:t}}buildTree(e,s,t=0){const o=Math.max(s.max.x-s.min.x,s.max.y-s.min.y,s.max.z-s.min.z);if(e.length===0)return{bounds:s,size:o,centerOfMass:{x:0,y:0,z:0},mass:0,isLeaf:!0,node:null,children:[]};if(e.length===1||t>20){let m=0;const b={x:0,y:0,z:0};for(const M of e)m+=M.mass,b.x+=M.position.x*M.mass,b.y+=M.position.y*M.mass,b.z+=M.position.z*M.mass;return m>0&&(b.x/=m,b.y/=m,b.z/=m),{bounds:s,size:o,centerOfMass:b,mass:m,isLeaf:!0,node:e[0],children:[]}}const i=(s.min.x+s.max.x)/2,a=(s.min.y+s.max.y)/2,r=(s.min.z+s.max.z)/2,c=[[],[],[],[],[],[],[],[]];for(const m of e){const b=(m.position.x>=i?1:0)+(m.position.y>=a?2:0)+(m.position.z>=r?4:0);c[b].push(m)}const d=[{min:{x:s.min.x,y:s.min.y,z:s.min.z},max:{x:i,y:a,z:r}},{min:{x:i,y:s.min.y,z:s.min.z},max:{x:s.max.x,y:a,z:r}},{min:{x:s.min.x,y:a,z:s.min.z},max:{x:i,y:s.max.y,z:r}},{min:{x:i,y:a,z:s.min.z},max:{x:s.max.x,y:s.max.y,z:r}},{min:{x:s.min.x,y:s.min.y,z:r},max:{x:i,y:a,z:s.max.z}},{min:{x:i,y:s.min.y,z:r},max:{x:s.max.x,y:a,z:s.max.z}},{min:{x:s.min.x,y:a,z:r},max:{x:i,y:s.max.y,z:s.max.z}},{min:{x:i,y:a,z:r},max:{x:s.max.x,y:s.max.y,z:s.max.z}}],u=[];let f=0;const x={x:0,y:0,z:0};for(let m=0;m<8;m++)if(c[m].length>0){const b=this.buildTree(c[m],d[m],t+1);u.push(b),f+=b.mass,x.x+=b.centerOfMass.x*b.mass,x.y+=b.centerOfMass.y*b.mass,x.z+=b.centerOfMass.z*b.mass}else u.push(null);return f>0&&(x.x/=f,x.y/=f,x.z/=f),{bounds:s,size:o,centerOfMass:x,mass:f,isLeaf:!1,node:null,children:u}}}class Be{constructor(e,s,t,o=60){l(this,"sceneManager");l(this,"animationId",null);l(this,"isRunning",!1);l(this,"frameInterval");l(this,"lastFrameTime",0);l(this,"onSimulate");l(this,"onRender");l(this,"frameCount",0);l(this,"fpsStartTime",0);l(this,"currentFPS",60);l(this,"animate",()=>{if(!this.isRunning)return;this.animationId=requestAnimationFrame(this.animate);const e=performance.now(),s=e-this.lastFrameTime;if(s<this.frameInterval)return;this.lastFrameTime=e-s%this.frameInterval,this.frameCount++;const t=e-this.fpsStartTime;t>=1e3&&(this.currentFPS=this.frameCount/(t/1e3),this.frameCount=0,this.fpsStartTime=e),this.onSimulate(),this.onRender(),this.sceneManager.render()});this.sceneManager=e,this.onSimulate=s,this.onRender=t,this.frameInterval=1e3/o}start(){this.isRunning||(this.isRunning=!0,this.lastFrameTime=performance.now(),this.fpsStartTime=performance.now(),this.frameCount=0,this.animate())}stop(){this.isRunning=!1,this.animationId!==null&&(cancelAnimationFrame(this.animationId),this.animationId=null)}getFPS(){return Math.round(this.currentFPS)}setTargetFPS(e){this.frameInterval=1e3/e}isAnimating(){return this.isRunning}dispose(){this.stop()}}class Ve{constructor(){l(this,"envMap",null);l(this,"materialCache",new Map);l(this,"COLORS",[16777215,16750950,16764057,16772829,16746564]);this.createEnvironmentMap()}createEnvironmentMap(){const s=[],t=[{colors:["#1a1a2e","#16213e","#0f3460"]},{colors:["#2d1f1f","#1a1a1a","#0f0f0f"]},{colors:["#1f2d2d","#1a1a2e","#101020"]},{colors:["#0a0a0a","#050505","#000000"]},{colors:["#1a1a2e","#0f1a2a","#0a0a15"]},{colors:["#2d1a1a","#1a0a0a","#0f0505"]}];for(const o of t){const i=document.createElement("canvas");i.width=256,i.height=256;const a=i.getContext("2d"),r=a.createRadialGradient(256/2,256/2,0,256/2,256/2,256*.8);r.addColorStop(0,o.colors[0]),r.addColorStop(.5,o.colors[1]),r.addColorStop(1,o.colors[2]),a.fillStyle=r,a.fillRect(0,0,256,256);const c=a.getImageData(0,0,256,256);for(let d=0;d<c.data.length;d+=4){const u=(Math.random()-.5)*5;c.data[d]=Math.min(255,Math.max(0,c.data[d]+u)),c.data[d+1]=Math.min(255,Math.max(0,c.data[d+1]+u)),c.data[d+2]=Math.min(255,Math.max(0,c.data[d+2]+u))}a.putImageData(c,0,0),s.push(i)}this.envMap=new y.CubeTexture(s.map(o=>{const i=new Image;return i.src=o.toDataURL(),i})),this.envMap.needsUpdate=!0}getRandomColor(){return this.COLORS[Math.floor(Math.random()*this.COLORS.length)]}createGlassMaterial(e){const t="glass-single";if(this.materialCache.has(t))return this.materialCache.get(t).clone();const o=new y.Color(16750950),i=new y.ShaderMaterial({uniforms:{uColor:{value:o},uEnvMap:{value:this.envMap},uGlowColor:{value:new y.Color(16777215)},uGlowIntensity:{value:.8},uReflectivity:{value:.4},uFresnelPower:{value:2.5}},vertexShader:`
9
9
  varying vec3 vNormal;
10
10
  varying vec3 vViewPosition;
11
11
  varying vec3 vWorldPosition;
@@ -63,7 +63,7 @@
63
63
 
64
64
  gl_FragColor = vec4(finalColor, opacity);
65
65
  }
66
- `,transparent:!0,side:u.FrontSide,depthWrite:!0,blending:u.NormalBlending});return this.materialCache.set(t,o),o.clone()}createEdgeMaterial(e=6710886,s=.4){return new u.LineBasicMaterial({color:e,transparent:!0,opacity:s,linewidth:1})}createHighlightedEdgeMaterial(){return new u.LineBasicMaterial({color:16750950,transparent:!1,opacity:1,linewidth:2})}createLabelMaterial(e,s=24){const t=document.createElement("canvas"),i=t.getContext("2d");i.font=`600 ${s}px Inter, -apple-system, sans-serif`;const a=i.measureText(e).width;t.width=Math.max(128,a+24),t.height=s+20,i.clearRect(0,0,t.width,t.height),i.font=`600 ${s}px Inter, -apple-system, sans-serif`,i.textAlign="center",i.textBaseline="middle",i.shadowColor="rgba(0, 0, 0, 0.8)",i.shadowBlur=4,i.shadowOffsetX=1,i.shadowOffsetY=1,i.fillStyle="rgba(255, 255, 255, 0.95)",i.fillText(e,t.width/2,t.height/2);const l=new u.CanvasTexture(t);return l.needsUpdate=!0,new u.SpriteMaterial({map:l,transparent:!0,depthTest:!1,depthWrite:!1})}getEnvMap(){return this.envMap}dispose(){this.materialCache.forEach(e=>e.dispose()),this.materialCache.clear(),this.envMap&&this.envMap.dispose()}}class Be{constructor(e,s=2,t=[32,16,8]){r(this,"materialFactory");r(this,"geometryCache",new Map);r(this,"nodeRadius");r(this,"lodSegments");this.materialFactory=e,this.nodeRadius=s,this.lodSegments=t,this.initGeometryCache()}initGeometryCache(){this.lodSegments.forEach((e,s)=>{const t=`lod-${s}`;this.geometryCache.set(t,new u.SphereGeometry(this.nodeRadius,e,e))})}getGeometry(e){const s=`lod-${e}`;return this.geometryCache.has(s)?this.geometryCache.get(s):this.geometryCache.get("lod-0")}createNode(e,s=0){const t=new u.Group;t.name=`node-${e.id}`,t.userData={nodeId:e.id,nodeData:e};const i=this.getGeometry(s),o=this.materialFactory.createGlassMaterial(e.color??4886754),a=new u.Mesh(i,o);a.castShadow=!0,a.receiveShadow=!0,t.add(a);const l=this.materialFactory.createLabelMaterial(e.label),p=new u.Sprite(l);return p.position.y=this.nodeRadius+1.5,p.scale.set(4,1,1),t.add(p),e.position&&t.position.set(e.position.x,e.position.y,e.position.z),{group:t,sphere:a,label:p,lodLevel:s}}updateNodeLOD(e,s){if(e.lodLevel===s)return;const t=this.getGeometry(s);e.sphere.geometry=t,e.lodLevel=s}updateNodeColor(e,s){e.sphere.material instanceof u.Material&&e.sphere.material.dispose(),e.sphere.material=this.materialFactory.createGlassMaterial(s)}updateNodeLabel(e,s){e.label.material instanceof u.SpriteMaterial&&(e.label.material.map&&e.label.material.map.dispose(),e.label.material.dispose()),e.label.material=this.materialFactory.createLabelMaterial(s)}disposeNode(e){e.sphere.material instanceof u.Material&&e.sphere.material.dispose(),e.label.material instanceof u.SpriteMaterial&&(e.label.material.map&&e.label.material.map.dispose(),e.label.material.dispose())}dispose(){this.geometryCache.forEach(e=>e.dispose()),this.geometryCache.clear()}}class Ue{constructor(e,s=10066329,t=.5){r(this,"materialFactory");r(this,"edgeColor");r(this,"edgeOpacity");r(this,"defaultMaterial",null);r(this,"highlightMaterial",null);this.materialFactory=e,this.edgeColor=s,this.edgeOpacity=t}getDefaultMaterial(){return this.defaultMaterial||(this.defaultMaterial=this.materialFactory.createEdgeMaterial(this.edgeColor,this.edgeOpacity)),this.defaultMaterial}getHighlightMaterial(){return this.highlightMaterial||(this.highlightMaterial=this.materialFactory.createHighlightedEdgeMaterial()),this.highlightMaterial}createEdge(e,s,t,i,o){const a=new u.BufferGeometry,l=new Float32Array([i.x,i.y,i.z,o.x,o.y,o.z]);a.setAttribute("position",new u.BufferAttribute(l,3));const p=this.getDefaultMaterial().clone(),g=new u.Line(a,p);return g.name=`edge-${e.source}-${e.target}`,g.userData={source:e.source,target:e.target,edge:e,sourceNode:s,targetNode:t},g.frustumCulled=!0,{line:g,source:e.source,target:e.target}}highlightEdge(e){e.line.material instanceof u.Material&&e.line.material.dispose(),e.line.material=this.getHighlightMaterial().clone()}unhighlightEdge(e){e.line.material instanceof u.Material&&e.line.material.dispose(),e.line.material=this.getDefaultMaterial().clone()}updateEdgePositions(e,s,t){const i=e.line.geometry.attributes.position,o=i.array;o[0]=s.x,o[1]=s.y,o[2]=s.z,o[3]=t.x,o[4]=t.y,o[5]=t.z,i.needsUpdate=!0,e.line.geometry.computeBoundingSphere()}disposeEdge(e){e.line.geometry.dispose(),e.line.material instanceof u.Material&&e.line.material.dispose()}dispose(){this.defaultMaterial&&this.defaultMaterial.dispose(),this.highlightMaterial&&this.highlightMaterial.dispose()}}class _e{constructor(e,s=[50,100,200],t=!0){r(this,"camera");r(this,"lodDistances");r(this,"enabled");this.camera=e,this.lodDistances=s,this.enabled=t}getLODLevel(e){if(!this.enabled)return D.HIGH;const s=e.x-this.camera.position.x,t=e.y-this.camera.position.y,i=e.z-this.camera.position.z,o=Math.sqrt(s*s+t*t+i*i);return o<this.lodDistances[0]?D.HIGH:o<this.lodDistances[1]?D.MEDIUM:D.LOW}shouldRenderNode(e,s=500){const t=e.x-this.camera.position.x,i=e.y-this.camera.position.y,o=e.z-this.camera.position.z;return Math.sqrt(t*t+i*i+o*o)<s}setLODDistances(e){this.lodDistances=e}setEnabled(e){this.enabled=e}}class Xe{constructor(e,s=!0){r(this,"camera");r(this,"frustum");r(this,"projScreenMatrix");r(this,"enabled");this.camera=e,this.frustum=new u.Frustum,this.projScreenMatrix=new u.Matrix4,this.enabled=s}update(){this.projScreenMatrix.multiplyMatrices(this.camera.projectionMatrix,this.camera.matrixWorldInverse),this.frustum.setFromProjectionMatrix(this.projScreenMatrix)}isPointVisible(e){if(!this.enabled)return!0;const s=new u.Vector3(e.x,e.y,e.z);return this.frustum.containsPoint(s)}isSphereVisible(e,s){if(!this.enabled)return!0;const t=new u.Sphere(new u.Vector3(e.x,e.y,e.z),s);return this.frustum.intersectsSphere(t)}isLineVisible(e,s){if(!this.enabled)return!0;const t=new u.Vector3(e.x,e.y,e.z),i=new u.Vector3(s.x,s.y,s.z);if(this.frustum.containsPoint(t)||this.frustum.containsPoint(i))return!0;const o=new u.Vector3((e.x+s.x)/2,(e.y+s.y)/2,(e.z+s.z)/2),a=o.distanceTo(t),l=new u.Sphere(o,a);return this.frustum.intersectsSphere(l)}setEnabled(e){this.enabled=e}}class qe{constructor(e,s){r(this,"sceneManager");r(this,"raycaster");r(this,"mouse");r(this,"container");r(this,"onNodeClick",null);r(this,"onNodeHover",null);r(this,"onEdgeHover",null);r(this,"hoveredNodeId",null);r(this,"hoveredEdgeKey",null);r(this,"nodeObjects",[]);r(this,"edgeObjects",[]);this.sceneManager=e,this.container=s,this.raycaster=new u.Raycaster,this.raycaster.params.Line={threshold:.5},this.mouse=new u.Vector2,this.handleClick=this.handleClick.bind(this),this.handleMouseMove=this.handleMouseMove.bind(this),s.addEventListener("click",this.handleClick),s.addEventListener("mousemove",this.handleMouseMove)}setNodeObjects(e){this.nodeObjects=e}setEdgeObjects(e){this.edgeObjects=e}setClickCallback(e){this.onNodeClick=e}setHoverCallback(e){this.onNodeHover=e}setEdgeHoverCallback(e){this.onEdgeHover=e}handleClick(e){const s=this.getIntersectedNode(e);s&&this.onNodeClick&&this.onNodeClick(s)}handleMouseMove(e){const s=this.getIntersectedNode(e),t=(s==null?void 0:s.id)??null;if(t!==this.hoveredNodeId&&(this.hoveredNodeId=t,this.onNodeHover&&this.onNodeHover(s)),s){this.hoveredEdgeKey!==null&&this.onEdgeHover&&(this.hoveredEdgeKey=null,this.onEdgeHover(null)),this.container.style.cursor="pointer";return}const i=this.getIntersectedEdge(e),o=i?`${i.edge.source}-${i.edge.target}`:null;o!==this.hoveredEdgeKey&&(this.hoveredEdgeKey=o,this.onEdgeHover&&this.onEdgeHover(i)),this.container.style.cursor=i?"pointer":"default"}getIntersectedNode(e){var i;const s=this.container.getBoundingClientRect();this.mouse.x=(e.clientX-s.left)/s.width*2-1,this.mouse.y=-((e.clientY-s.top)/s.height)*2+1,this.raycaster.setFromCamera(this.mouse,this.sceneManager.camera);const t=this.raycaster.intersectObjects(this.nodeObjects,!0);if(t.length>0){let o=t[0].object;for(;o;){if((i=o.userData)!=null&&i.nodeData)return o.userData.nodeData;o=o.parent}}return null}getIntersectedEdge(e){const s=this.container.getBoundingClientRect();this.mouse.x=(e.clientX-s.left)/s.width*2-1,this.mouse.y=-((e.clientY-s.top)/s.height)*2+1,this.raycaster.setFromCamera(this.mouse,this.sceneManager.camera);const t=this.raycaster.intersectObjects(this.edgeObjects,!1);if(t.length>0){const i=t[0].object,o=i.userData;if(o!=null&&o.edge&&(o!=null&&o.sourceNode)&&(o!=null&&o.targetNode))return{edge:o.edge,sourceNode:o.sourceNode,targetNode:o.targetNode,edgeLine:i}}return null}getIntersectedNodeId(e,s){var o;const t=this.container.getBoundingClientRect();this.mouse.x=(e-t.left)/t.width*2-1,this.mouse.y=-((s-t.top)/t.height)*2+1,this.raycaster.setFromCamera(this.mouse,this.sceneManager.camera);const i=this.raycaster.intersectObjects(this.nodeObjects,!0);if(i.length>0){let a=i[0].object;for(;a;){if((o=a.userData)!=null&&o.nodeId)return a.userData.nodeId;a=a.parent}}return null}dispose(){this.container.removeEventListener("click",this.handleClick),this.container.removeEventListener("mousemove",this.handleMouseMove)}}class We{constructor(e){r(this,"container");r(this,"panel",null);r(this,"currentNodeId",null);r(this,"visible",!1);r(this,"panelTemplate",null);r(this,"panelStyles",{});r(this,"onExpand",null);this.container=e,this.createPanel()}createPanel(){this.panel=document.createElement("div"),this.panel.className="force-graph-panel",this.panel.style.cssText=`
66
+ `,transparent:!0,side:y.FrontSide,depthWrite:!0,blending:y.NormalBlending});return this.materialCache.set(t,i),i.clone()}createEdgeMaterial(e=6710886,s=.4){return new y.LineBasicMaterial({color:e,transparent:!0,opacity:s,linewidth:1})}createHighlightedEdgeMaterial(){return new y.LineBasicMaterial({color:16750950,transparent:!1,opacity:1,linewidth:2})}createLabelMaterial(e,s=24){const t=document.createElement("canvas"),o=t.getContext("2d");o.font=`600 ${s}px Inter, -apple-system, sans-serif`;const a=o.measureText(e).width;t.width=Math.max(128,a+24),t.height=s+20,o.clearRect(0,0,t.width,t.height),o.font=`600 ${s}px Inter, -apple-system, sans-serif`,o.textAlign="center",o.textBaseline="middle",o.shadowColor="rgba(0, 0, 0, 0.8)",o.shadowBlur=4,o.shadowOffsetX=1,o.shadowOffsetY=1,o.fillStyle="rgba(255, 255, 255, 0.95)",o.fillText(e,t.width/2,t.height/2);const r=new y.CanvasTexture(t);return r.needsUpdate=!0,new y.SpriteMaterial({map:r,transparent:!0,depthTest:!1,depthWrite:!1})}getEnvMap(){return this.envMap}dispose(){this.materialCache.forEach(e=>e.dispose()),this.materialCache.clear(),this.envMap&&this.envMap.dispose()}}class Ke{constructor(e,s=2,t=[32,16,8]){l(this,"materialFactory");l(this,"geometryCache",new Map);l(this,"nodeRadius");l(this,"lodSegments");this.materialFactory=e,this.nodeRadius=s,this.lodSegments=t,this.initGeometryCache()}initGeometryCache(){this.lodSegments.forEach((e,s)=>{const t=`lod-${s}`;this.geometryCache.set(t,new y.SphereGeometry(this.nodeRadius,e,e))})}getGeometry(e){const s=`lod-${e}`;return this.geometryCache.has(s)?this.geometryCache.get(s):this.geometryCache.get("lod-0")}createNode(e,s=0){const t=new y.Group;t.name=`node-${e.id}`,t.userData={nodeId:e.id,nodeData:e};const o=this.getGeometry(s),i=this.materialFactory.createGlassMaterial(e.color??4886754),a=new y.Mesh(o,i);a.castShadow=!0,a.receiveShadow=!0,t.add(a);const r=this.materialFactory.createLabelMaterial(e.label),c=new y.Sprite(r);return c.position.y=this.nodeRadius+1.5,c.scale.set(4,1,1),t.add(c),e.position&&t.position.set(e.position.x,e.position.y,e.position.z),{group:t,sphere:a,label:c,lodLevel:s}}updateNodeLOD(e,s){if(e.lodLevel===s)return;const t=this.getGeometry(s);e.sphere.geometry=t,e.lodLevel=s}updateNodeColor(e,s){e.sphere.material instanceof y.Material&&e.sphere.material.dispose(),e.sphere.material=this.materialFactory.createGlassMaterial(s)}updateNodeLabel(e,s){e.label.material instanceof y.SpriteMaterial&&(e.label.material.map&&e.label.material.map.dispose(),e.label.material.dispose()),e.label.material=this.materialFactory.createLabelMaterial(s)}disposeNode(e){e.sphere.material instanceof y.Material&&e.sphere.material.dispose(),e.label.material instanceof y.SpriteMaterial&&(e.label.material.map&&e.label.material.map.dispose(),e.label.material.dispose())}dispose(){this.geometryCache.forEach(e=>e.dispose()),this.geometryCache.clear()}}class Ue{constructor(e,s=10066329,t=.5){l(this,"materialFactory");l(this,"edgeColor");l(this,"edgeOpacity");l(this,"defaultMaterial",null);l(this,"highlightMaterial",null);this.materialFactory=e,this.edgeColor=s,this.edgeOpacity=t}getDefaultMaterial(){return this.defaultMaterial||(this.defaultMaterial=this.materialFactory.createEdgeMaterial(this.edgeColor,this.edgeOpacity)),this.defaultMaterial}getHighlightMaterial(){return this.highlightMaterial||(this.highlightMaterial=this.materialFactory.createHighlightedEdgeMaterial()),this.highlightMaterial}createEdge(e,s,t,o,i){const a=new y.BufferGeometry,r=new Float32Array([o.x,o.y,o.z,i.x,i.y,i.z]);a.setAttribute("position",new y.BufferAttribute(r,3));const c=this.getDefaultMaterial().clone(),d=new y.Line(a,c);return d.name=`edge-${e.source}-${e.target}`,d.userData={source:e.source,target:e.target,edge:e,sourceNode:s,targetNode:t},d.frustumCulled=!0,{line:d,source:e.source,target:e.target}}highlightEdge(e){e.line.material instanceof y.Material&&e.line.material.dispose(),e.line.material=this.getHighlightMaterial().clone()}unhighlightEdge(e){e.line.material instanceof y.Material&&e.line.material.dispose(),e.line.material=this.getDefaultMaterial().clone()}updateEdgePositions(e,s,t){const o=e.line.geometry.attributes.position,i=o.array;i[0]=s.x,i[1]=s.y,i[2]=s.z,i[3]=t.x,i[4]=t.y,i[5]=t.z,o.needsUpdate=!0,e.line.geometry.computeBoundingSphere()}disposeEdge(e){e.line.geometry.dispose(),e.line.material instanceof y.Material&&e.line.material.dispose()}dispose(){this.defaultMaterial&&this.defaultMaterial.dispose(),this.highlightMaterial&&this.highlightMaterial.dispose()}}class Xe{constructor(e,s=[50,100,200],t=!0){l(this,"camera");l(this,"lodDistances");l(this,"enabled");this.camera=e,this.lodDistances=s,this.enabled=t}getLODLevel(e){if(!this.enabled)return H.HIGH;const s=e.x-this.camera.position.x,t=e.y-this.camera.position.y,o=e.z-this.camera.position.z,i=Math.sqrt(s*s+t*t+o*o);return i<this.lodDistances[0]?H.HIGH:i<this.lodDistances[1]?H.MEDIUM:H.LOW}shouldRenderNode(e,s=500){const t=e.x-this.camera.position.x,o=e.y-this.camera.position.y,i=e.z-this.camera.position.z;return Math.sqrt(t*t+o*o+i*i)<s}setLODDistances(e){this.lodDistances=e}setEnabled(e){this.enabled=e}}class _e{constructor(e,s=!0){l(this,"camera");l(this,"frustum");l(this,"projScreenMatrix");l(this,"enabled");this.camera=e,this.frustum=new y.Frustum,this.projScreenMatrix=new y.Matrix4,this.enabled=s}update(){this.projScreenMatrix.multiplyMatrices(this.camera.projectionMatrix,this.camera.matrixWorldInverse),this.frustum.setFromProjectionMatrix(this.projScreenMatrix)}isPointVisible(e){if(!this.enabled)return!0;const s=new y.Vector3(e.x,e.y,e.z);return this.frustum.containsPoint(s)}isSphereVisible(e,s){if(!this.enabled)return!0;const t=new y.Sphere(new y.Vector3(e.x,e.y,e.z),s);return this.frustum.intersectsSphere(t)}isLineVisible(e,s){if(!this.enabled)return!0;const t=new y.Vector3(e.x,e.y,e.z),o=new y.Vector3(s.x,s.y,s.z);if(this.frustum.containsPoint(t)||this.frustum.containsPoint(o))return!0;const i=new y.Vector3((e.x+s.x)/2,(e.y+s.y)/2,(e.z+s.z)/2),a=i.distanceTo(t),r=new y.Sphere(i,a);return this.frustum.intersectsSphere(r)}setEnabled(e){this.enabled=e}}class qe{constructor(e,s){l(this,"sceneManager");l(this,"raycaster");l(this,"mouse");l(this,"container");l(this,"onNodeClick",null);l(this,"onNodeHover",null);l(this,"onEdgeHover",null);l(this,"onEdgeClick",null);l(this,"hoveredNodeId",null);l(this,"hoveredEdgeKey",null);l(this,"nodeObjects",[]);l(this,"edgeObjects",[]);this.sceneManager=e,this.container=s,this.raycaster=new y.Raycaster,this.raycaster.params.Line={threshold:.5},this.mouse=new y.Vector2,this.handleClick=this.handleClick.bind(this),this.handleMouseMove=this.handleMouseMove.bind(this),s.addEventListener("click",this.handleClick),s.addEventListener("mousemove",this.handleMouseMove)}setNodeObjects(e){this.nodeObjects=e}setEdgeObjects(e){this.edgeObjects=e}setClickCallback(e){this.onNodeClick=e}setHoverCallback(e){this.onNodeHover=e}setEdgeHoverCallback(e){this.onEdgeHover=e}setEdgeClickCallback(e){this.onEdgeClick=e}handleClick(e){const s=this.getIntersectedNode(e);if(s&&this.onNodeClick){this.onNodeClick(s);return}const t=this.getIntersectedEdge(e);t&&this.onEdgeClick&&this.onEdgeClick(t)}handleMouseMove(e){const s=this.getIntersectedNode(e),t=(s==null?void 0:s.id)??null;if(t!==this.hoveredNodeId&&(this.hoveredNodeId=t,this.onNodeHover&&this.onNodeHover(s)),s){this.hoveredEdgeKey!==null&&this.onEdgeHover&&(this.hoveredEdgeKey=null,this.onEdgeHover(null)),this.container.style.cursor="pointer";return}const o=this.getIntersectedEdge(e),i=o?`${o.edge.source}-${o.edge.target}`:null;i!==this.hoveredEdgeKey&&(this.hoveredEdgeKey=i,this.onEdgeHover&&this.onEdgeHover(o)),this.container.style.cursor=o?"pointer":"default"}getIntersectedNode(e){var o;const s=this.container.getBoundingClientRect();this.mouse.x=(e.clientX-s.left)/s.width*2-1,this.mouse.y=-((e.clientY-s.top)/s.height)*2+1,this.raycaster.setFromCamera(this.mouse,this.sceneManager.camera);const t=this.raycaster.intersectObjects(this.nodeObjects,!0);if(t.length>0){let i=t[0].object;for(;i;){if((o=i.userData)!=null&&o.nodeData)return i.userData.nodeData;i=i.parent}}return null}getIntersectedEdge(e){const s=this.container.getBoundingClientRect();this.mouse.x=(e.clientX-s.left)/s.width*2-1,this.mouse.y=-((e.clientY-s.top)/s.height)*2+1,this.raycaster.setFromCamera(this.mouse,this.sceneManager.camera);const t=this.raycaster.intersectObjects(this.edgeObjects,!1);if(t.length>0){const o=t[0].object,i=o.userData;if(i!=null&&i.edge&&(i!=null&&i.sourceNode)&&(i!=null&&i.targetNode))return{edge:i.edge,sourceNode:i.sourceNode,targetNode:i.targetNode,edgeLine:o}}return null}getIntersectedNodeId(e,s){var i;const t=this.container.getBoundingClientRect();this.mouse.x=(e-t.left)/t.width*2-1,this.mouse.y=-((s-t.top)/t.height)*2+1,this.raycaster.setFromCamera(this.mouse,this.sceneManager.camera);const o=this.raycaster.intersectObjects(this.nodeObjects,!0);if(o.length>0){let a=o[0].object;for(;a;){if((i=a.userData)!=null&&i.nodeId)return a.userData.nodeId;a=a.parent}}return null}dispose(){this.container.removeEventListener("click",this.handleClick),this.container.removeEventListener("mousemove",this.handleMouseMove)}}class We{constructor(e){l(this,"container");l(this,"panel",null);l(this,"currentNodeId",null);l(this,"visible",!1);l(this,"panelTemplate",null);l(this,"panelStyles",{});l(this,"onExpand",null);this.container=e,this.createPanel()}createPanel(){this.panel=document.createElement("div"),this.panel.className="force-graph-panel",this.panel.style.cssText=`
67
67
  position: absolute;
68
68
  right: 20px;
69
69
  top: 50%;
@@ -86,7 +86,7 @@
86
86
  opacity: 0;
87
87
  pointer-events: none;
88
88
  transition: opacity 0.3s ease, transform 0.3s ease;
89
- `,Object.entries(this.panelStyles).forEach(([e,s])=>{this.panel.style.setProperty(e,s)}),this.container.appendChild(this.panel)}setPanelTemplate(e){this.panelTemplate=e}setPanelStyles(e){this.panelStyles=e,this.panel&&Object.entries(e).forEach(([s,t])=>{this.panel.style.setProperty(s,t)})}setExpandCallback(e){this.onExpand=e}show(e,s){if(!this.panel)return;this.currentNodeId=e.id;let t;this.panelTemplate?t=this.panelTemplate(e,s):t=this.generateDefaultContent(e,s),this.panel.innerHTML=t;const i=this.panel.querySelector('[data-action="expand"]'),o=this.panel.querySelector("[data-depth-select]");i&&this.onExpand&&i.addEventListener("click",()=>{if(this.currentNodeId){const l=o?parseInt(o.value,10):1;this.onExpand(this.currentNodeId,l)}});const a=this.panel.querySelector('[data-action="close"]');a&&a.addEventListener("click",()=>{this.hide()}),this.panel.style.opacity="1",this.panel.style.pointerEvents="auto",this.panel.style.transform="translateY(-50%) translateX(0)",this.visible=!0}generateDefaultContent(e,s){const t=e.color?`#${e.color.toString(16).padStart(6,"0")}`:"#4A90E2";return`
89
+ `,Object.entries(this.panelStyles).forEach(([e,s])=>{this.panel.style.setProperty(e,s)}),this.container.appendChild(this.panel)}setPanelTemplate(e){this.panelTemplate=e}setPanelStyles(e){this.panelStyles=e,this.panel&&Object.entries(e).forEach(([s,t])=>{this.panel.style.setProperty(s,t)})}setExpandCallback(e){this.onExpand=e}show(e,s){if(!this.panel)return;this.currentNodeId=e.id;let t;this.panelTemplate?t=this.panelTemplate(e,s):t=this.generateDefaultContent(e,s),this.panel.innerHTML=t;const o=this.panel.querySelector('[data-action="expand"]'),i=this.panel.querySelector("[data-depth-select]");o&&this.onExpand&&o.addEventListener("click",()=>{if(this.currentNodeId){const r=i?parseInt(i.value,10):1;this.onExpand(this.currentNodeId,r)}});const a=this.panel.querySelector('[data-action="close"]');a&&a.addEventListener("click",()=>{this.hide()}),this.panel.style.opacity="1",this.panel.style.pointerEvents="auto",this.panel.style.transform="translateY(-50%) translateX(0)",this.visible=!0}generateDefaultContent(e,s){const t=e.color?`#${e.color.toString(16).padStart(6,"0")}`:"#4A90E2";return`
90
90
  <style>
91
91
  .force-graph-panel h2 {
92
92
  margin: 0 0 16px 0;
@@ -230,7 +230,7 @@
230
230
  ${s.length>0?`
231
231
  <div class="neighbors-section">
232
232
  <div class="neighbors-title">Connected To</div>
233
- ${s.slice(0,5).map(i=>`<span class="neighbor-chip">${this.escapeHtml(i.label)}</span>`).join("")}
233
+ ${s.slice(0,5).map(o=>`<span class="neighbor-chip">${this.escapeHtml(o.label)}</span>`).join("")}
234
234
  ${s.length>5?`<span class="neighbor-chip">+${s.length-5} more</span>`:""}
235
235
  </div>
236
236
  `:""}
@@ -249,7 +249,157 @@
249
249
  <button class="btn-expand" data-action="expand">Expand</button>
250
250
  <button class="btn-close" data-action="close">Close</button>
251
251
  </div>
252
- `}escapeHtml(e){const s=document.createElement("div");return s.textContent=e,s.innerHTML}hide(){this.panel&&(this.panel.style.opacity="0",this.panel.style.pointerEvents="none",this.panel.style.transform="translateY(-50%) translateX(20px)",this.visible=!1,this.currentNodeId=null)}isVisible(){return this.visible}getCurrentNodeId(){return this.currentNodeId}dispose(){this.panel&&this.panel.parentNode&&this.panel.parentNode.removeChild(this.panel),this.panel=null}}class Ze{constructor(){r(this,"tooltip",null);r(this,"visible",!1);this.createTooltip(),this.setupMouseTracking()}createTooltip(){this.tooltip=document.createElement("div"),this.tooltip.className="force-graph-edge-tooltip",this.tooltip.style.cssText=`
252
+ `}escapeHtml(e){const s=document.createElement("div");return s.textContent=e,s.innerHTML}hide(){this.panel&&(this.panel.style.opacity="0",this.panel.style.pointerEvents="none",this.panel.style.transform="translateY(-50%) translateX(20px)",this.visible=!1,this.currentNodeId=null)}isVisible(){return this.visible}getCurrentNodeId(){return this.currentNodeId}dispose(){this.panel&&this.panel.parentNode&&this.panel.parentNode.removeChild(this.panel),this.panel=null}}class Ze{constructor(e){l(this,"container");l(this,"panel",null);l(this,"currentEdgeKey",null);l(this,"visible",!1);l(this,"panelTemplate",null);l(this,"onClose",null);l(this,"onNodeClick",null);this.container=e,this.createPanel()}createPanel(){this.panel=document.createElement("div"),this.panel.className="force-graph-edge-panel",this.panel.style.cssText=`
253
+ position: absolute;
254
+ right: 20px;
255
+ top: 50%;
256
+ transform: translateY(-50%);
257
+ width: 300px;
258
+ max-height: 80vh;
259
+ overflow-y: auto;
260
+ background: rgba(15, 15, 25, 0.85);
261
+ backdrop-filter: blur(20px);
262
+ -webkit-backdrop-filter: blur(20px);
263
+ border: 1px solid rgba(255, 255, 255, 0.1);
264
+ border-radius: 16px;
265
+ padding: 24px;
266
+ color: white;
267
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
268
+ box-shadow:
269
+ 0 8px 32px rgba(0, 0, 0, 0.4),
270
+ inset 0 0 0 1px rgba(255, 255, 255, 0.05);
271
+ z-index: 1000;
272
+ opacity: 0;
273
+ pointer-events: none;
274
+ transition: opacity 0.3s ease, transform 0.3s ease;
275
+ `,this.container.appendChild(this.panel)}setPanelTemplate(e){this.panelTemplate=e}setCloseCallback(e){this.onClose=e}setNodeClickCallback(e){this.onNodeClick=e}show(e,s,t){if(!this.panel)return;this.currentEdgeKey=`${e.source}-${e.target}`;let o;this.panelTemplate?o=this.panelTemplate(e,s,t):o=this.generateDefaultContent(e,s,t),this.panel.innerHTML=o;const i=this.panel.querySelector('[data-action="close"]');i&&i.addEventListener("click",()=>{this.hide(),this.onClose&&this.onClose()});const a=this.panel.querySelector('[data-action="goto-source"]');a&&this.onNodeClick&&a.addEventListener("click",()=>{this.onNodeClick&&this.onNodeClick(e.source)});const r=this.panel.querySelector('[data-action="goto-target"]');r&&this.onNodeClick&&r.addEventListener("click",()=>{this.onNodeClick&&this.onNodeClick(e.target)}),this.panel.style.opacity="1",this.panel.style.pointerEvents="auto",this.panel.style.transform="translateY(-50%) translateX(0)",this.visible=!0}generateDefaultContent(e,s,t){const o=s.color?`#${s.color.toString(16).padStart(6,"0")}`:"#ff9966",i=t.color?`#${t.color.toString(16).padStart(6,"0")}`:"#ff9966",a=e.relationship||"connected to";return`
276
+ <style>
277
+ .force-graph-edge-panel .panel-header {
278
+ display: flex;
279
+ align-items: center;
280
+ justify-content: space-between;
281
+ margin-bottom: 20px;
282
+ }
283
+ .force-graph-edge-panel .panel-title {
284
+ font-size: 14px;
285
+ text-transform: uppercase;
286
+ letter-spacing: 1px;
287
+ color: rgba(255, 255, 255, 0.6);
288
+ margin: 0;
289
+ }
290
+ .force-graph-edge-panel .relationship-section {
291
+ background: rgba(255, 255, 255, 0.05);
292
+ border-radius: 12px;
293
+ padding: 16px;
294
+ text-align: center;
295
+ margin-bottom: 20px;
296
+ }
297
+ .force-graph-edge-panel .relationship-label {
298
+ font-size: 18px;
299
+ font-weight: 600;
300
+ color: #a78bfa;
301
+ letter-spacing: 0.5px;
302
+ }
303
+ .force-graph-edge-panel .node-card {
304
+ background: rgba(255, 255, 255, 0.05);
305
+ border: 1px solid rgba(255, 255, 255, 0.1);
306
+ border-radius: 12px;
307
+ padding: 14px;
308
+ margin-bottom: 12px;
309
+ cursor: pointer;
310
+ transition: all 0.2s ease;
311
+ }
312
+ .force-graph-edge-panel .node-card:hover {
313
+ background: rgba(255, 255, 255, 0.1);
314
+ border-color: rgba(255, 255, 255, 0.2);
315
+ transform: translateX(4px);
316
+ }
317
+ .force-graph-edge-panel .node-card-header {
318
+ display: flex;
319
+ align-items: center;
320
+ gap: 10px;
321
+ margin-bottom: 6px;
322
+ }
323
+ .force-graph-edge-panel .node-type {
324
+ font-size: 10px;
325
+ text-transform: uppercase;
326
+ letter-spacing: 1px;
327
+ color: rgba(255, 255, 255, 0.5);
328
+ }
329
+ .force-graph-edge-panel .color-dot {
330
+ width: 10px;
331
+ height: 10px;
332
+ border-radius: 50%;
333
+ flex-shrink: 0;
334
+ }
335
+ .force-graph-edge-panel .node-label {
336
+ font-size: 15px;
337
+ font-weight: 500;
338
+ color: rgba(255, 255, 255, 0.95);
339
+ white-space: nowrap;
340
+ overflow: hidden;
341
+ text-overflow: ellipsis;
342
+ }
343
+ .force-graph-edge-panel .connection-arrow {
344
+ text-align: center;
345
+ color: rgba(255, 255, 255, 0.4);
346
+ font-size: 18px;
347
+ margin: 8px 0;
348
+ }
349
+ .force-graph-edge-panel .btn-close {
350
+ width: 100%;
351
+ padding: 12px 16px;
352
+ border: none;
353
+ border-radius: 8px;
354
+ font-size: 13px;
355
+ font-weight: 500;
356
+ cursor: pointer;
357
+ transition: all 0.2s ease;
358
+ background: rgba(255, 255, 255, 0.1);
359
+ color: rgba(255, 255, 255, 0.8);
360
+ margin-top: 16px;
361
+ }
362
+ .force-graph-edge-panel .btn-close:hover {
363
+ background: rgba(255, 255, 255, 0.15);
364
+ }
365
+ .force-graph-edge-panel .hint-text {
366
+ font-size: 11px;
367
+ color: rgba(255, 255, 255, 0.4);
368
+ text-align: center;
369
+ margin-top: 8px;
370
+ }
371
+ </style>
372
+
373
+ <div class="panel-header">
374
+ <h3 class="panel-title">Relationship</h3>
375
+ </div>
376
+
377
+ <div class="relationship-section">
378
+ <span class="relationship-label">${this.escapeHtml(a)}</span>
379
+ </div>
380
+
381
+ <div class="node-card" data-action="goto-source" title="Click to focus on ${this.escapeHtml(s.label)}">
382
+ <div class="node-type">Source</div>
383
+ <div class="node-card-header">
384
+ <span class="color-dot" style="background: ${o}; box-shadow: 0 0 8px ${o}80;"></span>
385
+ <span class="node-label">${this.escapeHtml(s.label)}</span>
386
+ </div>
387
+ </div>
388
+
389
+ <div class="connection-arrow">↓</div>
390
+
391
+ <div class="node-card" data-action="goto-target" title="Click to focus on ${this.escapeHtml(t.label)}">
392
+ <div class="node-type">Target</div>
393
+ <div class="node-card-header">
394
+ <span class="color-dot" style="background: ${i}; box-shadow: 0 0 8px ${i}80;"></span>
395
+ <span class="node-label">${this.escapeHtml(t.label)}</span>
396
+ </div>
397
+ </div>
398
+
399
+ <p class="hint-text">Click on a node to focus on it</p>
400
+
401
+ <button class="btn-close" data-action="close">Close</button>
402
+ `}escapeHtml(e){const s=document.createElement("div");return s.textContent=e,s.innerHTML}hide(){this.panel&&(this.panel.style.opacity="0",this.panel.style.pointerEvents="none",this.panel.style.transform="translateY(-50%) translateX(20px)",this.visible=!1,this.currentEdgeKey=null)}isVisible(){return this.visible}getCurrentEdgeKey(){return this.currentEdgeKey}dispose(){this.panel&&this.panel.parentNode&&this.panel.parentNode.removeChild(this.panel),this.panel=null}}class Qe{constructor(){l(this,"tooltip",null);l(this,"visible",!1);this.createTooltip(),this.setupMouseTracking()}createTooltip(){this.tooltip=document.createElement("div"),this.tooltip.className="force-graph-edge-tooltip",this.tooltip.style.cssText=`
253
403
  position: fixed;
254
404
  padding: 10px 14px;
255
405
  background: rgba(30, 30, 30, 0.95);
@@ -270,7 +420,7 @@
270
420
  white-space: normal;
271
421
  word-wrap: break-word;
272
422
  overflow-wrap: break-word;
273
- `,document.body.appendChild(this.tooltip)}setupMouseTracking(){document.addEventListener("mousemove",e=>{this.visible&&this.tooltip&&this.positionTooltip(e.clientX,e.clientY)})}positionTooltip(e,s){if(!this.tooltip)return;const t=this.tooltip.getBoundingClientRect(),i=window.innerWidth,o=window.innerHeight;let a=e+15,l=s+15;a+t.width>i-10&&(a=e-t.width-15),l+t.height>o-10&&(l=s-t.height-15),a<10&&(a=10),l<10&&(l=10),this.tooltip.style.left=`${a}px`,this.tooltip.style.top=`${l}px`}show(e,s,t,i,o){if(!this.tooltip)return;const a=e.relationship||"connected to";this.tooltip.innerHTML=`
423
+ `,document.body.appendChild(this.tooltip)}setupMouseTracking(){document.addEventListener("mousemove",e=>{this.visible&&this.tooltip&&this.positionTooltip(e.clientX,e.clientY)})}positionTooltip(e,s){if(!this.tooltip)return;const t=this.tooltip.getBoundingClientRect(),o=window.innerWidth,i=window.innerHeight;let a=e+15,r=s+15;a+t.width>o-10&&(a=e-t.width-15),r+t.height>i-10&&(r=s-t.height-15),a<10&&(a=10),r<10&&(r=10),this.tooltip.style.left=`${a}px`,this.tooltip.style.top=`${r}px`}show(e,s,t,o,i){if(!this.tooltip)return;const a=e.relationship||"connected to";this.tooltip.innerHTML=`
274
424
  <div style="display: flex; flex-direction: column; gap: 4px;">
275
425
  <div style="display: flex; align-items: center; gap: 6px; flex-wrap: wrap;">
276
426
  <span style="font-weight: 600; color: #ff9966;">${this.escapeHtml(s.label)}</span>
@@ -282,7 +432,7 @@
282
432
  <span style="font-weight: 600; color: #ff9966;">${this.escapeHtml(t.label)}</span>
283
433
  </div>
284
434
  </div>
285
- `,this.positionTooltip(i,o),this.tooltip.style.opacity="1",this.tooltip.style.transform="translateY(0)",this.visible=!0}updatePosition(e,s){this.visible&&this.positionTooltip(e,s)}hide(){this.tooltip&&(this.tooltip.style.opacity="0",this.tooltip.style.transform="translateY(5px)",this.visible=!1)}isVisible(){return this.visible}escapeHtml(e){const s=document.createElement("div");return s.textContent=e,s.innerHTML}dispose(){this.tooltip&&this.tooltip.parentNode&&this.tooltip.parentNode.removeChild(this.tooltip),this.tooltip=null}}class Qe{constructor(e,s){r(this,"container");r(this,"searchContainer",null);r(this,"searchInput",null);r(this,"searchResults",null);r(this,"searchTimeout",null);r(this,"placeholder");r(this,"onSearch");r(this,"onResultClick");this.container=e,this.placeholder=s.placeholder||"Search nodes or relationships...",this.onSearch=s.onSearch,this.onResultClick=s.onResultClick,this.init()}init(){this.createSearchUI(),this.addEventListeners()}createSearchUI(){this.searchContainer=document.createElement("div"),this.searchContainer.className="f3d-search-container",Object.assign(this.searchContainer.style,{position:"absolute",top:"20px",left:"20px",zIndex:"100",width:"320px"});const e=document.createElement("div");e.className="f3d-search-input-wrapper",Object.assign(e.style,{position:"relative",display:"flex",alignItems:"center"}),e.innerHTML=`
435
+ `,this.positionTooltip(o,i),this.tooltip.style.opacity="1",this.tooltip.style.transform="translateY(0)",this.visible=!0}updatePosition(e,s){this.visible&&this.positionTooltip(e,s)}hide(){this.tooltip&&(this.tooltip.style.opacity="0",this.tooltip.style.transform="translateY(5px)",this.visible=!1)}isVisible(){return this.visible}escapeHtml(e){const s=document.createElement("div");return s.textContent=e,s.innerHTML}dispose(){this.tooltip&&this.tooltip.parentNode&&this.tooltip.parentNode.removeChild(this.tooltip),this.tooltip=null}}class Je{constructor(e,s){l(this,"container");l(this,"searchContainer",null);l(this,"searchInput",null);l(this,"searchResults",null);l(this,"searchTimeout",null);l(this,"placeholder");l(this,"onSearch");l(this,"onResultClick");this.container=e,this.placeholder=s.placeholder||"Search nodes or relationships...",this.onSearch=s.onSearch,this.onResultClick=s.onResultClick,this.init()}init(){this.createSearchUI(),this.addEventListeners()}createSearchUI(){this.searchContainer=document.createElement("div"),this.searchContainer.className="f3d-search-container",Object.assign(this.searchContainer.style,{position:"absolute",top:"20px",left:"175px",zIndex:"100",width:"320px"});const e=document.createElement("div");e.className="f3d-search-input-wrapper",Object.assign(e.style,{position:"relative",display:"flex",alignItems:"center"}),e.innerHTML=`
286
436
  <svg class="f3d-search-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor"
287
437
  stroke-width="2" style="position: absolute; left: 14px; z-index: 10; color: rgba(255, 255, 255, 0.5); pointer-events: none;">
288
438
  <circle cx="11" cy="11" r="8"></circle>
@@ -337,17 +487,52 @@
337
487
  .f3d-search-results::-webkit-scrollbar-track { background: transparent; }
338
488
  .f3d-search-results::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.15); border-radius: 3px; }
339
489
  .f3d-search-results::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.25); }
340
- `,document.head.appendChild(s)}addEventListeners(){!this.searchInput||!this.searchResults||(this.searchInput.addEventListener("input",e=>{const s=e.target.value;this.searchTimeout&&window.clearTimeout(this.searchTimeout),this.searchTimeout=window.setTimeout(()=>{this.performSearch(s)},150)}),this.searchInput.addEventListener("focus",()=>{this.searchInput&&this.searchInput.value.length>0&&(this.searchResults.style.display="block")}),document.addEventListener("click",e=>{this.searchContainer&&!this.searchContainer.contains(e.target)&&this.searchResults&&(this.searchResults.style.display="none")}))}performSearch(e){if(!this.searchResults)return;if(e.trim().length===0){this.searchResults.style.display="none";return}const{nodeResults:s,edgeResults:t}=this.onSearch(e);if(s.length===0&&t.length===0){this.searchResults.innerHTML='<div class="f3d-no-results">No results found</div>',this.searchResults.style.display="block";return}let i="";s.length>0&&(i+='<div class="f3d-search-section-header">Nodes</div>',s.slice(0,10).forEach(o=>{const a=o.type||"Node";i+=`
341
- <div class="f3d-search-result-item" data-node-id="${this.escapeHtml(o.id)}">
342
- <div class="f3d-result-label">${this.escapeHtml(o.label)}</div>
490
+ `,document.head.appendChild(s)}addEventListeners(){!this.searchInput||!this.searchResults||(this.searchInput.addEventListener("input",e=>{const s=e.target.value;this.searchTimeout&&window.clearTimeout(this.searchTimeout),this.searchTimeout=window.setTimeout(()=>{this.performSearch(s)},150)}),this.searchInput.addEventListener("focus",()=>{this.searchInput&&this.searchInput.value.length>0&&(this.searchResults.style.display="block")}),document.addEventListener("click",e=>{this.searchContainer&&!this.searchContainer.contains(e.target)&&this.searchResults&&(this.searchResults.style.display="none")}))}performSearch(e){if(!this.searchResults)return;if(e.trim().length===0){this.searchResults.style.display="none";return}const{nodeResults:s,edgeResults:t}=this.onSearch(e);if(s.length===0&&t.length===0){this.searchResults.innerHTML='<div class="f3d-no-results">No results found</div>',this.searchResults.style.display="block";return}let o="";s.length>0&&(o+='<div class="f3d-search-section-header">Nodes</div>',s.slice(0,10).forEach(i=>{const a=i.type||"Node";o+=`
491
+ <div class="f3d-search-result-item" data-node-id="${this.escapeHtml(i.id)}">
492
+ <div class="f3d-result-label">${this.escapeHtml(i.label)}</div>
343
493
  <div class="f3d-result-type">${this.escapeHtml(a)}</div>
344
494
  </div>
345
- `}),s.length>10&&(i+=`<div class="f3d-no-results">+ ${s.length-10} more nodes</div>`)),t.length>0&&(i+='<div class="f3d-search-section-header">Relationships</div>',t.slice(0,5).forEach(({edge:o,sourceNode:a,targetNode:l})=>{i+=`
346
- <div class="f3d-search-result-item" data-node-id="${this.escapeHtml(o.source)}">
347
- <div class="f3d-result-label">${this.escapeHtml(a.label)} → ${this.escapeHtml(l.label)}</div>
348
- <div class="f3d-result-relationship">${this.escapeHtml(o.relationship||"connected")}</div>
495
+ `}),s.length>10&&(o+=`<div class="f3d-no-results">+ ${s.length-10} more nodes</div>`)),t.length>0&&(o+='<div class="f3d-search-section-header">Relationships</div>',t.slice(0,5).forEach(({edge:i,sourceNode:a,targetNode:r})=>{o+=`
496
+ <div class="f3d-search-result-item" data-node-id="${this.escapeHtml(i.source)}">
497
+ <div class="f3d-result-label">${this.escapeHtml(a.label)} → ${this.escapeHtml(r.label)}</div>
498
+ <div class="f3d-result-relationship">${this.escapeHtml(i.relationship||"connected")}</div>
349
499
  </div>
350
- `}),t.length>5&&(i+=`<div class="f3d-no-results">+ ${t.length-5} more relationships</div>`)),this.searchResults.innerHTML=i,this.searchResults.style.display="block",this.searchResults.querySelectorAll(".f3d-search-result-item").forEach(o=>{o.addEventListener("click",()=>{const a=o.dataset.nodeId;a&&(this.onResultClick(a),this.searchResults&&(this.searchResults.style.display="none"),this.searchInput&&this.searchInput.blur())})})}escapeHtml(e){const s=document.createElement("div");return s.textContent=e,s.innerHTML}dispose(){this.searchContainer&&this.searchContainer.parentNode&&this.searchContainer.parentNode.removeChild(this.searchContainer)}}class Je{constructor(e,s={}){r(this,"options");r(this,"container");r(this,"sceneManager");r(this,"nodeManager");r(this,"edgeManager");r(this,"graphEngine");r(this,"rendererManager");r(this,"materialFactory");r(this,"nodeFactory");r(this,"edgeFactory");r(this,"lodManager");r(this,"frustumCuller");r(this,"raycasterManager");r(this,"panelManager");r(this,"edgeTooltipManager");r(this,"searchManager",null);r(this,"eventCallbacks",new Map);r(this,"initialized",!1);r(this,"devControls",null);this.options={...O,...s},this.container=Te(e),this.materialFactory=new Ve,this.nodeFactory=new Be(this.materialFactory,this.options.nodeRadius??O.nodeRadius,this.options.lodSegments??O.lodSegments),this.edgeFactory=new Ue(this.materialFactory,this.options.edgeColor??O.edgeColor,this.options.edgeOpacity??O.edgeOpacity),this.sceneManager=new He(this.container,this.options),this.lodManager=new _e(this.sceneManager.camera,this.options.lodDistances??O.lodDistances,this.options.enableLOD??O.enableLOD),this.frustumCuller=new Xe(this.sceneManager.camera,this.options.enableEdgeCulling??O.enableEdgeCulling),this.nodeManager=new $e(this.sceneManager,this.nodeFactory),this.edgeManager=new Ke(this.sceneManager,this.nodeManager,this.edgeFactory),this.graphEngine=new pe(this.nodeManager.getAllNodes(),this.edgeManager.getAllEdges(),{repulsionStrength:this.options.repulsionStrength,attractionStrength:this.options.attractionStrength,damping:this.options.damping,useBarnesHut:this.options.useBarnesHut,barnesHutTheta:this.options.barnesHutTheta}),this.rendererManager=new Ye(this.sceneManager,()=>this.onSimulate(),()=>this.onRender(),this.options.targetFPS??O.targetFPS),this.raycasterManager=new qe(this.sceneManager,this.container),this.panelManager=new We(this.container),this.edgeTooltipManager=new Ze,this.options.showSearch!==!1&&(this.searchManager=new Qe(this.container,{placeholder:this.options.searchPlaceholder,onSearch:t=>({nodeResults:this.searchNodes(t),edgeResults:this.searchEdges(t)}),onResultClick:t=>{this.focusOnNode(t),setTimeout(()=>{this.showNodePanel(t)},400)}})),this.setupCallbacks(),this.rendererManager.start(),this.initialized=!0,this.emit("ready")}setupCallbacks(){this.raycasterManager.setClickCallback(e=>{this.onNodeClick(e)}),this.options.onNodeHover&&this.raycasterManager.setHoverCallback(this.options.onNodeHover),this.panelManager.setExpandCallback((e,s)=>{this.expandNode(e,s)}),this.options.panelTemplate&&this.panelManager.setPanelTemplate(this.options.panelTemplate),this.options.panelStyles&&this.panelManager.setPanelStyles(this.options.panelStyles),this.raycasterManager.setEdgeHoverCallback(e=>{this.onEdgeHover(e)})}onEdgeHover(e){if(e){this.edgeManager.highlightEdge(e.edge.source,e.edge.target);const s=this.container.getBoundingClientRect(),t=s.left+s.width/2,i=s.top+s.height/2;this.edgeTooltipManager.show(e.edge,e.sourceNode,e.targetNode,t,i),this.options.onEdgeHover&&this.options.onEdgeHover(e.edge,e.sourceNode,e.targetNode),this.emit("edgeHover",e.edge,e.sourceNode,e.targetNode)}else this.edgeManager.unhighlightCurrentEdge(),this.edgeTooltipManager.hide(),this.options.onEdgeHover&&this.options.onEdgeHover(null,null,null),this.emit("edgeHover",null,null,null)}onNodeClick(e){const t=this.edgeManager.getNeighborIds(e.id).map(i=>this.nodeManager.getNode(i)).filter(i=>i!==void 0);this.options.showPanel!==!1&&this.panelManager.show(e,t),this.options.onNodeClick&&this.options.onNodeClick(e),this.emit("nodeClick",e)}onSimulate(){this.graphEngine.simulate();for(const[e,s]of this.nodeManager.getAllNodes())if(this.nodeManager.updateNodePosition(e,s.position),this.options.enableLOD){const t=this.lodManager.getLODLevel(s.position);this.nodeManager.updateNodeLOD(e,t)}this.edgeManager.updateEdgePositions()}onRender(){this.frustumCuller.update(),this.raycasterManager.setNodeObjects(this.nodeManager.getAllNodeObjects()),this.raycasterManager.setEdgeObjects(this.edgeManager.getAllEdgeLines())}setData(e){if(this.edgeManager.clear(),this.nodeManager.clear(),e.nodes&&Array.isArray(e.nodes))for(const s of e.nodes)this.addNode(s);if(e.edges&&Array.isArray(e.edges))for(const s of e.edges)this.addEdge(s);this.graphEngine=new pe(this.nodeManager.getAllNodes(),this.edgeManager.getAllEdges(),{repulsionStrength:this.options.repulsionStrength,attractionStrength:this.options.attractionStrength,damping:this.options.damping,useBarnesHut:this.options.useBarnesHut,barnesHutTheta:this.options.barnesHutTheta}),this.graphEngine.restart()}addNode(e){if(!Q(e))return!1;const s=this.nodeManager.addNode(e);return s&&(this.graphEngine.restart(),this.options.onNodeAdd&&this.options.onNodeAdd(e),this.emit("nodeAdd",e)),s}removeNode(e){if(!je(e))return!1;this.edgeManager.removeEdgesForNode(e);const s=this.nodeManager.removeNode(e);return s&&(this.graphEngine.restart(),this.options.onNodeRemove&&this.options.onNodeRemove(e),this.emit("nodeRemove",e),this.panelManager.getCurrentNodeId()===e&&this.panelManager.hide()),s}updateNode(e,s){return this.nodeManager.updateNode(e,s)}addEdge(e){if(!J(e))return!1;const s=this.edgeManager.addEdge(e);return s&&(this.graphEngine.setEdges(this.edgeManager.getAllEdges()),this.graphEngine.restart(),this.options.onEdgeAdd&&this.options.onEdgeAdd(e),this.emit("edgeAdd",e)),s}removeEdge(e,s){const t=this.edgeManager.removeEdge(e,s);return t&&(this.graphEngine.setEdges(this.edgeManager.getAllEdges()),this.options.onEdgeRemove&&this.options.onEdgeRemove({source:e,target:s}),this.emit("edgeRemove",{source:e,target:s})),t}async expandNode(e,s=1,t){const i=t??this.options.onExpand;if(!i)return console.warn("[ForceGraph3D] No expand callback provided"),!1;try{const o=await i(e,s);if(o.nodes&&Array.isArray(o.nodes))for(const a of o.nodes)this.addNode(a);if(o.edges&&Array.isArray(o.edges))for(const a of o.edges)this.addEdge(a);return this.panelManager.hide(),this.emit("expand",e,o),!0}catch(o){return console.error("[ForceGraph3D] Error expanding node:",o),!1}}getNode(e){return this.nodeManager.getNode(e)}getNeighbors(e){return this.edgeManager.getNeighborIds(e).map(t=>this.nodeManager.getNode(t)).filter(t=>t!==void 0)}getNodeCount(){return this.nodeManager.getNodeCount()}getEdgeCount(){return this.edgeManager.getEdgeCount()}setExpandCallback(e){this.options.onExpand=e}focusOnNode(e,s=30){const t=this.nodeManager.getNode(e);if(!t){console.warn(`[ForceGraph3D] Node "${e}" not found`);return}const i=t.position,o=this.sceneManager.camera,a=this.sceneManager.controls,l=o.position.clone().sub(a.target).normalize(),p={x:i.x+l.x*s,y:i.y+l.y*s,z:i.z+l.z*s},g={x:o.position.x,y:o.position.y,z:o.position.z},m={x:a.target.x,y:a.target.y,z:a.target.z},x=800,M=performance.now(),b=()=>{const y=performance.now()-M,w=Math.min(y/x,1),N=1-Math.pow(1-w,3);o.position.x=g.x+(p.x-g.x)*N,o.position.y=g.y+(p.y-g.y)*N,o.position.z=g.z+(p.z-g.z)*N,a.target.x=m.x+(i.x-m.x)*N,a.target.y=m.y+(i.y-m.y)*N,a.target.z=m.z+(i.z-m.z)*N,a.update(),w<1&&requestAnimationFrame(b)};b()}showNodePanel(e){const s=this.nodeManager.getNode(e);if(!s){console.warn(`[ForceGraph3D] Node "${e}" not found`);return}const t=this.getNeighbors(e);this.panelManager.show(s,t)}searchNodes(e){if(!e||e.trim()==="")return[];const s=e.toLowerCase().trim(),t=this.nodeManager.getAllNodes(),i=[];return t.forEach(o=>{var g,m,x;const a=(g=o.label)==null?void 0:g.toLowerCase().includes(s),l=(m=o.id)==null?void 0:m.toLowerCase().includes(s),p=(x=o.type)==null?void 0:x.toLowerCase().includes(s);(a||l||p)&&i.push(o)}),i}searchEdges(e){var o;if(!e||e.trim()==="")return[];const s=e.toLowerCase().trim(),t=this.edgeManager.getAllEdges(),i=[];for(const a of t)if((o=a.relationship)==null?void 0:o.toLowerCase().includes(s)){const p=this.nodeManager.getNode(a.source),g=this.nodeManager.getNode(a.target);p&&g&&i.push({edge:a,sourceNode:p,targetNode:g})}return i}getAllNodes(){const e=this.nodeManager.getAllNodes();return Array.from(e.values())}getAllEdges(){return this.edgeManager.getAllEdges()}isInitialized(){return this.initialized}on(e,s){this.eventCallbacks.has(e)||this.eventCallbacks.set(e,[]),this.eventCallbacks.get(e).push(s)}emit(e,...s){const t=this.eventCallbacks.get(e);t&&t.forEach(i=>i(...s))}setPhysicsParams(e){this.graphEngine.setPhysicsParams(e),this.graphEngine.restart()}createDevControls(){this.devControls=document.createElement("div"),this.devControls.className="force-graph-dev-controls",this.devControls.innerHTML=`
500
+ `}),t.length>5&&(o+=`<div class="f3d-no-results">+ ${t.length-5} more relationships</div>`)),this.searchResults.innerHTML=o,this.searchResults.style.display="block",this.searchResults.querySelectorAll(".f3d-search-result-item").forEach(i=>{i.addEventListener("click",()=>{const a=i.dataset.nodeId;a&&(this.onResultClick(a),this.searchResults&&(this.searchResults.style.display="none"),this.searchInput&&this.searchInput.blur())})})}escapeHtml(e){const s=document.createElement("div");return s.textContent=e,s.innerHTML}dispose(){this.searchContainer&&this.searchContainer.parentNode&&this.searchContainer.parentNode.removeChild(this.searchContainer)}}class et{constructor(e,s){l(this,"container");l(this,"toggleContainer",null);l(this,"currentMode","3d");l(this,"onViewChange");this.container=e,this.currentMode=s.initialMode||"3d",this.onViewChange=s.onViewChange,this.init()}init(){this.createToggleUI()}createToggleUI(){this.toggleContainer=document.createElement("div"),this.toggleContainer.className="f3d-view-toggle",Object.assign(this.toggleContainer.style,{position:"absolute",top:"20px",left:"20px",zIndex:"100",display:"flex",gap:"0",background:"rgba(255, 255, 255, 0.08)",backdropFilter:"blur(20px)",WebkitBackdropFilter:"blur(20px)",border:"1px solid rgba(255, 255, 255, 0.12)",borderRadius:"12px",padding:"5px",boxShadow:"0 4px 20px rgba(0, 0, 0, 0.3)"});const e=this.createButton("2D","2d"),s=this.createButton("3D","3d");this.toggleContainer.appendChild(e),this.toggleContainer.appendChild(s),this.container.appendChild(this.toggleContainer),this.updateButtonStates();const t=document.createElement("style");t.textContent=`
501
+ .f3d-view-btn {
502
+ padding: 8px 16px;
503
+ background: transparent;
504
+ border: none;
505
+ color: rgba(255, 255, 255, 0.5);
506
+ font-size: 12px;
507
+ font-weight: 600;
508
+ font-family: inherit;
509
+ letter-spacing: 0.5px;
510
+ cursor: pointer;
511
+ transition: all 0.2s ease;
512
+ border-radius: 8px;
513
+ min-width: 44px;
514
+ }
515
+ .f3d-view-btn:hover {
516
+ color: rgba(255, 255, 255, 0.8);
517
+ }
518
+ .f3d-view-btn.active {
519
+ background: linear-gradient(135deg, rgba(255, 153, 102, 0.3), rgba(255, 102, 153, 0.2));
520
+ color: white;
521
+ box-shadow: 0 0 15px rgba(255, 153, 102, 0.2);
522
+ }
523
+ .f3d-view-btn:focus {
524
+ outline: none;
525
+ }
526
+ `,document.head.appendChild(t)}createButton(e,s){const t=document.createElement("button");return t.className="f3d-view-btn",t.dataset.mode=s,t.innerHTML=this.getIcon(s)+`<span style="margin-left: 4px;">${e}</span>`,t.style.display="flex",t.style.alignItems="center",t.style.justifyContent="center",t.addEventListener("click",()=>{this.currentMode!==s&&(this.currentMode=s,this.updateButtonStates(),this.onViewChange(s))}),t}getIcon(e){return e==="2d"?`<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
527
+ <rect x="3" y="3" width="7" height="7"></rect>
528
+ <rect x="14" y="3" width="7" height="7"></rect>
529
+ <rect x="14" y="14" width="7" height="7"></rect>
530
+ <rect x="3" y="14" width="7" height="7"></rect>
531
+ </svg>`:`<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
532
+ <path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path>
533
+ <polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline>
534
+ <line x1="12" y1="22.08" x2="12" y2="12"></line>
535
+ </svg>`}updateButtonStates(){if(!this.toggleContainer)return;this.toggleContainer.querySelectorAll(".f3d-view-btn").forEach(s=>{s.dataset.mode===this.currentMode?s.classList.add("active"):s.classList.remove("active")})}setMode(e){this.currentMode!==e&&(this.currentMode=e,this.updateButtonStates())}getMode(){return this.currentMode}dispose(){this.toggleContainer&&this.toggleContainer.parentNode&&this.toggleContainer.parentNode.removeChild(this.toggleContainer)}}const tt={backgroundColor:"#0a0a0a",gridColor:"rgba(255, 255, 255, 0.03)",nodeRadius:24,edgeColor:"rgba(255, 255, 255, 0.15)",edgeOpacity:.4,repulsionStrength:500,attractionStrength:.001,damping:.85};class st{constructor(e,s={}){l(this,"container");l(this,"canvas");l(this,"ctx");l(this,"options");l(this,"nodes",new Map);l(this,"edges",[]);l(this,"nodeIdToIndex",new Map);l(this,"transform",{x:0,y:0,scale:1});l(this,"isDragging",!1);l(this,"isPanning",!1);l(this,"draggedNode",null);l(this,"hoveredNode",null);l(this,"hoveredEdge",null);l(this,"lastMousePos",{x:0,y:0});l(this,"dragStartPos",{x:0,y:0});l(this,"selectedNode",null);l(this,"animationId",null);l(this,"isSimulating",!0);l(this,"resizeHandler");this.container=e,this.options={...tt,...s},this.canvas=document.createElement("canvas"),this.canvas.style.position="absolute",this.canvas.style.top="0",this.canvas.style.left="0",this.canvas.style.width="100%",this.canvas.style.height="100%",this.canvas.style.cursor="grab",e.appendChild(this.canvas);const t=this.canvas.getContext("2d");if(!t)throw new Error("Failed to get 2D context");this.ctx=t,this.resizeHandler=this.handleResize.bind(this),window.addEventListener("resize",this.resizeHandler),this.handleResize(),this.transform.x=this.canvas.width/2,this.transform.y=this.canvas.height/2,this.setupInteractions(),this.startAnimation()}handleResize(){const e=this.container.getBoundingClientRect(),s=window.devicePixelRatio||1;this.canvas.width=e.width*s,this.canvas.height=e.height*s,this.ctx.scale(s,s)}setupInteractions(){this.canvas.addEventListener("wheel",e=>{e.preventDefault();const s=this.canvas.getBoundingClientRect(),t=e.clientX-s.left,o=e.clientY-s.top,i=e.deltaY>0?.9:1.1,a=Math.max(.1,Math.min(5,this.transform.scale*i)),r=a/this.transform.scale;this.transform.x=t-(t-this.transform.x)*r,this.transform.y=o-(o-this.transform.y)*r,this.transform.scale=a}),this.canvas.addEventListener("mousedown",e=>{const s=this.canvas.getBoundingClientRect(),t=e.clientX-s.left,o=e.clientY-s.top,i=this.screenToWorld(t,o),a=this.findNodeAt(i.x,i.y);this.dragStartPos={x:e.clientX,y:e.clientY},a?(this.isDragging=!0,this.draggedNode=a,this.canvas.style.cursor="grabbing",this.isSimulating=!0):(this.isPanning=!0,this.canvas.style.cursor="grabbing"),this.lastMousePos={x:e.clientX,y:e.clientY}}),this.canvas.addEventListener("mousemove",e=>{const s=this.canvas.getBoundingClientRect(),t=e.clientX-s.left,o=e.clientY-s.top,i=this.screenToWorld(t,o);if(this.isDragging&&this.draggedNode)this.draggedNode.x=i.x,this.draggedNode.y=i.y,this.draggedNode.vx=0,this.draggedNode.vy=0;else if(this.isPanning){const a=e.clientX-this.lastMousePos.x,r=e.clientY-this.lastMousePos.y;this.transform.x+=a,this.transform.y+=r,this.lastMousePos={x:e.clientX,y:e.clientY}}else{const a=this.findNodeAt(i.x,i.y);if(a!==this.hoveredNode&&(this.hoveredNode=a,a?(this.hoveredEdge&&(this.hoveredEdge=null,this.options.onEdgeHover&&this.options.onEdgeHover(null)),this.canvas.style.cursor="pointer",this.options.onNodeHover&&this.options.onNodeHover(a.data)):this.options.onNodeHover&&this.options.onNodeHover(null)),!a){const r=this.findEdgeAt(i.x,i.y);r!==this.hoveredEdge&&(this.hoveredEdge=r,this.canvas.style.cursor=r?"pointer":"grab",this.options.onEdgeHover&&this.options.onEdgeHover(r?r.data:null,e))}}}),this.canvas.addEventListener("mouseup",e=>{const s=Math.abs(e.clientX-this.dragStartPos.x),t=Math.abs(e.clientY-this.dragStartPos.y),o=s<5&&t<5;if(this.isDragging&&this.draggedNode)o&&this.options.onNodeClick&&(this.selectedNode=this.draggedNode,this.options.onNodeClick(this.draggedNode.data));else if(o&&!this.isPanning){const i=this.canvas.getBoundingClientRect(),a=this.screenToWorld(e.clientX-i.left,e.clientY-i.top),r=this.findEdgeAt(a.x,a.y);r&&this.options.onEdgeClick&&this.options.onEdgeClick(r.data)}this.isDragging=!1,this.isPanning=!1,this.draggedNode=null,this.canvas.style.cursor=this.hoveredNode?"pointer":"grab"}),this.canvas.addEventListener("mouseleave",()=>{this.isDragging=!1,this.isPanning=!1,this.draggedNode=null,this.hoveredNode=null,this.canvas.style.cursor="grab"})}screenToWorld(e,s){return{x:(e-this.transform.x)/this.transform.scale,y:(s-this.transform.y)/this.transform.scale}}findNodeAt(e,s){for(const t of this.nodes.values()){const o=t.x-e,i=t.y-s;if(Math.sqrt(o*o+i*i)<t.radius)return t}return null}findEdgeAt(e,s){for(const o of this.edges){const i=this.nodes.get(o.source),a=this.nodes.get(o.target);if(!i||!a)continue;const r=a.x-i.x,c=a.y-i.y,d=r*r+c*c;if(d===0)continue;const u=Math.max(0,Math.min(1,((e-i.x)*r+(s-i.y)*c)/d)),f=i.x+u*r,x=i.y+u*c,m=e-f,b=s-x;if(Math.sqrt(m*m+b*b)<8)return o}return null}startAnimation(){const e=()=>{this.isSimulating&&this.simulate(),this.render(),this.animationId=requestAnimationFrame(e)};e()}simulate(){const e=Array.from(this.nodes.values()),s=e.length;if(s===0)return;const t=60,o=5;let i=0;for(let r=0;r<s;r++)for(let c=r+1;c<s;c++){const d=e[r],u=e[c];let f=u.x-d.x,x=u.y-d.y,m=Math.sqrt(f*f+x*x);if(m<t*3){m<1&&(m=1);const b=this.options.repulsionStrength/(m*m),M=f/m*b,w=x/m*b;d.vx-=M,d.vy-=w,u.vx+=M,u.vy+=w}}const a=80;for(const r of this.edges){const c=this.nodes.get(r.source),d=this.nodes.get(r.target);if(!c||!d)continue;let u=d.x-c.x,f=d.y-c.y,x=Math.sqrt(u*u+f*f);x<1&&(x=1);const b=(x-a)*this.options.attractionStrength,M=u/x*b,w=f/x*b;c.vx+=M,c.vy+=w,d.vx-=M,d.vy-=w}for(const r of e){if(this.draggedNode===r)continue;r.vx*=this.options.damping,r.vy*=this.options.damping;const c=Math.sqrt(r.vx*r.vx+r.vy*r.vy);c>o&&(r.vx=r.vx/c*o,r.vy=r.vy/c*o),r.x+=r.vx,r.y+=r.vy,i+=r.vx*r.vx+r.vy*r.vy}i<.01&&!this.draggedNode&&(this.isSimulating=!1)}render(){const e=this.ctx,s=this.canvas.width/(window.devicePixelRatio||1),t=this.canvas.height/(window.devicePixelRatio||1);e.fillStyle=this.options.backgroundColor,e.fillRect(0,0,s,t),this.renderGrid(s,t),e.save(),e.translate(this.transform.x,this.transform.y),e.scale(this.transform.scale,this.transform.scale),this.renderEdges(),this.renderNodes(),e.restore()}renderGrid(e,s){const t=this.ctx,o=40*this.transform.scale,i=1.5,a=this.transform.x%o,r=this.transform.y%o;t.fillStyle=this.options.gridColor;for(let c=a;c<e;c+=o)for(let d=r;d<s;d+=o)t.beginPath(),t.arc(c,d,i,0,Math.PI*2),t.fill()}renderEdges(){const e=this.ctx;for(const s of this.edges){const t=this.nodes.get(s.source),o=this.nodes.get(s.target);if(!t||!o)continue;const i=e.createLinearGradient(t.x,t.y,o.x,o.y);i.addColorStop(0,"rgba(255, 153, 102, 0.3)"),i.addColorStop(.5,"rgba(255, 255, 255, 0.15)"),i.addColorStop(1,"rgba(102, 153, 255, 0.3)"),e.beginPath(),e.moveTo(t.x,t.y),e.lineTo(o.x,o.y),e.strokeStyle=i,e.lineWidth=1.5,e.stroke()}}renderNodes(){const e=this.ctx;for(const s of this.nodes.values()){const t=s===this.hoveredNode,o=s===this.selectedNode,i=s.radius*(t?1.1:1);if(t||o){const m=e.createRadialGradient(s.x,s.y,i*.5,s.x,s.y,i*2);m.addColorStop(0,"rgba(255, 153, 102, 0.4)"),m.addColorStop(1,"rgba(255, 153, 102, 0)"),e.fillStyle=m,e.beginPath(),e.arc(s.x,s.y,i*2,0,Math.PI*2),e.fill()}const a=e.createRadialGradient(s.x-i*.3,s.y-i*.3,0,s.x,s.y,i),r=s.color>>16&255,c=s.color>>8&255,d=s.color&255;a.addColorStop(0,`rgba(${Math.min(255,r+60)}, ${Math.min(255,c+60)}, ${Math.min(255,d+60)}, 0.95)`),a.addColorStop(.7,`rgba(${r}, ${c}, ${d}, 0.9)`),a.addColorStop(1,`rgba(${Math.max(0,r-40)}, ${Math.max(0,c-40)}, ${Math.max(0,d-40)}, 0.85)`),e.beginPath(),e.arc(s.x,s.y,i,0,Math.PI*2),e.fillStyle=a,e.fill(),e.strokeStyle="rgba(255, 255, 255, 0.2)",e.lineWidth=1,e.stroke(),e.beginPath(),e.arc(s.x-i*.25,s.y-i*.25,i*.3,0,Math.PI*2),e.fillStyle="rgba(255, 255, 255, 0.15)",e.fill(),e.fillStyle="white",e.font="600 11px Inter, -apple-system, BlinkMacSystemFont, sans-serif",e.textAlign="center",e.textBaseline="middle";const u=i*1.6;let f=s.label,x=e.measureText(f).width;if(x>u){for(;x>u&&f.length>3;)f=f.slice(0,-1),x=e.measureText(f+"...").width;f+="..."}e.shadowColor="rgba(0, 0, 0, 0.5)",e.shadowBlur=3,e.fillText(f,s.x,s.y),e.shadowBlur=0}}setData(e){this.nodes.clear(),this.edges=[],this.nodeIdToIndex.clear(),e.nodes.forEach((s,t)=>{const o=s.position||{x:(Math.random()-.5)*300,y:(Math.random()-.5)*300},i={id:s.id,label:s.label,x:o.x,y:o.y,vx:0,vy:0,color:s.color||16750950,radius:this.options.nodeRadius,data:s};this.nodes.set(s.id,i),this.nodeIdToIndex.set(s.id,t)}),this.edges=e.edges.map(s=>({source:s.source,target:s.target,relationship:s.relationship,data:s}))}addNode(e){const s=e.position||{x:(Math.random()-.5)*300,y:(Math.random()-.5)*300},t={id:e.id,label:e.label,x:s.x,y:s.y,vx:0,vy:0,color:e.color||16750950,radius:this.options.nodeRadius,data:e};this.nodes.set(e.id,t)}addEdge(e){this.edges.push({source:e.source,target:e.target,relationship:e.relationship,data:e})}removeNode(e){this.nodes.delete(e),this.edges=this.edges.filter(s=>s.source!==e&&s.target!==e)}getNode(e){return this.nodes.get(e)}getAllNodes(){return Array.from(this.nodes.values()).map(e=>e.data)}getNodeCount(){return this.nodes.size}getEdgeCount(){return this.edges.length}focusOnNode(e){const s=this.nodes.get(e);if(!s)return;const t=this.canvas.width/2/(window.devicePixelRatio||1)-s.x*this.transform.scale,o=this.canvas.height/2/(window.devicePixelRatio||1)-s.y*this.transform.scale,i=this.transform.x,a=this.transform.y,r=500,c=performance.now(),d=()=>{const u=performance.now()-c,f=Math.min(u/r,1),x=1-Math.pow(1-f,3);this.transform.x=i+(t-i)*x,this.transform.y=a+(o-a)*x,f<1?requestAnimationFrame(d):this.selectedNode=s};d()}syncFrom3D(e){e.forEach((s,t)=>{const o=this.nodes.get(t);o&&(o.x=s.position.x*3,o.y=s.position.y*3,o.vx=0,o.vy=0)}),this.isSimulating=!1}getPositions(){const e=new Map;return this.nodes.forEach((s,t)=>{e.set(t,{x:s.x,y:s.y})}),e}show(){this.canvas.style.display="block"}hide(){this.canvas.style.display="none"}setPhysicsParams(e){e.repulsionStrength!==void 0&&(this.options.repulsionStrength=e.repulsionStrength),e.attractionStrength!==void 0&&(this.options.attractionStrength=e.attractionStrength),e.damping!==void 0&&(this.options.damping=e.damping),this.isSimulating=!0}dispose(){this.animationId&&cancelAnimationFrame(this.animationId),window.removeEventListener("resize",this.resizeHandler),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}}class it{constructor(e,s={}){l(this,"options");l(this,"container");l(this,"sceneManager");l(this,"nodeManager");l(this,"edgeManager");l(this,"graphEngine");l(this,"rendererManager");l(this,"materialFactory");l(this,"nodeFactory");l(this,"edgeFactory");l(this,"lodManager");l(this,"frustumCuller");l(this,"raycasterManager");l(this,"panelManager");l(this,"edgePanelManager");l(this,"edgeTooltipManager");l(this,"searchManager",null);l(this,"viewToggleManager",null);l(this,"forceGraph2D",null);l(this,"eventCallbacks",new Map);l(this,"initialized",!1);l(this,"devControls",null);l(this,"viewMode","3d");l(this,"graphData",null);this.options={...P,...s},this.container=De(e),this.materialFactory=new Ve,this.nodeFactory=new Ke(this.materialFactory,this.options.nodeRadius??P.nodeRadius,this.options.lodSegments??P.lodSegments),this.edgeFactory=new Ue(this.materialFactory,this.options.edgeColor??P.edgeColor,this.options.edgeOpacity??P.edgeOpacity),this.sceneManager=new He(this.container,this.options),this.lodManager=new Xe(this.sceneManager.camera,this.options.lodDistances??P.lodDistances,this.options.enableLOD??P.enableLOD),this.frustumCuller=new _e(this.sceneManager.camera,this.options.enableEdgeCulling??P.enableEdgeCulling),this.nodeManager=new $e(this.sceneManager,this.nodeFactory),this.edgeManager=new Ge(this.sceneManager,this.nodeManager,this.edgeFactory),this.graphEngine=new ge(this.nodeManager.getAllNodes(),this.edgeManager.getAllEdges(),{repulsionStrength:this.options.repulsionStrength,attractionStrength:this.options.attractionStrength,damping:this.options.damping,useBarnesHut:this.options.useBarnesHut,barnesHutTheta:this.options.barnesHutTheta}),this.rendererManager=new Be(this.sceneManager,()=>this.onSimulate(),()=>this.onRender(),this.options.targetFPS??P.targetFPS),this.raycasterManager=new qe(this.sceneManager,this.container),this.panelManager=new We(this.container),this.edgePanelManager=new Ze(this.container),this.edgeTooltipManager=new Qe,this.edgePanelManager.setNodeClickCallback(t=>{this.edgePanelManager.hide(),this.focusOnNode(t),setTimeout(()=>{this.showNodePanel(t)},400)}),this.options.showSearch!==!1&&(this.searchManager=new Je(this.container,{placeholder:this.options.searchPlaceholder,onSearch:t=>({nodeResults:this.searchNodes(t),edgeResults:this.searchEdges(t)}),onResultClick:t=>{this.focusOnNode(t),setTimeout(()=>{this.showNodePanel(t)},400)}})),this.options.showViewToggle!==!1&&(this.viewMode=this.options.initialViewMode||"3d",this.viewToggleManager=new et(this.container,{initialMode:this.viewMode,onViewChange:t=>{this.switchView(t)}})),this.setupCallbacks(),this.rendererManager.start(),this.initialized=!0,this.emit("ready")}setupCallbacks(){this.raycasterManager.setClickCallback(e=>{this.onNodeClick(e)}),this.options.onNodeHover&&this.raycasterManager.setHoverCallback(this.options.onNodeHover),this.panelManager.setExpandCallback((e,s)=>{this.expandNode(e,s)}),this.options.panelTemplate&&this.panelManager.setPanelTemplate(this.options.panelTemplate),this.options.panelStyles&&this.panelManager.setPanelStyles(this.options.panelStyles),this.raycasterManager.setEdgeHoverCallback(e=>{this.onEdgeHover(e)}),this.raycasterManager.setEdgeClickCallback(e=>{this.onEdgeClick(e)})}onEdgeHover(e){if(e){this.edgeManager.highlightEdge(e.edge.source,e.edge.target);const s=this.container.getBoundingClientRect(),t=s.left+s.width/2,o=s.top+s.height/2;this.edgeTooltipManager.show(e.edge,e.sourceNode,e.targetNode,t,o),this.options.onEdgeHover&&this.options.onEdgeHover(e.edge,e.sourceNode,e.targetNode),this.emit("edgeHover",e.edge,e.sourceNode,e.targetNode)}else this.edgeManager.unhighlightCurrentEdge(),this.edgeTooltipManager.hide(),this.options.onEdgeHover&&this.options.onEdgeHover(null,null,null),this.emit("edgeHover",null,null,null)}onNodeClick(e){this.edgePanelManager.hide();const t=this.edgeManager.getNeighborIds(e.id).map(o=>this.nodeManager.getNode(o)).filter(o=>o!==void 0);this.options.showPanel!==!1&&this.panelManager.show(e,t),this.options.onNodeClick&&this.options.onNodeClick(e),this.emit("nodeClick",e)}onEdgeClick(e){this.panelManager.hide(),this.edgeTooltipManager.hide(),this.edgeManager.highlightEdge(e.edge.source,e.edge.target),this.edgePanelManager.show(e.edge,e.sourceNode,e.targetNode),this.focusOnEdge(e.edge.source,e.edge.target),this.emit("edgeClick",e.edge,e.sourceNode,e.targetNode)}onSimulate(){this.graphEngine.simulate();for(const[e,s]of this.nodeManager.getAllNodes())if(this.nodeManager.updateNodePosition(e,s.position),this.options.enableLOD){const t=this.lodManager.getLODLevel(s.position);this.nodeManager.updateNodeLOD(e,t)}this.edgeManager.updateEdgePositions()}onRender(){this.frustumCuller.update(),this.raycasterManager.setNodeObjects(this.nodeManager.getAllNodeObjects()),this.raycasterManager.setEdgeObjects(this.edgeManager.getAllEdgeLines())}setData(e){if(this.graphData=e,this.edgeManager.clear(),this.nodeManager.clear(),e.nodes&&Array.isArray(e.nodes))for(const s of e.nodes)this.addNode(s);if(e.edges&&Array.isArray(e.edges))for(const s of e.edges)this.addEdge(s);this.graphEngine=new ge(this.nodeManager.getAllNodes(),this.edgeManager.getAllEdges(),{repulsionStrength:this.options.repulsionStrength,attractionStrength:this.options.attractionStrength,damping:this.options.damping,useBarnesHut:this.options.useBarnesHut,barnesHutTheta:this.options.barnesHutTheta}),this.graphEngine.restart(),this.forceGraph2D&&this.forceGraph2D.setData(e)}addNode(e){if(!J(e))return!1;const s=this.nodeManager.addNode(e);return s&&(this.graphEngine.restart(),this.forceGraph2D&&this.forceGraph2D.addNode(e),this.options.onNodeAdd&&this.options.onNodeAdd(e),this.emit("nodeAdd",e)),s}removeNode(e){if(!Fe(e))return!1;this.edgeManager.removeEdgesForNode(e);const s=this.nodeManager.removeNode(e);return s&&(this.graphEngine.restart(),this.options.onNodeRemove&&this.options.onNodeRemove(e),this.emit("nodeRemove",e),this.panelManager.getCurrentNodeId()===e&&this.panelManager.hide()),s}updateNode(e,s){return this.nodeManager.updateNode(e,s)}addEdge(e){if(!ee(e))return!1;const s=this.edgeManager.addEdge(e);return s&&(this.graphEngine.setEdges(this.edgeManager.getAllEdges()),this.graphEngine.restart(),this.forceGraph2D&&this.forceGraph2D.addEdge(e),this.options.onEdgeAdd&&this.options.onEdgeAdd(e),this.emit("edgeAdd",e)),s}removeEdge(e,s){const t=this.edgeManager.removeEdge(e,s);return t&&(this.graphEngine.setEdges(this.edgeManager.getAllEdges()),this.options.onEdgeRemove&&this.options.onEdgeRemove({source:e,target:s}),this.emit("edgeRemove",{source:e,target:s})),t}async expandNode(e,s=1,t){const o=t??this.options.onExpand;if(!o)return console.warn("[ForceGraph3D] No expand callback provided"),!1;try{const i=await o(e,s);if(i.nodes&&Array.isArray(i.nodes))for(const a of i.nodes)this.addNode(a);if(i.edges&&Array.isArray(i.edges))for(const a of i.edges)this.addEdge(a);return this.panelManager.hide(),this.emit("expand",e,i),!0}catch(i){return console.error("[ForceGraph3D] Error expanding node:",i),!1}}getNode(e){return this.nodeManager.getNode(e)}getNeighbors(e){return this.edgeManager.getNeighborIds(e).map(t=>this.nodeManager.getNode(t)).filter(t=>t!==void 0)}getNodeCount(){return this.nodeManager.getNodeCount()}getEdgeCount(){return this.edgeManager.getEdgeCount()}setExpandCallback(e){this.options.onExpand=e}focusOnNode(e,s=30){if(this.viewMode==="2d"&&this.forceGraph2D){this.forceGraph2D.focusOnNode(e);return}const t=this.nodeManager.getNode(e);if(!t){console.warn(`[ForceGraph3D] Node "${e}" not found`);return}const o=t.position,i=this.sceneManager.camera,a=this.sceneManager.controls,r=i.position.clone().sub(a.target).normalize(),c={x:o.x+r.x*s,y:o.y+r.y*s,z:o.z+r.z*s},d={x:i.position.x,y:i.position.y,z:i.position.z},u={x:a.target.x,y:a.target.y,z:a.target.z},f=800,x=performance.now(),m=()=>{const b=performance.now()-x,M=Math.min(b/f,1),w=1-Math.pow(1-M,3);i.position.x=d.x+(c.x-d.x)*w,i.position.y=d.y+(c.y-d.y)*w,i.position.z=d.z+(c.z-d.z)*w,a.target.x=u.x+(o.x-u.x)*w,a.target.y=u.y+(o.y-u.y)*w,a.target.z=u.z+(o.z-u.z)*w,a.update(),M<1&&requestAnimationFrame(m)};m()}focusOnEdge(e,s,t=1.5){const o=this.nodeManager.getNode(e),i=this.nodeManager.getNode(s);if(!o||!i){console.warn(`[ForceGraph3D] Could not find nodes for edge "${e}" -> "${s}"`);return}const a=this.sceneManager.camera,r=this.sceneManager.controls,c={x:(o.position.x+i.position.x)/2,y:(o.position.y+i.position.y)/2,z:(o.position.z+i.position.z)/2},d=i.position.x-o.position.x,u=i.position.y-o.position.y,f=i.position.z-o.position.z,x=Math.sqrt(d*d+u*u+f*f),m=Math.max(x*t,40),b=a.position.clone().sub(r.target).normalize(),M={x:c.x+b.x*m,y:c.y+b.y*m,z:c.z+b.z*m},w={x:a.position.x,y:a.position.y,z:a.position.z},z={x:r.target.x,y:r.target.y,z:r.target.z},F=800,T=performance.now(),Y=()=>{const O=performance.now()-T,j=Math.min(O/F,1),E=1-Math.pow(1-j,3);a.position.x=w.x+(M.x-w.x)*E,a.position.y=w.y+(M.y-w.y)*E,a.position.z=w.z+(M.z-w.z)*E,r.target.x=z.x+(c.x-z.x)*E,r.target.y=z.y+(c.y-z.y)*E,r.target.z=z.z+(c.z-z.z)*E,r.update(),j<1&&requestAnimationFrame(Y)};Y()}showNodePanel(e){const s=this.nodeManager.getNode(e);if(!s){console.warn(`[ForceGraph3D] Node "${e}" not found`);return}const t=this.getNeighbors(e);this.panelManager.show(s,t)}searchNodes(e){if(!e||e.trim()==="")return[];const s=e.toLowerCase().trim(),t=this.nodeManager.getAllNodes(),o=[];return t.forEach(i=>{var d,u,f;const a=(d=i.label)==null?void 0:d.toLowerCase().includes(s),r=(u=i.id)==null?void 0:u.toLowerCase().includes(s),c=(f=i.type)==null?void 0:f.toLowerCase().includes(s);(a||r||c)&&o.push(i)}),o}searchEdges(e){var i;if(!e||e.trim()==="")return[];const s=e.toLowerCase().trim(),t=this.edgeManager.getAllEdges(),o=[];for(const a of t)if((i=a.relationship)==null?void 0:i.toLowerCase().includes(s)){const c=this.nodeManager.getNode(a.source),d=this.nodeManager.getNode(a.target);c&&d&&o.push({edge:a,sourceNode:c,targetNode:d})}return o}getAllNodes(){const e=this.nodeManager.getAllNodes();return Array.from(e.values())}getAllEdges(){return this.edgeManager.getAllEdges()}isInitialized(){return this.initialized}getViewMode(){return this.viewMode}switchView(e){this.viewMode!==e&&(this.viewMode=e,this.panelManager.hide(),this.edgePanelManager.hide(),this.edgeTooltipManager.hide(),e==="2d"?(this.sceneManager.renderer.domElement.style.display="none",this.rendererManager.stop(),this.forceGraph2D?(this.forceGraph2D.show(),this.forceGraph2D.syncFrom3D(this.nodeManager.getAllNodes())):(this.forceGraph2D=new st(this.container,{backgroundColor:"#0a0a0a",nodeRadius:24,onNodeClick:s=>{this.onNodeClick(s)},onNodeHover:s=>{this.options.onNodeHover&&this.options.onNodeHover(s)},onEdgeHover:(s,t)=>{if(s&&t){const o=this.nodeManager.getNode(s.source),i=this.nodeManager.getNode(s.target);o&&i&&this.edgeTooltipManager.show(s,o,i,t.clientX,t.clientY)}else this.edgeTooltipManager.hide()},onEdgeClick:s=>{const t=this.nodeManager.getNode(s.source),o=this.nodeManager.getNode(s.target);t&&o&&this.edgePanelManager.show(s,t,o)}}),this.graphData&&(this.forceGraph2D.setData(this.graphData),this.forceGraph2D.syncFrom3D(this.nodeManager.getAllNodes())))):(this.forceGraph2D&&this.forceGraph2D.hide(),this.sceneManager.renderer.domElement.style.display="block",this.rendererManager.start()),this.emit("viewChange",e))}on(e,s){this.eventCallbacks.has(e)||this.eventCallbacks.set(e,[]),this.eventCallbacks.get(e).push(s)}emit(e,...s){const t=this.eventCallbacks.get(e);t&&t.forEach(o=>o(...s))}setPhysicsParams(e){this.graphEngine.setPhysicsParams(e),this.graphEngine.restart(),this.forceGraph2D&&this.forceGraph2D.setPhysicsParams(e)}createDevControls(){this.devControls=document.createElement("div"),this.devControls.className="force-graph-dev-controls",this.devControls.innerHTML=`
351
536
  <style>
352
537
  .force-graph-dev-controls {
353
538
  position: absolute;
@@ -409,5 +594,5 @@
409
594
  <div>Edges: <span class="value" id="dev-edge-count">0</span></div>
410
595
  <div>FPS: <span class="value" id="dev-fps">60</span></div>
411
596
  </div>
412
- `,this.container.appendChild(this.devControls);const e=this.devControls.querySelector("#dev-repulsion"),s=this.devControls.querySelector("#dev-attraction"),t=this.devControls.querySelector("#dev-damping");e==null||e.addEventListener("input",()=>{const i=parseFloat(e.value);this.setPhysicsParams({repulsionStrength:i}),this.devControls.querySelector("#dev-repulsion-val").textContent=i.toString()}),s==null||s.addEventListener("input",()=>{const i=parseFloat(s.value)/1e3;this.setPhysicsParams({attractionStrength:i}),this.devControls.querySelector("#dev-attraction-val").textContent=i.toFixed(3)}),t==null||t.addEventListener("input",()=>{const i=parseFloat(t.value)/100;this.setPhysicsParams({damping:i}),this.devControls.querySelector("#dev-damping-val").textContent=i.toFixed(2)}),setInterval(()=>{const i=this.devControls.querySelector("#dev-node-count"),o=this.devControls.querySelector("#dev-edge-count"),a=this.devControls.querySelector("#dev-fps");i&&(i.textContent=this.getNodeCount().toString()),o&&(o.textContent=this.getEdgeCount().toString()),a&&(a.textContent=this.rendererManager.getFPS().toString())},500)}destroy(){this.rendererManager.dispose(),this.panelManager.dispose(),this.raycasterManager.dispose(),this.edgeTooltipManager.dispose(),this.searchManager&&this.searchManager.dispose(),this.edgeManager.dispose(),this.nodeManager.dispose(),this.nodeFactory.dispose(),this.materialFactory.dispose(),this.sceneManager.dispose(),this.devControls&&this.devControls.parentNode&&this.devControls.parentNode.removeChild(this.devControls),this.eventCallbacks.clear(),this.initialized=!1}}const ue=["Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta","Theta","Iota","Kappa","Lambda","Mu","Nu","Xi","Omicron","Pi","Rho","Sigma","Tau","Upsilon","Phi","Chi","Psi","Omega","Core","Hub","Node","Link","Point","Vertex"],U=["connects to","links with","relates to","depends on","references","extends","includes","partners with","collaborates with","supports"],ge=[16777215,16750950,16764057,16772829,16746564];function et(c=30){const e=[],s=[];for(let i=0;i<c;i++){const o=i<ue.length?ue[i]:`Node ${i+1}`;e.push({id:`node-${i}`,label:o,color:ge[i%ge.length],position:{x:(Math.random()-.5)*60,y:(Math.random()-.5)*60,z:(Math.random()-.5)*60}})}for(let i=1;i<c;i++){const o=Math.floor(Math.random()*i);s.push({source:`node-${i}`,target:`node-${o}`,relationship:U[Math.floor(Math.random()*U.length)]})}const t=Math.floor(c*.5);for(let i=0;i<t;i++){const o=Math.floor(Math.random()*c);let a=Math.floor(Math.random()*c);o===a&&(a=(a+1)%c);const l=`node-${o}`,p=`node-${a}`;s.some(m=>m.source===l&&m.target===p||m.source===p&&m.target===l)||s.push({source:l,target:p,relationship:U[Math.floor(Math.random()*U.length)]})}return{nodes:e,edges:s}}function tt(c=1e3){const e=[],s=[],t=Math.ceil(c/50),i=[];for(let o=0;o<t;o++)i.push({x:(Math.random()-.5)*200,y:(Math.random()-.5)*200,z:(Math.random()-.5)*200});for(let o=0;o<c;o++){const a=i[o%t];e.push({id:`node-${o}`,label:`N${o}`,position:{x:a.x+(Math.random()-.5)*40,y:a.y+(Math.random()-.5)*40,z:a.z+(Math.random()-.5)*40}})}for(let o=1;o<c;o++){const a=Math.floor(o/50)*50,l=a===0?Math.floor(Math.random()*o):a+Math.floor(Math.random()*Math.min(o-a,50));s.push({source:`node-${o}`,target:`node-${Math.min(l,o-1)}`,relationship:"links to"})}for(let o=1;o<t;o++){const a=o*50,l=(o-1)*50+Math.floor(Math.random()*50);s.push({source:`node-${a}`,target:`node-${l}`,relationship:"bridges to"})}return{nodes:e,edges:s}}C.DEFAULT_OPTIONS=O,C.ForceGraph3D=Je,C.LODLevel=D,C.createEdgeKey=k,C.generateLargeSampleData=tt,C.generateSampleData=et,C.validateEdgeData=J,C.validateNodeData=Q,Object.defineProperty(C,Symbol.toStringTag,{value:"Module"})});
597
+ `,this.container.appendChild(this.devControls);const e=this.devControls.querySelector("#dev-repulsion"),s=this.devControls.querySelector("#dev-attraction"),t=this.devControls.querySelector("#dev-damping");e==null||e.addEventListener("input",()=>{const o=parseFloat(e.value);this.setPhysicsParams({repulsionStrength:o}),this.devControls.querySelector("#dev-repulsion-val").textContent=o.toString()}),s==null||s.addEventListener("input",()=>{const o=parseFloat(s.value)/1e3;this.setPhysicsParams({attractionStrength:o}),this.devControls.querySelector("#dev-attraction-val").textContent=o.toFixed(3)}),t==null||t.addEventListener("input",()=>{const o=parseFloat(t.value)/100;this.setPhysicsParams({damping:o}),this.devControls.querySelector("#dev-damping-val").textContent=o.toFixed(2)}),setInterval(()=>{const o=this.devControls.querySelector("#dev-node-count"),i=this.devControls.querySelector("#dev-edge-count"),a=this.devControls.querySelector("#dev-fps");o&&(o.textContent=this.getNodeCount().toString()),i&&(i.textContent=this.getEdgeCount().toString()),a&&(a.textContent=this.rendererManager.getFPS().toString())},500)}destroy(){this.rendererManager.dispose(),this.panelManager.dispose(),this.raycasterManager.dispose(),this.edgeTooltipManager.dispose(),this.searchManager&&this.searchManager.dispose(),this.viewToggleManager&&this.viewToggleManager.dispose(),this.forceGraph2D&&this.forceGraph2D.dispose(),this.edgeManager.dispose(),this.nodeManager.dispose(),this.nodeFactory.dispose(),this.materialFactory.dispose(),this.sceneManager.dispose(),this.devControls&&this.devControls.parentNode&&this.devControls.parentNode.removeChild(this.devControls),this.eventCallbacks.clear(),this.initialized=!1}}const ue=["Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta","Theta","Iota","Kappa","Lambda","Mu","Nu","Xi","Omicron","Pi","Rho","Sigma","Tau","Upsilon","Phi","Chi","Psi","Omega","Core","Hub","Node","Link","Point","Vertex"],_=["connects to","links with","relates to","depends on","references","extends","includes","partners with","collaborates with","supports"],fe=[16777215,16750950,16764057,16772829,16746564];function ot(h=30){const e=[],s=[];for(let o=0;o<h;o++){const i=o<ue.length?ue[o]:`Node ${o+1}`;e.push({id:`node-${o}`,label:i,color:fe[o%fe.length],position:{x:(Math.random()-.5)*60,y:(Math.random()-.5)*60,z:(Math.random()-.5)*60}})}for(let o=1;o<h;o++){const i=Math.floor(Math.random()*o);s.push({source:`node-${o}`,target:`node-${i}`,relationship:_[Math.floor(Math.random()*_.length)]})}const t=Math.floor(h*.5);for(let o=0;o<t;o++){const i=Math.floor(Math.random()*h);let a=Math.floor(Math.random()*h);i===a&&(a=(a+1)%h);const r=`node-${i}`,c=`node-${a}`;s.some(u=>u.source===r&&u.target===c||u.source===c&&u.target===r)||s.push({source:r,target:c,relationship:_[Math.floor(Math.random()*_.length)]})}return{nodes:e,edges:s}}function nt(h=1e3){const e=[],s=[],t=Math.ceil(h/50),o=[];for(let i=0;i<t;i++)o.push({x:(Math.random()-.5)*200,y:(Math.random()-.5)*200,z:(Math.random()-.5)*200});for(let i=0;i<h;i++){const a=o[i%t];e.push({id:`node-${i}`,label:`N${i}`,position:{x:a.x+(Math.random()-.5)*40,y:a.y+(Math.random()-.5)*40,z:a.z+(Math.random()-.5)*40}})}for(let i=1;i<h;i++){const a=Math.floor(i/50)*50,r=a===0?Math.floor(Math.random()*i):a+Math.floor(Math.random()*Math.min(i-a,50));s.push({source:`node-${i}`,target:`node-${Math.min(r,i-1)}`,relationship:"links to"})}for(let i=1;i<t;i++){const a=i*50,r=(i-1)*50+Math.floor(Math.random()*50);s.push({source:`node-${a}`,target:`node-${r}`,relationship:"bridges to"})}return{nodes:e,edges:s}}N.DEFAULT_OPTIONS=P,N.ForceGraph3D=it,N.LODLevel=H,N.createEdgeKey=D,N.generateLargeSampleData=nt,N.generateSampleData=ot,N.validateEdgeData=ee,N.validateNodeData=J,Object.defineProperty(N,Symbol.toStringTag,{value:"Module"})});
413
598
  //# sourceMappingURL=force-3d-graph.umd.cjs.map