force-3d-graph 1.2.4 → 1.2.6

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,41 +86,41 @@ 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(), o = i.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 && o === i.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
125
  const t = this, i = {
126
126
  NONE: -1,
@@ -133,31 +133,31 @@ class gt extends ot {
133
133
  TOUCH_DOLLY_ROTATE: 6
134
134
  };
135
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();
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), o = i.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), o = i.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), o = i.PAN;
325
325
  } else {
326
326
  if (t.enableRotate === !1) return;
327
- de(n), o = i.ROTATE;
327
+ ge(n), o = i.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), o = i.ROTATE;
334
334
  } else {
335
335
  if (t.enablePan === !1) return;
336
- pe(n), o = i.PAN;
336
+ ue(n), o = i.PAN;
337
337
  }
338
338
  break;
339
339
  default:
340
340
  o = i.NONE;
341
341
  }
342
- o !== i.NONE && t.dispatchEvent(re);
342
+ o !== i.NONE && t.dispatchEvent(ce);
343
343
  }
344
- function _e(n) {
344
+ function We(n) {
345
345
  switch (o) {
346
346
  case i.ROTATE:
347
347
  if (t.enableRotate === !1) return;
348
- Ae(n);
348
+ $e(n);
349
349
  break;
350
350
  case i.DOLLY:
351
351
  if (t.enableZoom === !1) return;
352
- je(n);
352
+ Ge(n);
353
353
  break;
354
354
  case i.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 || o !== i.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,28 +374,28 @@ 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), o = i.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), o = i.TOUCH_PAN;
399
399
  break;
400
400
  default:
401
401
  o = i.NONE;
@@ -405,11 +405,11 @@ class gt extends ot {
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), o = i.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), o = i.TOUCH_DOLLY_ROTATE;
413
413
  break;
414
414
  default:
415
415
  o = i.NONE;
@@ -418,17 +418,17 @@ class gt extends ot {
418
418
  default:
419
419
  o = i.NONE;
420
420
  }
421
- o !== i.NONE && t.dispatchEvent(re);
421
+ o !== i.NONE && t.dispatchEvent(ce);
422
422
  }
423
- function Qe(n) {
424
- switch (Ee(n), o) {
423
+ function et(n) {
424
+ switch (Ne(n), o) {
425
425
  case i.TOUCH_ROTATE:
426
426
  if (t.enableRotate === !1) return;
427
- me(n), t.update();
427
+ xe(n), t.update();
428
428
  break;
429
429
  case i.TOUCH_PAN:
430
430
  if (t.enablePan === !1) return;
431
- ye(n), t.update();
431
+ be(n), t.update();
432
432
  break;
433
433
  case i.TOUCH_DOLLY_PAN:
434
434
  if (t.enableZoom === !1 && t.enablePan === !1) return;
@@ -442,32 +442,32 @@ class gt extends ot {
442
442
  o = i.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: i } = ke(e), o = s.cameraFov ?? 75;
482
+ this.camera = new y.PerspectiveCamera(o, t / i, 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, i), 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);
500
+ const i = new y.DirectionalLight(16777215, 0.3);
501
501
  i.position.set(0, -30, -50), this.scene.add(i);
502
- const o = new m.PointLight(16750950, 0.5, 150);
502
+ const o = new y.PointLight(16750950, 0.5, 150);
503
503
  o.position.set(40, 20, 40), this.scene.add(o);
504
- const a = new m.PointLight(16764057, 0.4, 150);
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
588
- }, i = {
591
+ const t = Math.max(50, Math.cbrt(V.expectedNodeCount) * 10), i = e.position ?? {
592
+ x: (Math.random() - 0.5) * t,
593
+ y: (Math.random() - 0.5) * t,
594
+ z: (Math.random() - 0.5) * t
595
+ }, o = {
589
596
  ...e,
590
- position: t,
597
+ position: i,
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: i },
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, o), this.nodeObjects.set(e.id, a), !0;
598
605
  }
599
606
  /**
600
607
  * Removes a node from the graph
@@ -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;
@@ -844,12 +854,51 @@ 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.05);
865
+ // Centering force strength
866
+ // Hub node pinning
867
+ l(this, "pinnedNodeId", null);
847
868
  // Simulation state
848
869
  l(this, "alpha", 1);
849
870
  l(this, "alphaDecay", 0.0228);
850
871
  l(this, "alphaMin", 1e-3);
851
872
  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;
873
+ 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, this.initializeNodeMassAndPin();
874
+ }
875
+ /**
876
+ * Assigns mass proportional to node degree (connection count) and
877
+ * pins the most-connected hub node at the origin.
878
+ */
879
+ initializeNodeMassAndPin() {
880
+ const e = /* @__PURE__ */ new Map();
881
+ for (const i of this.edges)
882
+ e.set(i.source, (e.get(i.source) || 0) + 1), e.set(i.target, (e.get(i.target) || 0) + 1);
883
+ let s = 0, t = null;
884
+ for (const [i, o] of e) {
885
+ o > s && (s = o, t = i);
886
+ const a = this.nodes.get(i);
887
+ a && (a.mass = 1 + Math.log2(1 + o));
888
+ }
889
+ if (t && s > 10) {
890
+ this.pinnedNodeId = t;
891
+ const i = this.nodes.get(t);
892
+ i && (i.position.x = 0, i.position.y = 0, i.position.z = 0, i.velocity.x = 0, i.velocity.y = 0, i.velocity.z = 0);
893
+ }
894
+ }
895
+ /**
896
+ * Computes effective repulsion strength scaled by node count.
897
+ * This keeps total repulsion energy bounded as N grows.
898
+ */
899
+ getEffectiveRepulsion() {
900
+ const e = this.nodes.size;
901
+ return e <= 500 ? this.repulsionStrength : this.repulsionStrength * Math.sqrt(500) / Math.sqrt(e);
853
902
  }
854
903
  /**
855
904
  * Runs one simulation step
@@ -857,21 +906,22 @@ class Le {
857
906
  simulate() {
858
907
  if (this.alpha < this.alphaMin) return;
859
908
  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;
909
+ (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
910
  }
862
911
  /**
863
912
  * Brute force repulsion - O(n²)
864
913
  */
865
914
  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;
915
+ const e = Array.from(this.nodes.values()), s = e.length, t = this.getEffectiveRepulsion();
916
+ for (let i = 0; i < s; i++) {
917
+ const o = e[i];
918
+ for (let a = i + 1; a < s; a++) {
919
+ const r = e[a], c = r.position.x - o.position.x, h = r.position.y - o.position.y, p = r.position.z - o.position.z;
920
+ let x = c * c + h * h + p * p;
921
+ if (x > this.REPULSION_CUTOFF_SQ) continue;
922
+ x < 0.01 && (x = 0.01);
923
+ const m = Math.sqrt(x), u = t * this.alpha / x, f = c / m * u, b = h / m * u, M = p / m * u;
924
+ o.velocity.x -= f / o.mass, o.velocity.y -= b / o.mass, o.velocity.z -= M / o.mass, r.velocity.x += f / r.mass, r.velocity.y += b / r.mass, r.velocity.z += M / r.mass;
875
925
  }
876
926
  }
877
927
  }
