force-3d-graph 1.3.8 → 1.3.9

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,9 +1,9 @@
1
1
  var it = Object.defineProperty;
2
- var ot = (d, e, s) => e in d ? it(d, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : d[e] = s;
3
- var l = (d, e, s) => ot(d, typeof e != "symbol" ? e + "" : e, s);
4
- import * as x from "three";
5
- import { EventDispatcher as nt, Vector3 as S, MOUSE as j, TOUCH as $, Spherical as Se, Quaternion as ze, Vector2 as k, Ray as at, Plane as rt, MathUtils as lt } from "three";
6
- const P = {
2
+ var nt = (p, e, s) => e in p ? it(p, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : p[e] = s;
3
+ var l = (p, e, s) => nt(p, typeof e != "symbol" ? e + "" : e, s);
4
+ import * as y from "three";
5
+ import { EventDispatcher as ot, Vector3 as k, MOUSE as j, TOUCH as B, Spherical as ze, Quaternion as Pe, Vector2 as P, Ray as at, Plane as rt, MathUtils as lt } from "three";
6
+ const C = {
7
7
  backgroundColor: 657930,
8
8
  cameraPosition: { x: 0, y: 0, z: 80 },
9
9
  cameraFov: 75,
@@ -30,98 +30,108 @@ const P = {
30
30
  showViewToggle: !0,
31
31
  showLegend: !0,
32
32
  targetFPS: 60,
33
- maxVisibleNodes: 1e4
33
+ maxVisibleNodes: 1e4,
34
+ performanceMode: "balanced",
35
+ enableAdaptivePerformance: !0,
36
+ minPixelRatio: 0.6,
37
+ maxPixelRatio: 2,
38
+ labelRenderMode: "adaptive",
39
+ labelDistance: 140,
40
+ disableEdgeInteractionsInLowMode: !0,
41
+ edgeBatchThreshold: 1200,
42
+ enableWorkerPhysics: !0,
43
+ workerPhysicsNodeThreshold: 1500
34
44
  };
35
- var _ = /* @__PURE__ */ ((d) => (d[d.HIGH = 0] = "HIGH", d[d.MEDIUM = 1] = "MEDIUM", d[d.LOW = 2] = "LOW", d))(_ || {});
45
+ var K = /* @__PURE__ */ ((p) => (p[p.HIGH = 0] = "HIGH", p[p.MEDIUM = 1] = "MEDIUM", p[p.LOW = 2] = "LOW", p))(K || {});
36
46
  function ct() {
37
- const d = document.createElement("div");
38
- return d.id = "force-graph-3d-container", d.style.cssText = `
47
+ const p = document.createElement("div");
48
+ return p.id = "force-graph-3d-container", p.style.cssText = `
39
49
  width: 100%;
40
50
  height: 100%;
41
51
  position: absolute;
42
52
  top: 0;
43
53
  left: 0;
44
54
  overflow: hidden;
45
- `, document.body.appendChild(d), d;
55
+ `, document.body.appendChild(p), p;
46
56
  }
47
- function ht(d) {
48
- return d && d instanceof HTMLElement ? d : (console.warn("[ForceGraph3D] No container provided, creating one automatically"), ct());
57
+ function ht(p) {
58
+ return p && p instanceof HTMLElement ? p : (console.warn("[ForceGraph3D] No container provided, creating one automatically"), ct());
49
59
  }
50
- function ke(d) {
51
- const e = d.getBoundingClientRect();
60
+ function Re(p) {
61
+ const e = p.getBoundingClientRect();
52
62
  return {
53
63
  width: e.width || window.innerWidth,
54
64
  height: e.height || window.innerHeight
55
65
  };
56
66
  }
57
- function Fe(d) {
58
- if (!d || typeof d != "object")
67
+ function ce(p) {
68
+ if (!p || typeof p != "object")
59
69
  return console.warn("[ForceGraph3D] Invalid node: must be an object"), !1;
60
- const e = d;
70
+ const e = p;
61
71
  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 && !pt(e.position) ? (console.warn("[ForceGraph3D] Invalid node: position must have x, y, z numbers"), !1) : !0;
62
72
  }
63
- function De(d) {
64
- if (!d || typeof d != "object")
73
+ function he(p) {
74
+ if (!p || typeof p != "object")
65
75
  return console.warn("[ForceGraph3D] Invalid edge: must be an object"), !1;
66
- const e = d;
76
+ const e = p;
67
77
  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;
68
78
  }
69
- function dt(d) {
70
- return typeof d != "string" || d.trim() === "" ? (console.warn("[ForceGraph3D] Invalid node ID: must be a non-empty string"), !1) : !0;
79
+ function dt(p) {
80
+ return typeof p != "string" || p.trim() === "" ? (console.warn("[ForceGraph3D] Invalid node ID: must be a non-empty string"), !1) : !0;
71
81
  }
72
- function pt(d) {
73
- if (!d || typeof d != "object") return !1;
74
- const e = d;
82
+ function pt(p) {
83
+ if (!p || typeof p != "object") return !1;
84
+ const e = p;
75
85
  return typeof e.x == "number" && typeof e.y == "number" && typeof e.z == "number";
76
86
  }
77
- function Dt(d, e) {
78
- return d === e ? `${d}-${e}` : d < e ? `${d}-${e}` : `${e}-${d}`;
87
+ function At(p, e) {
88
+ return p === e ? `${p}-${e}` : p < e ? `${p}-${e}` : `${e}-${p}`;
79
89
  }
80
- const Te = { type: "change" }, le = { type: "start" }, Pe = { type: "end" }, Q = new at(), Re = new rt(), gt = Math.cos(70 * lt.DEG2RAD);
81
- class ut extends nt {
90
+ const Le = { type: "change" }, le = { type: "start" }, Te = { type: "end" }, Q = new at(), Ie = new rt(), gt = Math.cos(70 * lt.DEG2RAD);
91
+ class ut extends ot {
82
92
  constructor(e, s) {
83
- super(), this.object = e, this.domElement = s, this.domElement.style.touchAction = "none", this.enabled = !0, this.target = new S(), this.cursor = new S(), 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 = 0.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: j.ROTATE, MIDDLE: j.DOLLY, RIGHT: j.PAN }, this.touches = { ONE: $.ROTATE, TWO: $.DOLLY_PAN }, this.target0 = this.target.clone(), this.position0 = this.object.position.clone(), this.zoom0 = this.object.zoom, this._domElementKeyEvents = null, this.getPolarAngle = function() {
84
- return r.phi;
93
+ super(), this.object = e, this.domElement = s, this.domElement.style.touchAction = "none", this.enabled = !0, this.target = new k(), this.cursor = new k(), 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 = 0.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: j.ROTATE, MIDDLE: j.DOLLY, RIGHT: j.PAN }, this.touches = { ONE: B.ROTATE, TWO: B.DOLLY_PAN }, this.target0 = this.target.clone(), this.position0 = this.object.position.clone(), this.zoom0 = this.object.zoom, this._domElementKeyEvents = null, this.getPolarAngle = function() {
94
+ return a.phi;
85
95
  }, this.getAzimuthalAngle = function() {
86
- return r.theta;
96
+ return a.theta;
87
97
  }, this.getDistance = function() {
88
98
  return this.object.position.distanceTo(this.target);
89
- }, this.listenToKeyEvents = function(a) {
90
- a.addEventListener("keydown", ae), this._domElementKeyEvents = a;
99
+ }, this.listenToKeyEvents = function(r) {
100
+ r.addEventListener("keydown", ae), this._domElementKeyEvents = r;
91
101
  }, this.stopListenToKeyEvents = function() {
92
102
  this._domElementKeyEvents.removeEventListener("keydown", ae), this._domElementKeyEvents = null;
93
103
  }, this.saveState = function() {
94
104
  t.target0.copy(t.target), t.position0.copy(t.object.position), t.zoom0 = t.object.zoom;
95
105
  }, this.reset = function() {
96
- t.target.copy(t.target0), t.object.position.copy(t.position0), t.object.zoom = t.zoom0, t.object.updateProjectionMatrix(), t.dispatchEvent(Te), t.update(), o = i.NONE;
106
+ t.target.copy(t.target0), t.object.position.copy(t.position0), t.object.zoom = t.zoom0, t.object.updateProjectionMatrix(), t.dispatchEvent(Le), t.update(), n = i.NONE;
97
107
  }, this.update = function() {
98
- const a = new S(), g = new ze().setFromUnitVectors(e.up, new S(0, 1, 0)), v = g.clone().invert(), M = new S(), C = new ze(), F = new S(), z = 2 * Math.PI;
108
+ const r = new k(), g = new Pe().setFromUnitVectors(e.up, new k(0, 1, 0)), v = g.clone().invert(), w = new k(), S = new Pe(), D = new k(), z = 2 * Math.PI;
99
109
  return function(st = null) {
100
- const Ne = t.object.position;
101
- a.copy(Ne).sub(t.target), a.applyQuaternion(g), r.setFromVector3(a), t.autoRotate && o === i.NONE && Y(He(st)), t.enableDamping ? (r.theta += h.theta * t.dampingFactor, r.phi += h.phi * t.dampingFactor) : (r.theta += h.theta, r.phi += h.phi);
102
- let L = t.minAzimuthAngle, I = t.maxAzimuthAngle;
103
- isFinite(L) && isFinite(I) && (L < -Math.PI ? L += z : L > Math.PI && (L -= z), I < -Math.PI ? I += z : I > Math.PI && (I -= z), 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(p, t.dampingFactor) : t.target.add(p), t.target.sub(t.cursor), t.target.clampLength(t.minTargetRadius, t.maxTargetRadius), t.target.add(t.cursor), t.zoomToCursor && D || t.object.isOrthographicCamera ? r.radius = oe(r.radius) : r.radius = oe(r.radius * c), a.setFromSpherical(r), a.applyQuaternion(v), Ne.copy(t.target).add(a), t.object.lookAt(t.target), t.enableDamping === !0 ? (h.theta *= 1 - t.dampingFactor, h.phi *= 1 - t.dampingFactor, p.multiplyScalar(1 - t.dampingFactor)) : (h.set(0, 0, 0), p.set(0, 0, 0));
110
+ const ke = t.object.position;
111
+ r.copy(ke).sub(t.target), r.applyQuaternion(g), a.setFromVector3(r), t.autoRotate && n === i.NONE && $(Ae(st)), t.enableDamping ? (a.theta += c.theta * t.dampingFactor, a.phi += c.phi * t.dampingFactor) : (a.theta += c.theta, a.phi += c.phi);
112
+ let T = t.minAzimuthAngle, I = t.maxAzimuthAngle;
113
+ isFinite(T) && isFinite(I) && (T < -Math.PI ? T += z : T > Math.PI && (T -= z), I < -Math.PI ? I += z : I > Math.PI && (I -= z), T <= I ? a.theta = Math.max(T, Math.min(I, a.theta)) : a.theta = a.theta > (T + I) / 2 ? Math.max(T, a.theta) : Math.min(I, a.theta)), a.phi = Math.max(t.minPolarAngle, Math.min(t.maxPolarAngle, a.phi)), a.makeSafe(), t.enableDamping === !0 ? t.target.addScaledVector(d, t.dampingFactor) : t.target.add(d), t.target.sub(t.cursor), t.target.clampLength(t.minTargetRadius, t.maxTargetRadius), t.target.add(t.cursor), t.zoomToCursor && F || t.object.isOrthographicCamera ? a.radius = ne(a.radius) : a.radius = ne(a.radius * h), r.setFromSpherical(a), r.applyQuaternion(v), ke.copy(t.target).add(r), t.object.lookAt(t.target), t.enableDamping === !0 ? (c.theta *= 1 - t.dampingFactor, c.phi *= 1 - t.dampingFactor, d.multiplyScalar(1 - t.dampingFactor)) : (c.set(0, 0, 0), d.set(0, 0, 0));
104
114
  let re = !1;
105
- if (t.zoomToCursor && D) {
106
- let K = null;
115
+ if (t.zoomToCursor && F) {
116
+ let W = null;
107
117
  if (t.object.isPerspectiveCamera) {
108
- const U = a.length();
109
- K = oe(U * c);
110
- const Z = U - K;
118
+ const U = r.length();
119
+ W = ne(U * h);
120
+ const Z = U - W;
111
121
  t.object.position.addScaledVector(G, Z), t.object.updateMatrixWorld();
112
122
  } else if (t.object.isOrthographicCamera) {
113
- const U = new S(T.x, T.y, 0);
114
- U.unproject(t.object), t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom / c)), t.object.updateProjectionMatrix(), re = !0;
115
- const Z = new S(T.x, T.y, 0);
116
- Z.unproject(t.object), t.object.position.sub(Z).add(U), t.object.updateMatrixWorld(), K = a.length();
123
+ const U = new k(R.x, R.y, 0);
124
+ U.unproject(t.object), t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom / h)), t.object.updateProjectionMatrix(), re = !0;
125
+ const Z = new k(R.x, R.y, 0);
126
+ Z.unproject(t.object), t.object.position.sub(Z).add(U), t.object.updateMatrixWorld(), W = r.length();
117
127
  } else
118
128
  console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."), t.zoomToCursor = !1;
119
- K !== null && (this.screenSpacePanning ? t.target.set(0, 0, -1).transformDirection(t.object.matrix).multiplyScalar(K).add(t.object.position) : (Q.origin.copy(t.object.position), Q.direction.set(0, 0, -1).transformDirection(t.object.matrix), Math.abs(t.object.up.dot(Q.direction)) < gt ? e.lookAt(t.target) : (Re.setFromNormalAndCoplanarPoint(t.object.up, t.target), Q.intersectPlane(Re, t.target))));
120
- } else t.object.isOrthographicCamera && (t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom / c)), t.object.updateProjectionMatrix(), re = !0);
121
- return c = 1, D = !1, re || M.distanceToSquared(t.object.position) > n || 8 * (1 - C.dot(t.object.quaternion)) > n || F.distanceToSquared(t.target) > 0 ? (t.dispatchEvent(Te), M.copy(t.object.position), C.copy(t.object.quaternion), F.copy(t.target), !0) : !1;
129
+ W !== null && (this.screenSpacePanning ? t.target.set(0, 0, -1).transformDirection(t.object.matrix).multiplyScalar(W).add(t.object.position) : (Q.origin.copy(t.object.position), Q.direction.set(0, 0, -1).transformDirection(t.object.matrix), Math.abs(t.object.up.dot(Q.direction)) < gt ? e.lookAt(t.target) : (Ie.setFromNormalAndCoplanarPoint(t.object.up, t.target), Q.intersectPlane(Ie, t.target))));
130
+ } else t.object.isOrthographicCamera && (t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom / h)), t.object.updateProjectionMatrix(), re = !0);
131
+ return h = 1, F = !1, re || w.distanceToSquared(t.object.position) > o || 8 * (1 - S.dot(t.object.quaternion)) > o || D.distanceToSquared(t.target) > 0 ? (t.dispatchEvent(Le), w.copy(t.object.position), S.copy(t.object.quaternion), D.copy(t.target), !0) : !1;
122
132
  };
123
133
  }(), this.dispose = function() {
124
- t.domElement.removeEventListener("contextmenu", Ee), t.domElement.removeEventListener("pointerdown", ve), t.domElement.removeEventListener("pointercancel", B), t.domElement.removeEventListener("wheel", we), t.domElement.removeEventListener("pointermove", ne), t.domElement.removeEventListener("pointerup", B), t._domElementKeyEvents !== null && (t._domElementKeyEvents.removeEventListener("keydown", ae), t._domElementKeyEvents = null);
134
+ t.domElement.removeEventListener("contextmenu", Se), t.domElement.removeEventListener("pointerdown", we), t.domElement.removeEventListener("pointercancel", Y), t.domElement.removeEventListener("wheel", Ee), t.domElement.removeEventListener("pointermove", oe), t.domElement.removeEventListener("pointerup", Y), t._domElementKeyEvents !== null && (t._domElementKeyEvents.removeEventListener("keydown", ae), t._domElementKeyEvents = null);
125
135
  };
126
136
  const t = this, i = {
127
137
  NONE: -1,
@@ -133,175 +143,175 @@ class ut extends nt {
133
143
  TOUCH_DOLLY_PAN: 5,
134
144
  TOUCH_DOLLY_ROTATE: 6
135
145
  };
136
- let o = i.NONE;
137
- const n = 1e-6, r = new Se(), h = new Se();
138
- let c = 1;
139
- const p = new S(), f = new k(), m = new k(), u = new k(), y = new k(), b = new k(), w = new k(), N = new k(), O = new k(), R = new k(), G = new S(), T = new k();
140
- let D = !1;
141
- const E = [], V = {};
146
+ let n = i.NONE;
147
+ const o = 1e-6, a = new ze(), c = new ze();
148
+ let h = 1;
149
+ const d = new k(), f = new P(), m = new P(), u = new P(), b = new P(), x = new P(), M = new P(), N = new P(), O = new P(), L = new P(), G = new k(), R = new P();
150
+ let F = !1;
151
+ const E = [], _ = {};
142
152
  let te = !1;
143
- function He(a) {
144
- return a !== null ? 2 * Math.PI / 60 * t.autoRotateSpeed * a : 2 * Math.PI / 60 / 60 * t.autoRotateSpeed;
153
+ function Ae(r) {
154
+ return r !== null ? 2 * Math.PI / 60 * t.autoRotateSpeed * r : 2 * Math.PI / 60 / 60 * t.autoRotateSpeed;
145
155
  }
146
- function q(a) {
147
- const g = Math.abs(a * 0.01);
156
+ function V(r) {
157
+ const g = Math.abs(r * 0.01);
148
158
  return Math.pow(0.95, t.zoomSpeed * g);
149
159
  }
150
- function Y(a) {
151
- h.theta -= a;
160
+ function $(r) {
161
+ c.theta -= r;
152
162
  }
153
- function W(a) {
154
- h.phi -= a;
163
+ function X(r) {
164
+ c.phi -= r;
155
165
  }
156
- const ce = function() {
157
- const a = new S();
158
- return function(v, M) {
159
- a.setFromMatrixColumn(M, 0), a.multiplyScalar(-v), p.add(a);
166
+ const de = function() {
167
+ const r = new k();
168
+ return function(v, w) {
169
+ r.setFromMatrixColumn(w, 0), r.multiplyScalar(-v), d.add(r);
160
170
  };
161
- }(), he = function() {
162
- const a = new S();
163
- return function(v, M) {
164
- t.screenSpacePanning === !0 ? a.setFromMatrixColumn(M, 1) : (a.setFromMatrixColumn(M, 0), a.crossVectors(t.object.up, a)), a.multiplyScalar(v), p.add(a);
171
+ }(), pe = function() {
172
+ const r = new k();
173
+ return function(v, w) {
174
+ t.screenSpacePanning === !0 ? r.setFromMatrixColumn(w, 1) : (r.setFromMatrixColumn(w, 0), r.crossVectors(t.object.up, r)), r.multiplyScalar(v), d.add(r);
165
175
  };
166
- }(), H = function() {
167
- const a = new S();
168
- return function(v, M) {
169
- const C = t.domElement;
176
+ }(), A = function() {
177
+ const r = new k();
178
+ return function(v, w) {
179
+ const S = t.domElement;
170
180
  if (t.object.isPerspectiveCamera) {
171
- const F = t.object.position;
172
- a.copy(F).sub(t.target);
173
- let z = a.length();
174
- z *= Math.tan(t.object.fov / 2 * Math.PI / 180), ce(2 * v * z / C.clientHeight, t.object.matrix), he(2 * M * z / C.clientHeight, t.object.matrix);
175
- } else t.object.isOrthographicCamera ? (ce(v * (t.object.right - t.object.left) / t.object.zoom / C.clientWidth, t.object.matrix), he(M * (t.object.top - t.object.bottom) / t.object.zoom / C.clientHeight, t.object.matrix)) : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."), t.enablePan = !1);
181
+ const D = t.object.position;
182
+ r.copy(D).sub(t.target);
183
+ let z = r.length();
184
+ z *= Math.tan(t.object.fov / 2 * Math.PI / 180), de(2 * v * z / S.clientHeight, t.object.matrix), pe(2 * w * z / S.clientHeight, t.object.matrix);
185
+ } else t.object.isOrthographicCamera ? (de(v * (t.object.right - t.object.left) / t.object.zoom / S.clientWidth, t.object.matrix), pe(w * (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);
176
186
  };
177
187
  }();
178
- function se(a) {
179
- t.object.isPerspectiveCamera || t.object.isOrthographicCamera ? c /= a : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), t.enableZoom = !1);
188
+ function se(r) {
189
+ t.object.isPerspectiveCamera || t.object.isOrthographicCamera ? h /= r : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), t.enableZoom = !1);
180
190
  }
181
- function de(a) {
182
- t.object.isPerspectiveCamera || t.object.isOrthographicCamera ? c *= a : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), t.enableZoom = !1);
191
+ function ge(r) {
192
+ t.object.isPerspectiveCamera || t.object.isOrthographicCamera ? h *= r : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), t.enableZoom = !1);
183
193
  }
184
- function ie(a, g) {
194
+ function ie(r, g) {
185
195
  if (!t.zoomToCursor)
186
196
  return;
187
- D = !0;
188
- const v = t.domElement.getBoundingClientRect(), M = a - v.left, C = g - v.top, F = v.width, z = v.height;
189
- T.x = M / F * 2 - 1, T.y = -(C / z) * 2 + 1, G.set(T.x, T.y, 1).unproject(t.object).sub(t.object.position).normalize();
197
+ F = !0;
198
+ const v = t.domElement.getBoundingClientRect(), w = r - v.left, S = g - v.top, D = v.width, z = v.height;
199
+ R.x = w / D * 2 - 1, R.y = -(S / z) * 2 + 1, G.set(R.x, R.y, 1).unproject(t.object).sub(t.object.position).normalize();
190
200
  }
191
- function oe(a) {
192
- return Math.max(t.minDistance, Math.min(t.maxDistance, a));
201
+ function ne(r) {
202
+ return Math.max(t.minDistance, Math.min(t.maxDistance, r));
193
203
  }
194
- function pe(a) {
195
- f.set(a.clientX, a.clientY);
204
+ function ue(r) {
205
+ f.set(r.clientX, r.clientY);
196
206
  }
197
- function Ae(a) {
198
- ie(a.clientX, a.clientX), N.set(a.clientX, a.clientY);
207
+ function He(r) {
208
+ ie(r.clientX, r.clientX), N.set(r.clientX, r.clientY);
199
209
  }
200
- function ge(a) {
201
- y.set(a.clientX, a.clientY);
210
+ function fe(r) {
211
+ b.set(r.clientX, r.clientY);
202
212
  }
203
- function je(a) {
204
- m.set(a.clientX, a.clientY), u.subVectors(m, f).multiplyScalar(t.rotateSpeed);
213
+ function je(r) {
214
+ m.set(r.clientX, r.clientY), u.subVectors(m, f).multiplyScalar(t.rotateSpeed);
205
215
  const g = t.domElement;
206
- Y(2 * Math.PI * u.x / g.clientHeight), W(2 * Math.PI * u.y / g.clientHeight), f.copy(m), t.update();
216
+ $(2 * Math.PI * u.x / g.clientHeight), X(2 * Math.PI * u.y / g.clientHeight), f.copy(m), t.update();
207
217
  }
208
- function $e(a) {
209
- O.set(a.clientX, a.clientY), R.subVectors(O, N), R.y > 0 ? se(q(R.y)) : R.y < 0 && de(q(R.y)), N.copy(O), t.update();
218
+ function Be(r) {
219
+ O.set(r.clientX, r.clientY), L.subVectors(O, N), L.y > 0 ? se(V(L.y)) : L.y < 0 && ge(V(L.y)), N.copy(O), t.update();
210
220
  }
211
- function Ge(a) {
212
- b.set(a.clientX, a.clientY), w.subVectors(b, y).multiplyScalar(t.panSpeed), H(w.x, w.y), y.copy(b), t.update();
221
+ function Ge(r) {
222
+ x.set(r.clientX, r.clientY), M.subVectors(x, b).multiplyScalar(t.panSpeed), A(M.x, M.y), b.copy(x), t.update();
213
223
  }
214
- function Ye(a) {
215
- ie(a.clientX, a.clientY), a.deltaY < 0 ? de(q(a.deltaY)) : a.deltaY > 0 && se(q(a.deltaY)), t.update();
224
+ function $e(r) {
225
+ ie(r.clientX, r.clientY), r.deltaY < 0 ? ge(V(r.deltaY)) : r.deltaY > 0 && se(V(r.deltaY)), t.update();
216
226
  }
217
- function Be(a) {
227
+ function Ye(r) {
218
228
  let g = !1;
219
- switch (a.code) {
229
+ switch (r.code) {
220
230
  case t.keys.UP:
221
- a.ctrlKey || a.metaKey || a.shiftKey ? W(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : H(0, t.keyPanSpeed), g = !0;
231
+ r.ctrlKey || r.metaKey || r.shiftKey ? X(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(0, t.keyPanSpeed), g = !0;
222
232
  break;
223
233
  case t.keys.BOTTOM:
224
- a.ctrlKey || a.metaKey || a.shiftKey ? W(-2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : H(0, -t.keyPanSpeed), g = !0;
234
+ r.ctrlKey || r.metaKey || r.shiftKey ? X(-2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(0, -t.keyPanSpeed), g = !0;
225
235
  break;
226
236
  case t.keys.LEFT:
227
- a.ctrlKey || a.metaKey || a.shiftKey ? Y(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : H(t.keyPanSpeed, 0), g = !0;
237
+ r.ctrlKey || r.metaKey || r.shiftKey ? $(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(t.keyPanSpeed, 0), g = !0;
228
238
  break;
229
239
  case t.keys.RIGHT:
230
- a.ctrlKey || a.metaKey || a.shiftKey ? Y(-2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : H(-t.keyPanSpeed, 0), g = !0;
240
+ r.ctrlKey || r.metaKey || r.shiftKey ? $(-2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(-t.keyPanSpeed, 0), g = !0;
231
241
  break;
232
242
  }
233
- g && (a.preventDefault(), t.update());
243
+ g && (r.preventDefault(), t.update());
234
244
  }
235
- function ue(a) {
245
+ function me(r) {
236
246
  if (E.length === 1)
237
- f.set(a.pageX, a.pageY);
247
+ f.set(r.pageX, r.pageY);
238
248
  else {
239
- const g = A(a), v = 0.5 * (a.pageX + g.x), M = 0.5 * (a.pageY + g.y);
240
- f.set(v, M);
249
+ const g = H(r), v = 0.5 * (r.pageX + g.x), w = 0.5 * (r.pageY + g.y);
250
+ f.set(v, w);
241
251
  }
242
252
  }
243
- function fe(a) {
253
+ function ye(r) {
244
254
  if (E.length === 1)
245
- y.set(a.pageX, a.pageY);
255
+ b.set(r.pageX, r.pageY);
246
256
  else {
247
- const g = A(a), v = 0.5 * (a.pageX + g.x), M = 0.5 * (a.pageY + g.y);
248
- y.set(v, M);
257
+ const g = H(r), v = 0.5 * (r.pageX + g.x), w = 0.5 * (r.pageY + g.y);
258
+ b.set(v, w);
249
259
  }
250
260
  }
251
- function me(a) {
252
- const g = A(a), v = a.pageX - g.x, M = a.pageY - g.y, C = Math.sqrt(v * v + M * M);
253
- N.set(0, C);
261
+ function be(r) {
262
+ const g = H(r), v = r.pageX - g.x, w = r.pageY - g.y, S = Math.sqrt(v * v + w * w);
263
+ N.set(0, S);
254
264
  }
255
- function Ke(a) {
256
- t.enableZoom && me(a), t.enablePan && fe(a);
265
+ function We(r) {
266
+ t.enableZoom && be(r), t.enablePan && ye(r);
257
267
  }
258
- function Ue(a) {
259
- t.enableZoom && me(a), t.enableRotate && ue(a);
268
+ function Ue(r) {
269
+ t.enableZoom && be(r), t.enableRotate && me(r);
260
270
  }
261
- function ye(a) {
271
+ function xe(r) {
262
272
  if (E.length == 1)
263
- m.set(a.pageX, a.pageY);
273
+ m.set(r.pageX, r.pageY);
264
274
  else {
265
- const v = A(a), M = 0.5 * (a.pageX + v.x), C = 0.5 * (a.pageY + v.y);
266
- m.set(M, C);
275
+ const v = H(r), w = 0.5 * (r.pageX + v.x), S = 0.5 * (r.pageY + v.y);
276
+ m.set(w, S);
267
277
  }
268
278
  u.subVectors(m, f).multiplyScalar(t.rotateSpeed);
269
279
  const g = t.domElement;
270
- Y(2 * Math.PI * u.x / g.clientHeight), W(2 * Math.PI * u.y / g.clientHeight), f.copy(m);
280
+ $(2 * Math.PI * u.x / g.clientHeight), X(2 * Math.PI * u.y / g.clientHeight), f.copy(m);
271
281
  }
272
- function xe(a) {
282
+ function ve(r) {
273
283
  if (E.length === 1)
274
- b.set(a.pageX, a.pageY);
284
+ x.set(r.pageX, r.pageY);
275
285
  else {
276
- const g = A(a), v = 0.5 * (a.pageX + g.x), M = 0.5 * (a.pageY + g.y);
277
- b.set(v, M);
286
+ const g = H(r), v = 0.5 * (r.pageX + g.x), w = 0.5 * (r.pageY + g.y);
287
+ x.set(v, w);
278
288
  }
279
- w.subVectors(b, y).multiplyScalar(t.panSpeed), H(w.x, w.y), y.copy(b);
289
+ M.subVectors(x, b).multiplyScalar(t.panSpeed), A(M.x, M.y), b.copy(x);
280
290
  }
281
- function be(a) {
282
- const g = A(a), v = a.pageX - g.x, M = a.pageY - g.y, C = Math.sqrt(v * v + M * M);
283
- O.set(0, C), R.set(0, Math.pow(O.y / N.y, t.zoomSpeed)), se(R.y), N.copy(O);
284
- const F = (a.pageX + g.x) * 0.5, z = (a.pageY + g.y) * 0.5;
285
- ie(F, z);
291
+ function Me(r) {
292
+ const g = H(r), v = r.pageX - g.x, w = r.pageY - g.y, S = Math.sqrt(v * v + w * w);
293
+ O.set(0, S), L.set(0, Math.pow(O.y / N.y, t.zoomSpeed)), se(L.y), N.copy(O);
294
+ const D = (r.pageX + g.x) * 0.5, z = (r.pageY + g.y) * 0.5;
295
+ ie(D, z);
286
296
  }
287
- function _e(a) {
288
- t.enableZoom && be(a), t.enablePan && xe(a);
297
+ function Ke(r) {
298
+ t.enableZoom && Me(r), t.enablePan && ve(r);
289
299
  }
290
- function Xe(a) {
291
- t.enableZoom && be(a), t.enableRotate && ye(a);
300
+ function qe(r) {
301
+ t.enableZoom && Me(r), t.enableRotate && xe(r);
292
302
  }
293
- function ve(a) {
294
- t.enabled !== !1 && (E.length === 0 && (t.domElement.setPointerCapture(a.pointerId), t.domElement.addEventListener("pointermove", ne), t.domElement.addEventListener("pointerup", B)), et(a), a.pointerType === "touch" ? Qe(a) : Ve(a));
303
+ function we(r) {
304
+ t.enabled !== !1 && (E.length === 0 && (t.domElement.setPointerCapture(r.pointerId), t.domElement.addEventListener("pointermove", oe), t.domElement.addEventListener("pointerup", Y)), et(r), r.pointerType === "touch" ? Qe(r) : _e(r));
295
305
  }
296
- function ne(a) {
297
- t.enabled !== !1 && (a.pointerType === "touch" ? Je(a) : qe(a));
306
+ function oe(r) {
307
+ t.enabled !== !1 && (r.pointerType === "touch" ? Je(r) : Ve(r));
298
308
  }
299
- function B(a) {
300
- tt(a), E.length === 0 && (t.domElement.releasePointerCapture(a.pointerId), t.domElement.removeEventListener("pointermove", ne), t.domElement.removeEventListener("pointerup", B)), t.dispatchEvent(Pe), o = i.NONE;
309
+ function Y(r) {
310
+ tt(r), E.length === 0 && (t.domElement.releasePointerCapture(r.pointerId), t.domElement.removeEventListener("pointermove", oe), t.domElement.removeEventListener("pointerup", Y)), t.dispatchEvent(Te), n = i.NONE;
301
311
  }
302
- function Ve(a) {
312
+ function _e(r) {
303
313
  let g;
304
- switch (a.button) {
314
+ switch (r.button) {
305
315
  case 0:
306
316
  g = t.mouseButtons.LEFT;
307
317
  break;
@@ -317,55 +327,55 @@ class ut extends nt {
317
327
  switch (g) {
318
328
  case j.DOLLY:
319
329
  if (t.enableZoom === !1) return;
320
- Ae(a), o = i.DOLLY;
330
+ He(r), n = i.DOLLY;
321
331
  break;
322
332
  case j.ROTATE:
323
- if (a.ctrlKey || a.metaKey || a.shiftKey) {
333
+ if (r.ctrlKey || r.metaKey || r.shiftKey) {
324
334
  if (t.enablePan === !1) return;
325
- ge(a), o = i.PAN;
335
+ fe(r), n = i.PAN;
326
336
  } else {
327
337
  if (t.enableRotate === !1) return;
328
- pe(a), o = i.ROTATE;
338
+ ue(r), n = i.ROTATE;
329
339
  }
330
340
  break;
331
341
  case j.PAN:
332
- if (a.ctrlKey || a.metaKey || a.shiftKey) {
342
+ if (r.ctrlKey || r.metaKey || r.shiftKey) {
333
343
  if (t.enableRotate === !1) return;
334
- pe(a), o = i.ROTATE;
344
+ ue(r), n = i.ROTATE;
335
345
  } else {
336
346
  if (t.enablePan === !1) return;
337
- ge(a), o = i.PAN;
347
+ fe(r), n = i.PAN;
338
348
  }
339
349
  break;
340
350
  default:
341
- o = i.NONE;
351
+ n = i.NONE;
342
352
  }
343
- o !== i.NONE && t.dispatchEvent(le);
353
+ n !== i.NONE && t.dispatchEvent(le);
344
354
  }
345
- function qe(a) {
346
- switch (o) {
355
+ function Ve(r) {
356
+ switch (n) {
347
357
  case i.ROTATE:
348
358
  if (t.enableRotate === !1) return;
349
- je(a);
359
+ je(r);
350
360
  break;
351
361
  case i.DOLLY:
352
362
  if (t.enableZoom === !1) return;
353
- $e(a);
363
+ Be(r);
354
364
  break;
355
365
  case i.PAN:
356
366
  if (t.enablePan === !1) return;
357
- Ge(a);
367
+ Ge(r);
358
368
  break;
359
369
  }
360
370
  }
361
- function we(a) {
362
- t.enabled === !1 || t.enableZoom === !1 || o !== i.NONE || (a.preventDefault(), t.dispatchEvent(le), Ye(We(a)), t.dispatchEvent(Pe));
371
+ function Ee(r) {
372
+ t.enabled === !1 || t.enableZoom === !1 || n !== i.NONE || (r.preventDefault(), t.dispatchEvent(le), $e(Xe(r)), t.dispatchEvent(Te));
363
373
  }
364
- function We(a) {
365
- const g = a.deltaMode, v = {
366
- clientX: a.clientX,
367
- clientY: a.clientY,
368
- deltaY: a.deltaY
374
+ function Xe(r) {
375
+ const g = r.deltaMode, v = {
376
+ clientX: r.clientX,
377
+ clientY: r.clientY,
378
+ deltaY: r.deltaY
369
379
  };
370
380
  switch (g) {
371
381
  case 1:
@@ -375,97 +385,97 @@ class ut extends nt {
375
385
  v.deltaY *= 100;
376
386
  break;
377
387
  }
378
- return a.ctrlKey && !te && (v.deltaY *= 10), v;
388
+ return r.ctrlKey && !te && (v.deltaY *= 10), v;
379
389
  }
380
- function Ze(a) {
381
- a.key === "Control" && (te = !0, document.addEventListener("keyup", Me, { passive: !0, capture: !0 }));
390
+ function Ze(r) {
391
+ r.key === "Control" && (te = !0, document.addEventListener("keyup", Ce, { passive: !0, capture: !0 }));
382
392
  }
383
- function Me(a) {
384
- a.key === "Control" && (te = !1, document.removeEventListener("keyup", Me, { passive: !0, capture: !0 }));
393
+ function Ce(r) {
394
+ r.key === "Control" && (te = !1, document.removeEventListener("keyup", Ce, { passive: !0, capture: !0 }));
385
395
  }
386
- function ae(a) {
387
- t.enabled === !1 || t.enablePan === !1 || Be(a);
396
+ function ae(r) {
397
+ t.enabled === !1 || t.enablePan === !1 || Ye(r);
388
398
  }
389
- function Qe(a) {
390
- switch (Ce(a), E.length) {
399
+ function Qe(r) {
400
+ switch (Ne(r), E.length) {
391
401
  case 1:
392
402
  switch (t.touches.ONE) {
393
- case $.ROTATE:
403
+ case B.ROTATE:
394
404
  if (t.enableRotate === !1) return;
395
- ue(a), o = i.TOUCH_ROTATE;
405
+ me(r), n = i.TOUCH_ROTATE;
396
406
  break;
397
- case $.PAN:
407
+ case B.PAN:
398
408
  if (t.enablePan === !1) return;
399
- fe(a), o = i.TOUCH_PAN;
409
+ ye(r), n = i.TOUCH_PAN;
400
410
  break;
401
411
  default:
402
- o = i.NONE;
412
+ n = i.NONE;
403
413
  }
404
414
  break;
405
415
  case 2:
406
416
  switch (t.touches.TWO) {
407
- case $.DOLLY_PAN:
417
+ case B.DOLLY_PAN:
408
418
  if (t.enableZoom === !1 && t.enablePan === !1) return;
409
- Ke(a), o = i.TOUCH_DOLLY_PAN;
419
+ We(r), n = i.TOUCH_DOLLY_PAN;
410
420
  break;
411
- case $.DOLLY_ROTATE:
421
+ case B.DOLLY_ROTATE:
412
422
  if (t.enableZoom === !1 && t.enableRotate === !1) return;
413
- Ue(a), o = i.TOUCH_DOLLY_ROTATE;
423
+ Ue(r), n = i.TOUCH_DOLLY_ROTATE;
414
424
  break;
415
425
  default:
416
- o = i.NONE;
426
+ n = i.NONE;
417
427
  }
418
428
  break;
419
429
  default:
420
- o = i.NONE;
430
+ n = i.NONE;
421
431
  }
422
- o !== i.NONE && t.dispatchEvent(le);
432
+ n !== i.NONE && t.dispatchEvent(le);
423
433
  }
424
- function Je(a) {
425
- switch (Ce(a), o) {
434
+ function Je(r) {
435
+ switch (Ne(r), n) {
426
436
  case i.TOUCH_ROTATE:
427
437
  if (t.enableRotate === !1) return;
428
- ye(a), t.update();
438
+ xe(r), t.update();
429
439
  break;
430
440
  case i.TOUCH_PAN:
431
441
  if (t.enablePan === !1) return;
432
- xe(a), t.update();
442
+ ve(r), t.update();
433
443
  break;
434
444
  case i.TOUCH_DOLLY_PAN:
435
445
  if (t.enableZoom === !1 && t.enablePan === !1) return;
436
- _e(a), t.update();
446
+ Ke(r), t.update();
437
447
  break;
438
448
  case i.TOUCH_DOLLY_ROTATE:
439
449
  if (t.enableZoom === !1 && t.enableRotate === !1) return;
440
- Xe(a), t.update();
450
+ qe(r), t.update();
441
451
  break;
442
452
  default:
443
- o = i.NONE;
453
+ n = i.NONE;
444
454
  }
445
455
  }
446
- function Ee(a) {
447
- t.enabled !== !1 && a.preventDefault();
456
+ function Se(r) {
457
+ t.enabled !== !1 && r.preventDefault();
448
458
  }
449
- function et(a) {
450
- E.push(a.pointerId);
459
+ function et(r) {
460
+ E.push(r.pointerId);
451
461
  }
452
- function tt(a) {
453
- delete V[a.pointerId];
462
+ function tt(r) {
463
+ delete _[r.pointerId];
454
464
  for (let g = 0; g < E.length; g++)
455
- if (E[g] == a.pointerId) {
465
+ if (E[g] == r.pointerId) {
456
466
  E.splice(g, 1);
457
467
  return;
458
468
  }
459
469
  }
460
- function Ce(a) {
461
- let g = V[a.pointerId];
462
- g === void 0 && (g = new k(), V[a.pointerId] = g), g.set(a.pageX, a.pageY);
470
+ function Ne(r) {
471
+ let g = _[r.pointerId];
472
+ g === void 0 && (g = new P(), _[r.pointerId] = g), g.set(r.pageX, r.pageY);
463
473
  }
464
- function A(a) {
465
- const g = a.pointerId === E[0] ? E[1] : E[0];
466
- return V[g];
474
+ function H(r) {
475
+ const g = r.pointerId === E[0] ? E[1] : E[0];
476
+ return _[g];
467
477
  }
468
- t.domElement.addEventListener("contextmenu", Ee), t.domElement.addEventListener("pointerdown", ve), t.domElement.addEventListener("pointercancel", B), t.domElement.addEventListener("wheel", we, { passive: !1 }), document.addEventListener("keydown", Ze, { passive: !0, capture: !0 }), this.update();
478
+ t.domElement.addEventListener("contextmenu", Se), t.domElement.addEventListener("pointerdown", we), t.domElement.addEventListener("pointercancel", Y), t.domElement.addEventListener("wheel", Ee, { passive: !1 }), document.addEventListener("keydown", Ze, { passive: !0, capture: !0 }), this.update();
469
479
  }
470
480
  }
471
481
  class ft {
@@ -476,42 +486,43 @@ class ft {
476
486
  l(this, "controls");
477
487
  l(this, "container");
478
488
  l(this, "resizeHandler");
479
- this.container = e, this.scene = new x.Scene(), this.scene.background = new x.Color(
489
+ l(this, "maxPixelRatio");
490
+ this.container = e, this.maxPixelRatio = s.maxPixelRatio ?? 2, this.scene = new y.Scene(), this.scene.background = new y.Color(
480
491
  s.backgroundColor ?? 657930
481
492
  );
482
- const { width: t, height: i } = ke(e), o = s.cameraFov ?? 75;
483
- this.camera = new x.PerspectiveCamera(o, t / i, 0.1, 2e3);
484
- const n = s.cameraPosition ?? { x: 0, y: 0, z: 80 };
485
- this.camera.position.set(n.x, n.y, n.z), this.renderer = new x.WebGLRenderer({
493
+ const { width: t, height: i } = Re(e), n = s.cameraFov ?? 75;
494
+ this.camera = new y.PerspectiveCamera(n, t / i, 0.1, 2e3);
495
+ const o = s.cameraPosition ?? { x: 0, y: 0, z: 80 };
496
+ this.camera.position.set(o.x, o.y, o.z), this.renderer = new y.WebGLRenderer({
486
497
  antialias: !0,
487
498
  alpha: !0,
488
499
  powerPreference: "high-performance"
489
- }), this.renderer.setSize(t, i), this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)), this.renderer.toneMapping = x.ACESFilmicToneMapping, this.renderer.toneMappingExposure = 1, this.renderer.shadowMap.enabled = !0, this.renderer.shadowMap.type = x.PCFSoftShadowMap, e.appendChild(this.renderer.domElement), this.controls = new ut(this.camera, this.renderer.domElement), this.controls.enableDamping = !0, this.controls.dampingFactor = 0.05, this.controls.rotateSpeed = 0.8, this.controls.zoomSpeed = 1.2, this.controls.minDistance = 10, this.controls.maxDistance = 2e3, this.setupLighting(), this.resizeHandler = this.onWindowResize.bind(this), window.addEventListener("resize", this.resizeHandler);
500
+ }), this.renderer.setSize(t, i), this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, this.maxPixelRatio)), 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 ut(this.camera, this.renderer.domElement), this.controls.enableDamping = !0, this.controls.dampingFactor = 0.05, this.controls.rotateSpeed = 0.8, this.controls.zoomSpeed = 1.2, this.controls.minDistance = 10, this.controls.maxDistance = 2e3, this.setupLighting(), this.resizeHandler = this.onWindowResize.bind(this), window.addEventListener("resize", this.resizeHandler);
490
501
  }
491
502
  /**
492
503
  * Sets up scene lighting for gradient glass on dark background
493
504
  */
494
505
  setupLighting() {
495
- const e = new x.AmbientLight(16777215, 0.4);
506
+ const e = new y.AmbientLight(16777215, 0.4);
496
507
  this.scene.add(e);
497
- const s = new x.DirectionalLight(16777215, 0.9);
508
+ const s = new y.DirectionalLight(16777215, 0.9);
498
509
  s.position.set(50, 60, 40), s.castShadow = !0, s.shadow.mapSize.width = 1024, s.shadow.mapSize.height = 1024, this.scene.add(s);
499
- const t = new x.DirectionalLight(16773344, 0.4);
510
+ const t = new y.DirectionalLight(16773344, 0.4);
500
511
  t.position.set(-50, 30, -40), this.scene.add(t);
501
- const i = new x.DirectionalLight(16777215, 0.3);
512
+ const i = new y.DirectionalLight(16777215, 0.3);
502
513
  i.position.set(0, -30, -50), this.scene.add(i);
503
- const o = new x.PointLight(16750950, 0.5, 150);
504
- o.position.set(40, 20, 40), this.scene.add(o);
505
- const n = new x.PointLight(16764057, 0.4, 150);
506
- n.position.set(-40, -20, 40), this.scene.add(n);
507
- const r = new x.PointLight(6724095, 0.2, 100);
508
- r.position.set(0, 40, -40), this.scene.add(r);
514
+ const n = new y.PointLight(16750950, 0.5, 150);
515
+ n.position.set(40, 20, 40), this.scene.add(n);
516
+ const o = new y.PointLight(16764057, 0.4, 150);
517
+ o.position.set(-40, -20, 40), this.scene.add(o);
518
+ const a = new y.PointLight(6724095, 0.2, 100);
519
+ a.position.set(0, 40, -40), this.scene.add(a);
509
520
  }
510
521
  /**
511
522
  * Handle window resize
512
523
  */
513
524
  onWindowResize() {
514
- const { width: e, height: s } = ke(this.container);
525
+ const { width: e, height: s } = Re(this.container);
515
526
  this.camera.aspect = e / s, this.camera.updateProjectionMatrix(), this.renderer.setSize(e, s);
516
527
  }
517
528
  /**
@@ -532,6 +543,25 @@ class ft {
532
543
  render() {
533
544
  this.controls.update(), this.renderer.render(this.scene, this.camera);
534
545
  }
546
+ /**
547
+ * Updates renderer pixel ratio with bounds checking
548
+ */
549
+ setPixelRatio(e) {
550
+ const s = Math.max(0.3, Math.min(e, this.maxPixelRatio));
551
+ this.renderer.setPixelRatio(s);
552
+ }
553
+ /**
554
+ * Gets current renderer pixel ratio
555
+ */
556
+ getPixelRatio() {
557
+ return this.renderer.getPixelRatio();
558
+ }
559
+ /**
560
+ * Enables/disables expensive renderer features
561
+ */
562
+ setHighQualityRendering(e) {
563
+ this.renderer.shadowMap.enabled = e, this.renderer.toneMapping = e ? y.ACESFilmicToneMapping : y.NoToneMapping, this.renderer.toneMappingExposure = 1;
564
+ }
535
565
  /**
536
566
  * Gets the camera position
537
567
  */
@@ -546,7 +576,7 @@ class ft {
546
576
  * Gets the camera's forward direction
547
577
  */
548
578
  getCameraDirection() {
549
- const e = new x.Vector3();
579
+ const e = new y.Vector3();
550
580
  return this.camera.getWorldDirection(e), e;
551
581
  }
552
582
  /**
@@ -559,12 +589,16 @@ class ft {
559
589
  }
560
590
  }
561
591
  }
562
- const X = class X {
592
+ const q = class q {
563
593
  constructor(e, s) {
564
594
  l(this, "sceneManager");
565
595
  l(this, "nodeFactory");
566
596
  l(this, "nodes", /* @__PURE__ */ new Map());
567
597
  l(this, "nodeObjects", /* @__PURE__ */ new Map());
598
+ l(this, "nodeObjectCache", []);
599
+ l(this, "nodeObjectCacheDirty", !0);
600
+ l(this, "labelRenderMode", "adaptive");
601
+ l(this, "labelDistance", 140);
568
602
  this.sceneManager = e, this.nodeFactory = s;
569
603
  }
570
604
  /**
@@ -578,31 +612,31 @@ const X = class X {
578
612
  * Call this before adding nodes in bulk.
579
613
  */
580
614
  static setExpectedNodeCount(e) {
581
- X.expectedNodeCount = e;
615
+ q.expectedNodeCount = e;
582
616
  }
583
617
  /**
584
618
  * Adds a node to the graph
585
619
  * @returns true if added, false if node already exists or invalid
586
620
  */
587
621
  addNode(e, s = 0) {
588
- if (!Fe(e))
622
+ if (!ce(e))
589
623
  return !1;
590
624
  if (this.nodes.has(e.id))
591
625
  return console.warn(`[ForceGraph3D] Node with id "${e.id}" already exists`), !1;
592
- const t = Math.max(50, Math.cbrt(X.expectedNodeCount) * 10), i = e.position ?? {
626
+ const t = Math.max(50, Math.cbrt(q.expectedNodeCount) * 10), i = e.position ?? {
593
627
  x: (Math.random() - 0.5) * t,
594
628
  y: (Math.random() - 0.5) * t,
595
629
  z: (Math.random() - 0.5) * t
596
- }, o = {
630
+ }, n = {
597
631
  ...e,
598
632
  position: i,
599
633
  velocity: { x: 0, y: 0, z: 0 },
600
634
  mass: 1
601
- }, n = this.nodeFactory.createNode(
635
+ }, o = this.nodeFactory.createNode(
602
636
  { ...e, position: i },
603
637
  s
604
638
  );
605
- return this.sceneManager.add(n.group), this.nodes.set(e.id, o), this.nodeObjects.set(e.id, n), !0;
639
+ return this.sceneManager.add(o.group), this.nodes.set(e.id, n), this.nodeObjects.set(e.id, o), this.nodeObjectCacheDirty = !0, !0;
606
640
  }
607
641
  /**
608
642
  * Removes a node from the graph
@@ -610,15 +644,15 @@ const X = class X {
610
644
  */
611
645
  removeNode(e) {
612
646
  const s = this.nodes.get(e), t = this.nodeObjects.get(e);
613
- return !s || !t ? !1 : (this.sceneManager.remove(t.group), this.nodeFactory.disposeNode(t), this.nodes.delete(e), this.nodeObjects.delete(e), !0);
647
+ return !s || !t ? !1 : (this.sceneManager.remove(t.group), this.nodeFactory.disposeNode(t), this.nodes.delete(e), this.nodeObjects.delete(e), this.nodeObjectCacheDirty = !0, !0);
614
648
  }
615
649
  /**
616
650
  * Updates a node's properties
617
651
  */
618
652
  updateNode(e, s) {
619
653
  const t = this.nodes.get(e), i = this.nodeObjects.get(e);
620
- 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) => {
621
- o !== "id" && o !== "label" && o !== "color" && o !== "position" && (t[o] = s[o]);
654
+ 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((n) => {
655
+ n !== "id" && n !== "label" && n !== "color" && n !== "position" && (t[n] = s[n]);
622
656
  }), !0);
623
657
  }
624
658
  /**
@@ -657,10 +691,12 @@ const X = class X {
657
691
  * Gets all node objects (for raycasting)
658
692
  */
659
693
  getAllNodeObjects() {
694
+ if (!this.nodeObjectCacheDirty)
695
+ return this.nodeObjectCache;
660
696
  const e = [];
661
697
  return this.nodeObjects.forEach((s) => {
662
698
  e.push(s.group);
663
- }), e;
699
+ }), this.nodeObjectCache = e, this.nodeObjectCacheDirty = !1, this.nodeObjectCache;
664
700
  }
665
701
  /**
666
702
  * Gets all spheres (for raycasting)
@@ -683,6 +719,41 @@ const X = class X {
683
719
  clear() {
684
720
  this.nodes.forEach((e, s) => {
685
721
  this.removeNode(s);
722
+ }), this.nodeObjectCacheDirty = !0;
723
+ }
724
+ /**
725
+ * Controls label rendering strategy for performance
726
+ */
727
+ setLabelRenderMode(e) {
728
+ this.labelRenderMode = e;
729
+ }
730
+ /**
731
+ * Sets camera distance threshold used in adaptive label mode
732
+ */
733
+ setLabelDistance(e) {
734
+ this.labelDistance = Math.max(20, e);
735
+ }
736
+ /**
737
+ * Updates label visibility for all nodes
738
+ */
739
+ updateLabelVisibility(e, s = null, t = null) {
740
+ this.nodeObjects.forEach((i, n) => {
741
+ const o = n === s || n === t;
742
+ if (this.labelRenderMode === "none") {
743
+ i.label.visible = o;
744
+ return;
745
+ }
746
+ if (this.labelRenderMode === "all") {
747
+ i.label.visible = !0;
748
+ return;
749
+ }
750
+ const a = this.nodes.get(n);
751
+ if (!a) {
752
+ i.label.visible = !1;
753
+ return;
754
+ }
755
+ const c = a.position.x - e.x, h = a.position.y - e.y, d = a.position.z - e.z, f = c * c + h * h + d * d, m = o || f <= this.labelDistance * this.labelDistance;
756
+ i.label.visible = m;
686
757
  });
687
758
  }
688
759
  /**
@@ -693,8 +764,8 @@ const X = class X {
693
764
  }
694
765
  };
695
766
  // Scale spawn volume with expected graph size
696
- l(X, "expectedNodeCount", 100);
697
- let ee = X;
767
+ l(q, "expectedNodeCount", 100);
768
+ let ee = q;
698
769
  class mt {
699
770
  constructor(e, s, t) {
700
771
  l(this, "sceneManager");
@@ -704,6 +775,8 @@ class mt {
704
775
  l(this, "edges", []);
705
776
  // One visual line per directed pair (source -> target)
706
777
  l(this, "edgeObjects", []);
778
+ l(this, "edgeLineCache", []);
779
+ l(this, "edgeLineCacheDirty", !0);
707
780
  // Tracks which directed pairs currently have at least one relationship
708
781
  l(this, "edgeKeySet", /* @__PURE__ */ new Set());
709
782
  // Maps directed pair key to the relationship list for that pair
@@ -711,6 +784,9 @@ class mt {
711
784
  // Maps directed pair key to the corresponding visual line
712
785
  l(this, "edgeObjectMap", /* @__PURE__ */ new Map());
713
786
  l(this, "highlightedEdgeKey", null);
787
+ l(this, "batchRenderingEnabled", !1);
788
+ l(this, "batchLineSegments", null);
789
+ l(this, "batchGeometryDirty", !1);
714
790
  this.sceneManager = e, this.nodeManager = s, this.edgeFactory = t;
715
791
  }
716
792
  /**
@@ -725,7 +801,7 @@ class mt {
725
801
  * @returns true if added, false if invalid or nodes don't exist
726
802
  */
727
803
  addEdge(e) {
728
- if (!De(e))
804
+ if (!he(e))
729
805
  return !1;
730
806
  if (!this.nodeManager.hasNode(e.source))
731
807
  return console.warn(`[ForceGraph3D] Source node "${e.source}" does not exist`), !1;
@@ -733,20 +809,20 @@ class mt {
733
809
  return console.warn(`[ForceGraph3D] Target node "${e.target}" does not exist`), !1;
734
810
  const s = this.nodeManager.getNode(e.source), t = this.nodeManager.getNode(e.target), i = this.createDirectedEdgeKey(e.source, e.target);
735
811
  this.edges.push(e);
736
- const o = this.edgeGroups.get(i);
737
- if (o) {
738
- o.push(e);
739
- const r = this.edgeObjectMap.get(i);
740
- return r && this.updateEdgeUserData(r, o, s, t), !0;
812
+ const n = this.edgeGroups.get(i);
813
+ if (n) {
814
+ n.push(e);
815
+ const a = this.edgeObjectMap.get(i);
816
+ return a && this.updateEdgeUserData(a, n, s, t), !0;
741
817
  }
742
- const n = this.edgeFactory.createEdge(
818
+ const o = this.edgeFactory.createEdge(
743
819
  e,
744
820
  s,
745
821
  t,
746
822
  s.position,
747
823
  t.position
748
824
  );
749
- return this.sceneManager.add(n.line), this.edgeGroups.set(i, [e]), this.edgeObjectMap.set(i, n), this.edgeObjects.push(n), this.edgeKeySet.add(i), this.updateEdgeUserData(n, [e], s, t), !0;
825
+ return this.batchRenderingEnabled || this.sceneManager.add(o.line), this.edgeGroups.set(i, [e]), this.edgeObjectMap.set(i, o), this.edgeObjects.push(o), this.edgeLineCacheDirty = !0, this.edgeKeySet.add(i), this.updateEdgeUserData(o, [e], s, t), this.batchRenderingEnabled && (this.batchGeometryDirty = !0), !0;
750
826
  }
751
827
  /**
752
828
  * Removes an edge from the graph
@@ -758,32 +834,32 @@ class mt {
758
834
  if (!this.edgeKeySet.has(t))
759
835
  return !1;
760
836
  const i = this.edges.findIndex(
761
- (c) => c.source === e && c.target === s
837
+ (h) => h.source === e && h.target === s
762
838
  );
763
839
  if (i === -1)
764
840
  return !1;
765
- const o = this.edges[i];
841
+ const n = this.edges[i];
766
842
  this.edges.splice(i, 1);
767
- const n = this.edgeGroups.get(t);
768
- if (!n)
843
+ const o = this.edgeGroups.get(t);
844
+ if (!o)
769
845
  return !0;
770
- const r = n.findIndex((c) => c === o);
771
- if (r !== -1)
772
- n.splice(r, 1);
846
+ const a = o.findIndex((h) => h === n);
847
+ if (a !== -1)
848
+ o.splice(a, 1);
773
849
  else {
774
- const c = n.findIndex((p) => p.source === e && p.target === s);
775
- c !== -1 && n.splice(c, 1);
850
+ const h = o.findIndex((d) => d.source === e && d.target === s);
851
+ h !== -1 && o.splice(h, 1);
776
852
  }
777
- const h = this.edgeObjectMap.get(t);
778
- if (!h)
853
+ const c = this.edgeObjectMap.get(t);
854
+ if (!c)
779
855
  return !0;
780
- if (n.length === 0) {
781
- this.sceneManager.remove(h.line), this.edgeFactory.disposeEdge(h);
782
- const c = this.edgeObjects.findIndex((p) => p === h);
783
- c !== -1 && this.edgeObjects.splice(c, 1), this.edgeGroups.delete(t), this.edgeObjectMap.delete(t), this.edgeKeySet.delete(t), this.highlightedEdgeKey === t && (this.highlightedEdgeKey = null);
856
+ if (o.length === 0) {
857
+ this.sceneManager.remove(c.line), this.edgeFactory.disposeEdge(c);
858
+ const h = this.edgeObjects.findIndex((d) => d === c);
859
+ h !== -1 && (this.edgeObjects.splice(h, 1), this.edgeLineCacheDirty = !0), this.edgeGroups.delete(t), this.edgeObjectMap.delete(t), this.edgeKeySet.delete(t), this.highlightedEdgeKey === t && (this.highlightedEdgeKey = null), this.batchRenderingEnabled && (this.batchGeometryDirty = !0);
784
860
  } else {
785
- const c = this.nodeManager.getNode(e), p = this.nodeManager.getNode(s);
786
- c && p && this.updateEdgeUserData(h, n, c, p);
861
+ const h = this.nodeManager.getNode(e), d = this.nodeManager.getNode(s);
862
+ h && d && this.updateEdgeUserData(c, o, h, d), this.batchRenderingEnabled && (this.batchGeometryDirty = !0);
787
863
  }
788
864
  return !0;
789
865
  }
@@ -834,6 +910,14 @@ class mt {
834
910
  * Updates all edge positions based on current node positions
835
911
  */
836
912
  updateEdgePositions() {
913
+ if (this.batchRenderingEnabled && this.batchGeometryDirty) {
914
+ this.rebuildBatchGeometry(), this.batchGeometryDirty = !1;
915
+ return;
916
+ }
917
+ if (this.batchRenderingEnabled && this.batchLineSegments) {
918
+ this.updateBatchEdgePositions();
919
+ return;
920
+ }
837
921
  this.edgeObjects.forEach((e) => {
838
922
  const s = this.nodeManager.getNode(e.source), t = this.nodeManager.getNode(e.target);
839
923
  s && t && this.edgeFactory.updateEdgePositions(
@@ -853,7 +937,7 @@ class mt {
853
937
  * Gets all edge line objects (for raycasting)
854
938
  */
855
939
  getAllEdgeLines() {
856
- return this.edgeObjects.map((e) => e.line);
940
+ return this.edgeLineCacheDirty ? (this.edgeLineCache = this.edgeObjects.map((e) => e.line), this.edgeLineCacheDirty = !1, this.edgeLineCache) : this.edgeLineCache;
857
941
  }
858
942
  /**
859
943
  * Gets edge count
@@ -867,7 +951,23 @@ class mt {
867
951
  clear() {
868
952
  this.edgeObjects.forEach((e) => {
869
953
  this.sceneManager.remove(e.line), this.edgeFactory.disposeEdge(e);
870
- }), this.edges = [], this.edgeObjects = [], this.edgeKeySet.clear(), this.edgeGroups.clear(), this.edgeObjectMap.clear(), this.highlightedEdgeKey = null;
954
+ }), this.batchLineSegments && (this.sceneManager.remove(this.batchLineSegments), this.batchLineSegments.geometry.dispose(), this.batchLineSegments = null), this.edges = [], this.edgeObjects = [], this.edgeLineCache = [], this.edgeLineCacheDirty = !0, this.edgeKeySet.clear(), this.edgeGroups.clear(), this.edgeObjectMap.clear(), this.highlightedEdgeKey = null, this.batchGeometryDirty = !1;
955
+ }
956
+ /**
957
+ * Enables batched edge rendering (single LineSegments draw call)
958
+ */
959
+ setBatchRenderingEnabled(e) {
960
+ this.batchRenderingEnabled !== e && (this.batchRenderingEnabled = e, e ? (this.edgeObjects.forEach((s) => {
961
+ this.sceneManager.remove(s.line);
962
+ }), this.batchGeometryDirty = !0, this.rebuildBatchGeometry()) : (this.batchLineSegments && (this.sceneManager.remove(this.batchLineSegments), this.batchLineSegments.geometry.dispose(), this.batchLineSegments = null), this.edgeObjects.forEach((s) => {
963
+ this.sceneManager.add(s.line);
964
+ }), this.batchGeometryDirty = !1));
965
+ }
966
+ /**
967
+ * Checks whether batch rendering is active
968
+ */
969
+ isBatchRenderingEnabled() {
970
+ return this.batchRenderingEnabled;
871
971
  }
872
972
  /**
873
973
  * Creates a directed key (source -> target)
@@ -879,18 +979,46 @@ class mt {
879
979
  * Syncs relationship metadata to the line for hover/click UI
880
980
  */
881
981
  updateEdgeUserData(e, s, t, i) {
882
- const o = s[0];
982
+ const n = s[0];
883
983
  e.line.userData = {
884
984
  ...e.line.userData,
885
985
  source: e.source,
886
986
  target: e.target,
887
- edge: o,
987
+ edge: n,
888
988
  relationships: [...s],
889
989
  relationshipCount: s.length,
890
990
  sourceNode: t,
891
991
  targetNode: i
892
992
  };
893
993
  }
994
+ /**
995
+ * Rebuilds merged edge geometry used for low-end rendering mode
996
+ */
997
+ rebuildBatchGeometry() {
998
+ if (!this.batchRenderingEnabled || (this.batchLineSegments && (this.sceneManager.remove(this.batchLineSegments), this.batchLineSegments.geometry.dispose(), this.batchLineSegments = null), this.edgeObjects.length === 0)) return;
999
+ const e = new Float32Array(this.edgeObjects.length * 6), s = new y.BufferGeometry();
1000
+ s.setAttribute("position", new y.BufferAttribute(e, 3)), this.batchLineSegments = new y.LineSegments(
1001
+ s,
1002
+ this.edgeFactory.getSharedEdgeMaterial()
1003
+ ), this.batchLineSegments.name = "f3d-edge-batch", this.sceneManager.add(this.batchLineSegments), this.updateBatchEdgePositions();
1004
+ }
1005
+ /**
1006
+ * Updates merged edge geometry positions from node coordinates
1007
+ */
1008
+ updateBatchEdgePositions() {
1009
+ if (!this.batchLineSegments) return;
1010
+ const e = this.batchLineSegments.geometry.getAttribute("position"), s = e.array;
1011
+ let t = 0;
1012
+ for (const i of this.edgeObjects) {
1013
+ const n = this.nodeManager.getNode(i.source), o = this.nodeManager.getNode(i.target);
1014
+ if (!n || !o) {
1015
+ t += 6;
1016
+ continue;
1017
+ }
1018
+ s[t++] = n.position.x, s[t++] = n.position.y, s[t++] = n.position.z, s[t++] = o.position.x, s[t++] = o.position.y, s[t++] = o.position.z;
1019
+ }
1020
+ e.needsUpdate = !0, this.batchLineSegments.geometry.computeBoundingSphere();
1021
+ }
894
1022
  /**
895
1023
  * Dispose resources
896
1024
  */
@@ -898,7 +1026,7 @@ class mt {
898
1026
  this.clear();
899
1027
  }
900
1028
  }
901
- class Le {
1029
+ class Oe {
902
1030
  constructor(e, s, t = {}) {
903
1031
  l(this, "nodes");
904
1032
  l(this, "edges");
@@ -936,10 +1064,10 @@ class Le {
936
1064
  e.set(i.source, (e.get(i.source) || 0) + 1), e.set(i.target, (e.get(i.target) || 0) + 1);
937
1065
  console.log(`[ForceGraph3D] initializeNodeMassAndPin: ${this.edges.length} edges, ${this.nodes.size} nodes, ${e.size} unique endpoints`);
938
1066
  let s = 0, t = null;
939
- for (const [i, o] of e) {
940
- o > s && (s = o, t = i);
941
- const n = this.nodes.get(i);
942
- n && (n.mass = 1 + Math.log2(1 + o));
1067
+ for (const [i, n] of e) {
1068
+ n > s && (s = n, t = i);
1069
+ const o = this.nodes.get(i);
1070
+ o && (o.mass = 1 + Math.log2(1 + n));
943
1071
  }
944
1072
  if (console.log(`[ForceGraph3D] Hub detected: id="${t}", degree=${s}, threshold=10`), t && s > 10) {
945
1073
  this.pinnedNodeId = t;
@@ -970,14 +1098,14 @@ class Le {
970
1098
  calculateRepulsionBruteForce() {
971
1099
  const e = Array.from(this.nodes.values()), s = e.length, t = this.getEffectiveRepulsion();
972
1100
  for (let i = 0; i < s; i++) {
973
- const o = e[i];
974
- for (let n = i + 1; n < s; n++) {
975
- const r = e[n], h = r.position.x - o.position.x, c = r.position.y - o.position.y, p = r.position.z - o.position.z;
976
- let f = h * h + c * c + p * p;
1101
+ const n = e[i];
1102
+ for (let o = i + 1; o < s; o++) {
1103
+ const a = e[o], c = a.position.x - n.position.x, h = a.position.y - n.position.y, d = a.position.z - n.position.z;
1104
+ let f = c * c + h * h + d * d;
977
1105
  if (f > this.REPULSION_CUTOFF_SQ) continue;
978
1106
  f < 0.01 && (f = 0.01);
979
- const m = Math.sqrt(f), u = t * this.alpha / f, y = h / m * u, b = c / m * u, w = p / m * u;
980
- o.velocity.x -= y / o.mass, o.velocity.y -= b / o.mass, o.velocity.z -= w / o.mass, r.velocity.x += y / r.mass, r.velocity.y += b / r.mass, r.velocity.z += w / r.mass;
1107
+ const m = Math.sqrt(f), u = t * this.alpha / f, b = c / m * u, x = h / m * u, M = d / m * u;
1108
+ n.velocity.x -= b / n.mass, n.velocity.y -= x / n.mass, n.velocity.z -= M / n.mass, a.velocity.x += b / a.mass, a.velocity.y += x / a.mass, a.velocity.z += M / a.mass;
981
1109
  }
982
1110
  }
983
1111
  }
@@ -998,26 +1126,26 @@ class Le {
998
1126
  return;
999
1127
  }
1000
1128
  if (s.mass === 0) return;
1001
- const t = s.centerOfMass.x - e.position.x, i = s.centerOfMass.y - e.position.y, o = s.centerOfMass.z - e.position.z, n = t * t + i * i + o * o;
1002
- if (n > this.REPULSION_CUTOFF_SQ) return;
1003
- const r = Math.sqrt(n), h = this.getEffectiveRepulsion();
1004
- if (r > 0 && s.size / r < this.barnesHutTheta) {
1005
- const c = Math.max(n, 0.01), p = h * this.alpha * s.mass / c;
1006
- e.velocity.x -= t / r * p / e.mass, e.velocity.y -= i / r * p / e.mass, e.velocity.z -= o / r * p / e.mass;
1129
+ const t = s.centerOfMass.x - e.position.x, i = s.centerOfMass.y - e.position.y, n = s.centerOfMass.z - e.position.z, o = t * t + i * i + n * n;
1130
+ if (o > this.REPULSION_CUTOFF_SQ) return;
1131
+ const a = Math.sqrt(o), c = this.getEffectiveRepulsion();
1132
+ if (a > 0 && s.size / a < this.barnesHutTheta) {
1133
+ const h = Math.max(o, 0.01), d = c * this.alpha * s.mass / h;
1134
+ e.velocity.x -= t / a * d / e.mass, e.velocity.y -= i / a * d / e.mass, e.velocity.z -= n / a * d / e.mass;
1007
1135
  } else
1008
- for (const c of s.children)
1009
- c && this.calculateForceFromOctree(e, c);
1136
+ for (const h of s.children)
1137
+ h && this.calculateForceFromOctree(e, h);
1010
1138
  }
1011
1139
  /**
1012
1140
  * Apply repulsion between two nodes (with cutoff)
1013
1141
  */
1014
1142
  applyRepulsionBetween(e, s) {
1015
- const t = s.position.x - e.position.x, i = s.position.y - e.position.y, o = s.position.z - e.position.z;
1016
- let n = t * t + i * i + o * o;
1017
- if (n > this.REPULSION_CUTOFF_SQ) return;
1018
- n < 0.01 && (n = 0.01);
1019
- const r = Math.sqrt(n), c = this.getEffectiveRepulsion() * this.alpha / n;
1020
- e.velocity.x -= t / r * c / e.mass, e.velocity.y -= i / r * c / e.mass, e.velocity.z -= o / r * c / e.mass;
1143
+ const t = s.position.x - e.position.x, i = s.position.y - e.position.y, n = s.position.z - e.position.z;
1144
+ let o = t * t + i * i + n * n;
1145
+ if (o > this.REPULSION_CUTOFF_SQ) return;
1146
+ o < 0.01 && (o = 0.01);
1147
+ const a = Math.sqrt(o), h = this.getEffectiveRepulsion() * this.alpha / o;
1148
+ e.velocity.x -= t / a * h / e.mass, e.velocity.y -= i / a * h / e.mass, e.velocity.z -= n / a * h / e.mass;
1021
1149
  }
1022
1150
  /**
1023
1151
  * Calculate attraction forces along edges
@@ -1025,12 +1153,12 @@ class Le {
1025
1153
  calculateAttraction() {
1026
1154
  const e = this.nodes.size, s = e > 500 ? 1 + Math.log10(e / 500) : 1;
1027
1155
  for (const t of this.edges) {
1028
- const i = this.nodes.get(t.source), o = this.nodes.get(t.target);
1029
- if (!i || !o) continue;
1030
- const n = o.position.x - i.position.x, r = o.position.y - i.position.y, h = o.position.z - i.position.z, c = Math.sqrt(n * n + r * r + h * h);
1031
- if (c < 0.01) continue;
1032
- const f = (c - 15) * this.attractionStrength * s * this.alpha, m = n / c * f, u = r / c * f, y = h / c * f;
1033
- i.velocity.x += m / i.mass, i.velocity.y += u / i.mass, i.velocity.z += y / i.mass, o.velocity.x -= m / o.mass, o.velocity.y -= u / o.mass, o.velocity.z -= y / o.mass;
1156
+ const i = this.nodes.get(t.source), n = this.nodes.get(t.target);
1157
+ if (!i || !n) continue;
1158
+ const o = n.position.x - i.position.x, a = n.position.y - i.position.y, c = n.position.z - i.position.z, h = Math.sqrt(o * o + a * a + c * c);
1159
+ if (h < 0.01) continue;
1160
+ const f = (h - 15) * this.attractionStrength * s * this.alpha, m = o / h * f, u = a / h * f, b = c / h * f;
1161
+ i.velocity.x += m / i.mass, i.velocity.y += u / i.mass, i.velocity.z += b / i.mass, n.velocity.x -= m / n.mass, n.velocity.y -= u / n.mass, n.velocity.z -= b / n.mass;
1034
1162
  }
1035
1163
  }
1036
1164
  /**
@@ -1100,8 +1228,8 @@ class yt {
1100
1228
  max: { x: 100, y: 100, z: 100 }
1101
1229
  };
1102
1230
  const s = { x: 1 / 0, y: 1 / 0, z: 1 / 0 }, t = { x: -1 / 0, y: -1 / 0, z: -1 / 0 };
1103
- for (const o of e)
1104
- 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);
1231
+ for (const n of e)
1232
+ s.x = Math.min(s.x, n.position.x), s.y = Math.min(s.y, n.position.y), s.z = Math.min(s.z, n.position.z), t.x = Math.max(t.x, n.position.x), t.y = Math.max(t.y, n.position.y), t.z = Math.max(t.z, n.position.z);
1105
1233
  const i = 10;
1106
1234
  return s.x -= i, s.y -= i, s.z -= i, t.x += i, t.y += i, t.z += i, { min: s, max: t };
1107
1235
  }
@@ -1123,42 +1251,42 @@ class yt {
1123
1251
  };
1124
1252
  if (e.length === 1 || t > 20) {
1125
1253
  let u = 0;
1126
- const y = { x: 0, y: 0, z: 0 };
1127
- for (const b of e)
1128
- u += b.mass, y.x += b.position.x * b.mass, y.y += b.position.y * b.mass, y.z += b.position.z * b.mass;
1129
- return u > 0 && (y.x /= u, y.y /= u, y.z /= u), {
1254
+ const b = { x: 0, y: 0, z: 0 };
1255
+ for (const x of e)
1256
+ u += x.mass, b.x += x.position.x * x.mass, b.y += x.position.y * x.mass, b.z += x.position.z * x.mass;
1257
+ return u > 0 && (b.x /= u, b.y /= u, b.z /= u), {
1130
1258
  bounds: s,
1131
1259
  size: i,
1132
- centerOfMass: y,
1260
+ centerOfMass: b,
1133
1261
  mass: u,
1134
1262
  isLeaf: !0,
1135
1263
  node: e[0],
1136
1264
  children: []
1137
1265
  };
1138
1266
  }
1139
- const o = (s.min.x + s.max.x) / 2, n = (s.min.y + s.max.y) / 2, r = (s.min.z + s.max.z) / 2, h = [[], [], [], [], [], [], [], []];
1267
+ const n = (s.min.x + s.max.x) / 2, o = (s.min.y + s.max.y) / 2, a = (s.min.z + s.max.z) / 2, c = [[], [], [], [], [], [], [], []];
1140
1268
  for (const u of e) {
1141
- const y = (u.position.x >= o ? 1 : 0) + (u.position.y >= n ? 2 : 0) + (u.position.z >= r ? 4 : 0);
1142
- h[y].push(u);
1143
- }
1144
- const c = [
1145
- { min: { x: s.min.x, y: s.min.y, z: s.min.z }, max: { x: o, y: n, z: r } },
1146
- { min: { x: o, y: s.min.y, z: s.min.z }, max: { x: s.max.x, y: n, z: r } },
1147
- { min: { x: s.min.x, y: n, z: s.min.z }, max: { x: o, y: s.max.y, z: r } },
1148
- { min: { x: o, y: n, z: s.min.z }, max: { x: s.max.x, y: s.max.y, z: r } },
1149
- { min: { x: s.min.x, y: s.min.y, z: r }, max: { x: o, y: n, z: s.max.z } },
1150
- { min: { x: o, y: s.min.y, z: r }, max: { x: s.max.x, y: n, z: s.max.z } },
1151
- { min: { x: s.min.x, y: n, z: r }, max: { x: o, y: s.max.y, z: s.max.z } },
1152
- { min: { x: o, y: n, z: r }, max: { x: s.max.x, y: s.max.y, z: s.max.z } }
1153
- ], p = [];
1269
+ const b = (u.position.x >= n ? 1 : 0) + (u.position.y >= o ? 2 : 0) + (u.position.z >= a ? 4 : 0);
1270
+ c[b].push(u);
1271
+ }
1272
+ const h = [
1273
+ { min: { x: s.min.x, y: s.min.y, z: s.min.z }, max: { x: n, y: o, z: a } },
1274
+ { min: { x: n, y: s.min.y, z: s.min.z }, max: { x: s.max.x, y: o, z: a } },
1275
+ { min: { x: s.min.x, y: o, z: s.min.z }, max: { x: n, y: s.max.y, z: a } },
1276
+ { min: { x: n, y: o, z: s.min.z }, max: { x: s.max.x, y: s.max.y, z: a } },
1277
+ { min: { x: s.min.x, y: s.min.y, z: a }, max: { x: n, y: o, z: s.max.z } },
1278
+ { min: { x: n, y: s.min.y, z: a }, max: { x: s.max.x, y: o, z: s.max.z } },
1279
+ { min: { x: s.min.x, y: o, z: a }, max: { x: n, y: s.max.y, z: s.max.z } },
1280
+ { min: { x: n, y: o, z: a }, max: { x: s.max.x, y: s.max.y, z: s.max.z } }
1281
+ ], d = [];
1154
1282
  let f = 0;
1155
1283
  const m = { x: 0, y: 0, z: 0 };
1156
1284
  for (let u = 0; u < 8; u++)
1157
- if (h[u].length > 0) {
1158
- const y = this.buildTree(h[u], c[u], t + 1);
1159
- p.push(y), f += y.mass, m.x += y.centerOfMass.x * y.mass, m.y += y.centerOfMass.y * y.mass, m.z += y.centerOfMass.z * y.mass;
1285
+ if (c[u].length > 0) {
1286
+ const b = this.buildTree(c[u], h[u], t + 1);
1287
+ d.push(b), f += b.mass, m.x += b.centerOfMass.x * b.mass, m.y += b.centerOfMass.y * b.mass, m.z += b.centerOfMass.z * b.mass;
1160
1288
  } else
1161
- p.push(null);
1289
+ d.push(null);
1162
1290
  return f > 0 && (m.x /= f, m.y /= f, m.z /= f), {
1163
1291
  bounds: s,
1164
1292
  size: i,
@@ -1166,11 +1294,11 @@ class yt {
1166
1294
  mass: f,
1167
1295
  isLeaf: !1,
1168
1296
  node: null,
1169
- children: p
1297
+ children: d
1170
1298
  };
1171
1299
  }
1172
1300
  }
1173
- class xt {
1301
+ class bt {
1174
1302
  constructor(e, s, t, i = 60) {
1175
1303
  l(this, "sceneManager");
1176
1304
  l(this, "animationId", null);
@@ -1235,7 +1363,222 @@ class xt {
1235
1363
  this.stop();
1236
1364
  }
1237
1365
  }
1238
- class bt {
1366
+ class xt {
1367
+ constructor() {
1368
+ l(this, "worker", null);
1369
+ l(this, "nodeIds", []);
1370
+ l(this, "pendingStep", !1);
1371
+ l(this, "latestFrame", null);
1372
+ typeof Worker > "u" || typeof URL > "u" || typeof Blob > "u" || (this.worker = this.createWorker(), this.worker.onmessage = (e) => {
1373
+ const s = e.data;
1374
+ s.type === "positions" && s.positions && (this.latestFrame = {
1375
+ ids: this.nodeIds,
1376
+ positions: s.positions
1377
+ }, this.pendingStep = !1);
1378
+ });
1379
+ }
1380
+ isAvailable() {
1381
+ return this.worker !== null;
1382
+ }
1383
+ init(e, s, t) {
1384
+ if (!this.worker) return;
1385
+ this.nodeIds = Array.from(e.keys());
1386
+ const i = /* @__PURE__ */ new Map(), n = [];
1387
+ let o = 0;
1388
+ e.forEach((c, h) => {
1389
+ i.set(h, o++), n.push({
1390
+ id: h,
1391
+ x: c.position.x,
1392
+ y: c.position.y,
1393
+ z: c.position.z,
1394
+ mass: c.mass
1395
+ });
1396
+ });
1397
+ const a = [];
1398
+ s.forEach((c) => {
1399
+ const h = i.get(c.source), d = i.get(c.target);
1400
+ h !== void 0 && d !== void 0 && a.push([h, d]);
1401
+ }), this.latestFrame = null, this.pendingStep = !1, this.worker.postMessage({
1402
+ type: "init",
1403
+ nodes: n,
1404
+ edges: a,
1405
+ params: t
1406
+ });
1407
+ }
1408
+ setPhysicsParams(e) {
1409
+ this.worker && this.worker.postMessage({ type: "params", params: e });
1410
+ }
1411
+ requestStep() {
1412
+ !this.worker || this.pendingStep || (this.pendingStep = !0, this.worker.postMessage({ type: "step" }));
1413
+ }
1414
+ consumeLatestFrame() {
1415
+ if (!this.latestFrame) return null;
1416
+ const e = this.latestFrame;
1417
+ return this.latestFrame = null, e;
1418
+ }
1419
+ dispose() {
1420
+ this.worker && (this.worker.terminate(), this.worker = null), this.latestFrame = null, this.pendingStep = !1, this.nodeIds = [];
1421
+ }
1422
+ createWorker() {
1423
+ const e = `
1424
+ let nodes = [];
1425
+ let edges = [];
1426
+ let alpha = 1;
1427
+ let repulsion = 180;
1428
+ let attraction = 0.008;
1429
+ let damping = 0.95;
1430
+ let randState = 123456789;
1431
+
1432
+ function random() {
1433
+ randState = (1664525 * randState + 1013904223) >>> 0;
1434
+ return randState / 4294967296;
1435
+ }
1436
+
1437
+ function applySampledRepulsion() {
1438
+ const n = nodes.length;
1439
+ if (n < 2) return;
1440
+ const sampleCount = n > 2500 ? 18 : n > 1200 ? 24 : 40;
1441
+ const nScale = n > 0 ? Math.sqrt(n / 500) : 1;
1442
+
1443
+ for (let i = 0; i < n; i++) {
1444
+ const nodeA = nodes[i];
1445
+ for (let s = 0; s < sampleCount; s++) {
1446
+ const j = (i + 1 + Math.floor(random() * (n - 1))) % n;
1447
+ const nodeB = nodes[j];
1448
+ const dx = nodeB.x - nodeA.x;
1449
+ const dy = nodeB.y - nodeA.y;
1450
+ const dz = nodeB.z - nodeA.z;
1451
+ let distSq = dx * dx + dy * dy + dz * dz;
1452
+ if (distSq > 40000) continue;
1453
+ if (distSq < 0.01) distSq = 0.01;
1454
+ const dist = Math.sqrt(distSq);
1455
+ const force = (repulsion * alpha) / (distSq * nScale);
1456
+ const fx = (dx / dist) * force;
1457
+ const fy = (dy / dist) * force;
1458
+ const fz = (dz / dist) * force;
1459
+ nodeA.vx -= fx / nodeA.mass;
1460
+ nodeA.vy -= fy / nodeA.mass;
1461
+ nodeA.vz -= fz / nodeA.mass;
1462
+ }
1463
+ }
1464
+ }
1465
+
1466
+ function applyAttraction() {
1467
+ const targetDist = 15;
1468
+ const attrMul = nodes.length > 500 ? 1 + Math.log10(nodes.length / 500) : 1;
1469
+ for (let i = 0; i < edges.length; i++) {
1470
+ const e = edges[i];
1471
+ const source = nodes[e[0]];
1472
+ const target = nodes[e[1]];
1473
+ if (!source || !target) continue;
1474
+ const dx = target.x - source.x;
1475
+ const dy = target.y - source.y;
1476
+ const dz = target.z - source.z;
1477
+ const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
1478
+ if (dist < 0.01) continue;
1479
+ const force = (dist - targetDist) * attraction * attrMul * alpha;
1480
+ const fx = (dx / dist) * force;
1481
+ const fy = (dy / dist) * force;
1482
+ const fz = (dz / dist) * force;
1483
+ source.vx += fx / source.mass;
1484
+ source.vy += fy / source.mass;
1485
+ source.vz += fz / source.mass;
1486
+ target.vx -= fx / target.mass;
1487
+ target.vy -= fy / target.mass;
1488
+ target.vz -= fz / target.mass;
1489
+ }
1490
+ }
1491
+
1492
+ function integrate() {
1493
+ const gravity = 0.05 * alpha;
1494
+ const maxVelocity = 5;
1495
+
1496
+ for (let i = 0; i < nodes.length; i++) {
1497
+ const node = nodes[i];
1498
+ node.vx -= node.x * gravity;
1499
+ node.vy -= node.y * gravity;
1500
+ node.vz -= node.z * gravity;
1501
+
1502
+ node.vx *= damping;
1503
+ node.vy *= damping;
1504
+ node.vz *= damping;
1505
+
1506
+ const speed = Math.sqrt(node.vx * node.vx + node.vy * node.vy + node.vz * node.vz);
1507
+ if (speed > maxVelocity) {
1508
+ const scale = maxVelocity / speed;
1509
+ node.vx *= scale;
1510
+ node.vy *= scale;
1511
+ node.vz *= scale;
1512
+ }
1513
+
1514
+ node.x += node.vx;
1515
+ node.y += node.vy;
1516
+ node.z += node.vz;
1517
+ }
1518
+
1519
+ alpha += (0 - alpha) * 0.0228;
1520
+ if (alpha < 0.001) {
1521
+ alpha = 0.001;
1522
+ }
1523
+ }
1524
+
1525
+ function step() {
1526
+ if (nodes.length === 0) return;
1527
+ applySampledRepulsion();
1528
+ applyAttraction();
1529
+ integrate();
1530
+
1531
+ const positions = new Float32Array(nodes.length * 3);
1532
+ for (let i = 0; i < nodes.length; i++) {
1533
+ const node = nodes[i];
1534
+ const base = i * 3;
1535
+ positions[base] = node.x;
1536
+ positions[base + 1] = node.y;
1537
+ positions[base + 2] = node.z;
1538
+ }
1539
+
1540
+ postMessage({ type: 'positions', positions }, [positions.buffer]);
1541
+ }
1542
+
1543
+ self.onmessage = (event) => {
1544
+ const msg = event.data || {};
1545
+ if (msg.type === 'init') {
1546
+ nodes = (msg.nodes || []).map((node) => ({
1547
+ id: node.id,
1548
+ x: node.x,
1549
+ y: node.y,
1550
+ z: node.z,
1551
+ vx: 0,
1552
+ vy: 0,
1553
+ vz: 0,
1554
+ mass: node.mass || 1,
1555
+ }));
1556
+ edges = msg.edges || [];
1557
+ alpha = 1;
1558
+ if (msg.params) {
1559
+ if (typeof msg.params.repulsionStrength === 'number') repulsion = msg.params.repulsionStrength;
1560
+ if (typeof msg.params.attractionStrength === 'number') attraction = msg.params.attractionStrength;
1561
+ if (typeof msg.params.damping === 'number') damping = msg.params.damping;
1562
+ }
1563
+ return;
1564
+ }
1565
+
1566
+ if (msg.type === 'params') {
1567
+ if (typeof msg.params?.repulsionStrength === 'number') repulsion = msg.params.repulsionStrength;
1568
+ if (typeof msg.params?.attractionStrength === 'number') attraction = msg.params.attractionStrength;
1569
+ if (typeof msg.params?.damping === 'number') damping = msg.params.damping;
1570
+ return;
1571
+ }
1572
+
1573
+ if (msg.type === 'step') {
1574
+ step();
1575
+ }
1576
+ };
1577
+ `, s = new Blob([e], { type: "application/javascript" }), t = URL.createObjectURL(s), i = new Worker(t);
1578
+ return URL.revokeObjectURL(t), i;
1579
+ }
1580
+ }
1581
+ class vt {
1239
1582
  constructor() {
1240
1583
  l(this, "envMap", null);
1241
1584
  l(this, "materialCache", /* @__PURE__ */ new Map());
@@ -1274,9 +1617,9 @@ class bt {
1274
1617
  // -z
1275
1618
  ];
1276
1619
  for (const i of t) {
1277
- const o = document.createElement("canvas");
1278
- o.width = 256, o.height = 256;
1279
- const n = o.getContext("2d"), r = n.createRadialGradient(
1620
+ const n = document.createElement("canvas");
1621
+ n.width = 256, n.height = 256;
1622
+ const o = n.getContext("2d"), a = o.createRadialGradient(
1280
1623
  256 / 2,
1281
1624
  256 / 2,
1282
1625
  0,
@@ -1284,17 +1627,17 @@ class bt {
1284
1627
  256 / 2,
1285
1628
  256 * 0.8
1286
1629
  );
1287
- r.addColorStop(0, i.colors[0]), r.addColorStop(0.5, i.colors[1]), r.addColorStop(1, i.colors[2]), n.fillStyle = r, n.fillRect(0, 0, 256, 256);
1288
- const h = n.getImageData(0, 0, 256, 256);
1289
- for (let c = 0; c < h.data.length; c += 4) {
1290
- const p = (Math.random() - 0.5) * 5;
1291
- h.data[c] = Math.min(255, Math.max(0, h.data[c] + p)), h.data[c + 1] = Math.min(255, Math.max(0, h.data[c + 1] + p)), h.data[c + 2] = Math.min(255, Math.max(0, h.data[c + 2] + p));
1630
+ a.addColorStop(0, i.colors[0]), a.addColorStop(0.5, i.colors[1]), a.addColorStop(1, i.colors[2]), o.fillStyle = a, o.fillRect(0, 0, 256, 256);
1631
+ const c = o.getImageData(0, 0, 256, 256);
1632
+ for (let h = 0; h < c.data.length; h += 4) {
1633
+ const d = (Math.random() - 0.5) * 5;
1634
+ c.data[h] = Math.min(255, Math.max(0, c.data[h] + d)), c.data[h + 1] = Math.min(255, Math.max(0, c.data[h + 1] + d)), c.data[h + 2] = Math.min(255, Math.max(0, c.data[h + 2] + d));
1292
1635
  }
1293
- n.putImageData(h, 0, 0), s.push(o);
1636
+ o.putImageData(c, 0, 0), s.push(n);
1294
1637
  }
1295
- this.envMap = new x.CubeTexture(s.map((i) => {
1296
- const o = new Image();
1297
- return o.src = i.toDataURL(), o;
1638
+ this.envMap = new y.CubeTexture(s.map((i) => {
1639
+ const n = new Image();
1640
+ return n.src = i.toDataURL(), n;
1298
1641
  })), this.envMap.needsUpdate = !0;
1299
1642
  }
1300
1643
  /**
@@ -1311,11 +1654,11 @@ class bt {
1311
1654
  const t = "glass-single";
1312
1655
  if (this.materialCache.has(t))
1313
1656
  return this.materialCache.get(t).clone();
1314
- const i = new x.Color(16750950), o = new x.ShaderMaterial({
1657
+ const i = new y.Color(16750950), n = new y.ShaderMaterial({
1315
1658
  uniforms: {
1316
1659
  uColor: { value: i },
1317
1660
  uEnvMap: { value: this.envMap },
1318
- uGlowColor: { value: new x.Color(16777215) },
1661
+ uGlowColor: { value: new y.Color(16777215) },
1319
1662
  uGlowIntensity: { value: 0.8 },
1320
1663
  uReflectivity: { value: 0.4 },
1321
1664
  uFresnelPower: { value: 2.5 }
@@ -1381,17 +1724,17 @@ class bt {
1381
1724
  }
1382
1725
  `,
1383
1726
  transparent: !0,
1384
- side: x.FrontSide,
1727
+ side: y.FrontSide,
1385
1728
  depthWrite: !0,
1386
- blending: x.NormalBlending
1729
+ blending: y.NormalBlending
1387
1730
  });
1388
- return this.materialCache.set(t, o), o.clone();
1731
+ return this.materialCache.set(t, n), n.clone();
1389
1732
  }
1390
1733
  /**
1391
1734
  * Creates material for edges (light color for dark background)
1392
1735
  */
1393
1736
  createEdgeMaterial(e = 6710886, s = 0.4) {
1394
- return new x.LineBasicMaterial({
1737
+ return new y.LineBasicMaterial({
1395
1738
  color: e,
1396
1739
  transparent: !0,
1397
1740
  opacity: s,
@@ -1402,7 +1745,7 @@ class bt {
1402
1745
  * Creates highlighted edge material
1403
1746
  */
1404
1747
  createHighlightedEdgeMaterial() {
1405
- return new x.LineBasicMaterial({
1748
+ return new y.LineBasicMaterial({
1406
1749
  color: 16750950,
1407
1750
  // Tangerine highlight
1408
1751
  transparent: !1,
@@ -1416,11 +1759,11 @@ class bt {
1416
1759
  createLabelMaterial(e, s = 24) {
1417
1760
  const t = document.createElement("canvas"), i = t.getContext("2d");
1418
1761
  i.font = `600 ${s}px Inter, -apple-system, sans-serif`;
1419
- const n = i.measureText(e).width;
1420
- t.width = Math.max(128, n + 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);
1421
- const r = new x.CanvasTexture(t);
1422
- return r.needsUpdate = !0, new x.SpriteMaterial({
1423
- map: r,
1762
+ const o = i.measureText(e).width;
1763
+ t.width = Math.max(128, o + 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);
1764
+ const a = new y.CanvasTexture(t);
1765
+ return a.needsUpdate = !0, new y.SpriteMaterial({
1766
+ map: a,
1424
1767
  transparent: !0,
1425
1768
  depthTest: !1,
1426
1769
  depthWrite: !1
@@ -1439,7 +1782,7 @@ class bt {
1439
1782
  this.materialCache.forEach((e) => e.dispose()), this.materialCache.clear(), this.envMap && this.envMap.dispose();
1440
1783
  }
1441
1784
  }
1442
- class vt {
1785
+ class Mt {
1443
1786
  constructor(e, s = 2, t = [32, 16, 8], i = 16750950) {
1444
1787
  l(this, "materialFactory");
1445
1788
  l(this, "geometryCache", /* @__PURE__ */ new Map());
@@ -1456,7 +1799,7 @@ class vt {
1456
1799
  const t = `lod-${s}`;
1457
1800
  this.geometryCache.set(
1458
1801
  t,
1459
- new x.SphereGeometry(this.nodeRadius, e, e)
1802
+ new y.SphereGeometry(this.nodeRadius, e, e)
1460
1803
  );
1461
1804
  });
1462
1805
  }
@@ -1471,21 +1814,21 @@ class vt {
1471
1814
  * Creates a node visual (glass ball + label)
1472
1815
  */
1473
1816
  createNode(e, s = 0) {
1474
- const t = new x.Group();
1817
+ const t = new y.Group();
1475
1818
  t.name = `node-${e.id}`, t.userData = { nodeId: e.id, nodeData: e };
1476
- const i = this.getGeometry(s), o = this.materialFactory.createGlassMaterial(
1819
+ const i = this.getGeometry(s), n = this.materialFactory.createGlassMaterial(
1477
1820
  e.color ?? this.defaultNodeColor
1478
- ), n = new x.Mesh(i, o);
1479
- n.castShadow = !0, n.receiveShadow = !0, t.add(n);
1480
- const r = this.materialFactory.createLabelMaterial(e.label), h = new x.Sprite(r);
1481
- return h.position.y = this.nodeRadius + 1.5, h.scale.set(4, 1, 1), t.add(h), e.position && t.position.set(
1821
+ ), o = new y.Mesh(i, n);
1822
+ o.castShadow = !0, o.receiveShadow = !0, t.add(o);
1823
+ const a = this.materialFactory.createLabelMaterial(e.label), c = new y.Sprite(a);
1824
+ return c.position.y = this.nodeRadius + 1.5, c.scale.set(4, 1, 1), t.add(c), e.position && t.position.set(
1482
1825
  e.position.x,
1483
1826
  e.position.y,
1484
1827
  e.position.z
1485
1828
  ), {
1486
1829
  group: t,
1487
- sphere: n,
1488
- label: h,
1830
+ sphere: o,
1831
+ label: c,
1489
1832
  lodLevel: s
1490
1833
  };
1491
1834
  }
@@ -1501,19 +1844,19 @@ class vt {
1501
1844
  * Updates the color of a node
1502
1845
  */
1503
1846
  updateNodeColor(e, s) {
1504
- e.sphere.material instanceof x.Material && e.sphere.material.dispose(), e.sphere.material = this.materialFactory.createGlassMaterial(s);
1847
+ e.sphere.material instanceof y.Material && e.sphere.material.dispose(), e.sphere.material = this.materialFactory.createGlassMaterial(s);
1505
1848
  }
1506
1849
  /**
1507
1850
  * Updates the label of a node
1508
1851
  */
1509
1852
  updateNodeLabel(e, s) {
1510
- e.label.material instanceof x.SpriteMaterial && (e.label.material.map && e.label.material.map.dispose(), e.label.material.dispose()), e.label.material = this.materialFactory.createLabelMaterial(s);
1853
+ 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);
1511
1854
  }
1512
1855
  /**
1513
1856
  * Disposes a node's resources
1514
1857
  */
1515
1858
  disposeNode(e) {
1516
- e.sphere.material instanceof x.Material && e.sphere.material.dispose(), e.label.material instanceof x.SpriteMaterial && (e.label.material.map && e.label.material.map.dispose(), e.label.material.dispose());
1859
+ 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());
1517
1860
  }
1518
1861
  /**
1519
1862
  * Dispose factory resources
@@ -1549,17 +1892,17 @@ class wt {
1549
1892
  /**
1550
1893
  * Creates an edge line between two positions
1551
1894
  */
1552
- createEdge(e, s, t, i, o) {
1553
- const n = new x.BufferGeometry(), r = new Float32Array([
1895
+ createEdge(e, s, t, i, n) {
1896
+ const o = new y.BufferGeometry(), a = new Float32Array([
1554
1897
  i.x,
1555
1898
  i.y,
1556
1899
  i.z,
1557
- o.x,
1558
- o.y,
1559
- o.z
1900
+ n.x,
1901
+ n.y,
1902
+ n.z
1560
1903
  ]);
1561
- n.setAttribute("position", new x.BufferAttribute(r, 3));
1562
- const h = this.getDefaultMaterial().clone(), c = new x.Line(n, h);
1904
+ o.setAttribute("position", new y.BufferAttribute(a, 3));
1905
+ const c = new y.Line(o, this.getDefaultMaterial());
1563
1906
  return c.name = `edge-${e.source}-${e.target}`, c.userData = {
1564
1907
  source: e.source,
1565
1908
  target: e.target,
@@ -1576,26 +1919,35 @@ class wt {
1576
1919
  * Highlights an edge
1577
1920
  */
1578
1921
  highlightEdge(e) {
1579
- e.line.material instanceof x.Material && e.line.material.dispose(), e.line.material = this.getHighlightMaterial().clone();
1922
+ e.line.material = this.getHighlightMaterial();
1580
1923
  }
1581
1924
  /**
1582
1925
  * Resets an edge to default appearance
1583
1926
  */
1584
1927
  unhighlightEdge(e) {
1585
- e.line.material instanceof x.Material && e.line.material.dispose(), e.line.material = this.getDefaultMaterial().clone();
1928
+ e.line.material = this.getDefaultMaterial();
1586
1929
  }
1587
1930
  /**
1588
1931
  * Updates an edge's positions
1589
1932
  */
1590
1933
  updateEdgePositions(e, s, t) {
1591
- const i = e.line.geometry.attributes.position, o = i.array;
1592
- 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();
1934
+ const i = e.line.geometry.attributes.position, n = i.array;
1935
+ n[0] = s.x, n[1] = s.y, n[2] = s.z, n[3] = t.x, n[4] = t.y, n[5] = t.z, i.needsUpdate = !0, e.line.geometry.computeBoundingSphere();
1593
1936
  }
1594
1937
  /**
1595
1938
  * Disposes an edge's resources
1596
1939
  */
1597
1940
  disposeEdge(e) {
1598
- e.line.geometry.dispose(), e.line.material instanceof x.Material && e.line.material.dispose();
1941
+ if (e.line.geometry.dispose(), e.line.material instanceof y.Material) {
1942
+ const s = e.line.material;
1943
+ s !== this.defaultMaterial && s !== this.highlightMaterial && s.dispose();
1944
+ }
1945
+ }
1946
+ /**
1947
+ * Returns the shared edge material for batch rendering
1948
+ */
1949
+ getSharedEdgeMaterial() {
1950
+ return this.getDefaultMaterial();
1599
1951
  }
1600
1952
  /**
1601
1953
  * Dispose factory resources
@@ -1604,7 +1956,7 @@ class wt {
1604
1956
  this.defaultMaterial && this.defaultMaterial.dispose(), this.highlightMaterial && this.highlightMaterial.dispose();
1605
1957
  }
1606
1958
  }
1607
- class Mt {
1959
+ class Et {
1608
1960
  constructor(e, s = [50, 100, 200], t = !0) {
1609
1961
  l(this, "camera");
1610
1962
  l(this, "lodDistances");
@@ -1616,16 +1968,16 @@ class Mt {
1616
1968
  */
1617
1969
  getLODLevel(e) {
1618
1970
  if (!this.enabled)
1619
- return _.HIGH;
1620
- 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);
1621
- return o < this.lodDistances[0] ? _.HIGH : o < this.lodDistances[1] ? _.MEDIUM : _.LOW;
1971
+ return K.HIGH;
1972
+ const s = e.x - this.camera.position.x, t = e.y - this.camera.position.y, i = e.z - this.camera.position.z, n = Math.sqrt(s * s + t * t + i * i);
1973
+ return n < this.lodDistances[0] ? K.HIGH : n < this.lodDistances[1] ? K.MEDIUM : K.LOW;
1622
1974
  }
1623
1975
  /**
1624
1976
  * Checks if a node should be visible based on distance
1625
1977
  */
1626
1978
  shouldRenderNode(e, s = 500) {
1627
- const t = e.x - this.camera.position.x, i = e.y - this.camera.position.y, o = e.z - this.camera.position.z;
1628
- return Math.sqrt(t * t + i * i + o * o) < s;
1979
+ const t = e.x - this.camera.position.x, i = e.y - this.camera.position.y, n = e.z - this.camera.position.z;
1980
+ return Math.sqrt(t * t + i * i + n * n) < s;
1629
1981
  }
1630
1982
  /**
1631
1983
  * Sets the LOD distances
@@ -1640,13 +1992,13 @@ class Mt {
1640
1992
  this.enabled = e;
1641
1993
  }
1642
1994
  }
1643
- class Et {
1995
+ class Ct {
1644
1996
  constructor(e, s = !0) {
1645
1997
  l(this, "camera");
1646
1998
  l(this, "frustum");
1647
1999
  l(this, "projScreenMatrix");
1648
2000
  l(this, "enabled");
1649
- this.camera = e, this.frustum = new x.Frustum(), this.projScreenMatrix = new x.Matrix4(), this.enabled = s;
2001
+ this.camera = e, this.frustum = new y.Frustum(), this.projScreenMatrix = new y.Matrix4(), this.enabled = s;
1650
2002
  }
1651
2003
  /**
1652
2004
  * Updates the frustum from the camera
@@ -1662,7 +2014,7 @@ class Et {
1662
2014
  */
1663
2015
  isPointVisible(e) {
1664
2016
  if (!this.enabled) return !0;
1665
- const s = new x.Vector3(e.x, e.y, e.z);
2017
+ const s = new y.Vector3(e.x, e.y, e.z);
1666
2018
  return this.frustum.containsPoint(s);
1667
2019
  }
1668
2020
  /**
@@ -1670,8 +2022,8 @@ class Et {
1670
2022
  */
1671
2023
  isSphereVisible(e, s) {
1672
2024
  if (!this.enabled) return !0;
1673
- const t = new x.Sphere(
1674
- new x.Vector3(e.x, e.y, e.z),
2025
+ const t = new y.Sphere(
2026
+ new y.Vector3(e.x, e.y, e.z),
1675
2027
  s
1676
2028
  );
1677
2029
  return this.frustum.intersectsSphere(t);
@@ -1681,15 +2033,15 @@ class Et {
1681
2033
  */
1682
2034
  isLineVisible(e, s) {
1683
2035
  if (!this.enabled) return !0;
1684
- const t = new x.Vector3(e.x, e.y, e.z), i = new x.Vector3(s.x, s.y, s.z);
2036
+ const t = new y.Vector3(e.x, e.y, e.z), i = new y.Vector3(s.x, s.y, s.z);
1685
2037
  if (this.frustum.containsPoint(t) || this.frustum.containsPoint(i))
1686
2038
  return !0;
1687
- const o = new x.Vector3(
2039
+ const n = new y.Vector3(
1688
2040
  (e.x + s.x) / 2,
1689
2041
  (e.y + s.y) / 2,
1690
2042
  (e.z + s.z) / 2
1691
- ), n = o.distanceTo(t), r = new x.Sphere(o, n);
1692
- return this.frustum.intersectsSphere(r);
2043
+ ), o = n.distanceTo(t), a = new y.Sphere(n, o);
2044
+ return this.frustum.intersectsSphere(a);
1693
2045
  }
1694
2046
  /**
1695
2047
  * Enables/disables frustum culling
@@ -1698,7 +2050,7 @@ class Et {
1698
2050
  this.enabled = e;
1699
2051
  }
1700
2052
  }
1701
- class Ct {
2053
+ class St {
1702
2054
  constructor(e, s) {
1703
2055
  l(this, "sceneManager");
1704
2056
  l(this, "raycaster");
@@ -1710,9 +2062,10 @@ class Ct {
1710
2062
  l(this, "onEdgeClick", null);
1711
2063
  l(this, "hoveredNodeId", null);
1712
2064
  l(this, "hoveredEdgeKey", null);
2065
+ l(this, "edgeInteractionEnabled", !0);
1713
2066
  l(this, "nodeObjects", []);
1714
2067
  l(this, "edgeObjects", []);
1715
- this.sceneManager = e, this.container = s, this.raycaster = new x.Raycaster(), this.raycaster.params.Line = { threshold: 1.5 }, this.mouse = new x.Vector2(), this.handleClick = this.handleClick.bind(this), this.handleMouseMove = this.handleMouseMove.bind(this), s.addEventListener("click", this.handleClick), s.addEventListener("mousemove", this.handleMouseMove);
2068
+ this.sceneManager = e, this.container = s, this.raycaster = new y.Raycaster(), this.raycaster.params.Line = { threshold: 1.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);
1716
2069
  }
1717
2070
  /**
1718
2071
  * Updates the list of node objects to raycast against
@@ -1726,6 +2079,12 @@ class Ct {
1726
2079
  setEdgeObjects(e) {
1727
2080
  this.edgeObjects = e;
1728
2081
  }
2082
+ /**
2083
+ * Enables/disables edge hover and click raycasting
2084
+ */
2085
+ setEdgeInteractionEnabled(e) {
2086
+ this.edgeInteractionEnabled = e, e || (this.hoveredEdgeKey = null, this.onEdgeHover && this.onEdgeHover(null));
2087
+ }
1729
2088
  /**
1730
2089
  * Sets the click callback
1731
2090
  */
@@ -1759,7 +2118,7 @@ class Ct {
1759
2118
  this.onNodeClick(s);
1760
2119
  return;
1761
2120
  }
1762
- const t = this.getIntersectedEdge(e);
2121
+ const t = this.edgeInteractionEnabled ? this.getIntersectedEdge(e) : null;
1763
2122
  t && this.onEdgeClick && this.onEdgeClick(t);
1764
2123
  }
1765
2124
  /**
@@ -1771,8 +2130,14 @@ class Ct {
1771
2130
  this.hoveredEdgeKey !== null && this.onEdgeHover && (this.hoveredEdgeKey = null, this.onEdgeHover(null)), this.container.style.cursor = "pointer";
1772
2131
  return;
1773
2132
  }
1774
- const i = this.getIntersectedEdge(e), o = i ? `${i.edge.source}-${i.edge.target}` : null;
1775
- o !== this.hoveredEdgeKey && (this.hoveredEdgeKey = o, this.onEdgeHover && this.onEdgeHover(i)), this.container.style.cursor = i ? "pointer" : "default";
2133
+ const i = this.edgeInteractionEnabled ? this.getIntersectedEdge(e) : null, n = i ? `${i.edge.source}-${i.edge.target}` : null;
2134
+ n !== this.hoveredEdgeKey && (this.hoveredEdgeKey = n, this.onEdgeHover && this.onEdgeHover(i)), this.container.style.cursor = i ? "pointer" : "default";
2135
+ }
2136
+ /**
2137
+ * Gets currently hovered node ID
2138
+ */
2139
+ getHoveredNodeId() {
2140
+ return this.hoveredNodeId;
1776
2141
  }
1777
2142
  /**
1778
2143
  * Gets the intersected node from a mouse event
@@ -1783,11 +2148,11 @@ class Ct {
1783
2148
  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);
1784
2149
  const t = this.raycaster.intersectObjects(this.nodeObjects, !0);
1785
2150
  if (t.length > 0) {
1786
- let o = t[0].object;
1787
- for (; o; ) {
1788
- if ((i = o.userData) != null && i.nodeData)
1789
- return o.userData.nodeData;
1790
- o = o.parent;
2151
+ let n = t[0].object;
2152
+ for (; n; ) {
2153
+ if ((i = n.userData) != null && i.nodeData)
2154
+ return n.userData.nodeData;
2155
+ n = n.parent;
1791
2156
  }
1792
2157
  }
1793
2158
  return null;
@@ -1800,15 +2165,15 @@ class Ct {
1800
2165
  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);
1801
2166
  const t = this.raycaster.intersectObjects(this.edgeObjects, !1);
1802
2167
  if (t.length > 0) {
1803
- const i = t[0].object, o = i.userData;
1804
- if (o != null && o.edge && (o != null && o.sourceNode) && (o != null && o.targetNode)) {
1805
- const n = Array.isArray(o.relationships) ? o.relationships : [o.edge];
2168
+ const i = t[0].object, n = i.userData;
2169
+ if (n != null && n.edge && (n != null && n.sourceNode) && (n != null && n.targetNode)) {
2170
+ const o = Array.isArray(n.relationships) ? n.relationships : [n.edge];
1806
2171
  return {
1807
- edge: o.edge,
1808
- relationships: n,
1809
- relationshipCount: typeof o.relationshipCount == "number" ? o.relationshipCount : n.length,
1810
- sourceNode: o.sourceNode,
1811
- targetNode: o.targetNode,
2172
+ edge: n.edge,
2173
+ relationships: o,
2174
+ relationshipCount: typeof n.relationshipCount == "number" ? n.relationshipCount : o.length,
2175
+ sourceNode: n.sourceNode,
2176
+ targetNode: n.targetNode,
1812
2177
  edgeLine: i
1813
2178
  };
1814
2179
  }
@@ -1819,16 +2184,16 @@ class Ct {
1819
2184
  * Performs a raycast and returns the intersected node ID
1820
2185
  */
1821
2186
  getIntersectedNodeId(e, s) {
1822
- var o;
2187
+ var n;
1823
2188
  const t = this.container.getBoundingClientRect();
1824
2189
  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);
1825
2190
  const i = this.raycaster.intersectObjects(this.nodeObjects, !0);
1826
2191
  if (i.length > 0) {
1827
- let n = i[0].object;
1828
- for (; n; ) {
1829
- if ((o = n.userData) != null && o.nodeId)
1830
- return n.userData.nodeId;
1831
- n = n.parent;
2192
+ let o = i[0].object;
2193
+ for (; o; ) {
2194
+ if ((n = o.userData) != null && n.nodeId)
2195
+ return o.userData.nodeId;
2196
+ o = o.parent;
1832
2197
  }
1833
2198
  }
1834
2199
  return null;
@@ -1907,9 +2272,16 @@ class Nt {
1907
2272
  if (!this.panel) return;
1908
2273
  this.currentNodeId = e.id;
1909
2274
  let t;
1910
- this.panelTemplate ? t = this.panelTemplate(e, s) : t = this.generateDefaultContent(e, s), this.panel.innerHTML = t, this.onExpand;
1911
- const i = this.panel.querySelector('[data-action="close"]');
1912
- i && i.addEventListener("click", () => {
2275
+ this.panelTemplate ? t = this.panelTemplate(e, s) : t = this.generateDefaultContent(e, s), this.panel.innerHTML = t;
2276
+ const i = this.panel.querySelector('[data-action="expand"]'), n = this.panel.querySelector("[data-depth-select]");
2277
+ i && this.onExpand && i.addEventListener("click", () => {
2278
+ if (this.currentNodeId) {
2279
+ const a = n ? parseInt(n.value, 10) : 1;
2280
+ this.onExpand(this.currentNodeId, a);
2281
+ }
2282
+ });
2283
+ const o = this.panel.querySelector('[data-action="close"]');
2284
+ o && o.addEventListener("click", () => {
1913
2285
  this.hide();
1914
2286
  }), this.panel.style.opacity = "1", this.panel.style.pointerEvents = "auto", this.panel.style.transform = "translateY(-50%) translateX(0)", this.visible = !0;
1915
2287
  }
@@ -2078,7 +2450,7 @@ class Nt {
2078
2450
  this.panel && this.panel.parentNode && this.panel.parentNode.removeChild(this.panel), this.panel = null;
2079
2451
  }
2080
2452
  }
2081
- class St {
2453
+ class kt {
2082
2454
  constructor(e) {
2083
2455
  l(this, "container");
2084
2456
  l(this, "panel", null);
@@ -2140,18 +2512,18 @@ class St {
2140
2512
  show(e, s, t, i = [e]) {
2141
2513
  if (!this.panel) return;
2142
2514
  this.currentEdgeKey = `${e.source}-${e.target}`;
2143
- let o;
2144
- this.panelTemplate ? o = this.panelTemplate(e, s, t) : o = this.generateDefaultContent(e, s, t, i), this.panel.innerHTML = o;
2145
- const n = this.panel.querySelector('[data-action="close"]');
2146
- n && n.addEventListener("click", () => {
2515
+ let n;
2516
+ this.panelTemplate ? n = this.panelTemplate(e, s, t) : n = this.generateDefaultContent(e, s, t, i), this.panel.innerHTML = n;
2517
+ const o = this.panel.querySelector('[data-action="close"]');
2518
+ o && o.addEventListener("click", () => {
2147
2519
  this.hide(), this.onClose && this.onClose();
2148
2520
  });
2149
- const r = this.panel.querySelector('[data-action="goto-source"]');
2150
- r && this.onNodeClick && r.addEventListener("click", () => {
2521
+ const a = this.panel.querySelector('[data-action="goto-source"]');
2522
+ a && this.onNodeClick && a.addEventListener("click", () => {
2151
2523
  this.onNodeClick && this.onNodeClick(e.source);
2152
2524
  });
2153
- const h = this.panel.querySelector('[data-action="goto-target"]');
2154
- h && this.onNodeClick && h.addEventListener("click", () => {
2525
+ const c = this.panel.querySelector('[data-action="goto-target"]');
2526
+ c && this.onNodeClick && c.addEventListener("click", () => {
2155
2527
  this.onNodeClick && this.onNodeClick(e.target);
2156
2528
  }), this.panel.style.opacity = "1", this.panel.style.pointerEvents = "auto", this.panel.style.transform = "translateY(-50%) translateX(0)", this.visible = !0;
2157
2529
  }
@@ -2159,12 +2531,12 @@ class St {
2159
2531
  * Generates default panel content
2160
2532
  */
2161
2533
  generateDefaultContent(e, s, t, i = [e]) {
2162
- const o = s.color ? `#${s.color.toString(16).padStart(6, "0")}` : "#ff9966", n = t.color ? `#${t.color.toString(16).padStart(6, "0")}` : "#ff9966", r = this.getRelationshipLabel(e), h = i.length > 0 ? i : [e], c = this.summarizeRelationships(h), p = c.slice(0, 10).map((m) => `
2534
+ const n = s.color ? `#${s.color.toString(16).padStart(6, "0")}` : "#ff9966", o = t.color ? `#${t.color.toString(16).padStart(6, "0")}` : "#ff9966", a = this.getRelationshipLabel(e), c = i.length > 0 ? i : [e], h = this.summarizeRelationships(c), d = h.slice(0, 10).map((m) => `
2163
2535
  <div class="relationship-item">
2164
2536
  <span class="relationship-item-label">${this.escapeHtml(m.label)}</span>
2165
2537
  <span class="relationship-item-count">${m.count}</span>
2166
2538
  </div>
2167
- `).join(""), f = c.length - Math.min(c.length, 10);
2539
+ `).join(""), f = h.length - Math.min(h.length, 10);
2168
2540
  return `
2169
2541
  <style>
2170
2542
  .force-graph-edge-panel .panel-header {
@@ -2317,19 +2689,19 @@ class St {
2317
2689
  </div>
2318
2690
 
2319
2691
  <div class="relationship-section">
2320
- <span class="relationship-label">${this.escapeHtml(r)}</span>
2321
- <div class="relationship-count">${h.length} relationships</div>
2692
+ <span class="relationship-label">${this.escapeHtml(a)}</span>
2693
+ <div class="relationship-count">${c.length} relationships</div>
2322
2694
  </div>
2323
2695
 
2324
2696
  <div class="relationship-list">
2325
- ${p}
2697
+ ${d}
2326
2698
  ${f > 0 ? `<div class="relationship-more">+ ${f} more</div>` : ""}
2327
2699
  </div>
2328
2700
 
2329
2701
  <div class="node-card" data-action="goto-source" title="Click to focus on ${this.escapeHtml(s.label)}">
2330
2702
  <div class="node-type">Source</div>
2331
2703
  <div class="node-card-header">
2332
- <span class="color-dot" style="background: ${o}; box-shadow: 0 0 8px ${o}80;"></span>
2704
+ <span class="color-dot" style="background: ${n}; box-shadow: 0 0 8px ${n}80;"></span>
2333
2705
  <span class="node-label">${this.escapeHtml(s.label)}</span>
2334
2706
  </div>
2335
2707
  </div>
@@ -2339,7 +2711,7 @@ class St {
2339
2711
  <div class="node-card" data-action="goto-target" title="Click to focus on ${this.escapeHtml(t.label)}">
2340
2712
  <div class="node-type">Target</div>
2341
2713
  <div class="node-card-header">
2342
- <span class="color-dot" style="background: ${n}; box-shadow: 0 0 8px ${n}80;"></span>
2714
+ <span class="color-dot" style="background: ${o}; box-shadow: 0 0 8px ${o}80;"></span>
2343
2715
  <span class="node-label">${this.escapeHtml(t.label)}</span>
2344
2716
  </div>
2345
2717
  </div>
@@ -2438,25 +2810,25 @@ class zt {
2438
2810
  */
2439
2811
  positionTooltip(e, s) {
2440
2812
  if (!this.tooltip) return;
2441
- const t = this.tooltip.getBoundingClientRect(), i = window.innerWidth, o = window.innerHeight;
2442
- let n = e + 15, r = s + 15;
2443
- n + t.width > i - 10 && (n = e - t.width - 15), r + t.height > o - 10 && (r = s - t.height - 15), n < 10 && (n = 10), r < 10 && (r = 10), this.tooltip.style.left = `${n}px`, this.tooltip.style.top = `${r}px`;
2813
+ const t = this.tooltip.getBoundingClientRect(), i = window.innerWidth, n = window.innerHeight;
2814
+ let o = e + 15, a = s + 15;
2815
+ o + t.width > i - 10 && (o = e - t.width - 15), a + t.height > n - 10 && (a = s - t.height - 15), o < 10 && (o = 10), a < 10 && (a = 10), this.tooltip.style.left = `${o}px`, this.tooltip.style.top = `${a}px`;
2444
2816
  }
2445
2817
  /**
2446
2818
  * Shows the tooltip with edge info
2447
2819
  */
2448
- show(e, s, t, i, o, n = [e]) {
2820
+ show(e, s, t, i, n, o = [e]) {
2449
2821
  if (!this.tooltip) return;
2450
- const r = n.length > 0 ? n : [e], h = this.summarizeRelationships(r), c = r.length;
2451
- if (c <= 1) {
2452
- const p = this.getRelationshipLabel(r[0]);
2822
+ const a = o.length > 0 ? o : [e], c = this.summarizeRelationships(a), h = a.length;
2823
+ if (h <= 1) {
2824
+ const d = this.getRelationshipLabel(a[0]);
2453
2825
  this.tooltip.innerHTML = `
2454
2826
  <div style="display: flex; flex-direction: column; gap: 4px;">
2455
2827
  <div style="display: flex; align-items: center; gap: 6px; flex-wrap: wrap;">
2456
2828
  <span style="font-weight: 600; color: #ff9966;">${this.escapeHtml(s.label)}</span>
2457
2829
  </div>
2458
2830
  <div style="color: rgba(255, 255, 255, 0.6); font-style: italic; font-size: 12px; padding-left: 8px;">
2459
- ↳ ${this.escapeHtml(p)}
2831
+ ↳ ${this.escapeHtml(d)}
2460
2832
  </div>
2461
2833
  <div style="display: flex; align-items: center; gap: 6px; flex-wrap: wrap;">
2462
2834
  <span style="font-weight: 600; color: #ff9966;">${this.escapeHtml(t.label)}</span>
@@ -2464,7 +2836,7 @@ class zt {
2464
2836
  </div>
2465
2837
  `;
2466
2838
  } else {
2467
- const p = h.slice(0, 4), f = h.length - p.length, m = p.map((u) => `<div style="display:flex; justify-content:space-between; gap:10px; font-size:12px; color: rgba(255,255,255,0.8);">
2839
+ const d = c.slice(0, 4), f = c.length - d.length, m = d.map((u) => `<div style="display:flex; justify-content:space-between; gap:10px; font-size:12px; color: rgba(255,255,255,0.8);">
2468
2840
  <span style="overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">${this.escapeHtml(u.label)}</span>
2469
2841
  <span style="color: rgba(255,153,102,0.9); font-weight:600;">${u.count}</span>
2470
2842
  </div>`).join("");
@@ -2474,7 +2846,7 @@ class zt {
2474
2846
  ${this.escapeHtml(s.label)} → ${this.escapeHtml(t.label)}
2475
2847
  </div>
2476
2848
  <div style="font-size:11px; letter-spacing:0.4px; text-transform:uppercase; color: rgba(255,255,255,0.6);">
2477
- ${c} relationships
2849
+ ${h} relationships
2478
2850
  </div>
2479
2851
  <div style="display:flex; flex-direction:column; gap:4px;">
2480
2852
  ${m}
@@ -2483,7 +2855,7 @@ class zt {
2483
2855
  </div>
2484
2856
  `;
2485
2857
  }
2486
- this.positionTooltip(i, o), this.tooltip.style.opacity = "1", this.tooltip.style.transform = "translateY(0)", this.visible = !0;
2858
+ this.positionTooltip(i, n), this.tooltip.style.opacity = "1", this.tooltip.style.transform = "translateY(0)", this.visible = !0;
2487
2859
  }
2488
2860
  /**
2489
2861
  * Updates tooltip position (called externally on mouse move)
@@ -2528,7 +2900,7 @@ class zt {
2528
2900
  this.tooltip && this.tooltip.parentNode && this.tooltip.parentNode.removeChild(this.tooltip), this.tooltip = null;
2529
2901
  }
2530
2902
  }
2531
- class kt {
2903
+ class Pt {
2532
2904
  constructor(e, s) {
2533
2905
  l(this, "container");
2534
2906
  l(this, "searchContainer", null);
@@ -2672,25 +3044,25 @@ class kt {
2672
3044
  return;
2673
3045
  }
2674
3046
  let i = "";
2675
- s.length > 0 && (i += '<div class="f3d-search-section-header">Nodes</div>', s.slice(0, 10).forEach((o) => {
2676
- const n = o.type || "Node";
3047
+ s.length > 0 && (i += '<div class="f3d-search-section-header">Nodes</div>', s.slice(0, 10).forEach((n) => {
3048
+ const o = n.type || "Node";
2677
3049
  i += `
2678
- <div class="f3d-search-result-item" data-node-id="${this.escapeHtml(o.id)}">
2679
- <div class="f3d-result-label">${this.escapeHtml(o.label)}</div>
2680
- <div class="f3d-result-type">${this.escapeHtml(n)}</div>
3050
+ <div class="f3d-search-result-item" data-node-id="${this.escapeHtml(n.id)}">
3051
+ <div class="f3d-result-label">${this.escapeHtml(n.label)}</div>
3052
+ <div class="f3d-result-type">${this.escapeHtml(o)}</div>
2681
3053
  </div>
2682
3054
  `;
2683
- }), 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: n, targetNode: r }) => {
3055
+ }), 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: n, sourceNode: o, targetNode: a }) => {
2684
3056
  i += `
2685
- <div class="f3d-search-result-item" data-node-id="${this.escapeHtml(o.source)}">
2686
- <div class="f3d-result-label">${this.escapeHtml(n.label)} → ${this.escapeHtml(r.label)}</div>
2687
- <div class="f3d-result-relationship">${this.escapeHtml(o.relationship || "connected")}</div>
3057
+ <div class="f3d-search-result-item" data-node-id="${this.escapeHtml(n.source)}">
3058
+ <div class="f3d-result-label">${this.escapeHtml(o.label)} → ${this.escapeHtml(a.label)}</div>
3059
+ <div class="f3d-result-relationship">${this.escapeHtml(n.relationship || "connected")}</div>
2688
3060
  </div>
2689
3061
  `;
2690
- }), 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) => {
2691
- o.addEventListener("click", () => {
2692
- const n = o.dataset.nodeId;
2693
- n && (this.onResultClick(n), this.searchResults && (this.searchResults.style.display = "none"), this.searchInput && this.searchInput.blur());
3062
+ }), 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((n) => {
3063
+ n.addEventListener("click", () => {
3064
+ const o = n.dataset.nodeId;
3065
+ o && (this.onResultClick(o), this.searchResults && (this.searchResults.style.display = "none"), this.searchInput && this.searchInput.blur());
2694
3066
  });
2695
3067
  });
2696
3068
  }
@@ -2702,7 +3074,7 @@ class kt {
2702
3074
  this.searchContainer && this.searchContainer.parentNode && this.searchContainer.parentNode.removeChild(this.searchContainer);
2703
3075
  }
2704
3076
  }
2705
- class Tt {
3077
+ class Rt {
2706
3078
  constructor(e, s) {
2707
3079
  l(this, "container");
2708
3080
  l(this, "toggleContainer", null);
@@ -2794,7 +3166,7 @@ class Tt {
2794
3166
  this.toggleContainer && this.toggleContainer.parentNode && this.toggleContainer.parentNode.removeChild(this.toggleContainer);
2795
3167
  }
2796
3168
  }
2797
- class Pt {
3169
+ class Lt {
2798
3170
  constructor(e) {
2799
3171
  l(this, "container");
2800
3172
  l(this, "legendContainer", null);
@@ -2877,7 +3249,7 @@ class Pt {
2877
3249
  this.legendContainer && this.legendContainer.parentNode && this.legendContainer.parentNode.removeChild(this.legendContainer);
2878
3250
  }
2879
3251
  }
2880
- const Rt = {
3252
+ const Tt = {
2881
3253
  backgroundColor: "#0a0a0a",
2882
3254
  gridColor: "rgba(255, 255, 255, 0.03)",
2883
3255
  nodeRadius: 24,
@@ -2890,7 +3262,7 @@ const Rt = {
2890
3262
  damping: 0.85
2891
3263
  // Fast energy dissipation
2892
3264
  };
2893
- class Lt {
3265
+ class It {
2894
3266
  constructor(e, s = {}) {
2895
3267
  l(this, "container");
2896
3268
  l(this, "canvas");
@@ -2917,7 +3289,7 @@ class Lt {
2917
3289
  l(this, "isSimulating", !0);
2918
3290
  // Resize handler
2919
3291
  l(this, "resizeHandler");
2920
- this.container = e, this.options = { ...Rt, ...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);
3292
+ 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);
2921
3293
  const t = this.canvas.getContext("2d");
2922
3294
  if (!t)
2923
3295
  throw new Error("Failed to get 2D context");
@@ -2930,23 +3302,23 @@ class Lt {
2930
3302
  setupInteractions() {
2931
3303
  this.canvas.addEventListener("wheel", (e) => {
2932
3304
  e.preventDefault();
2933
- const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, o = e.deltaY > 0 ? 0.9 : 1.1, n = Math.max(0.1, Math.min(5, this.transform.scale * o)), r = n / this.transform.scale;
2934
- this.transform.x = t - (t - this.transform.x) * r, this.transform.y = i - (i - this.transform.y) * r, this.transform.scale = n;
3305
+ const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, n = e.deltaY > 0 ? 0.9 : 1.1, o = Math.max(0.1, Math.min(5, this.transform.scale * n)), a = o / this.transform.scale;
3306
+ this.transform.x = t - (t - this.transform.x) * a, this.transform.y = i - (i - this.transform.y) * a, this.transform.scale = o;
2935
3307
  }), this.canvas.addEventListener("mousedown", (e) => {
2936
- const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, o = this.screenToWorld(t, i), n = this.findNodeAt(o.x, o.y);
2937
- this.dragStartPos = { x: e.clientX, y: e.clientY }, n ? (this.isDragging = !0, this.draggedNode = n, this.canvas.style.cursor = "grabbing", this.isSimulating = !0) : (this.isPanning = !0, this.canvas.style.cursor = "grabbing"), this.lastMousePos = { x: e.clientX, y: e.clientY };
3308
+ const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, n = this.screenToWorld(t, i), o = this.findNodeAt(n.x, n.y);
3309
+ this.dragStartPos = { x: e.clientX, y: e.clientY }, o ? (this.isDragging = !0, this.draggedNode = o, this.canvas.style.cursor = "grabbing", this.isSimulating = !0) : (this.isPanning = !0, this.canvas.style.cursor = "grabbing"), this.lastMousePos = { x: e.clientX, y: e.clientY };
2938
3310
  }), this.canvas.addEventListener("mousemove", (e) => {
2939
- const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, o = this.screenToWorld(t, i);
3311
+ const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, n = this.screenToWorld(t, i);
2940
3312
  if (this.isDragging && this.draggedNode)
2941
- this.draggedNode.x = o.x, this.draggedNode.y = o.y, this.draggedNode.vx = 0, this.draggedNode.vy = 0;
3313
+ this.draggedNode.x = n.x, this.draggedNode.y = n.y, this.draggedNode.vx = 0, this.draggedNode.vy = 0;
2942
3314
  else if (this.isPanning) {
2943
- const n = e.clientX - this.lastMousePos.x, r = e.clientY - this.lastMousePos.y;
2944
- this.transform.x += n, this.transform.y += r, this.lastMousePos = { x: e.clientX, y: e.clientY };
3315
+ const o = e.clientX - this.lastMousePos.x, a = e.clientY - this.lastMousePos.y;
3316
+ this.transform.x += o, this.transform.y += a, this.lastMousePos = { x: e.clientX, y: e.clientY };
2945
3317
  } else {
2946
- const n = this.findNodeAt(o.x, o.y);
2947
- if (n !== this.hoveredNode && (this.hoveredNode = n, n ? (this.hoveredEdge && (this.hoveredEdge = null, this.options.onEdgeHover && this.options.onEdgeHover(null)), this.canvas.style.cursor = "pointer", this.options.onNodeHover && this.options.onNodeHover(n.data)) : this.options.onNodeHover && this.options.onNodeHover(null)), !n) {
2948
- const r = this.findEdgeAt(o.x, o.y);
2949
- r !== this.hoveredEdge && (this.hoveredEdge = r, this.canvas.style.cursor = r ? "pointer" : "grab", this.options.onEdgeHover && this.options.onEdgeHover(r ? r.data : null, e));
3318
+ const o = this.findNodeAt(n.x, n.y);
3319
+ if (o !== this.hoveredNode && (this.hoveredNode = o, o ? (this.hoveredEdge && (this.hoveredEdge = null, this.options.onEdgeHover && this.options.onEdgeHover(null)), this.canvas.style.cursor = "pointer", this.options.onNodeHover && this.options.onNodeHover(o.data)) : this.options.onNodeHover && this.options.onNodeHover(null)), !o) {
3320
+ const a = this.findEdgeAt(n.x, n.y);
3321
+ a !== this.hoveredEdge && (this.hoveredEdge = a, this.canvas.style.cursor = a ? "pointer" : "grab", this.options.onEdgeHover && this.options.onEdgeHover(a ? a.data : null, e));
2950
3322
  }
2951
3323
  }
2952
3324
  }), this.canvas.addEventListener("mouseup", (e) => {
@@ -2954,8 +3326,8 @@ class Lt {
2954
3326
  if (this.isDragging && this.draggedNode)
2955
3327
  i && this.options.onNodeClick && (this.selectedNode = this.draggedNode, this.options.onNodeClick(this.draggedNode.data));
2956
3328
  else if (i) {
2957
- const o = this.canvas.getBoundingClientRect(), n = this.screenToWorld(e.clientX - o.left, e.clientY - o.top), r = this.findEdgeAt(n.x, n.y);
2958
- r && this.options.onEdgeClick && this.options.onEdgeClick(r.data);
3329
+ const n = this.canvas.getBoundingClientRect(), o = this.screenToWorld(e.clientX - n.left, e.clientY - n.top), a = this.findEdgeAt(o.x, o.y);
3330
+ a && this.options.onEdgeClick && this.options.onEdgeClick(a.data);
2959
3331
  }
2960
3332
  this.isDragging = !1, this.isPanning = !1, this.draggedNode = null, this.canvas.style.cursor = this.hoveredNode ? "pointer" : "grab";
2961
3333
  }), this.canvas.addEventListener("mouseleave", () => {
@@ -2970,20 +3342,20 @@ class Lt {
2970
3342
  }
2971
3343
  findNodeAt(e, s) {
2972
3344
  for (const t of this.nodes.values()) {
2973
- const i = t.x - e, o = t.y - s;
2974
- if (Math.sqrt(i * i + o * o) < t.radius)
3345
+ const i = t.x - e, n = t.y - s;
3346
+ if (Math.sqrt(i * i + n * n) < t.radius)
2975
3347
  return t;
2976
3348
  }
2977
3349
  return null;
2978
3350
  }
2979
3351
  findEdgeAt(e, s) {
2980
3352
  for (const i of this.edges) {
2981
- const o = this.nodes.get(i.source), n = this.nodes.get(i.target);
2982
- if (!o || !n) continue;
2983
- const r = n.x - o.x, h = n.y - o.y, c = r * r + h * h;
2984
- if (c === 0) continue;
2985
- const p = Math.max(0, Math.min(1, ((e - o.x) * r + (s - o.y) * h) / c)), f = o.x + p * r, m = o.y + p * h, u = e - f, y = s - m;
2986
- if (Math.sqrt(u * u + y * y) < 12)
3353
+ const n = this.nodes.get(i.source), o = this.nodes.get(i.target);
3354
+ if (!n || !o) continue;
3355
+ const a = o.x - n.x, c = o.y - n.y, h = a * a + c * c;
3356
+ if (h === 0) continue;
3357
+ const d = Math.max(0, Math.min(1, ((e - n.x) * a + (s - n.y) * c) / h)), f = n.x + d * a, m = n.y + d * c, u = e - f, b = s - m;
3358
+ if (Math.sqrt(u * u + b * b) < 12)
2987
3359
  return i;
2988
3360
  }
2989
3361
  return null;
@@ -2998,79 +3370,79 @@ class Lt {
2998
3370
  const e = Array.from(this.nodes.values()), s = e.length;
2999
3371
  if (s === 0) return;
3000
3372
  const t = 60, i = 5;
3001
- let o = 0;
3002
- for (let r = 0; r < s; r++)
3003
- for (let h = r + 1; h < s; h++) {
3004
- const c = e[r], p = e[h];
3005
- let f = p.x - c.x, m = p.y - c.y, u = Math.sqrt(f * f + m * m);
3373
+ let n = 0;
3374
+ for (let a = 0; a < s; a++)
3375
+ for (let c = a + 1; c < s; c++) {
3376
+ const h = e[a], d = e[c];
3377
+ let f = d.x - h.x, m = d.y - h.y, u = Math.sqrt(f * f + m * m);
3006
3378
  if (u < t * 3) {
3007
3379
  u < 1 && (u = 1);
3008
- const y = this.options.repulsionStrength / (u * u), b = f / u * y, w = m / u * y;
3009
- c.vx -= b, c.vy -= w, p.vx += b, p.vy += w;
3380
+ const b = this.options.repulsionStrength / (u * u), x = f / u * b, M = m / u * b;
3381
+ h.vx -= x, h.vy -= M, d.vx += x, d.vy += M;
3010
3382
  }
3011
3383
  }
3012
- const n = 80;
3013
- for (const r of this.edges) {
3014
- const h = this.nodes.get(r.source), c = this.nodes.get(r.target);
3015
- if (!h || !c) continue;
3016
- let p = c.x - h.x, f = c.y - h.y, m = Math.sqrt(p * p + f * f);
3384
+ const o = 80;
3385
+ for (const a of this.edges) {
3386
+ const c = this.nodes.get(a.source), h = this.nodes.get(a.target);
3387
+ if (!c || !h) continue;
3388
+ let d = h.x - c.x, f = h.y - c.y, m = Math.sqrt(d * d + f * f);
3017
3389
  m < 1 && (m = 1);
3018
- const y = (m - n) * this.options.attractionStrength, b = p / m * y, w = f / m * y;
3019
- h.vx += b, h.vy += w, c.vx -= b, c.vy -= w;
3390
+ const b = (m - o) * this.options.attractionStrength, x = d / m * b, M = f / m * b;
3391
+ c.vx += x, c.vy += M, h.vx -= x, h.vy -= M;
3020
3392
  }
3021
- for (const r of e) {
3022
- if (this.draggedNode === r) continue;
3023
- r.vx *= this.options.damping, r.vy *= this.options.damping;
3024
- const h = Math.sqrt(r.vx * r.vx + r.vy * r.vy);
3025
- h > i && (r.vx = r.vx / h * i, r.vy = r.vy / h * i), r.x += r.vx, r.y += r.vy, o += r.vx * r.vx + r.vy * r.vy;
3393
+ for (const a of e) {
3394
+ if (this.draggedNode === a) continue;
3395
+ a.vx *= this.options.damping, a.vy *= this.options.damping;
3396
+ const c = Math.sqrt(a.vx * a.vx + a.vy * a.vy);
3397
+ c > i && (a.vx = a.vx / c * i, a.vy = a.vy / c * i), a.x += a.vx, a.y += a.vy, n += a.vx * a.vx + a.vy * a.vy;
3026
3398
  }
3027
- o < 0.01 && !this.draggedNode && (this.isSimulating = !1);
3399
+ n < 0.01 && !this.draggedNode && (this.isSimulating = !1);
3028
3400
  }
3029
3401
  render() {
3030
3402
  const e = this.ctx, s = this.canvas.width / (window.devicePixelRatio || 1), t = this.canvas.height / (window.devicePixelRatio || 1);
3031
3403
  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();
3032
3404
  }
3033
3405
  renderGrid(e, s) {
3034
- const t = this.ctx, i = 40 * this.transform.scale, o = 1.5, n = this.transform.x % i, r = this.transform.y % i;
3406
+ const t = this.ctx, i = 40 * this.transform.scale, n = 1.5, o = this.transform.x % i, a = this.transform.y % i;
3035
3407
  t.fillStyle = this.options.gridColor;
3036
- for (let h = n; h < e; h += i)
3037
- for (let c = r; c < s; c += i)
3038
- t.beginPath(), t.arc(h, c, o, 0, Math.PI * 2), t.fill();
3408
+ for (let c = o; c < e; c += i)
3409
+ for (let h = a; h < s; h += i)
3410
+ t.beginPath(), t.arc(c, h, n, 0, Math.PI * 2), t.fill();
3039
3411
  }
3040
3412
  renderEdges() {
3041
3413
  const e = this.ctx;
3042
3414
  for (const s of this.edges) {
3043
3415
  const t = this.nodes.get(s.source), i = this.nodes.get(s.target);
3044
3416
  if (!t || !i) continue;
3045
- const o = s === this.hoveredEdge, n = e.createLinearGradient(t.x, t.y, i.x, i.y);
3046
- o ? (n.addColorStop(0, "rgba(255, 153, 102, 0.8)"), n.addColorStop(0.5, "rgba(255, 255, 255, 0.5)"), n.addColorStop(1, "rgba(102, 153, 255, 0.8)"), e.lineWidth = 3) : (n.addColorStop(0, "rgba(255, 153, 102, 0.3)"), n.addColorStop(0.5, "rgba(255, 255, 255, 0.15)"), n.addColorStop(1, "rgba(102, 153, 255, 0.3)"), e.lineWidth = 1.5), e.beginPath(), e.moveTo(t.x, t.y), e.lineTo(i.x, i.y), e.strokeStyle = n, e.stroke();
3417
+ const n = s === this.hoveredEdge, o = e.createLinearGradient(t.x, t.y, i.x, i.y);
3418
+ n ? (o.addColorStop(0, "rgba(255, 153, 102, 0.8)"), o.addColorStop(0.5, "rgba(255, 255, 255, 0.5)"), o.addColorStop(1, "rgba(102, 153, 255, 0.8)"), e.lineWidth = 3) : (o.addColorStop(0, "rgba(255, 153, 102, 0.3)"), o.addColorStop(0.5, "rgba(255, 255, 255, 0.15)"), o.addColorStop(1, "rgba(102, 153, 255, 0.3)"), e.lineWidth = 1.5), e.beginPath(), e.moveTo(t.x, t.y), e.lineTo(i.x, i.y), e.strokeStyle = o, e.stroke();
3047
3419
  }
3048
3420
  }
3049
3421
  renderNodes() {
3050
3422
  const e = this.ctx;
3051
3423
  for (const s of this.nodes.values()) {
3052
- const t = s === this.hoveredNode, i = s === this.selectedNode, o = this.hoveredEdge && (s.data.id === this.hoveredEdge.source || s.data.id === this.hoveredEdge.target), n = s.radius * (t ? 1.1 : 1);
3053
- if (t || i || o) {
3054
- const y = e.createRadialGradient(
3424
+ const t = s === this.hoveredNode, i = s === this.selectedNode, n = this.hoveredEdge && (s.data.id === this.hoveredEdge.source || s.data.id === this.hoveredEdge.target), o = s.radius * (t ? 1.1 : 1);
3425
+ if (t || i || n) {
3426
+ const b = e.createRadialGradient(
3055
3427
  s.x,
3056
3428
  s.y,
3057
- n * 0.5,
3429
+ o * 0.5,
3058
3430
  s.x,
3059
3431
  s.y,
3060
- n * 2
3061
- ), b = t || i ? 0.4 : 0.25;
3062
- y.addColorStop(0, `rgba(255, 153, 102, ${b})`), y.addColorStop(1, "rgba(255, 153, 102, 0)"), e.fillStyle = y, e.beginPath(), e.arc(s.x, s.y, n * 2, 0, Math.PI * 2), e.fill();
3432
+ o * 2
3433
+ ), x = t || i ? 0.4 : 0.25;
3434
+ b.addColorStop(0, `rgba(255, 153, 102, ${x})`), b.addColorStop(1, "rgba(255, 153, 102, 0)"), e.fillStyle = b, e.beginPath(), e.arc(s.x, s.y, o * 2, 0, Math.PI * 2), e.fill();
3063
3435
  }
3064
- const r = e.createRadialGradient(
3065
- s.x - n * 0.3,
3066
- s.y - n * 0.3,
3436
+ const a = e.createRadialGradient(
3437
+ s.x - o * 0.3,
3438
+ s.y - o * 0.3,
3067
3439
  0,
3068
3440
  s.x,
3069
3441
  s.y,
3070
- n
3071
- ), h = s.color >> 16 & 255, c = s.color >> 8 & 255, p = s.color & 255;
3072
- r.addColorStop(0, `rgba(${Math.min(255, h + 60)}, ${Math.min(255, c + 60)}, ${Math.min(255, p + 60)}, 0.95)`), r.addColorStop(0.7, `rgba(${h}, ${c}, ${p}, 0.9)`), r.addColorStop(1, `rgba(${Math.max(0, h - 40)}, ${Math.max(0, c - 40)}, ${Math.max(0, p - 40)}, 0.85)`), e.beginPath(), e.arc(s.x, s.y, n, 0, Math.PI * 2), e.fillStyle = r, e.fill(), e.strokeStyle = "rgba(255, 255, 255, 0.2)", e.lineWidth = 1, e.stroke(), e.beginPath(), e.arc(s.x - n * 0.25, s.y - n * 0.25, n * 0.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";
3073
- const f = n * 1.6;
3442
+ o
3443
+ ), c = s.color >> 16 & 255, h = s.color >> 8 & 255, d = s.color & 255;
3444
+ a.addColorStop(0, `rgba(${Math.min(255, c + 60)}, ${Math.min(255, h + 60)}, ${Math.min(255, d + 60)}, 0.95)`), a.addColorStop(0.7, `rgba(${c}, ${h}, ${d}, 0.9)`), a.addColorStop(1, `rgba(${Math.max(0, c - 40)}, ${Math.max(0, h - 40)}, ${Math.max(0, d - 40)}, 0.85)`), e.beginPath(), e.arc(s.x, s.y, o, 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 - o * 0.25, s.y - o * 0.25, o * 0.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";
3445
+ const f = o * 1.6;
3074
3446
  let m = s.label, u = e.measureText(m).width;
3075
3447
  if (u > f) {
3076
3448
  for (; u > f && m.length > 3; )
@@ -3088,7 +3460,7 @@ class Lt {
3088
3460
  const i = s.position || {
3089
3461
  x: (Math.random() - 0.5) * 300,
3090
3462
  y: (Math.random() - 0.5) * 300
3091
- }, o = {
3463
+ }, n = {
3092
3464
  id: s.id,
3093
3465
  label: s.label,
3094
3466
  x: i.x,
@@ -3100,7 +3472,7 @@ class Lt {
3100
3472
  radius: this.options.nodeRadius,
3101
3473
  data: s
3102
3474
  };
3103
- this.nodes.set(s.id, o), this.nodeIdToIndex.set(s.id, t);
3475
+ this.nodes.set(s.id, n), this.nodeIdToIndex.set(s.id, t);
3104
3476
  }), this.edges = e.edges.map((s) => ({
3105
3477
  source: s.source,
3106
3478
  target: s.target,
@@ -3176,11 +3548,11 @@ class Lt {
3176
3548
  focusOnNode(e) {
3177
3549
  const s = this.nodes.get(e);
3178
3550
  if (!s) return;
3179
- const t = this.canvas.width / 2 / (window.devicePixelRatio || 1) - s.x * this.transform.scale, i = this.canvas.height / 2 / (window.devicePixelRatio || 1) - s.y * this.transform.scale, o = this.transform.x, n = this.transform.y, r = 500, h = performance.now(), c = () => {
3180
- const p = performance.now() - h, f = Math.min(p / r, 1), m = 1 - Math.pow(1 - f, 3);
3181
- this.transform.x = o + (t - o) * m, this.transform.y = n + (i - n) * m, f < 1 ? requestAnimationFrame(c) : this.selectedNode = s;
3551
+ const t = this.canvas.width / 2 / (window.devicePixelRatio || 1) - s.x * this.transform.scale, i = this.canvas.height / 2 / (window.devicePixelRatio || 1) - s.y * this.transform.scale, n = this.transform.x, o = this.transform.y, a = 500, c = performance.now(), h = () => {
3552
+ const d = performance.now() - c, f = Math.min(d / a, 1), m = 1 - Math.pow(1 - f, 3);
3553
+ this.transform.x = n + (t - n) * m, this.transform.y = o + (i - o) * m, f < 1 ? requestAnimationFrame(h) : this.selectedNode = s;
3182
3554
  };
3183
- c();
3555
+ h();
3184
3556
  }
3185
3557
  /**
3186
3558
  * Updates node positions from 3D data
@@ -3223,7 +3595,6 @@ class Lt {
3223
3595
  }
3224
3596
  }
3225
3597
  class Ht {
3226
- // Store graph data for view switching
3227
3598
  constructor(e, s = {}) {
3228
3599
  // Options
3229
3600
  l(this, "options");
@@ -3234,6 +3605,8 @@ class Ht {
3234
3605
  l(this, "edgeManager");
3235
3606
  l(this, "graphEngine");
3236
3607
  l(this, "rendererManager");
3608
+ l(this, "physicsWorkerBridge", null);
3609
+ l(this, "useWorkerPhysics", !1);
3237
3610
  // Factories
3238
3611
  l(this, "materialFactory");
3239
3612
  l(this, "nodeFactory");
@@ -3258,23 +3631,33 @@ class Ht {
3258
3631
  l(this, "devControls", null);
3259
3632
  l(this, "viewMode", "3d");
3260
3633
  l(this, "graphData", null);
3261
- this.options = { ...P, ...s }, this.container = ht(e), this.materialFactory = new bt(), this.nodeFactory = new vt(
3634
+ // Store graph data for view switching
3635
+ l(this, "simulationStride", 1);
3636
+ l(this, "simulationTick", 0);
3637
+ l(this, "labelUpdateIntervalMs", 140);
3638
+ l(this, "lastLabelUpdateAt", 0);
3639
+ l(this, "performanceCheckIntervalMs", 1e3);
3640
+ l(this, "lastPerformanceCheckAt", 0);
3641
+ l(this, "currentPixelRatio", 1);
3642
+ l(this, "edgeInteractionsEnabled", !0);
3643
+ l(this, "physicsWorkerNeedsSync", !0);
3644
+ this.options = { ...C, ...s }, this.container = ht(e), this.materialFactory = new vt(), this.nodeFactory = new Mt(
3262
3645
  this.materialFactory,
3263
- this.options.nodeRadius ?? P.nodeRadius,
3264
- this.options.lodSegments ?? P.lodSegments,
3265
- this.options.defaultNodeColor ?? P.defaultNodeColor
3646
+ this.options.nodeRadius ?? C.nodeRadius,
3647
+ this.options.lodSegments ?? C.lodSegments,
3648
+ this.options.defaultNodeColor ?? C.defaultNodeColor
3266
3649
  ), this.edgeFactory = new wt(
3267
3650
  this.materialFactory,
3268
- this.options.edgeColor ?? P.edgeColor,
3269
- this.options.edgeOpacity ?? P.edgeOpacity
3270
- ), this.sceneManager = new ft(this.container, this.options), this.lodManager = new Mt(
3651
+ this.options.edgeColor ?? C.edgeColor,
3652
+ this.options.edgeOpacity ?? C.edgeOpacity
3653
+ ), this.sceneManager = new ft(this.container, this.options), this.currentPixelRatio = this.sceneManager.getPixelRatio(), this.lodManager = new Et(
3271
3654
  this.sceneManager.camera,
3272
- this.options.lodDistances ?? P.lodDistances,
3273
- this.options.enableLOD ?? P.enableLOD
3274
- ), this.frustumCuller = new Et(
3655
+ this.options.lodDistances ?? C.lodDistances,
3656
+ this.options.enableLOD ?? C.enableLOD
3657
+ ), this.frustumCuller = new Ct(
3275
3658
  this.sceneManager.camera,
3276
- this.options.enableEdgeCulling ?? P.enableEdgeCulling
3277
- ), this.nodeManager = new ee(this.sceneManager, this.nodeFactory), this.edgeManager = new mt(this.sceneManager, this.nodeManager, this.edgeFactory), this.graphEngine = new Le(
3659
+ this.options.enableEdgeCulling ?? C.enableEdgeCulling
3660
+ ), this.nodeManager = new ee(this.sceneManager, this.nodeFactory), this.edgeManager = new mt(this.sceneManager, this.nodeManager, this.edgeFactory), this.graphEngine = new Oe(
3278
3661
  this.nodeManager.getAllNodes(),
3279
3662
  this.edgeManager.getAllEdges(),
3280
3663
  {
@@ -3284,16 +3667,16 @@ class Ht {
3284
3667
  useBarnesHut: this.options.useBarnesHut,
3285
3668
  barnesHutTheta: this.options.barnesHutTheta
3286
3669
  }
3287
- ), this.rendererManager = new xt(
3670
+ ), this.rendererManager = new bt(
3288
3671
  this.sceneManager,
3289
3672
  () => this.onSimulate(),
3290
3673
  () => this.onRender(),
3291
- this.options.targetFPS ?? P.targetFPS
3292
- ), this.raycasterManager = new Ct(this.sceneManager, this.container), this.panelManager = new Nt(this.container), this.edgePanelManager = new St(this.container), this.edgeTooltipManager = new zt(), this.edgePanelManager.setNodeClickCallback((t) => {
3674
+ this.options.targetFPS ?? C.targetFPS
3675
+ ), this.raycasterManager = new St(this.sceneManager, this.container), this.panelManager = new Nt(this.container), this.edgePanelManager = new kt(this.container), this.edgeTooltipManager = new zt(), this.edgePanelManager.setNodeClickCallback((t) => {
3293
3676
  this.edgePanelManager.hide(), this.focusOnNode(t), setTimeout(() => {
3294
3677
  this.showNodePanel(t);
3295
3678
  }, 400);
3296
- }), this.options.showSearch !== !1 && (this.searchManager = new kt(this.container, {
3679
+ }), this.options.showSearch !== !1 && (this.searchManager = new Pt(this.container, {
3297
3680
  placeholder: this.options.searchPlaceholder,
3298
3681
  onSearch: (t) => ({
3299
3682
  nodeResults: this.searchNodes(t),
@@ -3304,12 +3687,12 @@ class Ht {
3304
3687
  this.showNodePanel(t);
3305
3688
  }, 400);
3306
3689
  }
3307
- })), this.options.showViewToggle !== !1 && (this.viewMode = this.options.initialViewMode || "3d", this.viewToggleManager = new Tt(this.container, {
3690
+ })), this.options.showViewToggle !== !1 && (this.viewMode = this.options.initialViewMode || "3d", this.viewToggleManager = new Rt(this.container, {
3308
3691
  initialMode: this.viewMode,
3309
3692
  onViewChange: (t) => {
3310
3693
  this.switchView(t);
3311
3694
  }
3312
- })), this.options.showLegend !== !1 && (this.legendManager = new Pt(this.container), this.updateLegendCounts()), this.setupCallbacks(), this.rendererManager.start(), this.initialized = !0, this.emit("ready");
3695
+ })), this.options.showLegend !== !1 && (this.legendManager = new Lt(this.container), this.updateLegendCounts()), this.setupCallbacks(), this.applyPerformanceModeSettings(), this.rendererManager.start(), this.initialized = !0, this.emit("ready");
3313
3696
  }
3314
3697
  /**
3315
3698
  * Sets up internal callbacks
@@ -3361,19 +3744,50 @@ class Ht {
3361
3744
  * Called every simulation step
3362
3745
  */
3363
3746
  onSimulate() {
3364
- this.graphEngine.simulate();
3365
- for (const [e, s] of this.nodeManager.getAllNodes())
3366
- if (this.nodeManager.updateNodePosition(e, s.position), this.options.enableLOD) {
3367
- const t = this.lodManager.getLODLevel(s.position);
3368
- this.nodeManager.updateNodeLOD(e, t);
3747
+ if (this.useWorkerPhysics && this.physicsWorkerBridge) {
3748
+ const e = this.physicsWorkerBridge.consumeLatestFrame();
3749
+ if (e) {
3750
+ const { ids: s, positions: t } = e;
3751
+ for (let i = 0; i < s.length; i++) {
3752
+ const n = i * 3, o = s[i];
3753
+ if (this.nodeManager.updateNodePosition(o, {
3754
+ x: t[n],
3755
+ y: t[n + 1],
3756
+ z: t[n + 2]
3757
+ }), this.options.enableLOD) {
3758
+ const a = this.nodeManager.getNode(o);
3759
+ if (a) {
3760
+ const c = this.lodManager.getLODLevel(a.position);
3761
+ this.nodeManager.updateNodeLOD(o, c);
3762
+ }
3763
+ }
3764
+ }
3765
+ this.edgeManager.updateEdgePositions();
3369
3766
  }
3370
- this.edgeManager.updateEdgePositions();
3767
+ this.physicsWorkerBridge.requestStep();
3768
+ return;
3769
+ }
3770
+ if (this.simulationTick = (this.simulationTick + 1) % this.simulationStride, this.simulationTick === 0) {
3771
+ this.graphEngine.simulate();
3772
+ for (const [e, s] of this.nodeManager.getAllNodes())
3773
+ if (this.nodeManager.updateNodePosition(e, s.position), this.options.enableLOD) {
3774
+ const t = this.lodManager.getLODLevel(s.position);
3775
+ this.nodeManager.updateNodeLOD(e, t);
3776
+ }
3777
+ this.edgeManager.updateEdgePositions();
3778
+ }
3371
3779
  }
3372
3780
  /**
3373
3781
  * Called every render frame
3374
3782
  */
3375
3783
  onRender() {
3376
- this.frustumCuller.update(), this.raycasterManager.setNodeObjects(this.nodeManager.getAllNodeObjects()), this.raycasterManager.setEdgeObjects(this.edgeManager.getAllEdgeLines());
3784
+ this.frustumCuller.update(), this.raycasterManager.setNodeObjects(this.nodeManager.getAllNodeObjects()), this.raycasterManager.setEdgeInteractionEnabled(this.edgeInteractionsEnabled), this.edgeInteractionsEnabled ? this.raycasterManager.setEdgeObjects(this.edgeManager.getAllEdgeLines()) : this.raycasterManager.setEdgeObjects([]);
3785
+ const e = performance.now();
3786
+ e - this.lastLabelUpdateAt >= this.labelUpdateIntervalMs && (this.nodeManager.updateLabelVisibility(
3787
+ this.sceneManager.getCameraPosition(),
3788
+ this.panelManager.getCurrentNodeId(),
3789
+ this.raycasterManager.getHoveredNodeId()
3790
+ ), this.lastLabelUpdateAt = e), (this.options.enableAdaptivePerformance ?? !0) && e - this.lastPerformanceCheckAt >= this.performanceCheckIntervalMs && (this.tunePerformanceForCurrentFPS(), this.lastPerformanceCheckAt = e);
3377
3791
  }
3378
3792
  /**
3379
3793
  * Updates bottom-right legend counts
@@ -3381,6 +3795,55 @@ class Ht {
3381
3795
  updateLegendCounts() {
3382
3796
  this.legendManager && this.legendManager.updateCounts(this.getNodeCount(), this.getEdgeCount());
3383
3797
  }
3798
+ /**
3799
+ * Applies baseline performance preset from constructor options
3800
+ */
3801
+ applyPerformanceModeSettings() {
3802
+ const e = this.options.performanceMode ?? "balanced";
3803
+ this.nodeManager.setLabelDistance(this.options.labelDistance ?? C.labelDistance), e === "quality" ? (this.sceneManager.setHighQualityRendering(!0), this.rendererManager.setTargetFPS(this.options.targetFPS ?? 60), this.simulationStride = 1, this.nodeManager.setLabelRenderMode("all"), this.edgeInteractionsEnabled = !0) : e === "low" ? (this.sceneManager.setHighQualityRendering(!1), this.rendererManager.setTargetFPS(Math.min(this.options.targetFPS ?? 60, 45)), this.simulationStride = 2, this.nodeManager.setLabelRenderMode(
3804
+ this.options.labelRenderMode === "all" ? "adaptive" : this.options.labelRenderMode ?? "none"
3805
+ ), this.edgeInteractionsEnabled = !(this.options.disableEdgeInteractionsInLowMode ?? !0), this.currentPixelRatio = Math.min(this.currentPixelRatio, 1), this.sceneManager.setPixelRatio(this.currentPixelRatio)) : (this.sceneManager.setHighQualityRendering(!0), this.rendererManager.setTargetFPS(this.options.targetFPS ?? 60), this.simulationStride = 1, this.nodeManager.setLabelRenderMode(this.options.labelRenderMode ?? "adaptive"), this.edgeInteractionsEnabled = !0), this.refreshPhysicsBackend();
3806
+ }
3807
+ /**
3808
+ * Applies adaptive quality tuning based on runtime FPS
3809
+ */
3810
+ tunePerformanceForCurrentFPS() {
3811
+ const e = this.rendererManager.getFPS(), s = this.options.minPixelRatio ?? C.minPixelRatio, t = Math.min(
3812
+ this.options.maxPixelRatio ?? C.maxPixelRatio,
3813
+ window.devicePixelRatio || 1
3814
+ );
3815
+ e < 24 ? (this.simulationStride = 3, this.currentPixelRatio > s && (this.currentPixelRatio = Math.max(s, this.currentPixelRatio - 0.1), this.sceneManager.setPixelRatio(this.currentPixelRatio)), this.options.performanceMode !== "quality" && this.nodeManager.setLabelRenderMode("none")) : e < 35 ? (this.simulationStride = Math.max(this.simulationStride, 2), this.currentPixelRatio > s && (this.currentPixelRatio = Math.max(s, this.currentPixelRatio - 0.06), this.sceneManager.setPixelRatio(this.currentPixelRatio)), this.options.performanceMode === "balanced" && this.nodeManager.setLabelRenderMode("adaptive")) : e > 52 ? (this.simulationStride = 1, this.options.performanceMode !== "low" && this.nodeManager.setLabelRenderMode(this.options.labelRenderMode ?? "adaptive"), this.currentPixelRatio < t && (this.currentPixelRatio = Math.min(t, this.currentPixelRatio + 0.05), this.sceneManager.setPixelRatio(this.currentPixelRatio))) : this.simulationStride = Math.min(this.simulationStride, 2), this.refreshPerformanceRenderingMode(), this.refreshPhysicsBackend();
3816
+ }
3817
+ /**
3818
+ * Chooses edge rendering strategy based on graph size and mode
3819
+ */
3820
+ refreshPerformanceRenderingMode() {
3821
+ const e = this.getEdgeCount(), s = this.options.edgeBatchThreshold ?? C.edgeBatchThreshold, t = this.options.performanceMode === "low" && e >= s;
3822
+ this.edgeManager.setBatchRenderingEnabled(t), t && (this.options.disableEdgeInteractionsInLowMode ?? !0) ? this.edgeInteractionsEnabled = !1 : this.edgeInteractionsEnabled = !0;
3823
+ }
3824
+ /**
3825
+ * Enables worker-based physics on large graphs when requested
3826
+ */
3827
+ refreshPhysicsBackend() {
3828
+ const e = this.options.workerPhysicsNodeThreshold ?? C.workerPhysicsNodeThreshold;
3829
+ if (!((this.options.enableWorkerPhysics ?? C.enableWorkerPhysics) && this.options.performanceMode !== "quality" && this.getNodeCount() >= e)) {
3830
+ this.useWorkerPhysics = !1, this.physicsWorkerBridge && (this.physicsWorkerBridge.dispose(), this.physicsWorkerBridge = null), this.physicsWorkerNeedsSync = !0;
3831
+ return;
3832
+ }
3833
+ if (this.physicsWorkerBridge || (this.physicsWorkerBridge = new xt()), !this.physicsWorkerBridge.isAvailable()) {
3834
+ this.useWorkerPhysics = !1;
3835
+ return;
3836
+ }
3837
+ (!this.useWorkerPhysics || this.physicsWorkerNeedsSync) && (this.physicsWorkerBridge.init(
3838
+ this.nodeManager.getAllNodes(),
3839
+ this.edgeManager.getAllEdges(),
3840
+ {
3841
+ repulsionStrength: this.options.repulsionStrength,
3842
+ attractionStrength: this.options.attractionStrength,
3843
+ damping: this.options.damping
3844
+ }
3845
+ ), this.physicsWorkerBridge.requestStep(), this.physicsWorkerNeedsSync = !1), this.useWorkerPhysics = !0, this.simulationStride = 1;
3846
+ }
3384
3847
  // ==========================================================================
3385
3848
  // Public API
3386
3849
  // ==========================================================================
@@ -3388,23 +3851,23 @@ class Ht {
3388
3851
  * Sets the graph data
3389
3852
  */
3390
3853
  setData(e) {
3391
- var n;
3392
- const s = (n = e.data) != null && n.nodes ? e.data : e, i = (s.edges || s.links || []).map((r) => ({
3393
- ...r,
3394
- relationship: r.relationship || r.label || "related_to"
3395
- })), o = {
3854
+ var o;
3855
+ const s = (o = e.data) != null && o.nodes ? e.data : e, i = (s.edges || s.links || []).map((a) => ({
3856
+ ...a,
3857
+ relationship: a.relationship || a.label || "related_to"
3858
+ })), n = {
3396
3859
  nodes: s.nodes || [],
3397
3860
  edges: i
3398
3861
  };
3399
- if (this.graphData = o, this.edgeManager.clear(), this.nodeManager.clear(), o.nodes && Array.isArray(o.nodes)) {
3400
- ee.setExpectedNodeCount(o.nodes.length);
3401
- for (const r of o.nodes)
3402
- this.addNode(r);
3403
- }
3404
- if (o.edges && Array.isArray(o.edges))
3405
- for (const r of o.edges)
3406
- this.addEdge(r);
3407
- this.graphEngine = new Le(
3862
+ if (this.graphData = n, this.edgeManager.clear(), this.nodeManager.clear(), n.nodes && Array.isArray(n.nodes)) {
3863
+ ee.setExpectedNodeCount(n.nodes.length);
3864
+ for (const a of n.nodes)
3865
+ ce(a) && this.nodeManager.addNode(a);
3866
+ }
3867
+ if (n.edges && Array.isArray(n.edges))
3868
+ for (const a of n.edges)
3869
+ he(a) && this.edgeManager.addEdge(a);
3870
+ this.graphEngine = new Oe(
3408
3871
  this.nodeManager.getAllNodes(),
3409
3872
  this.edgeManager.getAllEdges(),
3410
3873
  {
@@ -3414,17 +3877,17 @@ class Ht {
3414
3877
  useBarnesHut: this.options.useBarnesHut,
3415
3878
  barnesHutTheta: this.options.barnesHutTheta
3416
3879
  }
3417
- ), this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.setData(o), this.updateLegendCounts();
3880
+ ), this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.setData(n), this.updateLegendCounts(), this.refreshPerformanceRenderingMode(), this.physicsWorkerNeedsSync = !0, this.refreshPhysicsBackend();
3418
3881
  }
3419
3882
  /**
3420
3883
  * Adds a node to the graph
3421
3884
  * @returns true if added, false if node already exists or invalid
3422
3885
  */
3423
3886
  addNode(e) {
3424
- if (!Fe(e))
3887
+ if (!ce(e))
3425
3888
  return !1;
3426
3889
  const s = this.nodeManager.addNode(e);
3427
- return s && (this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.addNode(e), this.options.onNodeAdd && this.options.onNodeAdd(e), this.emit("nodeAdd", e), this.updateLegendCounts()), s;
3890
+ return s && (this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.addNode(e), this.options.onNodeAdd && this.options.onNodeAdd(e), this.emit("nodeAdd", e), this.updateLegendCounts(), this.refreshPerformanceRenderingMode(), this.physicsWorkerNeedsSync = !0, this.refreshPhysicsBackend()), s;
3428
3891
  }
3429
3892
  /**
3430
3893
  * Removes a node from the graph
@@ -3435,7 +3898,7 @@ class Ht {
3435
3898
  return !1;
3436
3899
  this.edgeManager.removeEdgesForNode(e);
3437
3900
  const s = this.nodeManager.removeNode(e);
3438
- return s && (this.graphEngine.restart(), this.options.onNodeRemove && this.options.onNodeRemove(e), this.emit("nodeRemove", e), this.panelManager.getCurrentNodeId() === e && this.panelManager.hide(), this.updateLegendCounts()), s;
3901
+ return s && (this.graphEngine.restart(), this.options.onNodeRemove && this.options.onNodeRemove(e), this.emit("nodeRemove", e), this.panelManager.getCurrentNodeId() === e && this.panelManager.hide(), this.updateLegendCounts(), this.refreshPerformanceRenderingMode(), this.physicsWorkerNeedsSync = !0, this.refreshPhysicsBackend()), s;
3439
3902
  }
3440
3903
  /**
3441
3904
  * Updates a node's properties
@@ -3448,10 +3911,10 @@ class Ht {
3448
3911
  * @returns true if added, false if invalid or nodes don't exist
3449
3912
  */
3450
3913
  addEdge(e) {
3451
- if (!De(e))
3914
+ if (!he(e))
3452
3915
  return !1;
3453
3916
  const s = this.edgeManager.addEdge(e);
3454
- 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), this.updateLegendCounts()), s;
3917
+ 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), this.updateLegendCounts(), this.refreshPerformanceRenderingMode(), this.physicsWorkerNeedsSync = !0, this.refreshPhysicsBackend()), s;
3455
3918
  }
3456
3919
  /**
3457
3920
  * Removes an edge from the graph
@@ -3459,7 +3922,7 @@ class Ht {
3459
3922
  */
3460
3923
  removeEdge(e, s) {
3461
3924
  const t = this.edgeManager.removeEdge(e, s);
3462
- 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 }), this.updateLegendCounts()), t;
3925
+ return t && (this.graphEngine.setEdges(this.edgeManager.getAllEdges()), this.graphEngine.restart(), this.options.onEdgeRemove && this.options.onEdgeRemove({ source: e, target: s }), this.emit("edgeRemove", { source: e, target: s }), this.updateLegendCounts(), this.refreshPerformanceRenderingMode(), this.physicsWorkerNeedsSync = !0, this.refreshPhysicsBackend()), t;
3463
3926
  }
3464
3927
  /**
3465
3928
  * Expands a node by fetching more data
@@ -3472,16 +3935,16 @@ class Ht {
3472
3935
  if (!i)
3473
3936
  return console.warn("[ForceGraph3D] No expand callback provided"), !1;
3474
3937
  try {
3475
- const o = await i(e, s);
3476
- if (o.nodes && Array.isArray(o.nodes))
3477
- for (const n of o.nodes)
3478
- this.addNode(n);
3479
- if (o.edges && Array.isArray(o.edges))
3480
- for (const n of o.edges)
3481
- this.addEdge(n);
3482
- return this.panelManager.hide(), this.emit("expand", e, o), !0;
3483
- } catch (o) {
3484
- return console.error("[ForceGraph3D] Error expanding node:", o), !1;
3938
+ const n = await i(e, s);
3939
+ if (n.nodes && Array.isArray(n.nodes))
3940
+ for (const o of n.nodes)
3941
+ this.addNode(o);
3942
+ if (n.edges && Array.isArray(n.edges))
3943
+ for (const o of n.edges)
3944
+ this.addEdge(o);
3945
+ return this.panelManager.hide(), this.emit("expand", e, n), !0;
3946
+ } catch (n) {
3947
+ return console.error("[ForceGraph3D] Error expanding node:", n), !1;
3485
3948
  }
3486
3949
  }
3487
3950
  /**
@@ -3528,13 +3991,13 @@ class Ht {
3528
3991
  console.warn(`[ForceGraph3D] Node "${e}" not found`);
3529
3992
  return;
3530
3993
  }
3531
- const i = t.position, o = this.sceneManager.camera, n = this.sceneManager.controls, r = o.position.clone().sub(n.target).normalize(), h = {
3532
- x: i.x + r.x * s,
3533
- y: i.y + r.y * s,
3534
- z: i.z + r.z * s
3535
- }, c = { x: o.position.x, y: o.position.y, z: o.position.z }, p = { x: n.target.x, y: n.target.y, z: n.target.z }, f = 800, m = performance.now(), u = () => {
3536
- const y = performance.now() - m, b = Math.min(y / f, 1), w = 1 - Math.pow(1 - b, 3);
3537
- o.position.x = c.x + (h.x - c.x) * w, o.position.y = c.y + (h.y - c.y) * w, o.position.z = c.z + (h.z - c.z) * w, n.target.x = p.x + (i.x - p.x) * w, n.target.y = p.y + (i.y - p.y) * w, n.target.z = p.z + (i.z - p.z) * w, n.update(), b < 1 && requestAnimationFrame(u);
3994
+ const i = t.position, n = this.sceneManager.camera, o = this.sceneManager.controls, a = n.position.clone().sub(o.target).normalize(), c = {
3995
+ x: i.x + a.x * s,
3996
+ y: i.y + a.y * s,
3997
+ z: i.z + a.z * s
3998
+ }, h = { x: n.position.x, y: n.position.y, z: n.position.z }, d = { x: o.target.x, y: o.target.y, z: o.target.z }, f = 800, m = performance.now(), u = () => {
3999
+ const b = performance.now() - m, x = Math.min(b / f, 1), M = 1 - Math.pow(1 - x, 3);
4000
+ n.position.x = h.x + (c.x - h.x) * M, n.position.y = h.y + (c.y - h.y) * M, n.position.z = h.z + (c.z - h.z) * M, o.target.x = d.x + (i.x - d.x) * M, o.target.y = d.y + (i.y - d.y) * M, o.target.z = d.z + (i.z - d.z) * M, o.update(), x < 1 && requestAnimationFrame(u);
3538
4001
  };
3539
4002
  u();
3540
4003
  }
@@ -3543,22 +4006,22 @@ class Ht {
3543
4006
  * Camera targets the midpoint and zooms out enough to see both nodes
3544
4007
  */
3545
4008
  focusOnEdge(e, s, t = 1.5) {
3546
- const i = this.nodeManager.getNode(e), o = this.nodeManager.getNode(s);
3547
- if (!i || !o) {
4009
+ const i = this.nodeManager.getNode(e), n = this.nodeManager.getNode(s);
4010
+ if (!i || !n) {
3548
4011
  console.warn(`[ForceGraph3D] Could not find nodes for edge "${e}" -> "${s}"`);
3549
4012
  return;
3550
4013
  }
3551
- const n = this.sceneManager.camera, r = this.sceneManager.controls, h = {
3552
- x: (i.position.x + o.position.x) / 2,
3553
- y: (i.position.y + o.position.y) / 2,
3554
- z: (i.position.z + o.position.z) / 2
3555
- }, c = o.position.x - i.position.x, p = o.position.y - i.position.y, f = o.position.z - i.position.z, m = Math.sqrt(c * c + p * p + f * f), u = Math.max(m * t, 40), y = n.position.clone().sub(r.target).normalize(), b = {
3556
- x: h.x + y.x * u,
3557
- y: h.y + y.y * u,
3558
- z: h.z + y.z * u
3559
- }, w = { x: n.position.x, y: n.position.y, z: n.position.z }, N = { x: r.target.x, y: r.target.y, z: r.target.z }, O = 800, R = performance.now(), G = () => {
3560
- const T = performance.now() - R, D = Math.min(T / O, 1), E = 1 - Math.pow(1 - D, 3);
3561
- n.position.x = w.x + (b.x - w.x) * E, n.position.y = w.y + (b.y - w.y) * E, n.position.z = w.z + (b.z - w.z) * E, r.target.x = N.x + (h.x - N.x) * E, r.target.y = N.y + (h.y - N.y) * E, r.target.z = N.z + (h.z - N.z) * E, r.update(), D < 1 && requestAnimationFrame(G);
4014
+ const o = this.sceneManager.camera, a = this.sceneManager.controls, c = {
4015
+ x: (i.position.x + n.position.x) / 2,
4016
+ y: (i.position.y + n.position.y) / 2,
4017
+ z: (i.position.z + n.position.z) / 2
4018
+ }, h = n.position.x - i.position.x, d = n.position.y - i.position.y, f = n.position.z - i.position.z, m = Math.sqrt(h * h + d * d + f * f), u = Math.max(m * t, 40), b = o.position.clone().sub(a.target).normalize(), x = {
4019
+ x: c.x + b.x * u,
4020
+ y: c.y + b.y * u,
4021
+ z: c.z + b.z * u
4022
+ }, M = { x: o.position.x, y: o.position.y, z: o.position.z }, N = { x: a.target.x, y: a.target.y, z: a.target.z }, O = 800, L = performance.now(), G = () => {
4023
+ const R = performance.now() - L, F = Math.min(R / O, 1), E = 1 - Math.pow(1 - F, 3);
4024
+ o.position.x = M.x + (x.x - M.x) * E, o.position.y = M.y + (x.y - M.y) * E, o.position.z = M.z + (x.z - M.z) * E, a.target.x = N.x + (c.x - N.x) * E, a.target.y = N.y + (c.y - N.y) * E, a.target.z = N.z + (c.z - N.z) * E, a.update(), F < 1 && requestAnimationFrame(G);
3562
4025
  };
3563
4026
  G();
3564
4027
  }
@@ -3582,10 +4045,10 @@ class Ht {
3582
4045
  if (!e || e.trim() === "")
3583
4046
  return [];
3584
4047
  const s = e.toLowerCase().trim(), t = this.nodeManager.getAllNodes(), i = [];
3585
- return t.forEach((o) => {
3586
- var c, p, f;
3587
- const n = (c = o.label) == null ? void 0 : c.toLowerCase().includes(s), r = (p = o.id) == null ? void 0 : p.toLowerCase().includes(s), h = (f = o.type) == null ? void 0 : f.toLowerCase().includes(s);
3588
- (n || r || h) && i.push(o);
4048
+ return t.forEach((n) => {
4049
+ var h, d, f;
4050
+ const o = (h = n.label) == null ? void 0 : h.toLowerCase().includes(s), a = (d = n.id) == null ? void 0 : d.toLowerCase().includes(s), c = (f = n.type) == null ? void 0 : f.toLowerCase().includes(s);
4051
+ (o || a || c) && i.push(n);
3589
4052
  }), i;
3590
4053
  }
3591
4054
  /**
@@ -3593,14 +4056,14 @@ class Ht {
3593
4056
  * @returns Array of matching edges with source/target node info
3594
4057
  */
3595
4058
  searchEdges(e) {
3596
- var o;
4059
+ var n;
3597
4060
  if (!e || e.trim() === "")
3598
4061
  return [];
3599
4062
  const s = e.toLowerCase().trim(), t = this.edgeManager.getAllEdges(), i = [];
3600
- for (const n of t)
3601
- if ((o = n.relationship) == null ? void 0 : o.toLowerCase().includes(s)) {
3602
- const h = this.nodeManager.getNode(n.source), c = this.nodeManager.getNode(n.target);
3603
- h && c && i.push({ edge: n, sourceNode: h, targetNode: c });
4063
+ for (const o of t)
4064
+ if ((n = o.relationship) == null ? void 0 : n.toLowerCase().includes(s)) {
4065
+ const c = this.nodeManager.getNode(o.source), h = this.nodeManager.getNode(o.target);
4066
+ c && h && i.push({ edge: o, sourceNode: c, targetNode: h });
3604
4067
  }
3605
4068
  return i;
3606
4069
  }
@@ -3633,7 +4096,7 @@ class Ht {
3633
4096
  * Switches between 2D and 3D view modes
3634
4097
  */
3635
4098
  switchView(e) {
3636
- 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 Lt(this.container, {
4099
+ 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 It(this.container, {
3637
4100
  backgroundColor: "#0a0a0a",
3638
4101
  nodeRadius: 24,
3639
4102
  onNodeClick: (s) => {
@@ -3644,16 +4107,16 @@ class Ht {
3644
4107
  },
3645
4108
  onEdgeHover: (s, t) => {
3646
4109
  if (s && t) {
3647
- const i = this.nodeManager.getNode(s.source), o = this.nodeManager.getNode(s.target);
3648
- if (i && o) {
3649
- const n = this.edgeManager.getAllEdges().filter((r) => r.source === s.source && r.target === s.target);
4110
+ const i = this.nodeManager.getNode(s.source), n = this.nodeManager.getNode(s.target);
4111
+ if (i && n) {
4112
+ const o = this.edgeManager.getAllEdges().filter((a) => a.source === s.source && a.target === s.target);
3650
4113
  this.edgeTooltipManager.show(
3651
4114
  s,
3652
4115
  i,
3653
- o,
4116
+ n,
3654
4117
  t.clientX,
3655
4118
  t.clientY,
3656
- n.length > 0 ? n : [s]
4119
+ o.length > 0 ? o : [s]
3657
4120
  );
3658
4121
  }
3659
4122
  } else
@@ -3662,12 +4125,12 @@ class Ht {
3662
4125
  onEdgeClick: (s) => {
3663
4126
  const t = this.nodeManager.getNode(s.source), i = this.nodeManager.getNode(s.target);
3664
4127
  if (t && i) {
3665
- const o = this.edgeManager.getAllEdges().filter((n) => n.source === s.source && n.target === s.target);
4128
+ const n = this.edgeManager.getAllEdges().filter((o) => o.source === s.source && o.target === s.target);
3666
4129
  this.edgePanelManager.show(
3667
4130
  s,
3668
4131
  t,
3669
4132
  i,
3670
- o.length > 0 ? o : [s]
4133
+ n.length > 0 ? n : [s]
3671
4134
  );
3672
4135
  }
3673
4136
  }
@@ -3690,7 +4153,7 @@ class Ht {
3690
4153
  * Sets physics parameters for both 3D and 2D views
3691
4154
  */
3692
4155
  setPhysicsParams(e) {
3693
- this.graphEngine.setPhysicsParams(e), this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.setPhysicsParams(e);
4156
+ 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.graphEngine.setPhysicsParams(e), this.graphEngine.restart(), this.physicsWorkerBridge && this.physicsWorkerBridge.setPhysicsParams(e), this.forceGraph2D && this.forceGraph2D.setPhysicsParams(e);
3694
4157
  }
3695
4158
  /**
3696
4159
  * Creates dev mode controls (only in development)
@@ -3770,18 +4233,18 @@ class Ht {
3770
4233
  const i = parseFloat(t.value) / 100;
3771
4234
  this.setPhysicsParams({ damping: i }), this.devControls.querySelector("#dev-damping-val").textContent = i.toFixed(2);
3772
4235
  }), setInterval(() => {
3773
- const i = this.devControls.querySelector("#dev-node-count"), o = this.devControls.querySelector("#dev-edge-count"), n = this.devControls.querySelector("#dev-fps");
3774
- i && (i.textContent = this.getNodeCount().toString()), o && (o.textContent = this.getEdgeCount().toString()), n && (n.textContent = this.rendererManager.getFPS().toString());
4236
+ const i = this.devControls.querySelector("#dev-node-count"), n = this.devControls.querySelector("#dev-edge-count"), o = this.devControls.querySelector("#dev-fps");
4237
+ i && (i.textContent = this.getNodeCount().toString()), n && (n.textContent = this.getEdgeCount().toString()), o && (o.textContent = this.rendererManager.getFPS().toString());
3775
4238
  }, 500);
3776
4239
  }
3777
4240
  /**
3778
4241
  * Destroys the graph and releases all resources
3779
4242
  */
3780
4243
  destroy() {
3781
- this.rendererManager.dispose(), this.panelManager.dispose(), this.raycasterManager.dispose(), this.edgeTooltipManager.dispose(), this.searchManager && this.searchManager.dispose(), this.viewToggleManager && this.viewToggleManager.dispose(), this.legendManager && this.legendManager.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;
4244
+ this.rendererManager.dispose(), this.panelManager.dispose(), this.raycasterManager.dispose(), this.edgeTooltipManager.dispose(), this.searchManager && this.searchManager.dispose(), this.viewToggleManager && this.viewToggleManager.dispose(), this.legendManager && this.legendManager.dispose(), this.physicsWorkerBridge && (this.physicsWorkerBridge.dispose(), this.physicsWorkerBridge = null), 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;
3782
4245
  }
3783
4246
  }
3784
- const Ie = [
4247
+ const De = [
3785
4248
  "Alpha",
3786
4249
  "Beta",
3787
4250
  "Gamma",
@@ -3823,7 +4286,7 @@ const Ie = [
3823
4286
  "partners with",
3824
4287
  "collaborates with",
3825
4288
  "supports"
3826
- ], Oe = [
4289
+ ], Fe = [
3827
4290
  16777215,
3828
4291
  // White
3829
4292
  16750950,
@@ -3835,14 +4298,14 @@ const Ie = [
3835
4298
  16746564
3836
4299
  // Darker tangerine
3837
4300
  ];
3838
- function At(d = 30) {
4301
+ function jt(p = 30) {
3839
4302
  const e = [], s = [];
3840
- for (let i = 0; i < d; i++) {
3841
- const o = i < Ie.length ? Ie[i] : `Node ${i + 1}`;
4303
+ for (let i = 0; i < p; i++) {
4304
+ const n = i < De.length ? De[i] : `Node ${i + 1}`;
3842
4305
  e.push({
3843
4306
  id: `node-${i}`,
3844
- label: o,
3845
- color: Oe[i % Oe.length],
4307
+ label: n,
4308
+ color: Fe[i % Fe.length],
3846
4309
  position: {
3847
4310
  x: (Math.random() - 0.5) * 60,
3848
4311
  y: (Math.random() - 0.5) * 60,
@@ -3850,76 +4313,76 @@ function At(d = 30) {
3850
4313
  }
3851
4314
  });
3852
4315
  }
3853
- for (let i = 1; i < d; i++) {
3854
- const o = Math.floor(Math.random() * i);
4316
+ for (let i = 1; i < p; i++) {
4317
+ const n = Math.floor(Math.random() * i);
3855
4318
  s.push({
3856
4319
  source: `node-${i}`,
3857
- target: `node-${o}`,
4320
+ target: `node-${n}`,
3858
4321
  relationship: J[Math.floor(Math.random() * J.length)]
3859
4322
  });
3860
4323
  }
3861
- const t = Math.floor(d * 0.5);
4324
+ const t = Math.floor(p * 0.5);
3862
4325
  for (let i = 0; i < t; i++) {
3863
- const o = Math.floor(Math.random() * d);
3864
- let n = Math.floor(Math.random() * d);
3865
- o === n && (n = (n + 1) % d);
3866
- const r = `node-${o}`, h = `node-${n}`;
4326
+ const n = Math.floor(Math.random() * p);
4327
+ let o = Math.floor(Math.random() * p);
4328
+ n === o && (o = (o + 1) % p);
4329
+ const a = `node-${n}`, c = `node-${o}`;
3867
4330
  s.some(
3868
- (p) => p.source === r && p.target === h || p.source === h && p.target === r
4331
+ (d) => d.source === a && d.target === c || d.source === c && d.target === a
3869
4332
  ) || s.push({
3870
- source: r,
3871
- target: h,
4333
+ source: a,
4334
+ target: c,
3872
4335
  relationship: J[Math.floor(Math.random() * J.length)]
3873
4336
  });
3874
4337
  }
3875
4338
  return { nodes: e, edges: s };
3876
4339
  }
3877
- function jt(d = 1e3) {
3878
- const e = [], s = [], t = Math.ceil(d / 50), i = [];
3879
- for (let o = 0; o < t; o++)
4340
+ function Bt(p = 1e3) {
4341
+ const e = [], s = [], t = Math.ceil(p / 50), i = [];
4342
+ for (let n = 0; n < t; n++)
3880
4343
  i.push({
3881
4344
  x: (Math.random() - 0.5) * 200,
3882
4345
  y: (Math.random() - 0.5) * 200,
3883
4346
  z: (Math.random() - 0.5) * 200
3884
4347
  });
3885
- for (let o = 0; o < d; o++) {
3886
- const n = i[o % t];
4348
+ for (let n = 0; n < p; n++) {
4349
+ const o = i[n % t];
3887
4350
  e.push({
3888
- id: `node-${o}`,
3889
- label: `N${o}`,
4351
+ id: `node-${n}`,
4352
+ label: `N${n}`,
3890
4353
  position: {
3891
- x: n.x + (Math.random() - 0.5) * 40,
3892
- y: n.y + (Math.random() - 0.5) * 40,
3893
- z: n.z + (Math.random() - 0.5) * 40
4354
+ x: o.x + (Math.random() - 0.5) * 40,
4355
+ y: o.y + (Math.random() - 0.5) * 40,
4356
+ z: o.z + (Math.random() - 0.5) * 40
3894
4357
  }
3895
4358
  });
3896
4359
  }
3897
- for (let o = 1; o < d; o++) {
3898
- const n = Math.floor(o / 50) * 50, r = n === 0 ? Math.floor(Math.random() * o) : n + Math.floor(Math.random() * Math.min(o - n, 50));
4360
+ for (let n = 1; n < p; n++) {
4361
+ const o = Math.floor(n / 50) * 50, a = o === 0 ? Math.floor(Math.random() * n) : o + Math.floor(Math.random() * Math.min(n - o, 50));
3899
4362
  s.push({
3900
- source: `node-${o}`,
3901
- target: `node-${Math.min(r, o - 1)}`,
4363
+ source: `node-${n}`,
4364
+ target: `node-${Math.min(a, n - 1)}`,
3902
4365
  relationship: "links to"
3903
4366
  });
3904
4367
  }
3905
- for (let o = 1; o < t; o++) {
3906
- const n = o * 50, r = (o - 1) * 50 + Math.floor(Math.random() * 50);
4368
+ for (let n = 1; n < t; n++) {
4369
+ const o = n * 50, a = (n - 1) * 50 + Math.floor(Math.random() * 50);
3907
4370
  s.push({
3908
- source: `node-${n}`,
3909
- target: `node-${r}`,
4371
+ source: `node-${o}`,
4372
+ target: `node-${a}`,
3910
4373
  relationship: "bridges to"
3911
4374
  });
3912
4375
  }
3913
4376
  return { nodes: e, edges: s };
3914
4377
  }
3915
4378
  export {
3916
- P as DEFAULT_OPTIONS,
4379
+ C as DEFAULT_OPTIONS,
3917
4380
  Ht as ForceGraph3D,
3918
- _ as LODLevel,
3919
- Dt as createEdgeKey,
3920
- jt as generateLargeSampleData,
3921
- At as generateSampleData,
3922
- De as validateEdgeData,
3923
- Fe as validateNodeData
4381
+ K as LODLevel,
4382
+ At as createEdgeKey,
4383
+ Bt as generateLargeSampleData,
4384
+ jt as generateSampleData,
4385
+ he as validateEdgeData,
4386
+ ce as validateNodeData
3924
4387
  };
3925
4388
  //# sourceMappingURL=force-3d-graph.js.map