force-3d-graph 1.2.3 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,9 @@
1
- var st = Object.defineProperty;
2
- var it = (h, e, s) => e in h ? st(h, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : h[e] = s;
3
- var l = (h, e, s) => it(h, typeof e != "symbol" ? e + "" : e, s);
4
- import * as m from "three";
5
- import { EventDispatcher as ot, Vector3 as S, MOUSE as $, TOUCH as G, Spherical as Ne, Quaternion as Se, Vector2 as k, Ray as nt, Plane as at, MathUtils as rt } from "three";
6
- const T = {
1
+ var ot = Object.defineProperty;
2
+ var nt = (d, e, s) => e in d ? ot(d, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : d[e] = s;
3
+ var l = (d, e, s) => nt(d, typeof e != "symbol" ? e + "" : e, s);
4
+ import * as y from "three";
5
+ import { EventDispatcher as at, Vector3 as S, MOUSE as $, TOUCH as G, Spherical as ze, Quaternion as Te, Vector2 as T, Ray as rt, Plane as lt, MathUtils as ct } from "three";
6
+ const P = {
7
7
  backgroundColor: 657930,
8
8
  cameraPosition: { x: 0, y: 0, z: 80 },
9
9
  cameraFov: 75,
@@ -31,53 +31,53 @@ const T = {
31
31
  targetFPS: 60,
32
32
  maxVisibleNodes: 1e4
33
33
  };
34
- var U = /* @__PURE__ */ ((h) => (h[h.HIGH = 0] = "HIGH", h[h.MEDIUM = 1] = "MEDIUM", h[h.LOW = 2] = "LOW", h))(U || {});
35
- function lt() {
36
- const h = document.createElement("div");
37
- return h.id = "force-graph-3d-container", h.style.cssText = `
34
+ var X = /* @__PURE__ */ ((d) => (d[d.HIGH = 0] = "HIGH", d[d.MEDIUM = 1] = "MEDIUM", d[d.LOW = 2] = "LOW", d))(X || {});
35
+ function ht() {
36
+ const d = document.createElement("div");
37
+ return d.id = "force-graph-3d-container", d.style.cssText = `
38
38
  width: 100%;
39
39
  height: 100%;
40
40
  position: absolute;
41
41
  top: 0;
42
42
  left: 0;
43
43
  overflow: hidden;
44
- `, document.body.appendChild(h), h;
44
+ `, document.body.appendChild(d), d;
45
45
  }
46
- function ct(h) {
47
- return h && h instanceof HTMLElement ? h : (console.warn("[ForceGraph3D] No container provided, creating one automatically"), lt());
46
+ function dt(d) {
47
+ return d && d instanceof HTMLElement ? d : (console.warn("[ForceGraph3D] No container provided, creating one automatically"), ht());
48
48
  }
49
- function ze(h) {
50
- const e = h.getBoundingClientRect();
49
+ function ke(d) {
50
+ const e = d.getBoundingClientRect();
51
51
  return {
52
52
  width: e.width || window.innerWidth,
53
53
  height: e.height || window.innerHeight
54
54
  };
55
55
  }
56
- function Oe(h) {
57
- if (!h || typeof h != "object")
56
+ function He(d) {
57
+ if (!d || typeof d != "object")
58
58
  return console.warn("[ForceGraph3D] Invalid node: must be an object"), !1;
59
- const e = h;
60
- 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 && !dt(e.position) ? (console.warn("[ForceGraph3D] Invalid node: position must have x, y, z numbers"), !1) : !0;
59
+ const e = d;
60
+ 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 && !gt(e.position) ? (console.warn("[ForceGraph3D] Invalid node: position must have x, y, z numbers"), !1) : !0;
61
61
  }
62
- function Fe(h) {
63
- if (!h || typeof h != "object")
62
+ function De(d) {
63
+ if (!d || typeof d != "object")
64
64
  return console.warn("[ForceGraph3D] Invalid edge: must be an object"), !1;
65
- const e = h;
65
+ const e = d;
66
66
  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;
67
67
  }
68
- function ht(h) {
69
- return typeof h != "string" || h.trim() === "" ? (console.warn("[ForceGraph3D] Invalid node ID: must be a non-empty string"), !1) : !0;
68
+ function pt(d) {
69
+ return typeof d != "string" || d.trim() === "" ? (console.warn("[ForceGraph3D] Invalid node ID: must be a non-empty string"), !1) : !0;
70
70
  }
71
- function dt(h) {
72
- if (!h || typeof h != "object") return !1;
73
- const e = h;
71
+ function gt(d) {
72
+ if (!d || typeof d != "object") return !1;
73
+ const e = d;
74
74
  return typeof e.x == "number" && typeof e.y == "number" && typeof e.z == "number";
75
75
  }
76
- function D(h, e) {
77
- return h === e ? `${h}-${e}` : h < e ? `${h}-${e}` : `${e}-${h}`;
76
+ function D(d, e) {
77
+ return d === e ? `${d}-${e}` : d < e ? `${d}-${e}` : `${e}-${d}`;
78
78
  }
79
- const ke = { type: "change" }, re = { type: "start" }, Pe = { type: "end" }, Q = new nt(), Te = new at(), pt = Math.cos(70 * rt.DEG2RAD);
80
- class gt extends ot {
79
+ const Pe = { type: "change" }, ce = { type: "start" }, Re = { type: "end" }, J = new rt(), Ie = new lt(), ut = Math.cos(70 * ct.DEG2RAD);
80
+ class ft extends at {
81
81
  constructor(e, s) {
82
82
  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: $.ROTATE, MIDDLE: $.DOLLY, RIGHT: $.PAN }, this.touches = { ONE: G.ROTATE, TWO: G.DOLLY_PAN }, this.target0 = this.target.clone(), this.position0 = this.object.position.clone(), this.zoom0 = this.object.zoom, this._domElementKeyEvents = null, this.getPolarAngle = function() {
83
83
  return r.phi;
@@ -86,43 +86,43 @@ class gt extends ot {
86
86
  }, this.getDistance = function() {
87
87
  return this.object.position.distanceTo(this.target);
88
88
  }, this.listenToKeyEvents = function(n) {
89
- n.addEventListener("keydown", ne), this._domElementKeyEvents = n;
89
+ n.addEventListener("keydown", re), this._domElementKeyEvents = n;
90
90
  }, this.stopListenToKeyEvents = function() {
91
- this._domElementKeyEvents.removeEventListener("keydown", ne), this._domElementKeyEvents = null;
91
+ this._domElementKeyEvents.removeEventListener("keydown", re), this._domElementKeyEvents = null;
92
92
  }, this.saveState = function() {
93
93
  t.target0.copy(t.target), t.position0.copy(t.object.position), t.zoom0 = t.object.zoom;
94
94
  }, this.reset = function() {
95
- t.target.copy(t.target0), t.object.position.copy(t.position0), t.object.zoom = t.zoom0, t.object.updateProjectionMatrix(), t.dispatchEvent(ke), t.update(), o = i.NONE;
95
+ t.target.copy(t.target0), t.object.position.copy(t.position0), t.object.zoom = t.zoom0, t.object.updateProjectionMatrix(), t.dispatchEvent(Pe), t.update(), i = o.NONE;
96
96
  }, this.update = function() {
97
- const n = new S(), g = new Se().setFromUnitVectors(e.up, new S(0, 1, 0)), v = g.clone().invert(), w = new S(), C = new Se(), F = new S(), z = 2 * Math.PI;
98
- return function(tt = null) {
99
- const Ce = t.object.position;
100
- n.copy(Ce).sub(t.target), n.applyQuaternion(g), r.setFromVector3(n), t.autoRotate && o === i.NONE && B(He(tt)), t.enableDamping ? (r.theta += c.theta * t.dampingFactor, r.phi += c.phi * t.dampingFactor) : (r.theta += c.theta, r.phi += c.phi);
101
- let I = t.minAzimuthAngle, R = t.maxAzimuthAngle;
102
- isFinite(I) && isFinite(R) && (I < -Math.PI ? I += z : I > Math.PI && (I -= z), R < -Math.PI ? R += z : R > Math.PI && (R -= z), I <= R ? r.theta = Math.max(I, Math.min(R, r.theta)) : r.theta = r.theta > (I + R) / 2 ? Math.max(I, r.theta) : Math.min(R, 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 && H || t.object.isOrthographicCamera ? r.radius = ie(r.radius) : r.radius = ie(r.radius * d), n.setFromSpherical(r), n.applyQuaternion(v), Ce.copy(t.target).add(n), t.object.lookAt(t.target), t.enableDamping === !0 ? (c.theta *= 1 - t.dampingFactor, c.phi *= 1 - t.dampingFactor, p.multiplyScalar(1 - t.dampingFactor)) : (c.set(0, 0, 0), p.set(0, 0, 0));
103
- let ae = !1;
97
+ const n = new S(), g = new Te().setFromUnitVectors(e.up, new S(0, 1, 0)), v = g.clone().invert(), w = new S(), C = new Te(), F = new S(), z = 2 * Math.PI;
98
+ return function(it = null) {
99
+ const Se = t.object.position;
100
+ n.copy(Se).sub(t.target), n.applyQuaternion(g), r.setFromVector3(n), t.autoRotate && i === o.NONE && B(Ae(it)), t.enableDamping ? (r.theta += c.theta * t.dampingFactor, r.phi += c.phi * t.dampingFactor) : (r.theta += c.theta, r.phi += c.phi);
101
+ let I = t.minAzimuthAngle, L = t.maxAzimuthAngle;
102
+ isFinite(I) && isFinite(L) && (I < -Math.PI ? I += z : I > Math.PI && (I -= z), L < -Math.PI ? L += z : L > Math.PI && (L -= z), I <= L ? r.theta = Math.max(I, Math.min(L, r.theta)) : r.theta = r.theta > (I + L) / 2 ? Math.max(I, r.theta) : Math.min(L, 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 && H || t.object.isOrthographicCamera ? r.radius = ne(r.radius) : r.radius = ne(r.radius * h), n.setFromSpherical(r), n.applyQuaternion(v), Se.copy(t.target).add(n), t.object.lookAt(t.target), t.enableDamping === !0 ? (c.theta *= 1 - t.dampingFactor, c.phi *= 1 - t.dampingFactor, p.multiplyScalar(1 - t.dampingFactor)) : (c.set(0, 0, 0), p.set(0, 0, 0));
103
+ let le = !1;
104
104
  if (t.zoomToCursor && H) {
105
- let X = null;
105
+ let U = null;
106
106
  if (t.object.isPerspectiveCamera) {
107
- const V = n.length();
108
- X = ie(V * d);
109
- const Z = V - X;
110
- t.object.position.addScaledVector(Y, Z), t.object.updateMatrixWorld();
107
+ const _ = n.length();
108
+ U = ne(_ * h);
109
+ const Q = _ - U;
110
+ t.object.position.addScaledVector(Y, Q), t.object.updateMatrixWorld();
111
111
  } else if (t.object.isOrthographicCamera) {
112
- const V = new S(P.x, P.y, 0);
113
- V.unproject(t.object), t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom / d)), t.object.updateProjectionMatrix(), ae = !0;
114
- const Z = new S(P.x, P.y, 0);
115
- Z.unproject(t.object), t.object.position.sub(Z).add(V), t.object.updateMatrixWorld(), X = n.length();
112
+ const _ = new S(k.x, k.y, 0);
113
+ _.unproject(t.object), t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom / h)), t.object.updateProjectionMatrix(), le = !0;
114
+ const Q = new S(k.x, k.y, 0);
115
+ Q.unproject(t.object), t.object.position.sub(Q).add(_), t.object.updateMatrixWorld(), U = n.length();
116
116
  } else
117
117
  console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."), t.zoomToCursor = !1;
118
- X !== null && (this.screenSpacePanning ? t.target.set(0, 0, -1).transformDirection(t.object.matrix).multiplyScalar(X).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)) < pt ? e.lookAt(t.target) : (Te.setFromNormalAndCoplanarPoint(t.object.up, t.target), Q.intersectPlane(Te, t.target))));
119
- } else t.object.isOrthographicCamera && (t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom / d)), t.object.updateProjectionMatrix(), ae = !0);
120
- return d = 1, H = !1, ae || w.distanceToSquared(t.object.position) > a || 8 * (1 - C.dot(t.object.quaternion)) > a || F.distanceToSquared(t.target) > 0 ? (t.dispatchEvent(ke), w.copy(t.object.position), C.copy(t.object.quaternion), F.copy(t.target), !0) : !1;
118
+ U !== null && (this.screenSpacePanning ? t.target.set(0, 0, -1).transformDirection(t.object.matrix).multiplyScalar(U).add(t.object.position) : (J.origin.copy(t.object.position), J.direction.set(0, 0, -1).transformDirection(t.object.matrix), Math.abs(t.object.up.dot(J.direction)) < ut ? e.lookAt(t.target) : (Ie.setFromNormalAndCoplanarPoint(t.object.up, t.target), J.intersectPlane(Ie, t.target))));
119
+ } else t.object.isOrthographicCamera && (t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom / h)), t.object.updateProjectionMatrix(), le = !0);
120
+ return h = 1, H = !1, le || w.distanceToSquared(t.object.position) > a || 8 * (1 - C.dot(t.object.quaternion)) > a || F.distanceToSquared(t.target) > 0 ? (t.dispatchEvent(Pe), w.copy(t.object.position), C.copy(t.object.quaternion), F.copy(t.target), !0) : !1;
121
121
  };
122
122
  }(), this.dispose = function() {
123
- t.domElement.removeEventListener("contextmenu", we), t.domElement.removeEventListener("pointerdown", be), t.domElement.removeEventListener("pointercancel", K), t.domElement.removeEventListener("wheel", ve), t.domElement.removeEventListener("pointermove", oe), t.domElement.removeEventListener("pointerup", K), t._domElementKeyEvents !== null && (t._domElementKeyEvents.removeEventListener("keydown", ne), t._domElementKeyEvents = null);
123
+ t.domElement.removeEventListener("contextmenu", Ce), t.domElement.removeEventListener("pointerdown", Me), t.domElement.removeEventListener("pointercancel", K), t.domElement.removeEventListener("wheel", we), t.domElement.removeEventListener("pointermove", ae), t.domElement.removeEventListener("pointerup", K), t._domElementKeyEvents !== null && (t._domElementKeyEvents.removeEventListener("keydown", re), t._domElementKeyEvents = null);
124
124
  };
125
- const t = this, i = {
125
+ const t = this, o = {
126
126
  NONE: -1,
127
127
  ROTATE: 0,
128
128
  DOLLY: 1,
@@ -132,32 +132,32 @@ class gt extends ot {
132
132
  TOUCH_DOLLY_PAN: 5,
133
133
  TOUCH_DOLLY_ROTATE: 6
134
134
  };
135
- let o = i.NONE;
136
- const a = 1e-6, r = new Ne(), c = new Ne();
137
- let d = 1;
138
- const p = new S(), x = new k(), f = new k(), u = new k(), y = new k(), b = new k(), M = new k(), N = new k(), O = new k(), L = new k(), Y = new S(), P = new k();
135
+ let i = o.NONE;
136
+ const a = 1e-6, r = new ze(), c = new ze();
137
+ let h = 1;
138
+ const p = new S(), x = new T(), m = new T(), u = new T(), f = new T(), b = new T(), M = new T(), N = new T(), O = new T(), R = new T(), Y = new S(), k = new T();
139
139
  let H = !1;
140
- const E = [], _ = {};
141
- let ee = !1;
142
- function He(n) {
140
+ const E = [], q = {};
141
+ let se = !1;
142
+ function Ae(n) {
143
143
  return n !== null ? 2 * Math.PI / 60 * t.autoRotateSpeed * n : 2 * Math.PI / 60 / 60 * t.autoRotateSpeed;
144
144
  }
145
- function q(n) {
145
+ function W(n) {
146
146
  const g = Math.abs(n * 0.01);
147
147
  return Math.pow(0.95, t.zoomSpeed * g);
148
148
  }
149
149
  function B(n) {
150
150
  c.theta -= n;
151
151
  }
152
- function W(n) {
152
+ function Z(n) {
153
153
  c.phi -= n;
154
154
  }
155
- const le = function() {
155
+ const he = function() {
156
156
  const n = new S();
157
157
  return function(v, w) {
158
158
  n.setFromMatrixColumn(w, 0), n.multiplyScalar(-v), p.add(n);
159
159
  };
160
- }(), ce = function() {
160
+ }(), de = function() {
161
161
  const n = new S();
162
162
  return function(v, w) {
163
163
  t.screenSpacePanning === !0 ? n.setFromMatrixColumn(w, 1) : (n.setFromMatrixColumn(w, 0), n.crossVectors(t.object.up, n)), n.multiplyScalar(v), p.add(n);
@@ -170,57 +170,57 @@ class gt extends ot {
170
170
  const F = t.object.position;
171
171
  n.copy(F).sub(t.target);
172
172
  let z = n.length();
173
- z *= Math.tan(t.object.fov / 2 * Math.PI / 180), le(2 * v * z / C.clientHeight, t.object.matrix), ce(2 * w * z / C.clientHeight, t.object.matrix);
174
- } else t.object.isOrthographicCamera ? (le(v * (t.object.right - t.object.left) / t.object.zoom / C.clientWidth, t.object.matrix), ce(w * (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);
173
+ z *= Math.tan(t.object.fov / 2 * Math.PI / 180), he(2 * v * z / C.clientHeight, t.object.matrix), de(2 * w * z / C.clientHeight, t.object.matrix);
174
+ } else t.object.isOrthographicCamera ? (he(v * (t.object.right - t.object.left) / t.object.zoom / C.clientWidth, t.object.matrix), de(w * (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);
175
175
  };
176
176
  }();
177
- function te(n) {
178
- t.object.isPerspectiveCamera || t.object.isOrthographicCamera ? d /= n : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), t.enableZoom = !1);
177
+ function ie(n) {
178
+ t.object.isPerspectiveCamera || t.object.isOrthographicCamera ? h /= n : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), t.enableZoom = !1);
179
179
  }
180
- function he(n) {
181
- t.object.isPerspectiveCamera || t.object.isOrthographicCamera ? d *= n : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), t.enableZoom = !1);
180
+ function pe(n) {
181
+ t.object.isPerspectiveCamera || t.object.isOrthographicCamera ? h *= n : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), t.enableZoom = !1);
182
182
  }
183
- function se(n, g) {
183
+ function oe(n, g) {
184
184
  if (!t.zoomToCursor)
185
185
  return;
186
186
  H = !0;
187
187
  const v = t.domElement.getBoundingClientRect(), w = n - v.left, C = g - v.top, F = v.width, z = v.height;
188
- P.x = w / F * 2 - 1, P.y = -(C / z) * 2 + 1, Y.set(P.x, P.y, 1).unproject(t.object).sub(t.object.position).normalize();
188
+ k.x = w / F * 2 - 1, k.y = -(C / z) * 2 + 1, Y.set(k.x, k.y, 1).unproject(t.object).sub(t.object.position).normalize();
189
189
  }
190
- function ie(n) {
190
+ function ne(n) {
191
191
  return Math.max(t.minDistance, Math.min(t.maxDistance, n));
192
192
  }
193
- function de(n) {
193
+ function ge(n) {
194
194
  x.set(n.clientX, n.clientY);
195
195
  }
196
- function De(n) {
197
- se(n.clientX, n.clientX), N.set(n.clientX, n.clientY);
198
- }
199
- function pe(n) {
200
- y.set(n.clientX, n.clientY);
201
- }
202
- function Ae(n) {
203
- f.set(n.clientX, n.clientY), u.subVectors(f, x).multiplyScalar(t.rotateSpeed);
204
- const g = t.domElement;
205
- B(2 * Math.PI * u.x / g.clientHeight), W(2 * Math.PI * u.y / g.clientHeight), x.copy(f), t.update();
206
- }
207
196
  function je(n) {
208
- O.set(n.clientX, n.clientY), L.subVectors(O, N), L.y > 0 ? te(q(L.y)) : L.y < 0 && he(q(L.y)), N.copy(O), t.update();
197
+ oe(n.clientX, n.clientX), N.set(n.clientX, n.clientY);
198
+ }
199
+ function ue(n) {
200
+ f.set(n.clientX, n.clientY);
209
201
  }
210
202
  function $e(n) {
211
- b.set(n.clientX, n.clientY), M.subVectors(b, y).multiplyScalar(t.panSpeed), A(M.x, M.y), y.copy(b), t.update();
203
+ m.set(n.clientX, n.clientY), u.subVectors(m, x).multiplyScalar(t.rotateSpeed);
204
+ const g = t.domElement;
205
+ B(2 * Math.PI * u.x / g.clientHeight), Z(2 * Math.PI * u.y / g.clientHeight), x.copy(m), t.update();
212
206
  }
213
207
  function Ge(n) {
214
- se(n.clientX, n.clientY), n.deltaY < 0 ? he(q(n.deltaY)) : n.deltaY > 0 && te(q(n.deltaY)), t.update();
208
+ O.set(n.clientX, n.clientY), R.subVectors(O, N), R.y > 0 ? ie(W(R.y)) : R.y < 0 && pe(W(R.y)), N.copy(O), t.update();
215
209
  }
216
210
  function Ye(n) {
211
+ b.set(n.clientX, n.clientY), M.subVectors(b, f).multiplyScalar(t.panSpeed), A(M.x, M.y), f.copy(b), t.update();
212
+ }
213
+ function Be(n) {
214
+ oe(n.clientX, n.clientY), n.deltaY < 0 ? pe(W(n.deltaY)) : n.deltaY > 0 && ie(W(n.deltaY)), t.update();
215
+ }
216
+ function Ke(n) {
217
217
  let g = !1;
218
218
  switch (n.code) {
219
219
  case t.keys.UP:
220
- n.ctrlKey || n.metaKey || n.shiftKey ? W(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(0, t.keyPanSpeed), g = !0;
220
+ n.ctrlKey || n.metaKey || n.shiftKey ? Z(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(0, t.keyPanSpeed), g = !0;
221
221
  break;
222
222
  case t.keys.BOTTOM:
223
- n.ctrlKey || n.metaKey || n.shiftKey ? W(-2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(0, -t.keyPanSpeed), g = !0;
223
+ n.ctrlKey || n.metaKey || n.shiftKey ? Z(-2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(0, -t.keyPanSpeed), g = !0;
224
224
  break;
225
225
  case t.keys.LEFT:
226
226
  n.ctrlKey || n.metaKey || n.shiftKey ? B(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(t.keyPanSpeed, 0), g = !0;
@@ -231,7 +231,7 @@ class gt extends ot {
231
231
  }
232
232
  g && (n.preventDefault(), t.update());
233
233
  }
234
- function ge(n) {
234
+ function fe(n) {
235
235
  if (E.length === 1)
236
236
  x.set(n.pageX, n.pageY);
237
237
  else {
@@ -239,66 +239,66 @@ class gt extends ot {
239
239
  x.set(v, w);
240
240
  }
241
241
  }
242
- function ue(n) {
242
+ function me(n) {
243
243
  if (E.length === 1)
244
- y.set(n.pageX, n.pageY);
244
+ f.set(n.pageX, n.pageY);
245
245
  else {
246
246
  const g = j(n), v = 0.5 * (n.pageX + g.x), w = 0.5 * (n.pageY + g.y);
247
- y.set(v, w);
247
+ f.set(v, w);
248
248
  }
249
249
  }
250
- function fe(n) {
250
+ function ye(n) {
251
251
  const g = j(n), v = n.pageX - g.x, w = n.pageY - g.y, C = Math.sqrt(v * v + w * w);
252
252
  N.set(0, C);
253
253
  }
254
- function Be(n) {
255
- t.enableZoom && fe(n), t.enablePan && ue(n);
254
+ function Ue(n) {
255
+ t.enableZoom && ye(n), t.enablePan && me(n);
256
256
  }
257
- function Ke(n) {
258
- t.enableZoom && fe(n), t.enableRotate && ge(n);
257
+ function _e(n) {
258
+ t.enableZoom && ye(n), t.enableRotate && fe(n);
259
259
  }
260
- function me(n) {
260
+ function xe(n) {
261
261
  if (E.length == 1)
262
- f.set(n.pageX, n.pageY);
262
+ m.set(n.pageX, n.pageY);
263
263
  else {
264
264
  const v = j(n), w = 0.5 * (n.pageX + v.x), C = 0.5 * (n.pageY + v.y);
265
- f.set(w, C);
265
+ m.set(w, C);
266
266
  }
267
- u.subVectors(f, x).multiplyScalar(t.rotateSpeed);
267
+ u.subVectors(m, x).multiplyScalar(t.rotateSpeed);
268
268
  const g = t.domElement;
269
- B(2 * Math.PI * u.x / g.clientHeight), W(2 * Math.PI * u.y / g.clientHeight), x.copy(f);
269
+ B(2 * Math.PI * u.x / g.clientHeight), Z(2 * Math.PI * u.y / g.clientHeight), x.copy(m);
270
270
  }
271
- function ye(n) {
271
+ function be(n) {
272
272
  if (E.length === 1)
273
273
  b.set(n.pageX, n.pageY);
274
274
  else {
275
275
  const g = j(n), v = 0.5 * (n.pageX + g.x), w = 0.5 * (n.pageY + g.y);
276
276
  b.set(v, w);
277
277
  }
278
- M.subVectors(b, y).multiplyScalar(t.panSpeed), A(M.x, M.y), y.copy(b);
278
+ M.subVectors(b, f).multiplyScalar(t.panSpeed), A(M.x, M.y), f.copy(b);
279
279
  }
280
- function xe(n) {
280
+ function ve(n) {
281
281
  const g = j(n), v = n.pageX - g.x, w = n.pageY - g.y, C = Math.sqrt(v * v + w * w);
282
- O.set(0, C), L.set(0, Math.pow(O.y / N.y, t.zoomSpeed)), te(L.y), N.copy(O);
282
+ O.set(0, C), R.set(0, Math.pow(O.y / N.y, t.zoomSpeed)), ie(R.y), N.copy(O);
283
283
  const F = (n.pageX + g.x) * 0.5, z = (n.pageY + g.y) * 0.5;
284
- se(F, z);
284
+ oe(F, z);
285
285
  }
286
286
  function Xe(n) {
287
- t.enableZoom && xe(n), t.enablePan && ye(n);
287
+ t.enableZoom && ve(n), t.enablePan && be(n);
288
288
  }
289
289
  function Ve(n) {
290
- t.enableZoom && xe(n), t.enableRotate && me(n);
290
+ t.enableZoom && ve(n), t.enableRotate && xe(n);
291
291
  }
292
- function be(n) {
293
- t.enabled !== !1 && (E.length === 0 && (t.domElement.setPointerCapture(n.pointerId), t.domElement.addEventListener("pointermove", oe), t.domElement.addEventListener("pointerup", K)), Je(n), n.pointerType === "touch" ? Ze(n) : Ue(n));
292
+ function Me(n) {
293
+ t.enabled !== !1 && (E.length === 0 && (t.domElement.setPointerCapture(n.pointerId), t.domElement.addEventListener("pointermove", ae), t.domElement.addEventListener("pointerup", K)), tt(n), n.pointerType === "touch" ? Je(n) : qe(n));
294
294
  }
295
- function oe(n) {
296
- t.enabled !== !1 && (n.pointerType === "touch" ? Qe(n) : _e(n));
295
+ function ae(n) {
296
+ t.enabled !== !1 && (n.pointerType === "touch" ? et(n) : We(n));
297
297
  }
298
298
  function K(n) {
299
- et(n), E.length === 0 && (t.domElement.releasePointerCapture(n.pointerId), t.domElement.removeEventListener("pointermove", oe), t.domElement.removeEventListener("pointerup", K)), t.dispatchEvent(Pe), o = i.NONE;
299
+ st(n), E.length === 0 && (t.domElement.releasePointerCapture(n.pointerId), t.domElement.removeEventListener("pointermove", ae), t.domElement.removeEventListener("pointerup", K)), t.dispatchEvent(Re), i = o.NONE;
300
300
  }
301
- function Ue(n) {
301
+ function qe(n) {
302
302
  let g;
303
303
  switch (n.button) {
304
304
  case 0:
@@ -316,51 +316,51 @@ class gt extends ot {
316
316
  switch (g) {
317
317
  case $.DOLLY:
318
318
  if (t.enableZoom === !1) return;
319
- De(n), o = i.DOLLY;
319
+ je(n), i = o.DOLLY;
320
320
  break;
321
321
  case $.ROTATE:
322
322
  if (n.ctrlKey || n.metaKey || n.shiftKey) {
323
323
  if (t.enablePan === !1) return;
324
- pe(n), o = i.PAN;
324
+ ue(n), i = o.PAN;
325
325
  } else {
326
326
  if (t.enableRotate === !1) return;
327
- de(n), o = i.ROTATE;
327
+ ge(n), i = o.ROTATE;
328
328
  }
329
329
  break;
330
330
  case $.PAN:
331
331
  if (n.ctrlKey || n.metaKey || n.shiftKey) {
332
332
  if (t.enableRotate === !1) return;
333
- de(n), o = i.ROTATE;
333
+ ge(n), i = o.ROTATE;
334
334
  } else {
335
335
  if (t.enablePan === !1) return;
336
- pe(n), o = i.PAN;
336
+ ue(n), i = o.PAN;
337
337
  }
338
338
  break;
339
339
  default:
340
- o = i.NONE;
340
+ i = o.NONE;
341
341
  }
342
- o !== i.NONE && t.dispatchEvent(re);
342
+ i !== o.NONE && t.dispatchEvent(ce);
343
343
  }
344
- function _e(n) {
345
- switch (o) {
346
- case i.ROTATE:
344
+ function We(n) {
345
+ switch (i) {
346
+ case o.ROTATE:
347
347
  if (t.enableRotate === !1) return;
348
- Ae(n);
348
+ $e(n);
349
349
  break;
350
- case i.DOLLY:
350
+ case o.DOLLY:
351
351
  if (t.enableZoom === !1) return;
352
- je(n);
352
+ Ge(n);
353
353
  break;
354
- case i.PAN:
354
+ case o.PAN:
355
355
  if (t.enablePan === !1) return;
356
- $e(n);
356
+ Ye(n);
357
357
  break;
358
358
  }
359
359
  }
360
- function ve(n) {
361
- t.enabled === !1 || t.enableZoom === !1 || o !== i.NONE || (n.preventDefault(), t.dispatchEvent(re), Ge(qe(n)), t.dispatchEvent(Pe));
360
+ function we(n) {
361
+ t.enabled === !1 || t.enableZoom === !1 || i !== o.NONE || (n.preventDefault(), t.dispatchEvent(ce), Be(Ze(n)), t.dispatchEvent(Re));
362
362
  }
363
- function qe(n) {
363
+ function Ze(n) {
364
364
  const g = n.deltaMode, v = {
365
365
  clientX: n.clientX,
366
366
  clientY: n.clientY,
@@ -374,100 +374,100 @@ class gt extends ot {
374
374
  v.deltaY *= 100;
375
375
  break;
376
376
  }
377
- return n.ctrlKey && !ee && (v.deltaY *= 10), v;
377
+ return n.ctrlKey && !se && (v.deltaY *= 10), v;
378
378
  }
379
- function We(n) {
380
- n.key === "Control" && (ee = !0, document.addEventListener("keyup", Me, { passive: !0, capture: !0 }));
379
+ function Qe(n) {
380
+ n.key === "Control" && (se = !0, document.addEventListener("keyup", Ee, { passive: !0, capture: !0 }));
381
381
  }
382
- function Me(n) {
383
- n.key === "Control" && (ee = !1, document.removeEventListener("keyup", Me, { passive: !0, capture: !0 }));
382
+ function Ee(n) {
383
+ n.key === "Control" && (se = !1, document.removeEventListener("keyup", Ee, { passive: !0, capture: !0 }));
384
384
  }
385
- function ne(n) {
386
- t.enabled === !1 || t.enablePan === !1 || Ye(n);
385
+ function re(n) {
386
+ t.enabled === !1 || t.enablePan === !1 || Ke(n);
387
387
  }
388
- function Ze(n) {
389
- switch (Ee(n), E.length) {
388
+ function Je(n) {
389
+ switch (Ne(n), E.length) {
390
390
  case 1:
391
391
  switch (t.touches.ONE) {
392
392
  case G.ROTATE:
393
393
  if (t.enableRotate === !1) return;
394
- ge(n), o = i.TOUCH_ROTATE;
394
+ fe(n), i = o.TOUCH_ROTATE;
395
395
  break;
396
396
  case G.PAN:
397
397
  if (t.enablePan === !1) return;
398
- ue(n), o = i.TOUCH_PAN;
398
+ me(n), i = o.TOUCH_PAN;
399
399
  break;
400
400
  default:
401
- o = i.NONE;
401
+ i = o.NONE;
402
402
  }
403
403
  break;
404
404
  case 2:
405
405
  switch (t.touches.TWO) {
406
406
  case G.DOLLY_PAN:
407
407
  if (t.enableZoom === !1 && t.enablePan === !1) return;
408
- Be(n), o = i.TOUCH_DOLLY_PAN;
408
+ Ue(n), i = o.TOUCH_DOLLY_PAN;
409
409
  break;
410
410
  case G.DOLLY_ROTATE:
411
411
  if (t.enableZoom === !1 && t.enableRotate === !1) return;
412
- Ke(n), o = i.TOUCH_DOLLY_ROTATE;
412
+ _e(n), i = o.TOUCH_DOLLY_ROTATE;
413
413
  break;
414
414
  default:
415
- o = i.NONE;
415
+ i = o.NONE;
416
416
  }
417
417
  break;
418
418
  default:
419
- o = i.NONE;
419
+ i = o.NONE;
420
420
  }
421
- o !== i.NONE && t.dispatchEvent(re);
421
+ i !== o.NONE && t.dispatchEvent(ce);
422
422
  }
423
- function Qe(n) {
424
- switch (Ee(n), o) {
425
- case i.TOUCH_ROTATE:
423
+ function et(n) {
424
+ switch (Ne(n), i) {
425
+ case o.TOUCH_ROTATE:
426
426
  if (t.enableRotate === !1) return;
427
- me(n), t.update();
427
+ xe(n), t.update();
428
428
  break;
429
- case i.TOUCH_PAN:
429
+ case o.TOUCH_PAN:
430
430
  if (t.enablePan === !1) return;
431
- ye(n), t.update();
431
+ be(n), t.update();
432
432
  break;
433
- case i.TOUCH_DOLLY_PAN:
433
+ case o.TOUCH_DOLLY_PAN:
434
434
  if (t.enableZoom === !1 && t.enablePan === !1) return;
435
435
  Xe(n), t.update();
436
436
  break;
437
- case i.TOUCH_DOLLY_ROTATE:
437
+ case o.TOUCH_DOLLY_ROTATE:
438
438
  if (t.enableZoom === !1 && t.enableRotate === !1) return;
439
439
  Ve(n), t.update();
440
440
  break;
441
441
  default:
442
- o = i.NONE;
442
+ i = o.NONE;
443
443
  }
444
444
  }
445
- function we(n) {
445
+ function Ce(n) {
446
446
  t.enabled !== !1 && n.preventDefault();
447
447
  }
448
- function Je(n) {
448
+ function tt(n) {
449
449
  E.push(n.pointerId);
450
450
  }
451
- function et(n) {
452
- delete _[n.pointerId];
451
+ function st(n) {
452
+ delete q[n.pointerId];
453
453
  for (let g = 0; g < E.length; g++)
454
454
  if (E[g] == n.pointerId) {
455
455
  E.splice(g, 1);
456
456
  return;
457
457
  }
458
458
  }
459
- function Ee(n) {
460
- let g = _[n.pointerId];
461
- g === void 0 && (g = new k(), _[n.pointerId] = g), g.set(n.pageX, n.pageY);
459
+ function Ne(n) {
460
+ let g = q[n.pointerId];
461
+ g === void 0 && (g = new T(), q[n.pointerId] = g), g.set(n.pageX, n.pageY);
462
462
  }
463
463
  function j(n) {
464
464
  const g = n.pointerId === E[0] ? E[1] : E[0];
465
- return _[g];
465
+ return q[g];
466
466
  }
467
- t.domElement.addEventListener("contextmenu", we), t.domElement.addEventListener("pointerdown", be), t.domElement.addEventListener("pointercancel", K), t.domElement.addEventListener("wheel", ve, { passive: !1 }), document.addEventListener("keydown", We, { passive: !0, capture: !0 }), this.update();
467
+ t.domElement.addEventListener("contextmenu", Ce), t.domElement.addEventListener("pointerdown", Me), t.domElement.addEventListener("pointercancel", K), t.domElement.addEventListener("wheel", we, { passive: !1 }), document.addEventListener("keydown", Qe, { passive: !0, capture: !0 }), this.update();
468
468
  }
469
469
  }
470
- class ut {
470
+ class mt {
471
471
  constructor(e, s) {
472
472
  l(this, "scene");
473
473
  l(this, "camera");
@@ -475,42 +475,42 @@ class ut {
475
475
  l(this, "controls");
476
476
  l(this, "container");
477
477
  l(this, "resizeHandler");
478
- this.container = e, this.scene = new m.Scene(), this.scene.background = new m.Color(
478
+ this.container = e, this.scene = new y.Scene(), this.scene.background = new y.Color(
479
479
  s.backgroundColor ?? 657930
480
480
  );
481
- const { width: t, height: i } = ze(e), o = s.cameraFov ?? 75;
482
- this.camera = new m.PerspectiveCamera(o, t / i, 0.1, 2e3);
481
+ const { width: t, height: o } = ke(e), i = s.cameraFov ?? 75;
482
+ this.camera = new y.PerspectiveCamera(i, t / o, 0.1, 2e3);
483
483
  const a = s.cameraPosition ?? { x: 0, y: 0, z: 80 };
484
- this.camera.position.set(a.x, a.y, a.z), this.renderer = new m.WebGLRenderer({
484
+ this.camera.position.set(a.x, a.y, a.z), this.renderer = new y.WebGLRenderer({
485
485
  antialias: !0,
486
486
  alpha: !0,
487
487
  powerPreference: "high-performance"
488
- }), this.renderer.setSize(t, i), this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)), this.renderer.toneMapping = m.ACESFilmicToneMapping, this.renderer.toneMappingExposure = 1, this.renderer.shadowMap.enabled = !0, this.renderer.shadowMap.type = m.PCFSoftShadowMap, e.appendChild(this.renderer.domElement), this.controls = new gt(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 = 500, this.setupLighting(), this.resizeHandler = this.onWindowResize.bind(this), window.addEventListener("resize", this.resizeHandler);
488
+ }), this.renderer.setSize(t, o), this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)), this.renderer.toneMapping = y.ACESFilmicToneMapping, this.renderer.toneMappingExposure = 1, this.renderer.shadowMap.enabled = !0, this.renderer.shadowMap.type = y.PCFSoftShadowMap, e.appendChild(this.renderer.domElement), this.controls = new ft(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);
489
489
  }
490
490
  /**
491
491
  * Sets up scene lighting for gradient glass on dark background
492
492
  */
493
493
  setupLighting() {
494
- const e = new m.AmbientLight(16777215, 0.4);
494
+ const e = new y.AmbientLight(16777215, 0.4);
495
495
  this.scene.add(e);
496
- const s = new m.DirectionalLight(16777215, 0.9);
496
+ const s = new y.DirectionalLight(16777215, 0.9);
497
497
  s.position.set(50, 60, 40), s.castShadow = !0, s.shadow.mapSize.width = 1024, s.shadow.mapSize.height = 1024, this.scene.add(s);
498
- const t = new m.DirectionalLight(16773344, 0.4);
498
+ const t = new y.DirectionalLight(16773344, 0.4);
499
499
  t.position.set(-50, 30, -40), this.scene.add(t);
500
- const i = new m.DirectionalLight(16777215, 0.3);
501
- i.position.set(0, -30, -50), this.scene.add(i);
502
- const o = new m.PointLight(16750950, 0.5, 150);
503
- o.position.set(40, 20, 40), this.scene.add(o);
504
- const a = new m.PointLight(16764057, 0.4, 150);
500
+ const o = new y.DirectionalLight(16777215, 0.3);
501
+ o.position.set(0, -30, -50), this.scene.add(o);
502
+ const i = new y.PointLight(16750950, 0.5, 150);
503
+ i.position.set(40, 20, 40), this.scene.add(i);
504
+ const a = new y.PointLight(16764057, 0.4, 150);
505
505
  a.position.set(-40, -20, 40), this.scene.add(a);
506
- const r = new m.PointLight(6724095, 0.2, 100);
506
+ const r = new y.PointLight(6724095, 0.2, 100);
507
507
  r.position.set(0, 40, -40), this.scene.add(r);
508
508
  }
509
509
  /**
510
510
  * Handle window resize
511
511
  */
512
512
  onWindowResize() {
513
- const { width: e, height: s } = ze(this.container);
513
+ const { width: e, height: s } = ke(this.container);
514
514
  this.camera.aspect = e / s, this.camera.updateProjectionMatrix(), this.renderer.setSize(e, s);
515
515
  }
516
516
  /**
@@ -545,7 +545,7 @@ class ut {
545
545
  * Gets the camera's forward direction
546
546
  */
547
547
  getCameraDirection() {
548
- const e = new m.Vector3();
548
+ const e = new y.Vector3();
549
549
  return this.camera.getWorldDirection(e), e;
550
550
  }
551
551
  /**
@@ -558,7 +558,7 @@ class ut {
558
558
  }
559
559
  }
560
560
  }
561
- class ft {
561
+ const V = class V {
562
562
  constructor(e, s) {
563
563
  l(this, "sceneManager");
564
564
  l(this, "nodeFactory");
@@ -572,29 +572,36 @@ class ft {
572
572
  hasNode(e) {
573
573
  return this.nodes.has(e);
574
574
  }
575
+ /**
576
+ * Sets the expected total node count so spawn positions can be scaled.
577
+ * Call this before adding nodes in bulk.
578
+ */
579
+ static setExpectedNodeCount(e) {
580
+ V.expectedNodeCount = e;
581
+ }
575
582
  /**
576
583
  * Adds a node to the graph
577
584
  * @returns true if added, false if node already exists or invalid
578
585
  */
579
586
  addNode(e, s = 0) {
580
- if (!Oe(e))
587
+ if (!He(e))
581
588
  return !1;
582
589
  if (this.nodes.has(e.id))
583
590
  return console.warn(`[ForceGraph3D] Node with id "${e.id}" already exists`), !1;
584
- const t = e.position ?? {
585
- x: (Math.random() - 0.5) * 50,
586
- y: (Math.random() - 0.5) * 50,
587
- z: (Math.random() - 0.5) * 50
591
+ const t = Math.max(50, Math.cbrt(V.expectedNodeCount) * 10), o = e.position ?? {
592
+ x: (Math.random() - 0.5) * t,
593
+ y: (Math.random() - 0.5) * t,
594
+ z: (Math.random() - 0.5) * t
588
595
  }, i = {
589
596
  ...e,
590
- position: t,
597
+ position: o,
591
598
  velocity: { x: 0, y: 0, z: 0 },
592
599
  mass: 1
593
- }, o = this.nodeFactory.createNode(
594
- { ...e, position: t },
600
+ }, a = this.nodeFactory.createNode(
601
+ { ...e, position: o },
595
602
  s
596
603
  );
597
- return this.sceneManager.add(o.group), this.nodes.set(e.id, i), this.nodeObjects.set(e.id, o), !0;
604
+ return this.sceneManager.add(a.group), this.nodes.set(e.id, i), this.nodeObjects.set(e.id, a), !0;
598
605
  }
599
606
  /**
600
607
  * Removes a node from the graph
@@ -608,17 +615,17 @@ class ft {
608
615
  * Updates a node's properties
609
616
  */
610
617
  updateNode(e, s) {
611
- const t = this.nodes.get(e), i = this.nodeObjects.get(e);
612
- 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) => {
613
- o !== "id" && o !== "label" && o !== "color" && o !== "position" && (t[o] = s[o]);
618
+ const t = this.nodes.get(e), o = this.nodeObjects.get(e);
619
+ return !t || !o ? (console.warn(`[ForceGraph3D] Node "${e}" not found`), !1) : (s.label !== void 0 && (t.label = s.label, this.nodeFactory.updateNodeLabel(o, s.label)), s.color !== void 0 && (t.color = s.color, this.nodeFactory.updateNodeColor(o, s.color)), Object.keys(s).forEach((i) => {
620
+ i !== "id" && i !== "label" && i !== "color" && i !== "position" && (t[i] = s[i]);
614
621
  }), !0);
615
622
  }
616
623
  /**
617
624
  * Updates a node's position (called by physics engine)
618
625
  */
619
626
  updateNodePosition(e, s) {
620
- const t = this.nodes.get(e), i = this.nodeObjects.get(e);
621
- t && i && (t.position = s, i.group.position.set(s.x, s.y, s.z));
627
+ const t = this.nodes.get(e), o = this.nodeObjects.get(e);
628
+ t && o && (t.position = s, o.group.position.set(s.x, s.y, s.z));
622
629
  }
623
630
  /**
624
631
  * Updates a node's LOD level
@@ -683,8 +690,11 @@ class ft {
683
690
  dispose() {
684
691
  this.clear();
685
692
  }
686
- }
687
- class mt {
693
+ };
694
+ // Scale spawn volume with expected graph size
695
+ l(V, "expectedNodeCount", 100);
696
+ let te = V;
697
+ class yt {
688
698
  constructor(e, s, t) {
689
699
  l(this, "sceneManager");
690
700
  l(this, "nodeManager");
@@ -707,7 +717,7 @@ class mt {
707
717
  * @returns true if added, false if edge already exists or nodes don't exist
708
718
  */
709
719
  addEdge(e) {
710
- if (!Fe(e))
720
+ if (!De(e))
711
721
  return !1;
712
722
  if (!this.nodeManager.hasNode(e.source))
713
723
  return console.warn(`[ForceGraph3D] Source node "${e.source}" does not exist`), !1;
@@ -716,14 +726,14 @@ class mt {
716
726
  const s = D(e.source, e.target);
717
727
  if (this.edgeKeySet.has(s))
718
728
  return console.warn(`[ForceGraph3D] Edge "${e.source}" -> "${e.target}" already exists`), !1;
719
- const t = this.nodeManager.getNode(e.source), i = this.nodeManager.getNode(e.target), o = this.edgeFactory.createEdge(
729
+ const t = this.nodeManager.getNode(e.source), o = this.nodeManager.getNode(e.target), i = this.edgeFactory.createEdge(
720
730
  e,
721
731
  t,
722
- i,
732
+ o,
723
733
  t.position,
724
- i.position
734
+ o.position
725
735
  );
726
- return this.sceneManager.add(o.line), this.edges.push(e), this.edgeObjects.push(o), this.edgeKeySet.add(s), !0;
736
+ return this.sceneManager.add(i.line), this.edges.push(e), this.edgeObjects.push(i), this.edgeKeySet.add(s), !0;
727
737
  }
728
738
  /**
729
739
  * Removes an edge from the graph
@@ -733,13 +743,13 @@ class mt {
733
743
  const t = D(e, s);
734
744
  if (!this.edgeKeySet.has(t))
735
745
  return !1;
736
- const i = this.edges.findIndex(
746
+ const o = this.edges.findIndex(
737
747
  (a) => D(a.source, a.target) === t
738
748
  );
739
- if (i === -1)
749
+ if (o === -1)
740
750
  return !1;
741
- const o = this.edgeObjects[i];
742
- return this.sceneManager.remove(o.line), this.edgeFactory.disposeEdge(o), this.edges.splice(i, 1), this.edgeObjects.splice(i, 1), this.edgeKeySet.delete(t), this.highlightedEdgeKey === t && (this.highlightedEdgeKey = null), !0;
751
+ const i = this.edgeObjects[o];
752
+ return this.sceneManager.remove(i.line), this.edgeFactory.disposeEdge(i), this.edges.splice(o, 1), this.edgeObjects.splice(o, 1), this.edgeKeySet.delete(t), this.highlightedEdgeKey === t && (this.highlightedEdgeKey = null), !0;
743
753
  }
744
754
  /**
745
755
  * Highlights an edge
@@ -747,10 +757,10 @@ class mt {
747
757
  highlightEdge(e, s) {
748
758
  const t = D(e, s);
749
759
  this.highlightedEdgeKey && this.highlightedEdgeKey !== t && this.unhighlightCurrentEdge();
750
- const i = this.edges.findIndex(
751
- (o) => D(o.source, o.target) === t
760
+ const o = this.edges.findIndex(
761
+ (i) => D(i.source, i.target) === t
752
762
  );
753
- i !== -1 && (this.edgeFactory.highlightEdge(this.edgeObjects[i]), this.highlightedEdgeKey = t);
763
+ o !== -1 && (this.edgeFactory.highlightEdge(this.edgeObjects[o]), this.highlightedEdgeKey = t);
754
764
  }
755
765
  /**
756
766
  * Unhighlights the currently highlighted edge
@@ -793,11 +803,11 @@ class mt {
793
803
  */
794
804
  updateEdgePositions() {
795
805
  this.edgeObjects.forEach((e, s) => {
796
- const t = this.edges[s], i = this.nodeManager.getNode(t.source), o = this.nodeManager.getNode(t.target);
797
- i && o && this.edgeFactory.updateEdgePositions(
806
+ const t = this.edges[s], o = this.nodeManager.getNode(t.source), i = this.nodeManager.getNode(t.target);
807
+ o && i && this.edgeFactory.updateEdgePositions(
798
808
  e,
799
- i.position,
800
- o.position
809
+ o.position,
810
+ i.position
801
811
  );
802
812
  });
803
813
  }
@@ -844,12 +854,29 @@ class Le {
844
854
  l(this, "damping");
845
855
  l(this, "useBarnesHut");
846
856
  l(this, "barnesHutTheta");
857
+ // Scaling safeguards
858
+ l(this, "MAX_VELOCITY", 5);
859
+ // Max units/step
860
+ l(this, "REPULSION_CUTOFF", 200);
861
+ // Skip repulsion beyond this distance
862
+ l(this, "REPULSION_CUTOFF_SQ");
863
+ // Precomputed cutoff²
864
+ l(this, "GRAVITY_STRENGTH", 0.02);
865
+ // Centering force strength
847
866
  // Simulation state
848
867
  l(this, "alpha", 1);
849
868
  l(this, "alphaDecay", 0.0228);
850
869
  l(this, "alphaMin", 1e-3);
851
870
  l(this, "alphaTarget", 0);
852
- this.nodes = e, this.edges = s, this.repulsionStrength = t.repulsionStrength ?? 100, this.attractionStrength = t.attractionStrength ?? 0.01, this.damping = t.damping ?? 0.9, this.useBarnesHut = t.useBarnesHut ?? !1, this.barnesHutTheta = t.barnesHutTheta ?? 0.5;
871
+ this.nodes = e, this.edges = s, this.repulsionStrength = t.repulsionStrength ?? 100, this.attractionStrength = t.attractionStrength ?? 0.01, this.damping = t.damping ?? 0.9, this.useBarnesHut = t.useBarnesHut ?? !1, this.barnesHutTheta = t.barnesHutTheta ?? 0.5, this.REPULSION_CUTOFF_SQ = this.REPULSION_CUTOFF * this.REPULSION_CUTOFF;
872
+ }
873
+ /**
874
+ * Computes effective repulsion strength scaled by node count.
875
+ * This keeps total repulsion energy bounded as N grows.
876
+ */
877
+ getEffectiveRepulsion() {
878
+ const e = this.nodes.size;
879
+ return e <= 500 ? this.repulsionStrength : this.repulsionStrength * Math.sqrt(500) / Math.sqrt(e);
853
880
  }
854
881
  /**
855
882
  * Runs one simulation step
@@ -857,21 +884,22 @@ class Le {
857
884
  simulate() {
858
885
  if (this.alpha < this.alphaMin) return;
859
886
  const e = this.nodes.size;
860
- (this.useBarnesHut || e >= 1e3) && e >= 100 ? this.calculateRepulsionBarnesHut() : this.calculateRepulsionBruteForce(), this.calculateAttraction(), this.applyForces(), this.alpha += (this.alphaTarget - this.alpha) * this.alphaDecay;
887
+ (this.useBarnesHut || e >= 1e3) && e >= 100 ? this.calculateRepulsionBarnesHut() : this.calculateRepulsionBruteForce(), this.calculateAttraction(), this.applyCenteringForce(), this.applyForces(), this.alpha += (this.alphaTarget - this.alpha) * this.alphaDecay;
861
888
  }
862
889
  /**
863
890
  * Brute force repulsion - O(n²)
864
891
  */
865
892
  calculateRepulsionBruteForce() {
866
- const e = Array.from(this.nodes.values()), s = e.length;
867
- for (let t = 0; t < s; t++) {
868
- const i = e[t];
869
- for (let o = t + 1; o < s; o++) {
870
- const a = e[o], r = a.position.x - i.position.x, c = a.position.y - i.position.y, d = a.position.z - i.position.z;
871
- let p = r * r + c * c + d * d;
872
- p < 0.01 && (p = 0.01);
873
- const x = Math.sqrt(p), f = this.repulsionStrength * this.alpha / p, u = r / x * f, y = c / x * f, b = d / x * f;
874
- i.velocity.x -= u / i.mass, i.velocity.y -= y / i.mass, i.velocity.z -= b / i.mass, a.velocity.x += u / a.mass, a.velocity.y += y / a.mass, a.velocity.z += b / a.mass;
893
+ const e = Array.from(this.nodes.values()), s = e.length, t = this.getEffectiveRepulsion();
894
+ for (let o = 0; o < s; o++) {
895
+ const i = e[o];
896
+ for (let a = o + 1; a < s; a++) {
897
+ const r = e[a], c = r.position.x - i.position.x, h = r.position.y - i.position.y, p = r.position.z - i.position.z;
898
+ let x = c * c + h * h + p * p;
899
+ if (x > this.REPULSION_CUTOFF_SQ) continue;
900
+ x < 0.01 && (x = 0.01);
901
+ const m = Math.sqrt(x), u = t * this.alpha / x, f = c / m * u, b = h / m * u, M = p / m * u;
902
+ i.velocity.x -= f / i.mass, i.velocity.y -= b / i.mass, i.velocity.z -= M / i.mass, r.velocity.x += f / r.mass, r.velocity.y += b / r.mass, r.velocity.z += M / r.mass;
875
903
  }
876
904
  }
877
905
  }
@@ -879,7 +907,7 @@ class Le {
879
907
  * Barnes-Hut approximation - O(n log n)
880
908
  */
881
909
  calculateRepulsionBarnesHut() {
882
- const e = Array.from(this.nodes.values()), s = new yt(e);
910
+ const e = Array.from(this.nodes.values()), s = new xt(e);
883
911
  for (const t of e)
884
912
  this.calculateForceFromOctree(t, s.root);
885
913
  }
@@ -892,43 +920,65 @@ class Le {
892
920
  return;
893
921
  }
894
922
  if (s.mass === 0) return;
895
- const t = s.centerOfMass.x - e.position.x, i = s.centerOfMass.y - e.position.y, o = s.centerOfMass.z - e.position.z, a = Math.sqrt(t * t + i * i + o * o);
896
- if (s.size / a < this.barnesHutTheta) {
897
- const r = Math.max(a * a, 0.01), c = this.repulsionStrength * this.alpha * s.mass / r;
898
- e.velocity.x -= t / a * c / e.mass, e.velocity.y -= i / a * c / e.mass, e.velocity.z -= o / a * c / e.mass;
923
+ const t = s.centerOfMass.x - e.position.x, o = s.centerOfMass.y - e.position.y, i = s.centerOfMass.z - e.position.z, a = t * t + o * o + i * i;
924
+ if (a > this.REPULSION_CUTOFF_SQ) return;
925
+ const r = Math.sqrt(a), c = this.getEffectiveRepulsion();
926
+ if (r > 0 && s.size / r < this.barnesHutTheta) {
927
+ const h = Math.max(a, 0.01), p = c * this.alpha * s.mass / h;
928
+ e.velocity.x -= t / r * p / e.mass, e.velocity.y -= o / r * p / e.mass, e.velocity.z -= i / r * p / e.mass;
899
929
  } else
900
- for (const r of s.children)
901
- r && this.calculateForceFromOctree(e, r);
930
+ for (const h of s.children)
931
+ h && this.calculateForceFromOctree(e, h);
902
932
  }
903
933
  /**
904
- * Apply repulsion between two nodes
934
+ * Apply repulsion between two nodes (with cutoff)
905
935
  */
906
936
  applyRepulsionBetween(e, s) {
907
- const t = s.position.x - e.position.x, i = s.position.y - e.position.y, o = s.position.z - e.position.z;
908
- let a = t * t + i * i + o * o;
937
+ const t = s.position.x - e.position.x, o = s.position.y - e.position.y, i = s.position.z - e.position.z;
938
+ let a = t * t + o * o + i * i;
939
+ if (a > this.REPULSION_CUTOFF_SQ) return;
909
940
  a < 0.01 && (a = 0.01);
910
- const r = Math.sqrt(a), c = this.repulsionStrength * this.alpha / a;
911
- e.velocity.x -= t / r * c / e.mass, e.velocity.y -= i / r * c / e.mass, e.velocity.z -= o / r * c / e.mass;
941
+ const r = Math.sqrt(a), h = this.getEffectiveRepulsion() * this.alpha / a;
942
+ e.velocity.x -= t / r * h / e.mass, e.velocity.y -= o / r * h / e.mass, e.velocity.z -= i / r * h / e.mass;
912
943
  }
913
944
  /**
914
945
  * Calculate attraction forces along edges
915
946
  */
916
947
  calculateAttraction() {
917
- for (const e of this.edges) {
918
- const s = this.nodes.get(e.source), t = this.nodes.get(e.target);
919
- if (!s || !t) continue;
920
- const i = t.position.x - s.position.x, o = t.position.y - s.position.y, a = t.position.z - s.position.z, r = Math.sqrt(i * i + o * o + a * a);
921
- if (r < 0.01) continue;
922
- const d = (r - 15) * this.attractionStrength * this.alpha, p = i / r * d, x = o / r * d, f = a / r * d;
923
- s.velocity.x += p / s.mass, s.velocity.y += x / s.mass, s.velocity.z += f / s.mass, t.velocity.x -= p / t.mass, t.velocity.y -= x / t.mass, t.velocity.z -= f / t.mass;
948
+ const e = this.nodes.size, s = e > 500 ? 1 + Math.log10(e / 500) : 1;
949
+ for (const t of this.edges) {
950
+ const o = this.nodes.get(t.source), i = this.nodes.get(t.target);
951
+ if (!o || !i) continue;
952
+ const a = i.position.x - o.position.x, r = i.position.y - o.position.y, c = i.position.z - o.position.z, h = Math.sqrt(a * a + r * r + c * c);
953
+ if (h < 0.01) continue;
954
+ const x = (h - 15) * this.attractionStrength * s * this.alpha, m = a / h * x, u = r / h * x, f = c / h * x;
955
+ o.velocity.x += m / o.mass, o.velocity.y += u / o.mass, o.velocity.z += f / o.mass, i.velocity.x -= m / i.mass, i.velocity.y -= u / i.mass, i.velocity.z -= f / i.mass;
924
956
  }
925
957
  }
926
958
  /**
927
- * Apply velocities and damping to positions
959
+ * Applies a weak centering/gravity force pulling all nodes toward origin.
960
+ * Prevents the graph from drifting infinitely away from the center.
961
+ */
962
+ applyCenteringForce() {
963
+ const e = this.GRAVITY_STRENGTH * this.alpha;
964
+ for (const s of this.nodes.values())
965
+ s.velocity.x -= s.position.x * e, s.velocity.y -= s.position.y * e, s.velocity.z -= s.position.z * e;
966
+ }
967
+ /**
968
+ * Apply velocities and damping to positions, with velocity capping
928
969
  */
929
970
  applyForces() {
930
- for (const e of this.nodes.values())
931
- e.velocity.x *= this.damping, e.velocity.y *= this.damping, e.velocity.z *= this.damping, e.position.x += e.velocity.x, e.position.y += e.velocity.y, e.position.z += e.velocity.z;
971
+ for (const e of this.nodes.values()) {
972
+ e.velocity.x *= this.damping, e.velocity.y *= this.damping, e.velocity.z *= this.damping;
973
+ const s = Math.sqrt(
974
+ e.velocity.x * e.velocity.x + e.velocity.y * e.velocity.y + e.velocity.z * e.velocity.z
975
+ );
976
+ if (s > this.MAX_VELOCITY) {
977
+ const t = this.MAX_VELOCITY / s;
978
+ e.velocity.x *= t, e.velocity.y *= t, e.velocity.z *= t;
979
+ }
980
+ e.position.x += e.velocity.x, e.position.y += e.velocity.y, e.position.z += e.velocity.z;
981
+ }
932
982
  }
933
983
  /**
934
984
  * Updates the edges reference
@@ -955,7 +1005,7 @@ class Le {
955
1005
  e.repulsionStrength !== void 0 && (this.repulsionStrength = e.repulsionStrength), e.attractionStrength !== void 0 && (this.attractionStrength = e.attractionStrength), e.damping !== void 0 && (this.damping = e.damping);
956
1006
  }
957
1007
  }
958
- class yt {
1008
+ class xt {
959
1009
  constructor(e) {
960
1010
  l(this, "root");
961
1011
  const s = this.calculateBounds(e);
@@ -968,13 +1018,13 @@ class yt {
968
1018
  max: { x: 100, y: 100, z: 100 }
969
1019
  };
970
1020
  const s = { x: 1 / 0, y: 1 / 0, z: 1 / 0 }, t = { x: -1 / 0, y: -1 / 0, z: -1 / 0 };
971
- for (const o of e)
972
- 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);
973
- const i = 10;
974
- return s.x -= i, s.y -= i, s.z -= i, t.x += i, t.y += i, t.z += i, { min: s, max: t };
1021
+ for (const i of e)
1022
+ s.x = Math.min(s.x, i.position.x), s.y = Math.min(s.y, i.position.y), s.z = Math.min(s.z, i.position.z), t.x = Math.max(t.x, i.position.x), t.y = Math.max(t.y, i.position.y), t.z = Math.max(t.z, i.position.z);
1023
+ const o = 10;
1024
+ return s.x -= o, s.y -= o, s.z -= o, t.x += o, t.y += o, t.z += o, { min: s, max: t };
975
1025
  }
976
1026
  buildTree(e, s, t = 0) {
977
- const i = Math.max(
1027
+ const o = Math.max(
978
1028
  s.max.x - s.min.x,
979
1029
  s.max.y - s.min.y,
980
1030
  s.max.z - s.min.z
@@ -982,7 +1032,7 @@ class yt {
982
1032
  if (e.length === 0)
983
1033
  return {
984
1034
  bounds: s,
985
- size: i,
1035
+ size: o,
986
1036
  centerOfMass: { x: 0, y: 0, z: 0 },
987
1037
  mass: 0,
988
1038
  isLeaf: !0,
@@ -991,46 +1041,46 @@ class yt {
991
1041
  };
992
1042
  if (e.length === 1 || t > 20) {
993
1043
  let u = 0;
994
- const y = { x: 0, y: 0, z: 0 };
1044
+ const f = { x: 0, y: 0, z: 0 };
995
1045
  for (const b of e)
996
- u += b.mass, y.x += b.position.x * b.mass, y.y += b.position.y * b.mass, y.z += b.position.z * b.mass;
997
- return u > 0 && (y.x /= u, y.y /= u, y.z /= u), {
1046
+ u += b.mass, f.x += b.position.x * b.mass, f.y += b.position.y * b.mass, f.z += b.position.z * b.mass;
1047
+ return u > 0 && (f.x /= u, f.y /= u, f.z /= u), {
998
1048
  bounds: s,
999
- size: i,
1000
- centerOfMass: y,
1049
+ size: o,
1050
+ centerOfMass: f,
1001
1051
  mass: u,
1002
1052
  isLeaf: !0,
1003
1053
  node: e[0],
1004
1054
  children: []
1005
1055
  };
1006
1056
  }
1007
- const o = (s.min.x + s.max.x) / 2, a = (s.min.y + s.max.y) / 2, r = (s.min.z + s.max.z) / 2, c = [[], [], [], [], [], [], [], []];
1057
+ const i = (s.min.x + s.max.x) / 2, a = (s.min.y + s.max.y) / 2, r = (s.min.z + s.max.z) / 2, c = [[], [], [], [], [], [], [], []];
1008
1058
  for (const u of e) {
1009
- const y = (u.position.x >= o ? 1 : 0) + (u.position.y >= a ? 2 : 0) + (u.position.z >= r ? 4 : 0);
1010
- c[y].push(u);
1011
- }
1012
- const d = [
1013
- { min: { x: s.min.x, y: s.min.y, z: s.min.z }, max: { x: o, y: a, z: r } },
1014
- { min: { x: o, y: s.min.y, z: s.min.z }, max: { x: s.max.x, y: a, z: r } },
1015
- { min: { x: s.min.x, y: a, z: s.min.z }, max: { x: o, y: s.max.y, z: r } },
1016
- { min: { x: o, y: a, z: s.min.z }, max: { x: s.max.x, y: s.max.y, z: r } },
1017
- { min: { x: s.min.x, y: s.min.y, z: r }, max: { x: o, y: a, z: s.max.z } },
1018
- { min: { x: o, y: s.min.y, z: r }, max: { x: s.max.x, y: a, z: s.max.z } },
1019
- { min: { x: s.min.x, y: a, z: r }, max: { x: o, y: s.max.y, z: s.max.z } },
1020
- { min: { x: o, y: a, z: r }, max: { x: s.max.x, y: s.max.y, z: s.max.z } }
1059
+ const f = (u.position.x >= i ? 1 : 0) + (u.position.y >= a ? 2 : 0) + (u.position.z >= r ? 4 : 0);
1060
+ c[f].push(u);
1061
+ }
1062
+ const h = [
1063
+ { min: { x: s.min.x, y: s.min.y, z: s.min.z }, max: { x: i, y: a, z: r } },
1064
+ { min: { x: i, y: s.min.y, z: s.min.z }, max: { x: s.max.x, y: a, z: r } },
1065
+ { min: { x: s.min.x, y: a, z: s.min.z }, max: { x: i, y: s.max.y, z: r } },
1066
+ { min: { x: i, y: a, z: s.min.z }, max: { x: s.max.x, y: s.max.y, z: r } },
1067
+ { min: { x: s.min.x, y: s.min.y, z: r }, max: { x: i, y: a, z: s.max.z } },
1068
+ { min: { x: i, y: s.min.y, z: r }, max: { x: s.max.x, y: a, z: s.max.z } },
1069
+ { min: { x: s.min.x, y: a, z: r }, max: { x: i, y: s.max.y, z: s.max.z } },
1070
+ { min: { x: i, y: a, z: r }, max: { x: s.max.x, y: s.max.y, z: s.max.z } }
1021
1071
  ], p = [];
1022
1072
  let x = 0;
1023
- const f = { x: 0, y: 0, z: 0 };
1073
+ const m = { x: 0, y: 0, z: 0 };
1024
1074
  for (let u = 0; u < 8; u++)
1025
1075
  if (c[u].length > 0) {
1026
- const y = this.buildTree(c[u], d[u], t + 1);
1027
- p.push(y), x += y.mass, f.x += y.centerOfMass.x * y.mass, f.y += y.centerOfMass.y * y.mass, f.z += y.centerOfMass.z * y.mass;
1076
+ const f = this.buildTree(c[u], h[u], t + 1);
1077
+ p.push(f), x += f.mass, m.x += f.centerOfMass.x * f.mass, m.y += f.centerOfMass.y * f.mass, m.z += f.centerOfMass.z * f.mass;
1028
1078
  } else
1029
1079
  p.push(null);
1030
- return x > 0 && (f.x /= x, f.y /= x, f.z /= x), {
1080
+ return x > 0 && (m.x /= x, m.y /= x, m.z /= x), {
1031
1081
  bounds: s,
1032
- size: i,
1033
- centerOfMass: f,
1082
+ size: o,
1083
+ centerOfMass: m,
1034
1084
  mass: x,
1035
1085
  isLeaf: !1,
1036
1086
  node: null,
@@ -1038,8 +1088,8 @@ class yt {
1038
1088
  };
1039
1089
  }
1040
1090
  }
1041
- class xt {
1042
- constructor(e, s, t, i = 60) {
1091
+ class bt {
1092
+ constructor(e, s, t, o = 60) {
1043
1093
  l(this, "sceneManager");
1044
1094
  l(this, "animationId", null);
1045
1095
  l(this, "isRunning", !1);
@@ -1064,7 +1114,7 @@ class xt {
1064
1114
  const t = e - this.fpsStartTime;
1065
1115
  t >= 1e3 && (this.currentFPS = this.frameCount / (t / 1e3), this.frameCount = 0, this.fpsStartTime = e), this.onSimulate(), this.onRender(), this.sceneManager.render();
1066
1116
  });
1067
- this.sceneManager = e, this.onSimulate = s, this.onRender = t, this.frameInterval = 1e3 / i;
1117
+ this.sceneManager = e, this.onSimulate = s, this.onRender = t, this.frameInterval = 1e3 / o;
1068
1118
  }
1069
1119
  /**
1070
1120
  * Starts the animation loop
@@ -1103,7 +1153,7 @@ class xt {
1103
1153
  this.stop();
1104
1154
  }
1105
1155
  }
1106
- class bt {
1156
+ class vt {
1107
1157
  constructor() {
1108
1158
  l(this, "envMap", null);
1109
1159
  l(this, "materialCache", /* @__PURE__ */ new Map());
@@ -1141,10 +1191,10 @@ class bt {
1141
1191
  { colors: ["#2d1a1a", "#1a0a0a", "#0f0505"] }
1142
1192
  // -z
1143
1193
  ];
1144
- for (const i of t) {
1145
- const o = document.createElement("canvas");
1146
- o.width = 256, o.height = 256;
1147
- const a = o.getContext("2d"), r = a.createRadialGradient(
1194
+ for (const o of t) {
1195
+ const i = document.createElement("canvas");
1196
+ i.width = 256, i.height = 256;
1197
+ const a = i.getContext("2d"), r = a.createRadialGradient(
1148
1198
  256 / 2,
1149
1199
  256 / 2,
1150
1200
  0,
@@ -1152,17 +1202,17 @@ class bt {
1152
1202
  256 / 2,
1153
1203
  256 * 0.8
1154
1204
  );
1155
- r.addColorStop(0, i.colors[0]), r.addColorStop(0.5, i.colors[1]), r.addColorStop(1, i.colors[2]), a.fillStyle = r, a.fillRect(0, 0, 256, 256);
1205
+ r.addColorStop(0, o.colors[0]), r.addColorStop(0.5, o.colors[1]), r.addColorStop(1, o.colors[2]), a.fillStyle = r, a.fillRect(0, 0, 256, 256);
1156
1206
  const c = a.getImageData(0, 0, 256, 256);
1157
- for (let d = 0; d < c.data.length; d += 4) {
1207
+ for (let h = 0; h < c.data.length; h += 4) {
1158
1208
  const p = (Math.random() - 0.5) * 5;
1159
- c.data[d] = Math.min(255, Math.max(0, c.data[d] + p)), c.data[d + 1] = Math.min(255, Math.max(0, c.data[d + 1] + p)), c.data[d + 2] = Math.min(255, Math.max(0, c.data[d + 2] + p));
1209
+ c.data[h] = Math.min(255, Math.max(0, c.data[h] + p)), c.data[h + 1] = Math.min(255, Math.max(0, c.data[h + 1] + p)), c.data[h + 2] = Math.min(255, Math.max(0, c.data[h + 2] + p));
1160
1210
  }
1161
- a.putImageData(c, 0, 0), s.push(o);
1211
+ a.putImageData(c, 0, 0), s.push(i);
1162
1212
  }
1163
- this.envMap = new m.CubeTexture(s.map((i) => {
1164
- const o = new Image();
1165
- return o.src = i.toDataURL(), o;
1213
+ this.envMap = new y.CubeTexture(s.map((o) => {
1214
+ const i = new Image();
1215
+ return i.src = o.toDataURL(), i;
1166
1216
  })), this.envMap.needsUpdate = !0;
1167
1217
  }
1168
1218
  /**
@@ -1179,11 +1229,11 @@ class bt {
1179
1229
  const t = "glass-single";
1180
1230
  if (this.materialCache.has(t))
1181
1231
  return this.materialCache.get(t).clone();
1182
- const i = new m.Color(16750950), o = new m.ShaderMaterial({
1232
+ const o = new y.Color(16750950), i = new y.ShaderMaterial({
1183
1233
  uniforms: {
1184
- uColor: { value: i },
1234
+ uColor: { value: o },
1185
1235
  uEnvMap: { value: this.envMap },
1186
- uGlowColor: { value: new m.Color(16777215) },
1236
+ uGlowColor: { value: new y.Color(16777215) },
1187
1237
  uGlowIntensity: { value: 0.8 },
1188
1238
  uReflectivity: { value: 0.4 },
1189
1239
  uFresnelPower: { value: 2.5 }
@@ -1249,17 +1299,17 @@ class bt {
1249
1299
  }
1250
1300
  `,
1251
1301
  transparent: !0,
1252
- side: m.FrontSide,
1302
+ side: y.FrontSide,
1253
1303
  depthWrite: !0,
1254
- blending: m.NormalBlending
1304
+ blending: y.NormalBlending
1255
1305
  });
1256
- return this.materialCache.set(t, o), o.clone();
1306
+ return this.materialCache.set(t, i), i.clone();
1257
1307
  }
1258
1308
  /**
1259
1309
  * Creates material for edges (light color for dark background)
1260
1310
  */
1261
1311
  createEdgeMaterial(e = 6710886, s = 0.4) {
1262
- return new m.LineBasicMaterial({
1312
+ return new y.LineBasicMaterial({
1263
1313
  color: e,
1264
1314
  transparent: !0,
1265
1315
  opacity: s,
@@ -1270,7 +1320,7 @@ class bt {
1270
1320
  * Creates highlighted edge material
1271
1321
  */
1272
1322
  createHighlightedEdgeMaterial() {
1273
- return new m.LineBasicMaterial({
1323
+ return new y.LineBasicMaterial({
1274
1324
  color: 16750950,
1275
1325
  // Tangerine highlight
1276
1326
  transparent: !1,
@@ -1282,12 +1332,12 @@ class bt {
1282
1332
  * Creates a sprite material for labels (light text for dark background)
1283
1333
  */
1284
1334
  createLabelMaterial(e, s = 24) {
1285
- const t = document.createElement("canvas"), i = t.getContext("2d");
1286
- i.font = `600 ${s}px Inter, -apple-system, sans-serif`;
1287
- const a = i.measureText(e).width;
1288
- t.width = Math.max(128, a + 24), t.height = s + 20, i.clearRect(0, 0, t.width, t.height), i.font = `600 ${s}px Inter, -apple-system, sans-serif`, i.textAlign = "center", i.textBaseline = "middle", i.shadowColor = "rgba(0, 0, 0, 0.8)", i.shadowBlur = 4, i.shadowOffsetX = 1, i.shadowOffsetY = 1, i.fillStyle = "rgba(255, 255, 255, 0.95)", i.fillText(e, t.width / 2, t.height / 2);
1289
- const r = new m.CanvasTexture(t);
1290
- return r.needsUpdate = !0, new m.SpriteMaterial({
1335
+ const t = document.createElement("canvas"), o = t.getContext("2d");
1336
+ o.font = `600 ${s}px Inter, -apple-system, sans-serif`;
1337
+ const a = o.measureText(e).width;
1338
+ t.width = Math.max(128, a + 24), t.height = s + 20, o.clearRect(0, 0, t.width, t.height), o.font = `600 ${s}px Inter, -apple-system, sans-serif`, o.textAlign = "center", o.textBaseline = "middle", o.shadowColor = "rgba(0, 0, 0, 0.8)", o.shadowBlur = 4, o.shadowOffsetX = 1, o.shadowOffsetY = 1, o.fillStyle = "rgba(255, 255, 255, 0.95)", o.fillText(e, t.width / 2, t.height / 2);
1339
+ const r = new y.CanvasTexture(t);
1340
+ return r.needsUpdate = !0, new y.SpriteMaterial({
1291
1341
  map: r,
1292
1342
  transparent: !0,
1293
1343
  depthTest: !1,
@@ -1307,14 +1357,14 @@ class bt {
1307
1357
  this.materialCache.forEach((e) => e.dispose()), this.materialCache.clear(), this.envMap && this.envMap.dispose();
1308
1358
  }
1309
1359
  }
1310
- class vt {
1311
- constructor(e, s = 2, t = [32, 16, 8], i = 16750950) {
1360
+ class Mt {
1361
+ constructor(e, s = 2, t = [32, 16, 8], o = 16750950) {
1312
1362
  l(this, "materialFactory");
1313
1363
  l(this, "geometryCache", /* @__PURE__ */ new Map());
1314
1364
  l(this, "nodeRadius");
1315
1365
  l(this, "lodSegments");
1316
1366
  l(this, "defaultNodeColor");
1317
- this.materialFactory = e, this.nodeRadius = s, this.lodSegments = t, this.defaultNodeColor = i, this.initGeometryCache();
1367
+ this.materialFactory = e, this.nodeRadius = s, this.lodSegments = t, this.defaultNodeColor = o, this.initGeometryCache();
1318
1368
  }
1319
1369
  /**
1320
1370
  * Pre-create geometries for each LOD level
@@ -1324,7 +1374,7 @@ class vt {
1324
1374
  const t = `lod-${s}`;
1325
1375
  this.geometryCache.set(
1326
1376
  t,
1327
- new m.SphereGeometry(this.nodeRadius, e, e)
1377
+ new y.SphereGeometry(this.nodeRadius, e, e)
1328
1378
  );
1329
1379
  });
1330
1380
  }
@@ -1339,13 +1389,13 @@ class vt {
1339
1389
  * Creates a node visual (glass ball + label)
1340
1390
  */
1341
1391
  createNode(e, s = 0) {
1342
- const t = new m.Group();
1392
+ const t = new y.Group();
1343
1393
  t.name = `node-${e.id}`, t.userData = { nodeId: e.id, nodeData: e };
1344
- const i = this.getGeometry(s), o = this.materialFactory.createGlassMaterial(
1394
+ const o = this.getGeometry(s), i = this.materialFactory.createGlassMaterial(
1345
1395
  e.color ?? this.defaultNodeColor
1346
- ), a = new m.Mesh(i, o);
1396
+ ), a = new y.Mesh(o, i);
1347
1397
  a.castShadow = !0, a.receiveShadow = !0, t.add(a);
1348
- const r = this.materialFactory.createLabelMaterial(e.label), c = new m.Sprite(r);
1398
+ const r = this.materialFactory.createLabelMaterial(e.label), c = new y.Sprite(r);
1349
1399
  return c.position.y = this.nodeRadius + 1.5, c.scale.set(4, 1, 1), t.add(c), e.position && t.position.set(
1350
1400
  e.position.x,
1351
1401
  e.position.y,
@@ -1369,19 +1419,19 @@ class vt {
1369
1419
  * Updates the color of a node
1370
1420
  */
1371
1421
  updateNodeColor(e, s) {
1372
- e.sphere.material instanceof m.Material && e.sphere.material.dispose(), e.sphere.material = this.materialFactory.createGlassMaterial(s);
1422
+ e.sphere.material instanceof y.Material && e.sphere.material.dispose(), e.sphere.material = this.materialFactory.createGlassMaterial(s);
1373
1423
  }
1374
1424
  /**
1375
1425
  * Updates the label of a node
1376
1426
  */
1377
1427
  updateNodeLabel(e, s) {
1378
- e.label.material instanceof m.SpriteMaterial && (e.label.material.map && e.label.material.map.dispose(), e.label.material.dispose()), e.label.material = this.materialFactory.createLabelMaterial(s);
1428
+ 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);
1379
1429
  }
1380
1430
  /**
1381
1431
  * Disposes a node's resources
1382
1432
  */
1383
1433
  disposeNode(e) {
1384
- e.sphere.material instanceof m.Material && e.sphere.material.dispose(), e.label.material instanceof m.SpriteMaterial && (e.label.material.map && e.label.material.map.dispose(), e.label.material.dispose());
1434
+ 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());
1385
1435
  }
1386
1436
  /**
1387
1437
  * Dispose factory resources
@@ -1390,7 +1440,7 @@ class vt {
1390
1440
  this.geometryCache.forEach((e) => e.dispose()), this.geometryCache.clear();
1391
1441
  }
1392
1442
  }
1393
- class Mt {
1443
+ class wt {
1394
1444
  constructor(e, s = 10066329, t = 0.5) {
1395
1445
  l(this, "materialFactory");
1396
1446
  l(this, "edgeColor");
@@ -1417,25 +1467,25 @@ class Mt {
1417
1467
  /**
1418
1468
  * Creates an edge line between two positions
1419
1469
  */
1420
- createEdge(e, s, t, i, o) {
1421
- const a = new m.BufferGeometry(), r = new Float32Array([
1422
- i.x,
1423
- i.y,
1424
- i.z,
1470
+ createEdge(e, s, t, o, i) {
1471
+ const a = new y.BufferGeometry(), r = new Float32Array([
1425
1472
  o.x,
1426
1473
  o.y,
1427
- o.z
1474
+ o.z,
1475
+ i.x,
1476
+ i.y,
1477
+ i.z
1428
1478
  ]);
1429
- a.setAttribute("position", new m.BufferAttribute(r, 3));
1430
- const c = this.getDefaultMaterial().clone(), d = new m.Line(a, c);
1431
- return d.name = `edge-${e.source}-${e.target}`, d.userData = {
1479
+ a.setAttribute("position", new y.BufferAttribute(r, 3));
1480
+ const c = this.getDefaultMaterial().clone(), h = new y.Line(a, c);
1481
+ return h.name = `edge-${e.source}-${e.target}`, h.userData = {
1432
1482
  source: e.source,
1433
1483
  target: e.target,
1434
1484
  edge: e,
1435
1485
  sourceNode: s,
1436
1486
  targetNode: t
1437
- }, d.frustumCulled = !0, {
1438
- line: d,
1487
+ }, h.frustumCulled = !0, {
1488
+ line: h,
1439
1489
  source: e.source,
1440
1490
  target: e.target
1441
1491
  };
@@ -1444,26 +1494,26 @@ class Mt {
1444
1494
  * Highlights an edge
1445
1495
  */
1446
1496
  highlightEdge(e) {
1447
- e.line.material instanceof m.Material && e.line.material.dispose(), e.line.material = this.getHighlightMaterial().clone();
1497
+ e.line.material instanceof y.Material && e.line.material.dispose(), e.line.material = this.getHighlightMaterial().clone();
1448
1498
  }
1449
1499
  /**
1450
1500
  * Resets an edge to default appearance
1451
1501
  */
1452
1502
  unhighlightEdge(e) {
1453
- e.line.material instanceof m.Material && e.line.material.dispose(), e.line.material = this.getDefaultMaterial().clone();
1503
+ e.line.material instanceof y.Material && e.line.material.dispose(), e.line.material = this.getDefaultMaterial().clone();
1454
1504
  }
1455
1505
  /**
1456
1506
  * Updates an edge's positions
1457
1507
  */
1458
1508
  updateEdgePositions(e, s, t) {
1459
- const i = e.line.geometry.attributes.position, o = i.array;
1460
- 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();
1509
+ const o = e.line.geometry.attributes.position, i = o.array;
1510
+ i[0] = s.x, i[1] = s.y, i[2] = s.z, i[3] = t.x, i[4] = t.y, i[5] = t.z, o.needsUpdate = !0, e.line.geometry.computeBoundingSphere();
1461
1511
  }
1462
1512
  /**
1463
1513
  * Disposes an edge's resources
1464
1514
  */
1465
1515
  disposeEdge(e) {
1466
- e.line.geometry.dispose(), e.line.material instanceof m.Material && e.line.material.dispose();
1516
+ e.line.geometry.dispose(), e.line.material instanceof y.Material && e.line.material.dispose();
1467
1517
  }
1468
1518
  /**
1469
1519
  * Dispose factory resources
@@ -1472,7 +1522,7 @@ class Mt {
1472
1522
  this.defaultMaterial && this.defaultMaterial.dispose(), this.highlightMaterial && this.highlightMaterial.dispose();
1473
1523
  }
1474
1524
  }
1475
- class wt {
1525
+ class Et {
1476
1526
  constructor(e, s = [50, 100, 200], t = !0) {
1477
1527
  l(this, "camera");
1478
1528
  l(this, "lodDistances");
@@ -1484,16 +1534,16 @@ class wt {
1484
1534
  */
1485
1535
  getLODLevel(e) {
1486
1536
  if (!this.enabled)
1487
- return U.HIGH;
1488
- 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);
1489
- return o < this.lodDistances[0] ? U.HIGH : o < this.lodDistances[1] ? U.MEDIUM : U.LOW;
1537
+ return X.HIGH;
1538
+ const s = e.x - this.camera.position.x, t = e.y - this.camera.position.y, o = e.z - this.camera.position.z, i = Math.sqrt(s * s + t * t + o * o);
1539
+ return i < this.lodDistances[0] ? X.HIGH : i < this.lodDistances[1] ? X.MEDIUM : X.LOW;
1490
1540
  }
1491
1541
  /**
1492
1542
  * Checks if a node should be visible based on distance
1493
1543
  */
1494
1544
  shouldRenderNode(e, s = 500) {
1495
- const t = e.x - this.camera.position.x, i = e.y - this.camera.position.y, o = e.z - this.camera.position.z;
1496
- return Math.sqrt(t * t + i * i + o * o) < s;
1545
+ const t = e.x - this.camera.position.x, o = e.y - this.camera.position.y, i = e.z - this.camera.position.z;
1546
+ return Math.sqrt(t * t + o * o + i * i) < s;
1497
1547
  }
1498
1548
  /**
1499
1549
  * Sets the LOD distances
@@ -1508,13 +1558,13 @@ class wt {
1508
1558
  this.enabled = e;
1509
1559
  }
1510
1560
  }
1511
- class Et {
1561
+ class Ct {
1512
1562
  constructor(e, s = !0) {
1513
1563
  l(this, "camera");
1514
1564
  l(this, "frustum");
1515
1565
  l(this, "projScreenMatrix");
1516
1566
  l(this, "enabled");
1517
- this.camera = e, this.frustum = new m.Frustum(), this.projScreenMatrix = new m.Matrix4(), this.enabled = s;
1567
+ this.camera = e, this.frustum = new y.Frustum(), this.projScreenMatrix = new y.Matrix4(), this.enabled = s;
1518
1568
  }
1519
1569
  /**
1520
1570
  * Updates the frustum from the camera
@@ -1530,7 +1580,7 @@ class Et {
1530
1580
  */
1531
1581
  isPointVisible(e) {
1532
1582
  if (!this.enabled) return !0;
1533
- const s = new m.Vector3(e.x, e.y, e.z);
1583
+ const s = new y.Vector3(e.x, e.y, e.z);
1534
1584
  return this.frustum.containsPoint(s);
1535
1585
  }
1536
1586
  /**
@@ -1538,8 +1588,8 @@ class Et {
1538
1588
  */
1539
1589
  isSphereVisible(e, s) {
1540
1590
  if (!this.enabled) return !0;
1541
- const t = new m.Sphere(
1542
- new m.Vector3(e.x, e.y, e.z),
1591
+ const t = new y.Sphere(
1592
+ new y.Vector3(e.x, e.y, e.z),
1543
1593
  s
1544
1594
  );
1545
1595
  return this.frustum.intersectsSphere(t);
@@ -1549,14 +1599,14 @@ class Et {
1549
1599
  */
1550
1600
  isLineVisible(e, s) {
1551
1601
  if (!this.enabled) return !0;
1552
- const t = new m.Vector3(e.x, e.y, e.z), i = new m.Vector3(s.x, s.y, s.z);
1553
- if (this.frustum.containsPoint(t) || this.frustum.containsPoint(i))
1602
+ const t = new y.Vector3(e.x, e.y, e.z), o = new y.Vector3(s.x, s.y, s.z);
1603
+ if (this.frustum.containsPoint(t) || this.frustum.containsPoint(o))
1554
1604
  return !0;
1555
- const o = new m.Vector3(
1605
+ const i = new y.Vector3(
1556
1606
  (e.x + s.x) / 2,
1557
1607
  (e.y + s.y) / 2,
1558
1608
  (e.z + s.z) / 2
1559
- ), a = o.distanceTo(t), r = new m.Sphere(o, a);
1609
+ ), a = i.distanceTo(t), r = new y.Sphere(i, a);
1560
1610
  return this.frustum.intersectsSphere(r);
1561
1611
  }
1562
1612
  /**
@@ -1566,7 +1616,7 @@ class Et {
1566
1616
  this.enabled = e;
1567
1617
  }
1568
1618
  }
1569
- class Ct {
1619
+ class Nt {
1570
1620
  constructor(e, s) {
1571
1621
  l(this, "sceneManager");
1572
1622
  l(this, "raycaster");
@@ -1580,7 +1630,7 @@ class Ct {
1580
1630
  l(this, "hoveredEdgeKey", null);
1581
1631
  l(this, "nodeObjects", []);
1582
1632
  l(this, "edgeObjects", []);
1583
- this.sceneManager = e, this.container = s, this.raycaster = new m.Raycaster(), this.raycaster.params.Line = { threshold: 1.5 }, this.mouse = new m.Vector2(), this.handleClick = this.handleClick.bind(this), this.handleMouseMove = this.handleMouseMove.bind(this), s.addEventListener("click", this.handleClick), s.addEventListener("mousemove", this.handleMouseMove);
1633
+ 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);
1584
1634
  }
1585
1635
  /**
1586
1636
  * Updates the list of node objects to raycast against
@@ -1639,23 +1689,23 @@ class Ct {
1639
1689
  this.hoveredEdgeKey !== null && this.onEdgeHover && (this.hoveredEdgeKey = null, this.onEdgeHover(null)), this.container.style.cursor = "pointer";
1640
1690
  return;
1641
1691
  }
1642
- const i = this.getIntersectedEdge(e), o = i ? `${i.edge.source}-${i.edge.target}` : null;
1643
- o !== this.hoveredEdgeKey && (this.hoveredEdgeKey = o, this.onEdgeHover && this.onEdgeHover(i)), this.container.style.cursor = i ? "pointer" : "default";
1692
+ const o = this.getIntersectedEdge(e), i = o ? `${o.edge.source}-${o.edge.target}` : null;
1693
+ i !== this.hoveredEdgeKey && (this.hoveredEdgeKey = i, this.onEdgeHover && this.onEdgeHover(o)), this.container.style.cursor = o ? "pointer" : "default";
1644
1694
  }
1645
1695
  /**
1646
1696
  * Gets the intersected node from a mouse event
1647
1697
  */
1648
1698
  getIntersectedNode(e) {
1649
- var i;
1699
+ var o;
1650
1700
  const s = this.container.getBoundingClientRect();
1651
1701
  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);
1652
1702
  const t = this.raycaster.intersectObjects(this.nodeObjects, !0);
1653
1703
  if (t.length > 0) {
1654
- let o = t[0].object;
1655
- for (; o; ) {
1656
- if ((i = o.userData) != null && i.nodeData)
1657
- return o.userData.nodeData;
1658
- o = o.parent;
1704
+ let i = t[0].object;
1705
+ for (; i; ) {
1706
+ if ((o = i.userData) != null && o.nodeData)
1707
+ return i.userData.nodeData;
1708
+ i = i.parent;
1659
1709
  }
1660
1710
  }
1661
1711
  return null;
@@ -1668,13 +1718,13 @@ class Ct {
1668
1718
  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);
1669
1719
  const t = this.raycaster.intersectObjects(this.edgeObjects, !1);
1670
1720
  if (t.length > 0) {
1671
- const i = t[0].object, o = i.userData;
1672
- if (o != null && o.edge && (o != null && o.sourceNode) && (o != null && o.targetNode))
1721
+ const o = t[0].object, i = o.userData;
1722
+ if (i != null && i.edge && (i != null && i.sourceNode) && (i != null && i.targetNode))
1673
1723
  return {
1674
- edge: o.edge,
1675
- sourceNode: o.sourceNode,
1676
- targetNode: o.targetNode,
1677
- edgeLine: i
1724
+ edge: i.edge,
1725
+ sourceNode: i.sourceNode,
1726
+ targetNode: i.targetNode,
1727
+ edgeLine: o
1678
1728
  };
1679
1729
  }
1680
1730
  return null;
@@ -1683,14 +1733,14 @@ class Ct {
1683
1733
  * Performs a raycast and returns the intersected node ID
1684
1734
  */
1685
1735
  getIntersectedNodeId(e, s) {
1686
- var o;
1736
+ var i;
1687
1737
  const t = this.container.getBoundingClientRect();
1688
1738
  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);
1689
- const i = this.raycaster.intersectObjects(this.nodeObjects, !0);
1690
- if (i.length > 0) {
1691
- let a = i[0].object;
1739
+ const o = this.raycaster.intersectObjects(this.nodeObjects, !0);
1740
+ if (o.length > 0) {
1741
+ let a = o[0].object;
1692
1742
  for (; a; ) {
1693
- if ((o = a.userData) != null && o.nodeId)
1743
+ if ((i = a.userData) != null && i.nodeId)
1694
1744
  return a.userData.nodeId;
1695
1745
  a = a.parent;
1696
1746
  }
@@ -1704,7 +1754,7 @@ class Ct {
1704
1754
  this.container.removeEventListener("click", this.handleClick), this.container.removeEventListener("mousemove", this.handleMouseMove);
1705
1755
  }
1706
1756
  }
1707
- class Nt {
1757
+ class St {
1708
1758
  constructor(e) {
1709
1759
  l(this, "container");
1710
1760
  l(this, "panel", null);
@@ -1774,10 +1824,10 @@ class Nt {
1774
1824
  this.currentNodeId = e.id;
1775
1825
  let t;
1776
1826
  this.panelTemplate ? t = this.panelTemplate(e, s) : t = this.generateDefaultContent(e, s), this.panel.innerHTML = t;
1777
- const i = this.panel.querySelector('[data-action="expand"]'), o = this.panel.querySelector("[data-depth-select]");
1778
- i && this.onExpand && i.addEventListener("click", () => {
1827
+ const o = this.panel.querySelector('[data-action="expand"]'), i = this.panel.querySelector("[data-depth-select]");
1828
+ o && this.onExpand && o.addEventListener("click", () => {
1779
1829
  if (this.currentNodeId) {
1780
- const r = o ? parseInt(o.value, 10) : 1;
1830
+ const r = i ? parseInt(i.value, 10) : 1;
1781
1831
  this.onExpand(this.currentNodeId, r);
1782
1832
  }
1783
1833
  });
@@ -1936,7 +1986,7 @@ class Nt {
1936
1986
  <div class="neighbors-section">
1937
1987
  <div class="neighbors-title">Connected To</div>
1938
1988
  ${s.slice(0, 5).map(
1939
- (i) => `<span class="neighbor-chip">${this.escapeHtml(i.label)}</span>`
1989
+ (o) => `<span class="neighbor-chip">${this.escapeHtml(o.label)}</span>`
1940
1990
  ).join("")}
1941
1991
  ${s.length > 5 ? `<span class="neighbor-chip">+${s.length - 5} more</span>` : ""}
1942
1992
  </div>
@@ -1990,7 +2040,7 @@ class Nt {
1990
2040
  this.panel && this.panel.parentNode && this.panel.parentNode.removeChild(this.panel), this.panel = null;
1991
2041
  }
1992
2042
  }
1993
- class St {
2043
+ class zt {
1994
2044
  constructor(e) {
1995
2045
  l(this, "container");
1996
2046
  l(this, "panel", null);
@@ -2054,10 +2104,10 @@ class St {
2054
2104
  show(e, s, t) {
2055
2105
  if (!this.panel) return;
2056
2106
  this.currentEdgeKey = `${e.source}-${e.target}`;
2057
- let i;
2058
- this.panelTemplate ? i = this.panelTemplate(e, s, t) : i = this.generateDefaultContent(e, s, t), this.panel.innerHTML = i;
2059
- const o = this.panel.querySelector('[data-action="close"]');
2060
- o && o.addEventListener("click", () => {
2107
+ let o;
2108
+ this.panelTemplate ? o = this.panelTemplate(e, s, t) : o = this.generateDefaultContent(e, s, t), this.panel.innerHTML = o;
2109
+ const i = this.panel.querySelector('[data-action="close"]');
2110
+ i && i.addEventListener("click", () => {
2061
2111
  this.hide(), this.onClose && this.onClose();
2062
2112
  });
2063
2113
  const a = this.panel.querySelector('[data-action="goto-source"]');
@@ -2073,7 +2123,7 @@ class St {
2073
2123
  * Generates default panel content
2074
2124
  */
2075
2125
  generateDefaultContent(e, s, t) {
2076
- const i = s.color ? `#${s.color.toString(16).padStart(6, "0")}` : "#ff9966", o = t.color ? `#${t.color.toString(16).padStart(6, "0")}` : "#ff9966", a = e.relationship || "connected to";
2126
+ const o = s.color ? `#${s.color.toString(16).padStart(6, "0")}` : "#ff9966", i = t.color ? `#${t.color.toString(16).padStart(6, "0")}` : "#ff9966", a = e.relationship || "connected to";
2077
2127
  return `
2078
2128
  <style>
2079
2129
  .force-graph-edge-panel .panel-header {
@@ -2183,7 +2233,7 @@ class St {
2183
2233
  <div class="node-card" data-action="goto-source" title="Click to focus on ${this.escapeHtml(s.label)}">
2184
2234
  <div class="node-type">Source</div>
2185
2235
  <div class="node-card-header">
2186
- <span class="color-dot" style="background: ${i}; box-shadow: 0 0 8px ${i}80;"></span>
2236
+ <span class="color-dot" style="background: ${o}; box-shadow: 0 0 8px ${o}80;"></span>
2187
2237
  <span class="node-label">${this.escapeHtml(s.label)}</span>
2188
2238
  </div>
2189
2239
  </div>
@@ -2193,7 +2243,7 @@ class St {
2193
2243
  <div class="node-card" data-action="goto-target" title="Click to focus on ${this.escapeHtml(t.label)}">
2194
2244
  <div class="node-type">Target</div>
2195
2245
  <div class="node-card-header">
2196
- <span class="color-dot" style="background: ${o}; box-shadow: 0 0 8px ${o}80;"></span>
2246
+ <span class="color-dot" style="background: ${i}; box-shadow: 0 0 8px ${i}80;"></span>
2197
2247
  <span class="node-label">${this.escapeHtml(t.label)}</span>
2198
2248
  </div>
2199
2249
  </div>
@@ -2235,7 +2285,7 @@ class St {
2235
2285
  this.panel && this.panel.parentNode && this.panel.parentNode.removeChild(this.panel), this.panel = null;
2236
2286
  }
2237
2287
  }
2238
- class zt {
2288
+ class Tt {
2239
2289
  constructor() {
2240
2290
  l(this, "tooltip", null);
2241
2291
  l(this, "visible", !1);
@@ -2281,14 +2331,14 @@ class zt {
2281
2331
  */
2282
2332
  positionTooltip(e, s) {
2283
2333
  if (!this.tooltip) return;
2284
- const t = this.tooltip.getBoundingClientRect(), i = window.innerWidth, o = window.innerHeight;
2334
+ const t = this.tooltip.getBoundingClientRect(), o = window.innerWidth, i = window.innerHeight;
2285
2335
  let a = e + 15, r = s + 15;
2286
- a + t.width > i - 10 && (a = e - t.width - 15), r + t.height > o - 10 && (r = s - t.height - 15), a < 10 && (a = 10), r < 10 && (r = 10), this.tooltip.style.left = `${a}px`, this.tooltip.style.top = `${r}px`;
2336
+ a + t.width > o - 10 && (a = e - t.width - 15), r + t.height > i - 10 && (r = s - t.height - 15), a < 10 && (a = 10), r < 10 && (r = 10), this.tooltip.style.left = `${a}px`, this.tooltip.style.top = `${r}px`;
2287
2337
  }
2288
2338
  /**
2289
2339
  * Shows the tooltip with edge info
2290
2340
  */
2291
- show(e, s, t, i, o) {
2341
+ show(e, s, t, o, i) {
2292
2342
  if (!this.tooltip) return;
2293
2343
  const a = e.relationship || "connected to";
2294
2344
  this.tooltip.innerHTML = `
@@ -2303,7 +2353,7 @@ class zt {
2303
2353
  <span style="font-weight: 600; color: #ff9966;">${this.escapeHtml(t.label)}</span>
2304
2354
  </div>
2305
2355
  </div>
2306
- `, this.positionTooltip(i, o), this.tooltip.style.opacity = "1", this.tooltip.style.transform = "translateY(0)", this.visible = !0;
2356
+ `, this.positionTooltip(o, i), this.tooltip.style.opacity = "1", this.tooltip.style.transform = "translateY(0)", this.visible = !0;
2307
2357
  }
2308
2358
  /**
2309
2359
  * Updates tooltip position (called externally on mouse move)
@@ -2480,25 +2530,25 @@ class kt {
2480
2530
  this.searchResults.innerHTML = '<div class="f3d-no-results">No results found</div>', this.searchResults.style.display = "block";
2481
2531
  return;
2482
2532
  }
2483
- let i = "";
2484
- s.length > 0 && (i += '<div class="f3d-search-section-header">Nodes</div>', s.slice(0, 10).forEach((o) => {
2485
- const a = o.type || "Node";
2486
- i += `
2487
- <div class="f3d-search-result-item" data-node-id="${this.escapeHtml(o.id)}">
2488
- <div class="f3d-result-label">${this.escapeHtml(o.label)}</div>
2533
+ let o = "";
2534
+ s.length > 0 && (o += '<div class="f3d-search-section-header">Nodes</div>', s.slice(0, 10).forEach((i) => {
2535
+ const a = i.type || "Node";
2536
+ o += `
2537
+ <div class="f3d-search-result-item" data-node-id="${this.escapeHtml(i.id)}">
2538
+ <div class="f3d-result-label">${this.escapeHtml(i.label)}</div>
2489
2539
  <div class="f3d-result-type">${this.escapeHtml(a)}</div>
2490
2540
  </div>
2491
2541
  `;
2492
- }), s.length > 10 && (i += `<div class="f3d-no-results">+ ${s.length - 10} more nodes</div>`)), t.length > 0 && (i += '<div class="f3d-search-section-header">Relationships</div>', t.slice(0, 5).forEach(({ edge: o, sourceNode: a, targetNode: r }) => {
2493
- i += `
2494
- <div class="f3d-search-result-item" data-node-id="${this.escapeHtml(o.source)}">
2542
+ }), s.length > 10 && (o += `<div class="f3d-no-results">+ ${s.length - 10} more nodes</div>`)), t.length > 0 && (o += '<div class="f3d-search-section-header">Relationships</div>', t.slice(0, 5).forEach(({ edge: i, sourceNode: a, targetNode: r }) => {
2543
+ o += `
2544
+ <div class="f3d-search-result-item" data-node-id="${this.escapeHtml(i.source)}">
2495
2545
  <div class="f3d-result-label">${this.escapeHtml(a.label)} → ${this.escapeHtml(r.label)}</div>
2496
- <div class="f3d-result-relationship">${this.escapeHtml(o.relationship || "connected")}</div>
2546
+ <div class="f3d-result-relationship">${this.escapeHtml(i.relationship || "connected")}</div>
2497
2547
  </div>
2498
2548
  `;
2499
- }), 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) => {
2500
- o.addEventListener("click", () => {
2501
- const a = o.dataset.nodeId;
2549
+ }), t.length > 5 && (o += `<div class="f3d-no-results">+ ${t.length - 5} more relationships</div>`)), this.searchResults.innerHTML = o, this.searchResults.style.display = "block", this.searchResults.querySelectorAll(".f3d-search-result-item").forEach((i) => {
2550
+ i.addEventListener("click", () => {
2551
+ const a = i.dataset.nodeId;
2502
2552
  a && (this.onResultClick(a), this.searchResults && (this.searchResults.style.display = "none"), this.searchInput && this.searchInput.blur());
2503
2553
  });
2504
2554
  });
@@ -2603,7 +2653,7 @@ class Pt {
2603
2653
  this.toggleContainer && this.toggleContainer.parentNode && this.toggleContainer.parentNode.removeChild(this.toggleContainer);
2604
2654
  }
2605
2655
  }
2606
- const Tt = {
2656
+ const Rt = {
2607
2657
  backgroundColor: "#0a0a0a",
2608
2658
  gridColor: "rgba(255, 255, 255, 0.03)",
2609
2659
  nodeRadius: 24,
@@ -2616,7 +2666,7 @@ const Tt = {
2616
2666
  damping: 0.85
2617
2667
  // Fast energy dissipation
2618
2668
  };
2619
- class Lt {
2669
+ class It {
2620
2670
  constructor(e, s = {}) {
2621
2671
  l(this, "container");
2622
2672
  l(this, "canvas");
@@ -2643,7 +2693,7 @@ class Lt {
2643
2693
  l(this, "isSimulating", !0);
2644
2694
  // Resize handler
2645
2695
  l(this, "resizeHandler");
2646
- 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);
2696
+ 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);
2647
2697
  const t = this.canvas.getContext("2d");
2648
2698
  if (!t)
2649
2699
  throw new Error("Failed to get 2D context");
@@ -2656,31 +2706,31 @@ class Lt {
2656
2706
  setupInteractions() {
2657
2707
  this.canvas.addEventListener("wheel", (e) => {
2658
2708
  e.preventDefault();
2659
- const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, o = e.deltaY > 0 ? 0.9 : 1.1, a = Math.max(0.1, Math.min(5, this.transform.scale * o)), r = a / this.transform.scale;
2660
- this.transform.x = t - (t - this.transform.x) * r, this.transform.y = i - (i - this.transform.y) * r, this.transform.scale = a;
2709
+ const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, o = e.clientY - s.top, i = e.deltaY > 0 ? 0.9 : 1.1, a = Math.max(0.1, Math.min(5, this.transform.scale * i)), r = a / this.transform.scale;
2710
+ this.transform.x = t - (t - this.transform.x) * r, this.transform.y = o - (o - this.transform.y) * r, this.transform.scale = a;
2661
2711
  }), this.canvas.addEventListener("mousedown", (e) => {
2662
- const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, o = this.screenToWorld(t, i), a = this.findNodeAt(o.x, o.y);
2712
+ const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, o = e.clientY - s.top, i = this.screenToWorld(t, o), a = this.findNodeAt(i.x, i.y);
2663
2713
  this.dragStartPos = { x: e.clientX, y: e.clientY }, a ? (this.isDragging = !0, this.draggedNode = a, this.canvas.style.cursor = "grabbing", this.isSimulating = !0) : (this.isPanning = !0, this.canvas.style.cursor = "grabbing"), this.lastMousePos = { x: e.clientX, y: e.clientY };
2664
2714
  }), this.canvas.addEventListener("mousemove", (e) => {
2665
- const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, o = this.screenToWorld(t, i);
2715
+ const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, o = e.clientY - s.top, i = this.screenToWorld(t, o);
2666
2716
  if (this.isDragging && this.draggedNode)
2667
- this.draggedNode.x = o.x, this.draggedNode.y = o.y, this.draggedNode.vx = 0, this.draggedNode.vy = 0;
2717
+ this.draggedNode.x = i.x, this.draggedNode.y = i.y, this.draggedNode.vx = 0, this.draggedNode.vy = 0;
2668
2718
  else if (this.isPanning) {
2669
2719
  const a = e.clientX - this.lastMousePos.x, r = e.clientY - this.lastMousePos.y;
2670
2720
  this.transform.x += a, this.transform.y += r, this.lastMousePos = { x: e.clientX, y: e.clientY };
2671
2721
  } else {
2672
- const a = this.findNodeAt(o.x, o.y);
2722
+ const a = this.findNodeAt(i.x, i.y);
2673
2723
  if (a !== this.hoveredNode && (this.hoveredNode = a, a ? (this.hoveredEdge && (this.hoveredEdge = null, this.options.onEdgeHover && this.options.onEdgeHover(null)), this.canvas.style.cursor = "pointer", this.options.onNodeHover && this.options.onNodeHover(a.data)) : this.options.onNodeHover && this.options.onNodeHover(null)), !a) {
2674
- const r = this.findEdgeAt(o.x, o.y);
2724
+ const r = this.findEdgeAt(i.x, i.y);
2675
2725
  r !== this.hoveredEdge && (this.hoveredEdge = r, this.canvas.style.cursor = r ? "pointer" : "grab", this.options.onEdgeHover && this.options.onEdgeHover(r ? r.data : null, e));
2676
2726
  }
2677
2727
  }
2678
2728
  }), this.canvas.addEventListener("mouseup", (e) => {
2679
- const s = Math.abs(e.clientX - this.dragStartPos.x), t = Math.abs(e.clientY - this.dragStartPos.y), i = s < 5 && t < 5;
2729
+ const s = Math.abs(e.clientX - this.dragStartPos.x), t = Math.abs(e.clientY - this.dragStartPos.y), o = s < 5 && t < 5;
2680
2730
  if (this.isDragging && this.draggedNode)
2681
- i && this.options.onNodeClick && (this.selectedNode = this.draggedNode, this.options.onNodeClick(this.draggedNode.data));
2682
- else if (i) {
2683
- const o = this.canvas.getBoundingClientRect(), a = this.screenToWorld(e.clientX - o.left, e.clientY - o.top), r = this.findEdgeAt(a.x, a.y);
2731
+ o && this.options.onNodeClick && (this.selectedNode = this.draggedNode, this.options.onNodeClick(this.draggedNode.data));
2732
+ else if (o) {
2733
+ const i = this.canvas.getBoundingClientRect(), a = this.screenToWorld(e.clientX - i.left, e.clientY - i.top), r = this.findEdgeAt(a.x, a.y);
2684
2734
  r && this.options.onEdgeClick && this.options.onEdgeClick(r.data);
2685
2735
  }
2686
2736
  this.isDragging = !1, this.isPanning = !1, this.draggedNode = null, this.canvas.style.cursor = this.hoveredNode ? "pointer" : "grab";
@@ -2696,21 +2746,21 @@ class Lt {
2696
2746
  }
2697
2747
  findNodeAt(e, s) {
2698
2748
  for (const t of this.nodes.values()) {
2699
- const i = t.x - e, o = t.y - s;
2700
- if (Math.sqrt(i * i + o * o) < t.radius)
2749
+ const o = t.x - e, i = t.y - s;
2750
+ if (Math.sqrt(o * o + i * i) < t.radius)
2701
2751
  return t;
2702
2752
  }
2703
2753
  return null;
2704
2754
  }
2705
2755
  findEdgeAt(e, s) {
2706
- for (const i of this.edges) {
2707
- const o = this.nodes.get(i.source), a = this.nodes.get(i.target);
2708
- if (!o || !a) continue;
2709
- const r = a.x - o.x, c = a.y - o.y, d = r * r + c * c;
2710
- if (d === 0) continue;
2711
- const p = Math.max(0, Math.min(1, ((e - o.x) * r + (s - o.y) * c) / d)), x = o.x + p * r, f = o.y + p * c, u = e - x, y = s - f;
2712
- if (Math.sqrt(u * u + y * y) < 12)
2713
- return i;
2756
+ for (const o of this.edges) {
2757
+ const i = this.nodes.get(o.source), a = this.nodes.get(o.target);
2758
+ if (!i || !a) continue;
2759
+ const r = a.x - i.x, c = a.y - i.y, h = r * r + c * c;
2760
+ if (h === 0) continue;
2761
+ const p = Math.max(0, Math.min(1, ((e - i.x) * r + (s - i.y) * c) / h)), x = i.x + p * r, m = i.y + p * c, u = e - x, f = s - m;
2762
+ if (Math.sqrt(u * u + f * f) < 12)
2763
+ return o;
2714
2764
  }
2715
2765
  return null;
2716
2766
  }
@@ -2723,69 +2773,69 @@ class Lt {
2723
2773
  simulate() {
2724
2774
  const e = Array.from(this.nodes.values()), s = e.length;
2725
2775
  if (s === 0) return;
2726
- const t = 60, i = 5;
2727
- let o = 0;
2776
+ const t = 60, o = 5;
2777
+ let i = 0;
2728
2778
  for (let r = 0; r < s; r++)
2729
2779
  for (let c = r + 1; c < s; c++) {
2730
- const d = e[r], p = e[c];
2731
- let x = p.x - d.x, f = p.y - d.y, u = Math.sqrt(x * x + f * f);
2780
+ const h = e[r], p = e[c];
2781
+ let x = p.x - h.x, m = p.y - h.y, u = Math.sqrt(x * x + m * m);
2732
2782
  if (u < t * 3) {
2733
2783
  u < 1 && (u = 1);
2734
- const y = this.options.repulsionStrength / (u * u), b = x / u * y, M = f / u * y;
2735
- d.vx -= b, d.vy -= M, p.vx += b, p.vy += M;
2784
+ const f = this.options.repulsionStrength / (u * u), b = x / u * f, M = m / u * f;
2785
+ h.vx -= b, h.vy -= M, p.vx += b, p.vy += M;
2736
2786
  }
2737
2787
  }
2738
2788
  const a = 80;
2739
2789
  for (const r of this.edges) {
2740
- const c = this.nodes.get(r.source), d = this.nodes.get(r.target);
2741
- if (!c || !d) continue;
2742
- let p = d.x - c.x, x = d.y - c.y, f = Math.sqrt(p * p + x * x);
2743
- f < 1 && (f = 1);
2744
- const y = (f - a) * this.options.attractionStrength, b = p / f * y, M = x / f * y;
2745
- c.vx += b, c.vy += M, d.vx -= b, d.vy -= M;
2790
+ const c = this.nodes.get(r.source), h = this.nodes.get(r.target);
2791
+ if (!c || !h) continue;
2792
+ let p = h.x - c.x, x = h.y - c.y, m = Math.sqrt(p * p + x * x);
2793
+ m < 1 && (m = 1);
2794
+ const f = (m - a) * this.options.attractionStrength, b = p / m * f, M = x / m * f;
2795
+ c.vx += b, c.vy += M, h.vx -= b, h.vy -= M;
2746
2796
  }
2747
2797
  for (const r of e) {
2748
2798
  if (this.draggedNode === r) continue;
2749
2799
  r.vx *= this.options.damping, r.vy *= this.options.damping;
2750
2800
  const c = Math.sqrt(r.vx * r.vx + r.vy * r.vy);
2751
- c > i && (r.vx = r.vx / c * i, r.vy = r.vy / c * i), r.x += r.vx, r.y += r.vy, o += r.vx * r.vx + r.vy * r.vy;
2801
+ c > o && (r.vx = r.vx / c * o, r.vy = r.vy / c * o), r.x += r.vx, r.y += r.vy, i += r.vx * r.vx + r.vy * r.vy;
2752
2802
  }
2753
- o < 0.01 && !this.draggedNode && (this.isSimulating = !1);
2803
+ i < 0.01 && !this.draggedNode && (this.isSimulating = !1);
2754
2804
  }
2755
2805
  render() {
2756
2806
  const e = this.ctx, s = this.canvas.width / (window.devicePixelRatio || 1), t = this.canvas.height / (window.devicePixelRatio || 1);
2757
2807
  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();
2758
2808
  }
2759
2809
  renderGrid(e, s) {
2760
- const t = this.ctx, i = 40 * this.transform.scale, o = 1.5, a = this.transform.x % i, r = this.transform.y % i;
2810
+ const t = this.ctx, o = 40 * this.transform.scale, i = 1.5, a = this.transform.x % o, r = this.transform.y % o;
2761
2811
  t.fillStyle = this.options.gridColor;
2762
- for (let c = a; c < e; c += i)
2763
- for (let d = r; d < s; d += i)
2764
- t.beginPath(), t.arc(c, d, o, 0, Math.PI * 2), t.fill();
2812
+ for (let c = a; c < e; c += o)
2813
+ for (let h = r; h < s; h += o)
2814
+ t.beginPath(), t.arc(c, h, i, 0, Math.PI * 2), t.fill();
2765
2815
  }
2766
2816
  renderEdges() {
2767
2817
  const e = this.ctx;
2768
2818
  for (const s of this.edges) {
2769
- const t = this.nodes.get(s.source), i = this.nodes.get(s.target);
2770
- if (!t || !i) continue;
2771
- const o = s === this.hoveredEdge, a = e.createLinearGradient(t.x, t.y, i.x, i.y);
2772
- o ? (a.addColorStop(0, "rgba(255, 153, 102, 0.8)"), a.addColorStop(0.5, "rgba(255, 255, 255, 0.5)"), a.addColorStop(1, "rgba(102, 153, 255, 0.8)"), e.lineWidth = 3) : (a.addColorStop(0, "rgba(255, 153, 102, 0.3)"), a.addColorStop(0.5, "rgba(255, 255, 255, 0.15)"), a.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 = a, e.stroke();
2819
+ const t = this.nodes.get(s.source), o = this.nodes.get(s.target);
2820
+ if (!t || !o) continue;
2821
+ const i = s === this.hoveredEdge, a = e.createLinearGradient(t.x, t.y, o.x, o.y);
2822
+ i ? (a.addColorStop(0, "rgba(255, 153, 102, 0.8)"), a.addColorStop(0.5, "rgba(255, 255, 255, 0.5)"), a.addColorStop(1, "rgba(102, 153, 255, 0.8)"), e.lineWidth = 3) : (a.addColorStop(0, "rgba(255, 153, 102, 0.3)"), a.addColorStop(0.5, "rgba(255, 255, 255, 0.15)"), a.addColorStop(1, "rgba(102, 153, 255, 0.3)"), e.lineWidth = 1.5), e.beginPath(), e.moveTo(t.x, t.y), e.lineTo(o.x, o.y), e.strokeStyle = a, e.stroke();
2773
2823
  }
2774
2824
  }
2775
2825
  renderNodes() {
2776
2826
  const e = this.ctx;
2777
2827
  for (const s of this.nodes.values()) {
2778
- const t = s === this.hoveredNode, i = s === this.selectedNode, o = this.hoveredEdge && (s.data.id === this.hoveredEdge.source || s.data.id === this.hoveredEdge.target), a = s.radius * (t ? 1.1 : 1);
2779
- if (t || i || o) {
2780
- const y = e.createRadialGradient(
2828
+ const t = s === this.hoveredNode, o = s === this.selectedNode, i = this.hoveredEdge && (s.data.id === this.hoveredEdge.source || s.data.id === this.hoveredEdge.target), a = s.radius * (t ? 1.1 : 1);
2829
+ if (t || o || i) {
2830
+ const f = e.createRadialGradient(
2781
2831
  s.x,
2782
2832
  s.y,
2783
2833
  a * 0.5,
2784
2834
  s.x,
2785
2835
  s.y,
2786
2836
  a * 2
2787
- ), b = t || i ? 0.4 : 0.25;
2788
- 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, a * 2, 0, Math.PI * 2), e.fill();
2837
+ ), b = t || o ? 0.4 : 0.25;
2838
+ f.addColorStop(0, `rgba(255, 153, 102, ${b})`), f.addColorStop(1, "rgba(255, 153, 102, 0)"), e.fillStyle = f, e.beginPath(), e.arc(s.x, s.y, a * 2, 0, Math.PI * 2), e.fill();
2789
2839
  }
2790
2840
  const r = e.createRadialGradient(
2791
2841
  s.x - a * 0.3,
@@ -2794,16 +2844,16 @@ class Lt {
2794
2844
  s.x,
2795
2845
  s.y,
2796
2846
  a
2797
- ), c = s.color >> 16 & 255, d = s.color >> 8 & 255, p = s.color & 255;
2798
- r.addColorStop(0, `rgba(${Math.min(255, c + 60)}, ${Math.min(255, d + 60)}, ${Math.min(255, p + 60)}, 0.95)`), r.addColorStop(0.7, `rgba(${c}, ${d}, ${p}, 0.9)`), r.addColorStop(1, `rgba(${Math.max(0, c - 40)}, ${Math.max(0, d - 40)}, ${Math.max(0, p - 40)}, 0.85)`), e.beginPath(), e.arc(s.x, s.y, a, 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 - a * 0.25, s.y - a * 0.25, a * 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";
2847
+ ), c = s.color >> 16 & 255, h = s.color >> 8 & 255, p = s.color & 255;
2848
+ r.addColorStop(0, `rgba(${Math.min(255, c + 60)}, ${Math.min(255, h + 60)}, ${Math.min(255, p + 60)}, 0.95)`), r.addColorStop(0.7, `rgba(${c}, ${h}, ${p}, 0.9)`), r.addColorStop(1, `rgba(${Math.max(0, c - 40)}, ${Math.max(0, h - 40)}, ${Math.max(0, p - 40)}, 0.85)`), e.beginPath(), e.arc(s.x, s.y, a, 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 - a * 0.25, s.y - a * 0.25, a * 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";
2799
2849
  const x = a * 1.6;
2800
- let f = s.label, u = e.measureText(f).width;
2850
+ let m = s.label, u = e.measureText(m).width;
2801
2851
  if (u > x) {
2802
- for (; u > x && f.length > 3; )
2803
- f = f.slice(0, -1), u = e.measureText(f + "...").width;
2804
- f += "...";
2852
+ for (; u > x && m.length > 3; )
2853
+ m = m.slice(0, -1), u = e.measureText(m + "...").width;
2854
+ m += "...";
2805
2855
  }
2806
- e.shadowColor = "rgba(0, 0, 0, 0.5)", e.shadowBlur = 3, e.fillText(f, s.x, s.y), e.shadowBlur = 0;
2856
+ e.shadowColor = "rgba(0, 0, 0, 0.5)", e.shadowBlur = 3, e.fillText(m, s.x, s.y), e.shadowBlur = 0;
2807
2857
  }
2808
2858
  }
2809
2859
  /**
@@ -2811,14 +2861,14 @@ class Lt {
2811
2861
  */
2812
2862
  setData(e) {
2813
2863
  this.nodes.clear(), this.edges = [], this.nodeIdToIndex.clear(), e.nodes.forEach((s, t) => {
2814
- const i = s.position || {
2864
+ const o = s.position || {
2815
2865
  x: (Math.random() - 0.5) * 300,
2816
2866
  y: (Math.random() - 0.5) * 300
2817
- }, o = {
2867
+ }, i = {
2818
2868
  id: s.id,
2819
2869
  label: s.label,
2820
- x: i.x,
2821
- y: i.y,
2870
+ x: o.x,
2871
+ y: o.y,
2822
2872
  vx: 0,
2823
2873
  vy: 0,
2824
2874
  color: s.color || 16750950,
@@ -2826,7 +2876,7 @@ class Lt {
2826
2876
  radius: this.options.nodeRadius,
2827
2877
  data: s
2828
2878
  };
2829
- this.nodes.set(s.id, o), this.nodeIdToIndex.set(s.id, t);
2879
+ this.nodes.set(s.id, i), this.nodeIdToIndex.set(s.id, t);
2830
2880
  }), this.edges = e.edges.map((s) => ({
2831
2881
  source: s.source,
2832
2882
  target: s.target,
@@ -2902,19 +2952,19 @@ class Lt {
2902
2952
  focusOnNode(e) {
2903
2953
  const s = this.nodes.get(e);
2904
2954
  if (!s) return;
2905
- 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, a = this.transform.y, r = 500, c = performance.now(), d = () => {
2906
- const p = performance.now() - c, x = Math.min(p / r, 1), f = 1 - Math.pow(1 - x, 3);
2907
- this.transform.x = o + (t - o) * f, this.transform.y = a + (i - a) * f, x < 1 ? requestAnimationFrame(d) : this.selectedNode = s;
2955
+ const t = this.canvas.width / 2 / (window.devicePixelRatio || 1) - s.x * this.transform.scale, o = this.canvas.height / 2 / (window.devicePixelRatio || 1) - s.y * this.transform.scale, i = this.transform.x, a = this.transform.y, r = 500, c = performance.now(), h = () => {
2956
+ const p = performance.now() - c, x = Math.min(p / r, 1), m = 1 - Math.pow(1 - x, 3);
2957
+ this.transform.x = i + (t - i) * m, this.transform.y = a + (o - a) * m, x < 1 ? requestAnimationFrame(h) : this.selectedNode = s;
2908
2958
  };
2909
- d();
2959
+ h();
2910
2960
  }
2911
2961
  /**
2912
2962
  * Updates node positions from 3D data
2913
2963
  */
2914
2964
  syncFrom3D(e) {
2915
2965
  e.forEach((s, t) => {
2916
- const i = this.nodes.get(t);
2917
- i && (i.x = s.position.x * 3, i.y = s.position.y * 3, i.vx = 0, i.vy = 0);
2966
+ const o = this.nodes.get(t);
2967
+ o && (o.x = s.position.x * 3, o.y = s.position.y * 3, o.vx = 0, o.vy = 0);
2918
2968
  }), this.isSimulating = !1;
2919
2969
  }
2920
2970
  /**
@@ -2948,7 +2998,7 @@ class Lt {
2948
2998
  this.animationId && cancelAnimationFrame(this.animationId), window.removeEventListener("resize", this.resizeHandler), this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);
2949
2999
  }
2950
3000
  }
2951
- class Ft {
3001
+ class Ht {
2952
3002
  // Store graph data for view switching
2953
3003
  constructor(e, s = {}) {
2954
3004
  // Options
@@ -2983,23 +3033,23 @@ class Ft {
2983
3033
  l(this, "devControls", null);
2984
3034
  l(this, "viewMode", "3d");
2985
3035
  l(this, "graphData", null);
2986
- this.options = { ...T, ...s }, this.container = ct(e), this.materialFactory = new bt(), this.nodeFactory = new vt(
3036
+ this.options = { ...P, ...s }, this.container = dt(e), this.materialFactory = new vt(), this.nodeFactory = new Mt(
2987
3037
  this.materialFactory,
2988
- this.options.nodeRadius ?? T.nodeRadius,
2989
- this.options.lodSegments ?? T.lodSegments,
2990
- this.options.defaultNodeColor ?? T.defaultNodeColor
2991
- ), this.edgeFactory = new Mt(
3038
+ this.options.nodeRadius ?? P.nodeRadius,
3039
+ this.options.lodSegments ?? P.lodSegments,
3040
+ this.options.defaultNodeColor ?? P.defaultNodeColor
3041
+ ), this.edgeFactory = new wt(
2992
3042
  this.materialFactory,
2993
- this.options.edgeColor ?? T.edgeColor,
2994
- this.options.edgeOpacity ?? T.edgeOpacity
2995
- ), this.sceneManager = new ut(this.container, this.options), this.lodManager = new wt(
3043
+ this.options.edgeColor ?? P.edgeColor,
3044
+ this.options.edgeOpacity ?? P.edgeOpacity
3045
+ ), this.sceneManager = new mt(this.container, this.options), this.lodManager = new Et(
2996
3046
  this.sceneManager.camera,
2997
- this.options.lodDistances ?? T.lodDistances,
2998
- this.options.enableLOD ?? T.enableLOD
2999
- ), this.frustumCuller = new Et(
3047
+ this.options.lodDistances ?? P.lodDistances,
3048
+ this.options.enableLOD ?? P.enableLOD
3049
+ ), this.frustumCuller = new Ct(
3000
3050
  this.sceneManager.camera,
3001
- this.options.enableEdgeCulling ?? T.enableEdgeCulling
3002
- ), this.nodeManager = new ft(this.sceneManager, this.nodeFactory), this.edgeManager = new mt(this.sceneManager, this.nodeManager, this.edgeFactory), this.graphEngine = new Le(
3051
+ this.options.enableEdgeCulling ?? P.enableEdgeCulling
3052
+ ), this.nodeManager = new te(this.sceneManager, this.nodeFactory), this.edgeManager = new yt(this.sceneManager, this.nodeManager, this.edgeFactory), this.graphEngine = new Le(
3003
3053
  this.nodeManager.getAllNodes(),
3004
3054
  this.edgeManager.getAllEdges(),
3005
3055
  {
@@ -3009,12 +3059,12 @@ class Ft {
3009
3059
  useBarnesHut: this.options.useBarnesHut,
3010
3060
  barnesHutTheta: this.options.barnesHutTheta
3011
3061
  }
3012
- ), this.rendererManager = new xt(
3062
+ ), this.rendererManager = new bt(
3013
3063
  this.sceneManager,
3014
3064
  () => this.onSimulate(),
3015
3065
  () => this.onRender(),
3016
- this.options.targetFPS ?? T.targetFPS
3017
- ), 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) => {
3066
+ this.options.targetFPS ?? P.targetFPS
3067
+ ), this.raycasterManager = new Nt(this.sceneManager, this.container), this.panelManager = new St(this.container), this.edgePanelManager = new zt(this.container), this.edgeTooltipManager = new Tt(), this.edgePanelManager.setNodeClickCallback((t) => {
3018
3068
  this.edgePanelManager.hide(), this.focusOnNode(t), setTimeout(() => {
3019
3069
  this.showNodePanel(t);
3020
3070
  }, 400);
@@ -3056,8 +3106,8 @@ class Ft {
3056
3106
  onEdgeHover(e) {
3057
3107
  if (e) {
3058
3108
  this.edgeManager.highlightEdge(e.edge.source, e.edge.target);
3059
- const s = this.container.getBoundingClientRect(), t = s.left + s.width / 2, i = s.top + s.height / 2;
3060
- this.edgeTooltipManager.show(e.edge, e.sourceNode, e.targetNode, t, i), this.options.onEdgeHover && this.options.onEdgeHover(e.edge, e.sourceNode, e.targetNode), this.emit("edgeHover", e.edge, e.sourceNode, e.targetNode);
3109
+ const s = this.container.getBoundingClientRect(), t = s.left + s.width / 2, o = s.top + s.height / 2;
3110
+ this.edgeTooltipManager.show(e.edge, e.sourceNode, e.targetNode, t, o), this.options.onEdgeHover && this.options.onEdgeHover(e.edge, e.sourceNode, e.targetNode), this.emit("edgeHover", e.edge, e.sourceNode, e.targetNode);
3061
3111
  } else
3062
3112
  this.edgeManager.unhighlightCurrentEdge(), this.edgeTooltipManager.hide(), this.options.onEdgeHover && this.options.onEdgeHover(null, null, null), this.emit("edgeHover", null, null, null);
3063
3113
  }
@@ -3066,7 +3116,7 @@ class Ft {
3066
3116
  */
3067
3117
  onNodeClick(e) {
3068
3118
  this.edgePanelManager.hide();
3069
- const t = this.edgeManager.getNeighborIds(e.id).map((i) => this.nodeManager.getNode(i)).filter((i) => i !== void 0);
3119
+ const t = this.edgeManager.getNeighborIds(e.id).map((o) => this.nodeManager.getNode(o)).filter((o) => o !== void 0);
3070
3120
  this.options.showPanel !== !1 && this.panelManager.show(e, t), this.options.onNodeClick && this.options.onNodeClick(e), this.emit("nodeClick", e);
3071
3121
  }
3072
3122
  /**
@@ -3100,12 +3150,22 @@ class Ft {
3100
3150
  * Sets the graph data
3101
3151
  */
3102
3152
  setData(e) {
3103
- if (this.graphData = e, this.edgeManager.clear(), this.nodeManager.clear(), e.nodes && Array.isArray(e.nodes))
3104
- for (const s of e.nodes)
3105
- this.addNode(s);
3106
- if (e.edges && Array.isArray(e.edges))
3107
- for (const s of e.edges)
3108
- this.addEdge(s);
3153
+ var a;
3154
+ const s = (a = e.data) != null && a.nodes ? e.data : e, o = (s.edges || s.links || []).map((r) => ({
3155
+ ...r,
3156
+ relationship: r.relationship || r.label || "related_to"
3157
+ })), i = {
3158
+ nodes: s.nodes || [],
3159
+ edges: o
3160
+ };
3161
+ if (this.graphData = i, this.edgeManager.clear(), this.nodeManager.clear(), i.nodes && Array.isArray(i.nodes)) {
3162
+ te.setExpectedNodeCount(i.nodes.length);
3163
+ for (const r of i.nodes)
3164
+ this.addNode(r);
3165
+ }
3166
+ if (i.edges && Array.isArray(i.edges))
3167
+ for (const r of i.edges)
3168
+ this.addEdge(r);
3109
3169
  this.graphEngine = new Le(
3110
3170
  this.nodeManager.getAllNodes(),
3111
3171
  this.edgeManager.getAllEdges(),
@@ -3116,14 +3176,14 @@ class Ft {
3116
3176
  useBarnesHut: this.options.useBarnesHut,
3117
3177
  barnesHutTheta: this.options.barnesHutTheta
3118
3178
  }
3119
- ), this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.setData(e);
3179
+ ), this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.setData(i);
3120
3180
  }
3121
3181
  /**
3122
3182
  * Adds a node to the graph
3123
3183
  * @returns true if added, false if node already exists or invalid
3124
3184
  */
3125
3185
  addNode(e) {
3126
- if (!Oe(e))
3186
+ if (!He(e))
3127
3187
  return !1;
3128
3188
  const s = this.nodeManager.addNode(e);
3129
3189
  return s && (this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.addNode(e), this.options.onNodeAdd && this.options.onNodeAdd(e), this.emit("nodeAdd", e)), s;
@@ -3133,7 +3193,7 @@ class Ft {
3133
3193
  * @returns true if removed, false if not found
3134
3194
  */
3135
3195
  removeNode(e) {
3136
- if (!ht(e))
3196
+ if (!pt(e))
3137
3197
  return !1;
3138
3198
  this.edgeManager.removeEdgesForNode(e);
3139
3199
  const s = this.nodeManager.removeNode(e);
@@ -3150,7 +3210,7 @@ class Ft {
3150
3210
  * @returns true if added, false if edge already exists or nodes don't exist
3151
3211
  */
3152
3212
  addEdge(e) {
3153
- if (!Fe(e))
3213
+ if (!De(e))
3154
3214
  return !1;
3155
3215
  const s = this.edgeManager.addEdge(e);
3156
3216
  return s && (this.graphEngine.setEdges(this.edgeManager.getAllEdges()), this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.addEdge(e), this.options.onEdgeAdd && this.options.onEdgeAdd(e), this.emit("edgeAdd", e)), s;
@@ -3170,20 +3230,20 @@ class Ft {
3170
3230
  * @param fetchFn - Optional fetch function to override the default
3171
3231
  */
3172
3232
  async expandNode(e, s = 1, t) {
3173
- const i = t ?? this.options.onExpand;
3174
- if (!i)
3233
+ const o = t ?? this.options.onExpand;
3234
+ if (!o)
3175
3235
  return console.warn("[ForceGraph3D] No expand callback provided"), !1;
3176
3236
  try {
3177
- const o = await i(e, s);
3178
- if (o.nodes && Array.isArray(o.nodes))
3179
- for (const a of o.nodes)
3237
+ const i = await o(e, s);
3238
+ if (i.nodes && Array.isArray(i.nodes))
3239
+ for (const a of i.nodes)
3180
3240
  this.addNode(a);
3181
- if (o.edges && Array.isArray(o.edges))
3182
- for (const a of o.edges)
3241
+ if (i.edges && Array.isArray(i.edges))
3242
+ for (const a of i.edges)
3183
3243
  this.addEdge(a);
3184
- return this.panelManager.hide(), this.emit("expand", e, o), !0;
3185
- } catch (o) {
3186
- return console.error("[ForceGraph3D] Error expanding node:", o), !1;
3244
+ return this.panelManager.hide(), this.emit("expand", e, i), !0;
3245
+ } catch (i) {
3246
+ return console.error("[ForceGraph3D] Error expanding node:", i), !1;
3187
3247
  }
3188
3248
  }
3189
3249
  /**
@@ -3230,13 +3290,13 @@ class Ft {
3230
3290
  console.warn(`[ForceGraph3D] Node "${e}" not found`);
3231
3291
  return;
3232
3292
  }
3233
- const i = t.position, o = this.sceneManager.camera, a = this.sceneManager.controls, r = o.position.clone().sub(a.target).normalize(), c = {
3234
- x: i.x + r.x * s,
3235
- y: i.y + r.y * s,
3236
- z: i.z + r.z * s
3237
- }, d = { x: o.position.x, y: o.position.y, z: o.position.z }, p = { x: a.target.x, y: a.target.y, z: a.target.z }, x = 800, f = performance.now(), u = () => {
3238
- const y = performance.now() - f, b = Math.min(y / x, 1), M = 1 - Math.pow(1 - b, 3);
3239
- o.position.x = d.x + (c.x - d.x) * M, o.position.y = d.y + (c.y - d.y) * M, o.position.z = d.z + (c.z - d.z) * M, a.target.x = p.x + (i.x - p.x) * M, a.target.y = p.y + (i.y - p.y) * M, a.target.z = p.z + (i.z - p.z) * M, a.update(), b < 1 && requestAnimationFrame(u);
3293
+ const o = t.position, i = this.sceneManager.camera, a = this.sceneManager.controls, r = i.position.clone().sub(a.target).normalize(), c = {
3294
+ x: o.x + r.x * s,
3295
+ y: o.y + r.y * s,
3296
+ z: o.z + r.z * s
3297
+ }, h = { x: i.position.x, y: i.position.y, z: i.position.z }, p = { x: a.target.x, y: a.target.y, z: a.target.z }, x = 800, m = performance.now(), u = () => {
3298
+ const f = performance.now() - m, b = Math.min(f / x, 1), M = 1 - Math.pow(1 - b, 3);
3299
+ i.position.x = h.x + (c.x - h.x) * M, i.position.y = h.y + (c.y - h.y) * M, i.position.z = h.z + (c.z - h.z) * M, a.target.x = p.x + (o.x - p.x) * M, a.target.y = p.y + (o.y - p.y) * M, a.target.z = p.z + (o.z - p.z) * M, a.update(), b < 1 && requestAnimationFrame(u);
3240
3300
  };
3241
3301
  u();
3242
3302
  }
@@ -3245,21 +3305,21 @@ class Ft {
3245
3305
  * Camera targets the midpoint and zooms out enough to see both nodes
3246
3306
  */
3247
3307
  focusOnEdge(e, s, t = 1.5) {
3248
- const i = this.nodeManager.getNode(e), o = this.nodeManager.getNode(s);
3249
- if (!i || !o) {
3308
+ const o = this.nodeManager.getNode(e), i = this.nodeManager.getNode(s);
3309
+ if (!o || !i) {
3250
3310
  console.warn(`[ForceGraph3D] Could not find nodes for edge "${e}" -> "${s}"`);
3251
3311
  return;
3252
3312
  }
3253
3313
  const a = this.sceneManager.camera, r = this.sceneManager.controls, c = {
3254
- x: (i.position.x + o.position.x) / 2,
3255
- y: (i.position.y + o.position.y) / 2,
3256
- z: (i.position.z + o.position.z) / 2
3257
- }, d = o.position.x - i.position.x, p = o.position.y - i.position.y, x = o.position.z - i.position.z, f = Math.sqrt(d * d + p * p + x * x), u = Math.max(f * t, 40), y = a.position.clone().sub(r.target).normalize(), b = {
3258
- x: c.x + y.x * u,
3259
- y: c.y + y.y * u,
3260
- z: c.z + y.z * u
3261
- }, M = { x: a.position.x, y: a.position.y, z: a.position.z }, N = { x: r.target.x, y: r.target.y, z: r.target.z }, O = 800, L = performance.now(), Y = () => {
3262
- const P = performance.now() - L, H = Math.min(P / O, 1), E = 1 - Math.pow(1 - H, 3);
3314
+ x: (o.position.x + i.position.x) / 2,
3315
+ y: (o.position.y + i.position.y) / 2,
3316
+ z: (o.position.z + i.position.z) / 2
3317
+ }, h = i.position.x - o.position.x, p = i.position.y - o.position.y, x = i.position.z - o.position.z, m = Math.sqrt(h * h + p * p + x * x), u = Math.max(m * t, 40), f = a.position.clone().sub(r.target).normalize(), b = {
3318
+ x: c.x + f.x * u,
3319
+ y: c.y + f.y * u,
3320
+ z: c.z + f.z * u
3321
+ }, M = { x: a.position.x, y: a.position.y, z: a.position.z }, N = { x: r.target.x, y: r.target.y, z: r.target.z }, O = 800, R = performance.now(), Y = () => {
3322
+ const k = performance.now() - R, H = Math.min(k / O, 1), E = 1 - Math.pow(1 - H, 3);
3263
3323
  a.position.x = M.x + (b.x - M.x) * E, a.position.y = M.y + (b.y - M.y) * E, a.position.z = M.z + (b.z - M.z) * E, r.target.x = N.x + (c.x - N.x) * E, r.target.y = N.y + (c.y - N.y) * E, r.target.z = N.z + (c.z - N.z) * E, r.update(), H < 1 && requestAnimationFrame(Y);
3264
3324
  };
3265
3325
  Y();
@@ -3283,28 +3343,28 @@ class Ft {
3283
3343
  searchNodes(e) {
3284
3344
  if (!e || e.trim() === "")
3285
3345
  return [];
3286
- const s = e.toLowerCase().trim(), t = this.nodeManager.getAllNodes(), i = [];
3287
- return t.forEach((o) => {
3288
- var d, p, x;
3289
- const a = (d = o.label) == null ? void 0 : d.toLowerCase().includes(s), r = (p = o.id) == null ? void 0 : p.toLowerCase().includes(s), c = (x = o.type) == null ? void 0 : x.toLowerCase().includes(s);
3290
- (a || r || c) && i.push(o);
3291
- }), i;
3346
+ const s = e.toLowerCase().trim(), t = this.nodeManager.getAllNodes(), o = [];
3347
+ return t.forEach((i) => {
3348
+ var h, p, x;
3349
+ const a = (h = i.label) == null ? void 0 : h.toLowerCase().includes(s), r = (p = i.id) == null ? void 0 : p.toLowerCase().includes(s), c = (x = i.type) == null ? void 0 : x.toLowerCase().includes(s);
3350
+ (a || r || c) && o.push(i);
3351
+ }), o;
3292
3352
  }
3293
3353
  /**
3294
3354
  * Searches edges by relationship (case-insensitive)
3295
3355
  * @returns Array of matching edges with source/target node info
3296
3356
  */
3297
3357
  searchEdges(e) {
3298
- var o;
3358
+ var i;
3299
3359
  if (!e || e.trim() === "")
3300
3360
  return [];
3301
- const s = e.toLowerCase().trim(), t = this.edgeManager.getAllEdges(), i = [];
3361
+ const s = e.toLowerCase().trim(), t = this.edgeManager.getAllEdges(), o = [];
3302
3362
  for (const a of t)
3303
- if ((o = a.relationship) == null ? void 0 : o.toLowerCase().includes(s)) {
3304
- const c = this.nodeManager.getNode(a.source), d = this.nodeManager.getNode(a.target);
3305
- c && d && i.push({ edge: a, sourceNode: c, targetNode: d });
3363
+ if ((i = a.relationship) == null ? void 0 : i.toLowerCase().includes(s)) {
3364
+ const c = this.nodeManager.getNode(a.source), h = this.nodeManager.getNode(a.target);
3365
+ c && h && o.push({ edge: a, sourceNode: c, targetNode: h });
3306
3366
  }
3307
- return i;
3367
+ return o;
3308
3368
  }
3309
3369
  /**
3310
3370
  * Gets all nodes as an array
@@ -3335,7 +3395,7 @@ class Ft {
3335
3395
  * Switches between 2D and 3D view modes
3336
3396
  */
3337
3397
  switchView(e) {
3338
- 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, {
3398
+ 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, {
3339
3399
  backgroundColor: "#0a0a0a",
3340
3400
  nodeRadius: 24,
3341
3401
  onNodeClick: (s) => {
@@ -3346,11 +3406,11 @@ class Ft {
3346
3406
  },
3347
3407
  onEdgeHover: (s, t) => {
3348
3408
  if (s && t) {
3349
- const i = this.nodeManager.getNode(s.source), o = this.nodeManager.getNode(s.target);
3350
- i && o && this.edgeTooltipManager.show(
3409
+ const o = this.nodeManager.getNode(s.source), i = this.nodeManager.getNode(s.target);
3410
+ o && i && this.edgeTooltipManager.show(
3351
3411
  s,
3352
- i,
3353
3412
  o,
3413
+ i,
3354
3414
  t.clientX,
3355
3415
  t.clientY
3356
3416
  );
@@ -3358,8 +3418,8 @@ class Ft {
3358
3418
  this.edgeTooltipManager.hide();
3359
3419
  },
3360
3420
  onEdgeClick: (s) => {
3361
- const t = this.nodeManager.getNode(s.source), i = this.nodeManager.getNode(s.target);
3362
- t && i && this.edgePanelManager.show(s, t, i);
3421
+ const t = this.nodeManager.getNode(s.source), o = this.nodeManager.getNode(s.target);
3422
+ t && o && this.edgePanelManager.show(s, t, o);
3363
3423
  }
3364
3424
  }), this.graphData && (this.forceGraph2D.setData(this.graphData), this.forceGraph2D.syncFrom3D(this.nodeManager.getAllNodes())))) : (this.forceGraph2D && this.forceGraph2D.hide(), this.sceneManager.renderer.domElement.style.display = "block", this.rendererManager.start()), this.emit("viewChange", e));
3365
3425
  }
@@ -3374,7 +3434,7 @@ class Ft {
3374
3434
  */
3375
3435
  emit(e, ...s) {
3376
3436
  const t = this.eventCallbacks.get(e);
3377
- t && t.forEach((i) => i(...s));
3437
+ t && t.forEach((o) => o(...s));
3378
3438
  }
3379
3439
  /**
3380
3440
  * Sets physics parameters for both 3D and 2D views
@@ -3451,17 +3511,17 @@ class Ft {
3451
3511
  `, this.container.appendChild(this.devControls);
3452
3512
  const e = this.devControls.querySelector("#dev-repulsion"), s = this.devControls.querySelector("#dev-attraction"), t = this.devControls.querySelector("#dev-damping");
3453
3513
  e == null || e.addEventListener("input", () => {
3454
- const i = parseFloat(e.value);
3455
- this.setPhysicsParams({ repulsionStrength: i }), this.devControls.querySelector("#dev-repulsion-val").textContent = i.toString();
3514
+ const o = parseFloat(e.value);
3515
+ this.setPhysicsParams({ repulsionStrength: o }), this.devControls.querySelector("#dev-repulsion-val").textContent = o.toString();
3456
3516
  }), s == null || s.addEventListener("input", () => {
3457
- const i = parseFloat(s.value) / 1e3;
3458
- this.setPhysicsParams({ attractionStrength: i }), this.devControls.querySelector("#dev-attraction-val").textContent = i.toFixed(3);
3517
+ const o = parseFloat(s.value) / 1e3;
3518
+ this.setPhysicsParams({ attractionStrength: o }), this.devControls.querySelector("#dev-attraction-val").textContent = o.toFixed(3);
3459
3519
  }), t == null || t.addEventListener("input", () => {
3460
- const i = parseFloat(t.value) / 100;
3461
- this.setPhysicsParams({ damping: i }), this.devControls.querySelector("#dev-damping-val").textContent = i.toFixed(2);
3520
+ const o = parseFloat(t.value) / 100;
3521
+ this.setPhysicsParams({ damping: o }), this.devControls.querySelector("#dev-damping-val").textContent = o.toFixed(2);
3462
3522
  }), setInterval(() => {
3463
- const i = this.devControls.querySelector("#dev-node-count"), o = this.devControls.querySelector("#dev-edge-count"), a = this.devControls.querySelector("#dev-fps");
3464
- i && (i.textContent = this.getNodeCount().toString()), o && (o.textContent = this.getEdgeCount().toString()), a && (a.textContent = this.rendererManager.getFPS().toString());
3523
+ const o = this.devControls.querySelector("#dev-node-count"), i = this.devControls.querySelector("#dev-edge-count"), a = this.devControls.querySelector("#dev-fps");
3524
+ o && (o.textContent = this.getNodeCount().toString()), i && (i.textContent = this.getEdgeCount().toString()), a && (a.textContent = this.rendererManager.getFPS().toString());
3465
3525
  }, 500);
3466
3526
  }
3467
3527
  /**
@@ -3471,7 +3531,7 @@ class Ft {
3471
3531
  this.rendererManager.dispose(), this.panelManager.dispose(), this.raycasterManager.dispose(), this.edgeTooltipManager.dispose(), this.searchManager && this.searchManager.dispose(), this.viewToggleManager && this.viewToggleManager.dispose(), this.forceGraph2D && this.forceGraph2D.dispose(), this.edgeManager.dispose(), this.nodeManager.dispose(), this.nodeFactory.dispose(), this.materialFactory.dispose(), this.sceneManager.dispose(), this.devControls && this.devControls.parentNode && this.devControls.parentNode.removeChild(this.devControls), this.eventCallbacks.clear(), this.initialized = !1;
3472
3532
  }
3473
3533
  }
3474
- const Ie = [
3534
+ const Oe = [
3475
3535
  "Alpha",
3476
3536
  "Beta",
3477
3537
  "Gamma",
@@ -3502,7 +3562,7 @@ const Ie = [
3502
3562
  "Link",
3503
3563
  "Point",
3504
3564
  "Vertex"
3505
- ], J = [
3565
+ ], ee = [
3506
3566
  "connects to",
3507
3567
  "links with",
3508
3568
  "relates to",
@@ -3513,7 +3573,7 @@ const Ie = [
3513
3573
  "partners with",
3514
3574
  "collaborates with",
3515
3575
  "supports"
3516
- ], Re = [
3576
+ ], Fe = [
3517
3577
  16777215,
3518
3578
  // White
3519
3579
  16750950,
@@ -3525,14 +3585,14 @@ const Ie = [
3525
3585
  16746564
3526
3586
  // Darker tangerine
3527
3587
  ];
3528
- function Ht(h = 30) {
3588
+ function Dt(d = 30) {
3529
3589
  const e = [], s = [];
3530
- for (let i = 0; i < h; i++) {
3531
- const o = i < Ie.length ? Ie[i] : `Node ${i + 1}`;
3590
+ for (let o = 0; o < d; o++) {
3591
+ const i = o < Oe.length ? Oe[o] : `Node ${o + 1}`;
3532
3592
  e.push({
3533
- id: `node-${i}`,
3534
- label: o,
3535
- color: Re[i % Re.length],
3593
+ id: `node-${o}`,
3594
+ label: i,
3595
+ color: Fe[o % Fe.length],
3536
3596
  position: {
3537
3597
  x: (Math.random() - 0.5) * 60,
3538
3598
  y: (Math.random() - 0.5) * 60,
@@ -3540,43 +3600,43 @@ function Ht(h = 30) {
3540
3600
  }
3541
3601
  });
3542
3602
  }
3543
- for (let i = 1; i < h; i++) {
3544
- const o = Math.floor(Math.random() * i);
3603
+ for (let o = 1; o < d; o++) {
3604
+ const i = Math.floor(Math.random() * o);
3545
3605
  s.push({
3546
- source: `node-${i}`,
3547
- target: `node-${o}`,
3548
- relationship: J[Math.floor(Math.random() * J.length)]
3606
+ source: `node-${o}`,
3607
+ target: `node-${i}`,
3608
+ relationship: ee[Math.floor(Math.random() * ee.length)]
3549
3609
  });
3550
3610
  }
3551
- const t = Math.floor(h * 0.5);
3552
- for (let i = 0; i < t; i++) {
3553
- const o = Math.floor(Math.random() * h);
3554
- let a = Math.floor(Math.random() * h);
3555
- o === a && (a = (a + 1) % h);
3556
- const r = `node-${o}`, c = `node-${a}`;
3611
+ const t = Math.floor(d * 0.5);
3612
+ for (let o = 0; o < t; o++) {
3613
+ const i = Math.floor(Math.random() * d);
3614
+ let a = Math.floor(Math.random() * d);
3615
+ i === a && (a = (a + 1) % d);
3616
+ const r = `node-${i}`, c = `node-${a}`;
3557
3617
  s.some(
3558
3618
  (p) => p.source === r && p.target === c || p.source === c && p.target === r
3559
3619
  ) || s.push({
3560
3620
  source: r,
3561
3621
  target: c,
3562
- relationship: J[Math.floor(Math.random() * J.length)]
3622
+ relationship: ee[Math.floor(Math.random() * ee.length)]
3563
3623
  });
3564
3624
  }
3565
3625
  return { nodes: e, edges: s };
3566
3626
  }
3567
- function Dt(h = 1e3) {
3568
- const e = [], s = [], t = Math.ceil(h / 50), i = [];
3569
- for (let o = 0; o < t; o++)
3570
- i.push({
3627
+ function At(d = 1e3) {
3628
+ const e = [], s = [], t = Math.ceil(d / 50), o = [];
3629
+ for (let i = 0; i < t; i++)
3630
+ o.push({
3571
3631
  x: (Math.random() - 0.5) * 200,
3572
3632
  y: (Math.random() - 0.5) * 200,
3573
3633
  z: (Math.random() - 0.5) * 200
3574
3634
  });
3575
- for (let o = 0; o < h; o++) {
3576
- const a = i[o % t];
3635
+ for (let i = 0; i < d; i++) {
3636
+ const a = o[i % t];
3577
3637
  e.push({
3578
- id: `node-${o}`,
3579
- label: `N${o}`,
3638
+ id: `node-${i}`,
3639
+ label: `N${i}`,
3580
3640
  position: {
3581
3641
  x: a.x + (Math.random() - 0.5) * 40,
3582
3642
  y: a.y + (Math.random() - 0.5) * 40,
@@ -3584,16 +3644,16 @@ function Dt(h = 1e3) {
3584
3644
  }
3585
3645
  });
3586
3646
  }
3587
- for (let o = 1; o < h; o++) {
3588
- const a = Math.floor(o / 50) * 50, r = a === 0 ? Math.floor(Math.random() * o) : a + Math.floor(Math.random() * Math.min(o - a, 50));
3647
+ for (let i = 1; i < d; i++) {
3648
+ const a = Math.floor(i / 50) * 50, r = a === 0 ? Math.floor(Math.random() * i) : a + Math.floor(Math.random() * Math.min(i - a, 50));
3589
3649
  s.push({
3590
- source: `node-${o}`,
3591
- target: `node-${Math.min(r, o - 1)}`,
3650
+ source: `node-${i}`,
3651
+ target: `node-${Math.min(r, i - 1)}`,
3592
3652
  relationship: "links to"
3593
3653
  });
3594
3654
  }
3595
- for (let o = 1; o < t; o++) {
3596
- const a = o * 50, r = (o - 1) * 50 + Math.floor(Math.random() * 50);
3655
+ for (let i = 1; i < t; i++) {
3656
+ const a = i * 50, r = (i - 1) * 50 + Math.floor(Math.random() * 50);
3597
3657
  s.push({
3598
3658
  source: `node-${a}`,
3599
3659
  target: `node-${r}`,
@@ -3603,13 +3663,13 @@ function Dt(h = 1e3) {
3603
3663
  return { nodes: e, edges: s };
3604
3664
  }
3605
3665
  export {
3606
- T as DEFAULT_OPTIONS,
3607
- Ft as ForceGraph3D,
3608
- U as LODLevel,
3666
+ P as DEFAULT_OPTIONS,
3667
+ Ht as ForceGraph3D,
3668
+ X as LODLevel,
3609
3669
  D as createEdgeKey,
3610
- Dt as generateLargeSampleData,
3611
- Ht as generateSampleData,
3612
- Fe as validateEdgeData,
3613
- Oe as validateNodeData
3670
+ At as generateLargeSampleData,
3671
+ Dt as generateSampleData,
3672
+ De as validateEdgeData,
3673
+ He as validateNodeData
3614
3674
  };
3615
3675
  //# sourceMappingURL=force-3d-graph.js.map