@@ -879,7 +929,7 @@ class Le {
879
929
  * Barnes-Hut approximation - O(n log n)
880
930
  */
881
931
  calculateRepulsionBarnesHut() {
882
- const e = Array.from(this.nodes.values()), s = new yt(e);
932
+ const e = Array.from(this.nodes.values()), s = new xt(e);
883
933
  for (const t of e)
884
934
  this.calculateForceFromOctree(t, s.root);
885
935
  }
@@ -892,43 +942,69 @@ class Le {
892
942
  return;
893
943
  }
894
944
  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;
945
+ const t = s.centerOfMass.x - e.position.x, i = s.centerOfMass.y - e.position.y, o = s.centerOfMass.z - e.position.z, a = t * t + i * i + o * o;
946
+ if (a > this.REPULSION_CUTOFF_SQ) return;
947
+ const r = Math.sqrt(a), c = this.getEffectiveRepulsion();
948
+ if (r > 0 && s.size / r < this.barnesHutTheta) {
949
+ const h = Math.max(a, 0.01), p = c * this.alpha * s.mass / h;
950
+ e.velocity.x -= t / r * p / e.mass, e.velocity.y -= i / r * p / e.mass, e.velocity.z -= o / r * p / e.mass;
899
951
  } else
900
- for (const r of s.children)
901
- r && this.calculateForceFromOctree(e, r);
952
+ for (const h of s.children)
953
+ h && this.calculateForceFromOctree(e, h);
902
954
  }
903
955
  /**
904
- * Apply repulsion between two nodes
956
+ * Apply repulsion between two nodes (with cutoff)
905
957
  */
906
958
  applyRepulsionBetween(e, s) {
907
959
  const t = s.position.x - e.position.x, i = s.position.y - e.position.y, o = s.position.z - e.position.z;
908
960
  let a = t * t + i * i + o * o;
961
+ if (a > this.REPULSION_CUTOFF_SQ) return;
909
962
  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;
963
+ const r = Math.sqrt(a), h = this.getEffectiveRepulsion() * this.alpha / a;
964
+ e.velocity.x -= t / r * h / e.mass, e.velocity.y -= i / r * h / e.mass, e.velocity.z -= o / r * h / e.mass;
912
965
  }
913
966
  /**
914
967
  * Calculate attraction forces along edges
915
968
  */
916
969
  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;
970
+ const e = this.nodes.size, s = e > 500 ? 1 + Math.log10(e / 500) : 1;
971
+ for (const t of this.edges) {
972
+ const i = this.nodes.get(t.source), o = this.nodes.get(t.target);
973
+ if (!i || !o) continue;
974
+ const a = o.position.x - i.position.x, r = o.position.y - i.position.y, c = o.position.z - i.position.z, h = Math.sqrt(a * a + r * r + c * c);
975
+ if (h < 0.01) continue;
976
+ const x = (h - 15) * this.attractionStrength * s * this.alpha, m = a / h * x, u = r / h * x, f = c / h * x;
977
+ i.velocity.x += m / i.mass, i.velocity.y += u / i.mass, i.velocity.z += f / i.mass, o.velocity.x -= m / o.mass, o.velocity.y -= u / o.mass, o.velocity.z -= f / o.mass;
924
978
  }
925
979
  }
926
980
  /**
927
- * Apply velocities and damping to positions
981
+ * Applies a weak centering/gravity force pulling all nodes toward origin.
982
+ * Prevents the graph from drifting infinitely away from the center.
983
+ */
984
+ applyCenteringForce() {
985
+ const e = this.GRAVITY_STRENGTH * this.alpha;
986
+ for (const s of this.nodes.values())
987
+ s.velocity.x -= s.position.x * e, s.velocity.y -= s.position.y * e, s.velocity.z -= s.position.z * e;
988
+ }
989
+ /**
990
+ * Apply velocities and damping to positions, with velocity capping
928
991
  */
929
992
  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;
993
+ for (const e of this.nodes.values()) {
994
+ if (e.id === this.pinnedNodeId) {
995
+ e.position.x = 0, e.position.y = 0, e.position.z = 0, e.velocity.x = 0, e.velocity.y = 0, e.velocity.z = 0;
996
+ continue;
997
+ }
998
+ e.velocity.x *= this.damping, e.velocity.y *= this.damping, e.velocity.z *= this.damping;
999
+ const s = Math.sqrt(
1000
+ e.velocity.x * e.velocity.x + e.velocity.y * e.velocity.y + e.velocity.z * e.velocity.z
1001
+ );
1002
+ if (s > this.MAX_VELOCITY) {
1003
+ const t = this.MAX_VELOCITY / s;
1004
+ e.velocity.x *= t, e.velocity.y *= t, e.velocity.z *= t;
1005
+ }
1006
+ e.position.x += e.velocity.x, e.position.y += e.velocity.y, e.position.z += e.velocity.z;
1007
+ }
932
1008
  }
933
1009
  /**
934
1010
  * Updates the edges reference
@@ -955,7 +1031,7 @@ class Le {
955
1031
  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
1032
  }
957
1033
  }
958
- class yt {
1034
+ class xt {
959
1035
  constructor(e) {
960
1036
  l(this, "root");
961
1037
  const s = this.calculateBounds(e);
@@ -991,13 +1067,13 @@ class yt {
991
1067
  };
992
1068
  if (e.length === 1 || t > 20) {
993
1069
  let u = 0;
994
- const y = { x: 0, y: 0, z: 0 };
1070
+ const f = { x: 0, y: 0, z: 0 };
995
1071
  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), {
1072
+ u += b.mass, f.x += b.position.x * b.mass, f.y += b.position.y * b.mass, f.z += b.position.z * b.mass;
1073
+ return u > 0 && (f.x /= u, f.y /= u, f.z /= u), {
998
1074
  bounds: s,
999
1075
  size: i,
1000
- centerOfMass: y,
1076
+ centerOfMass: f,
1001
1077
  mass: u,
1002
1078
  isLeaf: !0,
1003
1079
  node: e[0],
@@ -1006,10 +1082,10 @@ class yt {
1006
1082
  }
1007
1083
  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 = [[], [], [], [], [], [], [], []];
1008
1084
  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);
1085
+ const f = (u.position.x >= o ? 1 : 0) + (u.position.y >= a ? 2 : 0) + (u.position.z >= r ? 4 : 0);
1086
+ c[f].push(u);
1011
1087
  }
1012
- const d = [
1088
+ const h = [
1013
1089
  { min: { x: s.min.x, y: s.min.y, z: s.min.z }, max: { x: o, y: a, z: r } },
1014
1090
  { min: { x: o, y: s.min.y, z: s.min.z }, max: { x: s.max.x, y: a, z: r } },
1015
1091
  { min: { x: s.min.x, y: a, z: s.min.z }, max: { x: o, y: s.max.y, z: r } },
@@ -1020,17 +1096,17 @@ class yt {
1020
1096
  { min: { x: o, y: a, z: r }, max: { x: s.max.x, y: s.max.y, z: s.max.z } }
1021
1097
  ], p = [];
1022
1098
  let x = 0;
1023
- const f = { x: 0, y: 0, z: 0 };
1099
+ const m = { x: 0, y: 0, z: 0 };
1024
1100
  for (let u = 0; u < 8; u++)
1025
1101
  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;
1102
+ const f = this.buildTree(c[u], h[u], t + 1);
1103
+ 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
1104
  } else
1029
1105
  p.push(null);
1030
- return x > 0 && (f.x /= x, f.y /= x, f.z /= x), {
1106
+ return x > 0 && (m.x /= x, m.y /= x, m.z /= x), {
1031
1107
  bounds: s,
1032
1108
  size: i,
1033
- centerOfMass: f,
1109
+ centerOfMass: m,
1034
1110
  mass: x,
1035
1111
  isLeaf: !1,
1036
1112
  node: null,
@@ -1038,7 +1114,7 @@ class yt {
1038
1114
  };
1039
1115
  }
1040
1116
  }
1041
- class xt {
1117
+ class bt {
1042
1118
  constructor(e, s, t, i = 60) {
1043
1119
  l(this, "sceneManager");
1044
1120
  l(this, "animationId", null);
@@ -1103,7 +1179,7 @@ class xt {
1103
1179
  this.stop();
1104
1180
  }
1105
1181
  }
1106
- class bt {
1182
+ class vt {
1107
1183
  constructor() {
1108
1184
  l(this, "envMap", null);
1109
1185
  l(this, "materialCache", /* @__PURE__ */ new Map());
@@ -1154,13 +1230,13 @@ class bt {
1154
1230
  );
1155
1231
  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);
1156
1232
  const c = a.getImageData(0, 0, 256, 256);
1157
- for (let d = 0; d < c.data.length; d += 4) {
1233
+ for (let h = 0; h < c.data.length; h += 4) {
1158
1234
  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));
1235
+ 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
1236
  }
1161
1237
  a.putImageData(c, 0, 0), s.push(o);
1162
1238
  }
1163
- this.envMap = new m.CubeTexture(s.map((i) => {
1239
+ this.envMap = new y.CubeTexture(s.map((i) => {
1164
1240
  const o = new Image();
1165
1241
  return o.src = i.toDataURL(), o;
1166
1242
  })), this.envMap.needsUpdate = !0;
@@ -1179,11 +1255,11 @@ class bt {
1179
1255
  const t = "glass-single";
1180
1256
  if (this.materialCache.has(t))
1181
1257
  return this.materialCache.get(t).clone();
1182
- const i = new m.Color(16750950), o = new m.ShaderMaterial({
1258
+ const i = new y.Color(16750950), o = new y.ShaderMaterial({
1183
1259
  uniforms: {
1184
1260
  uColor: { value: i },
1185
1261
  uEnvMap: { value: this.envMap },
1186
- uGlowColor: { value: new m.Color(16777215) },
1262
+ uGlowColor: { value: new y.Color(16777215) },
1187
1263
  uGlowIntensity: { value: 0.8 },
1188
1264
  uReflectivity: { value: 0.4 },
1189
1265
  uFresnelPower: { value: 2.5 }
@@ -1249,9 +1325,9 @@ class bt {
1249
1325
  }
1250
1326
  `,
1251
1327
  transparent: !0,
1252
- side: m.FrontSide,
1328
+ side: y.FrontSide,
1253
1329
  depthWrite: !0,
1254
- blending: m.NormalBlending
1330
+ blending: y.NormalBlending
1255
1331
  });
1256
1332
  return this.materialCache.set(t, o), o.clone();
1257
1333
  }
@@ -1259,7 +1335,7 @@ class bt {
1259
1335
  * Creates material for edges (light color for dark background)
1260
1336
  */
1261
1337
  createEdgeMaterial(e = 6710886, s = 0.4) {
1262
- return new m.LineBasicMaterial({
1338
+ return new y.LineBasicMaterial({
1263
1339
  color: e,
1264
1340
  transparent: !0,
1265
1341
  opacity: s,
@@ -1270,7 +1346,7 @@ class bt {
1270
1346
  * Creates highlighted edge material
1271
1347
  */
1272
1348
  createHighlightedEdgeMaterial() {
1273
- return new m.LineBasicMaterial({
1349
+ return new y.LineBasicMaterial({
1274
1350
  color: 16750950,
1275
1351
  // Tangerine highlight
1276
1352
  transparent: !1,
@@ -1286,8 +1362,8 @@ class bt {
1286
1362
  i.font = `600 ${s}px Inter, -apple-system, sans-serif`;
1287
1363
  const a = i.measureText(e).width;
1288
1364
  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({
1365
+ const r = new y.CanvasTexture(t);
1366
+ return r.needsUpdate = !0, new y.SpriteMaterial({
1291
1367
  map: r,
1292
1368
  transparent: !0,
1293
1369
  depthTest: !1,
@@ -1307,7 +1383,7 @@ class bt {
1307
1383
  this.materialCache.forEach((e) => e.dispose()), this.materialCache.clear(), this.envMap && this.envMap.dispose();
1308
1384
  }
1309
1385
  }
1310
- class vt {
1386
+ class Mt {
1311
1387
  constructor(e, s = 2, t = [32, 16, 8], i = 16750950) {
1312
1388
  l(this, "materialFactory");
1313
1389
  l(this, "geometryCache", /* @__PURE__ */ new Map());
@@ -1324,7 +1400,7 @@ class vt {
1324
1400
  const t = `lod-${s}`;
1325
1401
  this.geometryCache.set(
1326
1402
  t,
1327
- new m.SphereGeometry(this.nodeRadius, e, e)
1403
+ new y.SphereGeometry(this.nodeRadius, e, e)
1328
1404
  );
1329
1405
  });
1330
1406
  }
@@ -1339,13 +1415,13 @@ class vt {
1339
1415
  * Creates a node visual (glass ball + label)
1340
1416
  */
1341
1417
  createNode(e, s = 0) {
1342
- const t = new m.Group();
1418
+ const t = new y.Group();
1343
1419
  t.name = `node-${e.id}`, t.userData = { nodeId: e.id, nodeData: e };
1344
1420
  const i = this.getGeometry(s), o = this.materialFactory.createGlassMaterial(
1345
1421
  e.color ?? this.defaultNodeColor
1346
- ), a = new m.Mesh(i, o);
1422
+ ), a = new y.Mesh(i, o);
1347
1423
  a.castShadow = !0, a.receiveShadow = !0, t.add(a);
1348
- const r = this.materialFactory.createLabelMaterial(e.label), c = new m.Sprite(r);
1424
+ const r = this.materialFactory.createLabelMaterial(e.label), c = new y.Sprite(r);
1349
1425
  return c.position.y = this.nodeRadius + 1.5, c.scale.set(4, 1, 1), t.add(c), e.position && t.position.set(
1350
1426
  e.position.x,
1351
1427
  e.position.y,
@@ -1369,19 +1445,19 @@ class vt {
1369
1445
  * Updates the color of a node
1370
1446
  */
1371
1447
  updateNodeColor(e, s) {
1372
- e.sphere.material instanceof m.Material && e.sphere.material.dispose(), e.sphere.material = this.materialFactory.createGlassMaterial(s);
1448
+ e.sphere.material instanceof y.Material && e.sphere.material.dispose(), e.sphere.material = this.materialFactory.createGlassMaterial(s);
1373
1449
  }
1374
1450
  /**
1375
1451
  * Updates the label of a node
1376
1452
  */
1377
1453
  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);
1454
+ 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
1455
  }
1380
1456
  /**
1381
1457
  * Disposes a node's resources
1382
1458
  */
1383
1459
  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());
1460
+ 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
1461
  }
1386
1462
  /**
1387
1463
  * Dispose factory resources
@@ -1390,7 +1466,7 @@ class vt {
1390
1466
  this.geometryCache.forEach((e) => e.dispose()), this.geometryCache.clear();
1391
1467
  }
1392
1468
  }
1393
- class Mt {
1469
+ class wt {
1394
1470
  constructor(e, s = 10066329, t = 0.5) {
1395
1471
  l(this, "materialFactory");
1396
1472
  l(this, "edgeColor");
@@ -1418,7 +1494,7 @@ class Mt {
1418
1494
  * Creates an edge line between two positions
1419
1495
  */
1420
1496
  createEdge(e, s, t, i, o) {
1421
- const a = new m.BufferGeometry(), r = new Float32Array([
1497
+ const a = new y.BufferGeometry(), r = new Float32Array([
1422
1498
  i.x,
1423
1499
  i.y,
1424
1500
  i.z,
@@ -1426,16 +1502,16 @@ class Mt {
1426
1502
  o.y,
1427
1503
  o.z
1428
1504
  ]);
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 = {
1505
+ a.setAttribute("position", new y.BufferAttribute(r, 3));
1506
+ const c = this.getDefaultMaterial().clone(), h = new y.Line(a, c);
1507
+ return h.name = `edge-${e.source}-${e.target}`, h.userData = {
1432
1508
  source: e.source,
1433
1509
  target: e.target,
1434
1510
  edge: e,
1435
1511
  sourceNode: s,
1436
1512
  targetNode: t
1437
- }, d.frustumCulled = !0, {
1438
- line: d,
1513
+ }, h.frustumCulled = !0, {
1514
+ line: h,
1439
1515
  source: e.source,
1440
1516
  target: e.target
1441
1517
  };
@@ -1444,13 +1520,13 @@ class Mt {
1444
1520
  * Highlights an edge
1445
1521
  */
1446
1522
  highlightEdge(e) {
1447
- e.line.material instanceof m.Material && e.line.material.dispose(), e.line.material = this.getHighlightMaterial().clone();
1523
+ e.line.material instanceof y.Material && e.line.material.dispose(), e.line.material = this.getHighlightMaterial().clone();
1448
1524
  }
1449
1525
  /**
1450
1526
  * Resets an edge to default appearance
1451
1527
  */
1452
1528
  unhighlightEdge(e) {
1453
- e.line.material instanceof m.Material && e.line.material.dispose(), e.line.material = this.getDefaultMaterial().clone();
1529
+ e.line.material instanceof y.Material && e.line.material.dispose(), e.line.material = this.getDefaultMaterial().clone();
1454
1530
  }
1455
1531
  /**
1456
1532
  * Updates an edge's positions
@@ -1463,7 +1539,7 @@ class Mt {
1463
1539
  * Disposes an edge's resources
1464
1540
  */
1465
1541
  disposeEdge(e) {
1466
- e.line.geometry.dispose(), e.line.material instanceof m.Material && e.line.material.dispose();
1542
+ e.line.geometry.dispose(), e.line.material instanceof y.Material && e.line.material.dispose();
1467
1543
  }
1468
1544
  /**
1469
1545
  * Dispose factory resources
@@ -1472,7 +1548,7 @@ class Mt {
1472
1548
  this.defaultMaterial && this.defaultMaterial.dispose(), this.highlightMaterial && this.highlightMaterial.dispose();
1473
1549
  }
1474
1550
  }
1475
- class wt {
1551
+ class Et {
1476
1552
  constructor(e, s = [50, 100, 200], t = !0) {
1477
1553
  l(this, "camera");
1478
1554
  l(this, "lodDistances");
@@ -1484,9 +1560,9 @@ class wt {
1484
1560
  */
1485
1561
  getLODLevel(e) {
1486
1562
  if (!this.enabled)
1487
- return U.HIGH;
1563
+ return X.HIGH;
1488
1564
  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;
1565
+ return o < this.lodDistances[0] ? X.HIGH : o < this.lodDistances[1] ? X.MEDIUM : X.LOW;
1490
1566
  }
1491
1567
  /**
1492
1568
  * Checks if a node should be visible based on distance
@@ -1508,13 +1584,13 @@ class wt {
1508
1584
  this.enabled = e;
1509
1585
  }
1510
1586
  }
1511
- class Et {
1587
+ class Ct {
1512
1588
  constructor(e, s = !0) {
1513
1589
  l(this, "camera");
1514
1590
  l(this, "frustum");
1515
1591
  l(this, "projScreenMatrix");
1516
1592
  l(this, "enabled");
1517
- this.camera = e, this.frustum = new m.Frustum(), this.projScreenMatrix = new m.Matrix4(), this.enabled = s;
1593
+ this.camera = e, this.frustum = new y.Frustum(), this.projScreenMatrix = new y.Matrix4(), this.enabled = s;
1518
1594
  }
1519
1595
  /**
1520
1596
  * Updates the frustum from the camera
@@ -1530,7 +1606,7 @@ class Et {
1530
1606
  */
1531
1607
  isPointVisible(e) {
1532
1608
  if (!this.enabled) return !0;
1533
- const s = new m.Vector3(e.x, e.y, e.z);
1609
+ const s = new y.Vector3(e.x, e.y, e.z);
1534
1610
  return this.frustum.containsPoint(s);
1535
1611
  }
1536
1612
  /**
@@ -1538,8 +1614,8 @@ class Et {
1538
1614
  */
1539
1615
  isSphereVisible(e, s) {
1540
1616
  if (!this.enabled) return !0;
1541
- const t = new m.Sphere(
1542
- new m.Vector3(e.x, e.y, e.z),
1617
+ const t = new y.Sphere(
1618
+ new y.Vector3(e.x, e.y, e.z),
1543
1619
  s
1544
1620
  );
1545
1621
  return this.frustum.intersectsSphere(t);
@@ -1549,14 +1625,14 @@ class Et {
1549
1625
  */
1550
1626
  isLineVisible(e, s) {
1551
1627
  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);
1628
+ const t = new y.Vector3(e.x, e.y, e.z), i = new y.Vector3(s.x, s.y, s.z);
1553
1629
  if (this.frustum.containsPoint(t) || this.frustum.containsPoint(i))
1554
1630
  return !0;
1555
- const o = new m.Vector3(
1631
+ const o = new y.Vector3(
1556
1632
  (e.x + s.x) / 2,
1557
1633
  (e.y + s.y) / 2,
1558
1634
  (e.z + s.z) / 2
1559
- ), a = o.distanceTo(t), r = new m.Sphere(o, a);
1635
+ ), a = o.distanceTo(t), r = new y.Sphere(o, a);
1560
1636
  return this.frustum.intersectsSphere(r);
1561
1637
  }
1562
1638
  /**
@@ -1566,7 +1642,7 @@ class Et {
1566
1642
  this.enabled = e;
1567
1643
  }
1568
1644
  }
1569
- class Ct {
1645
+ class Nt {
1570
1646
  constructor(e, s) {
1571
1647
  l(this, "sceneManager");
1572
1648
  l(this, "raycaster");
@@ -1580,7 +1656,7 @@ class Ct {
1580
1656
  l(this, "hoveredEdgeKey", null);
1581
1657
  l(this, "nodeObjects", []);
1582
1658
  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);
1659
+ 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
1660
  }
1585
1661
  /**
1586
1662
  * Updates the list of node objects to raycast against
@@ -1704,7 +1780,7 @@ class Ct {
1704
1780
  this.container.removeEventListener("click", this.handleClick), this.container.removeEventListener("mousemove", this.handleMouseMove);
1705
1781
  }
1706
1782
  }
1707
- class Nt {
1783
+ class St {
1708
1784
  constructor(e) {
1709
1785
  l(this, "container");
1710
1786
  l(this, "panel", null);
@@ -1990,7 +2066,7 @@ class Nt {
1990
2066
  this.panel && this.panel.parentNode && this.panel.parentNode.removeChild(this.panel), this.panel = null;
1991
2067
  }
1992
2068
  }
1993
- class St {
2069
+ class zt {
1994
2070
  constructor(e) {
1995
2071
  l(this, "container");
1996
2072
  l(this, "panel", null);
@@ -2235,7 +2311,7 @@ class St {
2235
2311
  this.panel && this.panel.parentNode && this.panel.parentNode.removeChild(this.panel), this.panel = null;
2236
2312
  }
2237
2313
  }
2238
- class zt {
2314
+ class Tt {
2239
2315
  constructor() {
2240
2316
  l(this, "tooltip", null);
2241
2317
  l(this, "visible", !1);
@@ -2603,7 +2679,7 @@ class Pt {
2603
2679
  this.toggleContainer && this.toggleContainer.parentNode && this.toggleContainer.parentNode.removeChild(this.toggleContainer);
2604
2680
  }
2605
2681
  }
2606
- const Tt = {
2682
+ const Rt = {
2607
2683
  backgroundColor: "#0a0a0a",
2608
2684
  gridColor: "rgba(255, 255, 255, 0.03)",
2609
2685
  nodeRadius: 24,
@@ -2616,7 +2692,7 @@ const Tt = {
2616
2692
  damping: 0.85
2617
2693
  // Fast energy dissipation
2618
2694
  };
2619
- class Lt {
2695
+ class It {
2620
2696
  constructor(e, s = {}) {
2621
2697
  l(this, "container");
2622
2698
  l(this, "canvas");
@@ -2643,7 +2719,7 @@ class Lt {
2643
2719
  l(this, "isSimulating", !0);
2644
2720
  // Resize handler
2645
2721
  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);
2722
+ 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
2723
  const t = this.canvas.getContext("2d");
2648
2724
  if (!t)
2649
2725
  throw new Error("Failed to get 2D context");
@@ -2706,10 +2782,10 @@ class Lt {
2706
2782
  for (const i of this.edges) {
2707
2783
  const o = this.nodes.get(i.source), a = this.nodes.get(i.target);
2708
2784
  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)
2785
+ const r = a.x - o.x, c = a.y - o.y, h = r * r + c * c;
2786
+ if (h === 0) continue;
2787
+ const p = Math.max(0, Math.min(1, ((e - o.x) * r + (s - o.y) * c) / h)), x = o.x + p * r, m = o.y + p * c, u = e - x, f = s - m;
2788
+ if (Math.sqrt(u * u + f * f) < 12)
2713
2789
  return i;
2714
2790
  }
2715
2791
  return null;
@@ -2727,22 +2803,22 @@ class Lt {
2727
2803
  let o = 0;
2728
2804
  for (let r = 0; r < s; r++)
2729
2805
  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);
2806
+ const h = e[r], p = e[c];
2807
+ let x = p.x - h.x, m = p.y - h.y, u = Math.sqrt(x * x + m * m);
2732
2808
  if (u < t * 3) {
2733
2809
  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;
2810
+ const f = this.options.repulsionStrength / (u * u), b = x / u * f, M = m / u * f;
2811
+ h.vx -= b, h.vy -= M, p.vx += b, p.vy += M;
2736
2812
  }
2737
2813
  }
2738
2814
  const a = 80;
2739
2815
  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;
2816
+ const c = this.nodes.get(r.source), h = this.nodes.get(r.target);
2817
+ if (!c || !h) continue;
2818
+ let p = h.x - c.x, x = h.y - c.y, m = Math.sqrt(p * p + x * x);
2819
+ m < 1 && (m = 1);
2820
+ const f = (m - a) * this.options.attractionStrength, b = p / m * f, M = x / m * f;
2821
+ c.vx += b, c.vy += M, h.vx -= b, h.vy -= M;
2746
2822
  }
2747
2823
  for (const r of e) {
2748
2824
  if (this.draggedNode === r) continue;
@@ -2760,8 +2836,8 @@ class Lt {
2760
2836
  const t = this.ctx, i = 40 * this.transform.scale, o = 1.5, a = this.transform.x % i, r = this.transform.y % i;
2761
2837
  t.fillStyle = this.options.gridColor;
2762
2838
  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();
2839
+ for (let h = r; h < s; h += i)
2840
+ t.beginPath(), t.arc(c, h, o, 0, Math.PI * 2), t.fill();
2765
2841
  }
2766
2842
  renderEdges() {
2767
2843
  const e = this.ctx;
@@ -2777,7 +2853,7 @@ class Lt {
2777
2853
  for (const s of this.nodes.values()) {
2778
2854
  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
2855
  if (t || i || o) {
2780
- const y = e.createRadialGradient(
2856
+ const f = e.createRadialGradient(
2781
2857
  s.x,
2782
2858
  s.y,
2783
2859
  a * 0.5,
@@ -2785,7 +2861,7 @@ class Lt {
2785
2861
  s.y,
2786
2862
  a * 2
2787
2863
  ), 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();
2864
+ 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
2865
  }
2790
2866
  const r = e.createRadialGradient(
2791
2867
  s.x - a * 0.3,
@@ -2794,16 +2870,16 @@ class Lt {
2794
2870
  s.x,
2795
2871
  s.y,
2796
2872
  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";
2873
+ ), c = s.color >> 16 & 255, h = s.color >> 8 & 255, p = s.color & 255;
2874
+ 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
2875
  const x = a * 1.6;
2800
- let f = s.label, u = e.measureText(f).width;
2876
+ let m = s.label, u = e.measureText(m).width;
2801
2877
  if (u > x) {
2802
- for (; u > x && f.length > 3; )
2803
- f = f.slice(0, -1), u = e.measureText(f + "...").width;
2804
- f += "...";
2878
+ for (; u > x && m.length > 3; )
2879
+ m = m.slice(0, -1), u = e.measureText(m + "...").width;
2880
+ m += "...";
2805
2881
  }
2806
- e.shadowColor = "rgba(0, 0, 0, 0.5)", e.shadowBlur = 3, e.fillText(f, s.x, s.y), e.shadowBlur = 0;
2882
+ e.shadowColor = "rgba(0, 0, 0, 0.5)", e.shadowBlur = 3, e.fillText(m, s.x, s.y), e.shadowBlur = 0;
2807
2883
  }
2808
2884
  }
2809
2885
  /**
@@ -2902,11 +2978,11 @@ class Lt {
2902
2978
  focusOnNode(e) {
2903
2979
  const s = this.nodes.get(e);
2904
2980
  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;
2981
+ 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(), h = () => {
2982
+ const p = performance.now() - c, x = Math.min(p / r, 1), m = 1 - Math.pow(1 - x, 3);
2983
+ this.transform.x = o + (t - o) * m, this.transform.y = a + (i - a) * m, x < 1 ? requestAnimationFrame(h) : this.selectedNode = s;
2908
2984
  };
2909
- d();
2985
+ h();
2910
2986
  }
2911
2987
  /**
2912
2988
  * Updates node positions from 3D data
@@ -2948,7 +3024,7 @@ class Lt {
2948
3024
  this.animationId && cancelAnimationFrame(this.animationId), window.removeEventListener("resize", this.resizeHandler), this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);
2949
3025
  }
2950
3026
  }
2951
- class Ft {
3027
+ class Ht {
2952
3028
  // Store graph data for view switching
2953
3029
  constructor(e, s = {}) {
2954
3030
  // Options
@@ -2983,23 +3059,23 @@ class Ft {
2983
3059
  l(this, "devControls", null);
2984
3060
  l(this, "viewMode", "3d");
2985
3061
  l(this, "graphData", null);
2986
- this.options = { ...T, ...s }, this.container = ct(e), this.materialFactory = new bt(), this.nodeFactory = new vt(
3062
+ this.options = { ...P, ...s }, this.container = dt(e), this.materialFactory = new vt(), this.nodeFactory = new Mt(
2987
3063
  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(
3064
+ this.options.nodeRadius ?? P.nodeRadius,
3065
+ this.options.lodSegments ?? P.lodSegments,
3066
+ this.options.defaultNodeColor ?? P.defaultNodeColor
3067
+ ), this.edgeFactory = new wt(
2992
3068
  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(
3069
+ this.options.edgeColor ?? P.edgeColor,
3070
+ this.options.edgeOpacity ?? P.edgeOpacity
3071
+ ), this.sceneManager = new mt(this.container, this.options), this.lodManager = new Et(
2996
3072
  this.sceneManager.camera,
2997
- this.options.lodDistances ?? T.lodDistances,
2998
- this.options.enableLOD ?? T.enableLOD
2999
- ), this.frustumCuller = new Et(
3073
+ this.options.lodDistances ?? P.lodDistances,
3074
+ this.options.enableLOD ?? P.enableLOD
3075
+ ), this.frustumCuller = new Ct(
3000
3076
  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(
3077
+ this.options.enableEdgeCulling ?? P.enableEdgeCulling
3078
+ ), this.nodeManager = new te(this.sceneManager, this.nodeFactory), this.edgeManager = new yt(this.sceneManager, this.nodeManager, this.edgeFactory), this.graphEngine = new Le(
3003
3079
  this.nodeManager.getAllNodes(),
3004
3080
  this.edgeManager.getAllEdges(),
3005
3081
  {
@@ -3009,12 +3085,12 @@ class Ft {
3009
3085
  useBarnesHut: this.options.useBarnesHut,
3010
3086
  barnesHutTheta: this.options.barnesHutTheta
3011
3087
  }
3012
- ), this.rendererManager = new xt(
3088
+ ), this.rendererManager = new bt(
3013
3089
  this.sceneManager,
3014
3090
  () => this.onSimulate(),
3015
3091
  () => 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) => {
3092
+ this.options.targetFPS ?? P.targetFPS
3093
+ ), 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
3094
  this.edgePanelManager.hide(), this.focusOnNode(t), setTimeout(() => {
3019
3095
  this.showNodePanel(t);
3020
3096
  }, 400);
@@ -3100,12 +3176,22 @@ class Ft {
3100
3176
  * Sets the graph data
3101
3177
  */
3102
3178
  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);
3179
+ var a;
3180
+ const s = (a = e.data) != null && a.nodes ? e.data : e, i = (s.edges || s.links || []).map((r) => ({
3181
+ ...r,
3182
+ relationship: r.relationship || r.label || "related_to"
3183
+ })), o = {
3184
+ nodes: s.nodes || [],
3185
+ edges: i
3186
+ };
3187
+ if (this.graphData = o, this.edgeManager.clear(), this.nodeManager.clear(), o.nodes && Array.isArray(o.nodes)) {
3188
+ te.setExpectedNodeCount(o.nodes.length);
3189
+ for (const r of o.nodes)
3190
+ this.addNode(r);
3191
+ }
3192
+ if (o.edges && Array.isArray(o.edges))
3193
+ for (const r of o.edges)
3194
+ this.addEdge(r);
3109
3195
  this.graphEngine = new Le(
3110
3196
  this.nodeManager.getAllNodes(),
3111
3197
  this.edgeManager.getAllEdges(),
@@ -3116,14 +3202,14 @@ class Ft {
3116
3202
  useBarnesHut: this.options.useBarnesHut,
3117
3203
  barnesHutTheta: this.options.barnesHutTheta
3118
3204
  }
3119
- ), this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.setData(e);
3205
+ ), this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.setData(o);
3120
3206
  }
3121
3207
  /**
3122
3208
  * Adds a node to the graph
3123
3209
  * @returns true if added, false if node already exists or invalid
3124
3210
  */
3125
3211
  addNode(e) {
3126
- if (!Oe(e))
3212
+ if (!He(e))
3127
3213
  return !1;
3128
3214
  const s = this.nodeManager.addNode(e);
3129
3215
  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 +3219,7 @@ class Ft {
3133
3219
  * @returns true if removed, false if not found
3134
3220
  */
3135
3221
  removeNode(e) {
3136
- if (!ht(e))
3222
+ if (!pt(e))
3137
3223
  return !1;
3138
3224
  this.edgeManager.removeEdgesForNode(e);
3139
3225
  const s = this.nodeManager.removeNode(e);
@@ -3150,7 +3236,7 @@ class Ft {
3150
3236
  * @returns true if added, false if edge already exists or nodes don't exist
3151
3237
  */
3152
3238
  addEdge(e) {
3153
- if (!Fe(e))
3239
+ if (!De(e))
3154
3240
  return !1;
3155
3241
  const s = this.edgeManager.addEdge(e);
3156
3242
  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;
@@ -3234,9 +3320,9 @@ class Ft {
3234
3320
  x: i.x + r.x * s,
3235
3321
  y: i.y + r.y * s,
3236
3322
  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);
3323
+ }, h = { 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, m = performance.now(), u = () => {
3324
+ const f = performance.now() - m, b = Math.min(f / x, 1), M = 1 - Math.pow(1 - b, 3);
3325
+ o.position.x = h.x + (c.x - h.x) * M, o.position.y = h.y + (c.y - h.y) * M, o.position.z = h.z + (c.z - h.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);
3240
3326
  };
3241
3327
  u();
3242
3328
  }
@@ -3254,12 +3340,12 @@ class Ft {
3254
3340
  x: (i.position.x + o.position.x) / 2,
3255
3341
  y: (i.position.y + o.position.y) / 2,
3256
3342
  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);
3343
+ }, h = o.position.x - i.position.x, p = o.position.y - i.position.y, x = o.position.z - i.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 = {
3344
+ x: c.x + f.x * u,
3345
+ y: c.y + f.y * u,
3346
+ z: c.z + f.z * u
3347
+ }, 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 = () => {
3348
+ const k = performance.now() - R, H = Math.min(k / O, 1), E = 1 - Math.pow(1 - H, 3);
3263
3349
  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
3350
  };
3265
3351
  Y();
@@ -3285,8 +3371,8 @@ class Ft {
3285
3371
  return [];
3286
3372
  const s = e.toLowerCase().trim(), t = this.nodeManager.getAllNodes(), i = [];
3287
3373
  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);
3374
+ var h, p, x;
3375
+ const a = (h = o.label) == null ? void 0 : h.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
3376
  (a || r || c) && i.push(o);
3291
3377
  }), i;
3292
3378
  }
@@ -3301,8 +3387,8 @@ class Ft {
3301
3387
  const s = e.toLowerCase().trim(), t = this.edgeManager.getAllEdges(), i = [];
3302
3388
  for (const a of t)
3303
3389
  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 });
3390
+ const c = this.nodeManager.getNode(a.source), h = this.nodeManager.getNode(a.target);
3391
+ c && h && i.push({ edge: a, sourceNode: c, targetNode: h });
3306
3392
  }
3307
3393
  return i;
3308
3394
  }
@@ -3335,7 +3421,7 @@ class Ft {
3335
3421
  * Switches between 2D and 3D view modes
3336
3422
  */
3337
3423
  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, {
3424
+ 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
3425
  backgroundColor: "#0a0a0a",
3340
3426
  nodeRadius: 24,
3341
3427
  onNodeClick: (s) => {
@@ -3471,7 +3557,7 @@ class Ft {
3471
3557
  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
3558
  }
3473
3559
  }
3474
- const Ie = [
3560
+ const Oe = [
3475
3561
  "Alpha",
3476
3562
  "Beta",
3477
3563
  "Gamma",
@@ -3502,7 +3588,7 @@ const Ie = [
3502
3588
  "Link",
3503
3589
  "Point",
3504
3590
  "Vertex"
3505
- ], J = [
3591
+ ], ee = [
3506
3592
  "connects to",
3507
3593
  "links with",
3508
3594
  "relates to",
@@ -3513,7 +3599,7 @@ const Ie = [
3513
3599
  "partners with",
3514
3600
  "collaborates with",
3515
3601
  "supports"
3516
- ], Re = [
3602
+ ], Fe = [
3517
3603
  16777215,
3518
3604
  // White
3519
3605
  16750950,
@@ -3525,14 +3611,14 @@ const Ie = [
3525
3611
  16746564
3526
3612
  // Darker tangerine
3527
3613
  ];
3528
- function Ht(h = 30) {
3614
+ function Dt(d = 30) {
3529
3615
  const e = [], s = [];
3530
- for (let i = 0; i < h; i++) {
3531
- const o = i < Ie.length ? Ie[i] : `Node ${i + 1}`;
3616
+ for (let i = 0; i < d; i++) {
3617
+ const o = i < Oe.length ? Oe[i] : `Node ${i + 1}`;
3532
3618
  e.push({
3533
3619
  id: `node-${i}`,
3534
3620
  label: o,
3535
- color: Re[i % Re.length],
3621
+ color: Fe[i % Fe.length],
3536
3622
  position: {
3537
3623
  x: (Math.random() - 0.5) * 60,
3538
3624
  y: (Math.random() - 0.5) * 60,
@@ -3540,39 +3626,39 @@ function Ht(h = 30) {
3540
3626
  }
3541
3627
  });
3542
3628
  }
3543
- for (let i = 1; i < h; i++) {
3629
+ for (let i = 1; i < d; i++) {
3544
3630
  const o = Math.floor(Math.random() * i);
3545
3631
  s.push({
3546
3632
  source: `node-${i}`,
3547
3633
  target: `node-${o}`,
3548
- relationship: J[Math.floor(Math.random() * J.length)]
3634
+ relationship: ee[Math.floor(Math.random() * ee.length)]
3549
3635
  });
3550
3636
  }
3551
- const t = Math.floor(h * 0.5);
3637
+ const t = Math.floor(d * 0.5);
3552
3638
  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);
3639
+ const o = Math.floor(Math.random() * d);
3640
+ let a = Math.floor(Math.random() * d);
3641
+ o === a && (a = (a + 1) % d);
3556
3642
  const r = `node-${o}`, c = `node-${a}`;
3557
3643
  s.some(
3558
3644
  (p) => p.source === r && p.target === c || p.source === c && p.target === r
3559
3645
  ) || s.push({
3560
3646
  source: r,
3561
3647
  target: c,
3562
- relationship: J[Math.floor(Math.random() * J.length)]
3648
+ relationship: ee[Math.floor(Math.random() * ee.length)]
3563
3649
  });
3564
3650
  }
3565
3651
  return { nodes: e, edges: s };
3566
3652
  }
3567
- function Dt(h = 1e3) {
3568
- const e = [], s = [], t = Math.ceil(h / 50), i = [];
3653
+ function At(d = 1e3) {
3654
+ const e = [], s = [], t = Math.ceil(d / 50), i = [];
3569
3655
  for (let o = 0; o < t; o++)
3570
3656
  i.push({
3571
3657
  x: (Math.random() - 0.5) * 200,
3572
3658
  y: (Math.random() - 0.5) * 200,
3573
3659
  z: (Math.random() - 0.5) * 200
3574
3660
  });
3575
- for (let o = 0; o < h; o++) {
3661
+ for (let o = 0; o < d; o++) {
3576
3662
  const a = i[o % t];
3577
3663
  e.push({
3578
3664
  id: `node-${o}`,
@@ -3584,7 +3670,7 @@ function Dt(h = 1e3) {
3584
3670
  }
3585
3671
  });
3586
3672
  }
3587
- for (let o = 1; o < h; o++) {
3673
+ for (let o = 1; o < d; o++) {
3588
3674
  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));
3589
3675
  s.push({
3590
3676
  source: `node-${o}`,
@@ -3603,13 +3689,13 @@ function Dt(h = 1e3) {
3603
3689
  return { nodes: e, edges: s };
3604
3690
  }
3605
3691
  export {
3606
- T as DEFAULT_OPTIONS,
3607
- Ft as ForceGraph3D,
3608
- U as LODLevel,
3692
+ P as DEFAULT_OPTIONS,
3693
+ Ht as ForceGraph3D,
3694
+ X as LODLevel,
3609
3695
  D as createEdgeKey,
3610
- Dt as generateLargeSampleData,
3611
- Ht as generateSampleData,
3612
- Fe as validateEdgeData,
3613
- Oe as validateNodeData
3696
+ At as generateLargeSampleData,
3697
+ Dt as generateSampleData,
3698
+ De as validateEdgeData,
3699
+ He as validateNodeData
3614
3700
  };
3615
3701
  //# sourceMappingURL=force-3d-graph.js.map