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.
package/dist/force-3d-graph.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var l = (
|
|
4
|
-
import * as
|
|
5
|
-
import { EventDispatcher as
|
|
6
|
-
const
|
|
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
|
|
35
|
-
function
|
|
36
|
-
const
|
|
37
|
-
return
|
|
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(
|
|
44
|
+
`, document.body.appendChild(d), d;
|
|
45
45
|
}
|
|
46
|
-
function
|
|
47
|
-
return
|
|
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
|
|
50
|
-
const e =
|
|
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
|
|
57
|
-
if (!
|
|
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 =
|
|
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 && !
|
|
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
|
|
63
|
-
if (!
|
|
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 =
|
|
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
|
|
69
|
-
return typeof
|
|
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
|
|
72
|
-
if (!
|
|
73
|
-
const e =
|
|
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(
|
|
77
|
-
return
|
|
76
|
+
function D(d, e) {
|
|
77
|
+
return d === e ? `${d}-${e}` : d < e ? `${d}-${e}` : `${e}-${d}`;
|
|
78
78
|
}
|
|
79
|
-
const
|
|
80
|
-
class
|
|
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",
|
|
89
|
+
n.addEventListener("keydown", re), this._domElementKeyEvents = n;
|
|
90
90
|
}, this.stopListenToKeyEvents = function() {
|
|
91
|
-
this._domElementKeyEvents.removeEventListener("keydown",
|
|
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(
|
|
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
|
|
98
|
-
return function(
|
|
99
|
-
const
|
|
100
|
-
n.copy(
|
|
101
|
-
let I = t.minAzimuthAngle,
|
|
102
|
-
isFinite(I) && isFinite(
|
|
103
|
-
let
|
|
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
|
|
105
|
+
let U = null;
|
|
106
106
|
if (t.object.isPerspectiveCamera) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
t.object.position.addScaledVector(Y,
|
|
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
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
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
|
-
|
|
119
|
-
} else t.object.isOrthographicCamera && (t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom /
|
|
120
|
-
return
|
|
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",
|
|
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
|
|
137
|
-
let
|
|
138
|
-
const p = new S(), x = new
|
|
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
|
|
142
|
-
function
|
|
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
|
|
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
|
|
152
|
+
function Z(n) {
|
|
153
153
|
c.phi -= n;
|
|
154
154
|
}
|
|
155
|
-
const
|
|
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
|
-
}(),
|
|
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),
|
|
174
|
-
} else t.object.isOrthographicCamera ? (
|
|
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
|
|
178
|
-
t.object.isPerspectiveCamera || t.object.isOrthographicCamera ?
|
|
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
|
|
181
|
-
t.object.isPerspectiveCamera || t.object.isOrthographicCamera ?
|
|
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
|
|
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
|
-
|
|
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
|
|
190
|
+
function ne(n) {
|
|
191
191
|
return Math.max(t.minDistance, Math.min(t.maxDistance, n));
|
|
192
192
|
}
|
|
193
|
-
function
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 ?
|
|
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 ?
|
|
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
|
|
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
|
|
242
|
+
function me(n) {
|
|
243
243
|
if (E.length === 1)
|
|
244
|
-
|
|
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
|
-
|
|
247
|
+
f.set(v, w);
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
|
-
function
|
|
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
|
|
255
|
-
t.enableZoom &&
|
|
254
|
+
function Ue(n) {
|
|
255
|
+
t.enableZoom && ye(n), t.enablePan && me(n);
|
|
256
256
|
}
|
|
257
|
-
function
|
|
258
|
-
t.enableZoom &&
|
|
257
|
+
function _e(n) {
|
|
258
|
+
t.enableZoom && ye(n), t.enableRotate && fe(n);
|
|
259
259
|
}
|
|
260
|
-
function
|
|
260
|
+
function xe(n) {
|
|
261
261
|
if (E.length == 1)
|
|
262
|
-
|
|
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
|
-
|
|
265
|
+
m.set(w, C);
|
|
266
266
|
}
|
|
267
|
-
u.subVectors(
|
|
267
|
+
u.subVectors(m, x).multiplyScalar(t.rotateSpeed);
|
|
268
268
|
const g = t.domElement;
|
|
269
|
-
B(2 * Math.PI * u.x / g.clientHeight),
|
|
269
|
+
B(2 * Math.PI * u.x / g.clientHeight), Z(2 * Math.PI * u.y / g.clientHeight), x.copy(m);
|
|
270
270
|
}
|
|
271
|
-
function
|
|
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,
|
|
278
|
+
M.subVectors(b, f).multiplyScalar(t.panSpeed), A(M.x, M.y), f.copy(b);
|
|
279
279
|
}
|
|
280
|
-
function
|
|
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),
|
|
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
|
-
|
|
284
|
+
oe(F, z);
|
|
285
285
|
}
|
|
286
286
|
function Xe(n) {
|
|
287
|
-
t.enableZoom &&
|
|
287
|
+
t.enableZoom && ve(n), t.enablePan && be(n);
|
|
288
288
|
}
|
|
289
289
|
function Ve(n) {
|
|
290
|
-
t.enableZoom &&
|
|
290
|
+
t.enableZoom && ve(n), t.enableRotate && xe(n);
|
|
291
291
|
}
|
|
292
|
-
function
|
|
293
|
-
t.enabled !== !1 && (E.length === 0 && (t.domElement.setPointerCapture(n.pointerId), t.domElement.addEventListener("pointermove",
|
|
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
|
|
296
|
-
t.enabled !== !1 && (n.pointerType === "touch" ?
|
|
295
|
+
function ae(n) {
|
|
296
|
+
t.enabled !== !1 && (n.pointerType === "touch" ? et(n) : We(n));
|
|
297
297
|
}
|
|
298
298
|
function K(n) {
|
|
299
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
324
|
+
ue(n), o = i.PAN;
|
|
325
325
|
} else {
|
|
326
326
|
if (t.enableRotate === !1) return;
|
|
327
|
-
|
|
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
|
-
|
|
333
|
+
ge(n), o = i.ROTATE;
|
|
334
334
|
} else {
|
|
335
335
|
if (t.enablePan === !1) return;
|
|
336
|
-
|
|
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(
|
|
342
|
+
o !== i.NONE && t.dispatchEvent(ce);
|
|
343
343
|
}
|
|
344
|
-
function
|
|
344
|
+
function We(n) {
|
|
345
345
|
switch (o) {
|
|
346
346
|
case i.ROTATE:
|
|
347
347
|
if (t.enableRotate === !1) return;
|
|
348
|
-
|
|
348
|
+
$e(n);
|
|
349
349
|
break;
|
|
350
350
|
case i.DOLLY:
|
|
351
351
|
if (t.enableZoom === !1) return;
|
|
352
|
-
|
|
352
|
+
Ge(n);
|
|
353
353
|
break;
|
|
354
354
|
case i.PAN:
|
|
355
355
|
if (t.enablePan === !1) return;
|
|
356
|
-
|
|
356
|
+
Ye(n);
|
|
357
357
|
break;
|
|
358
358
|
}
|
|
359
359
|
}
|
|
360
|
-
function
|
|
361
|
-
t.enabled === !1 || t.enableZoom === !1 || o !== i.NONE || (n.preventDefault(), t.dispatchEvent(
|
|
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
|
|
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 && !
|
|
377
|
+
return n.ctrlKey && !se && (v.deltaY *= 10), v;
|
|
378
378
|
}
|
|
379
|
-
function
|
|
380
|
-
n.key === "Control" && (
|
|
379
|
+
function Qe(n) {
|
|
380
|
+
n.key === "Control" && (se = !0, document.addEventListener("keyup", Ee, { passive: !0, capture: !0 }));
|
|
381
381
|
}
|
|
382
|
-
function
|
|
383
|
-
n.key === "Control" && (
|
|
382
|
+
function Ee(n) {
|
|
383
|
+
n.key === "Control" && (se = !1, document.removeEventListener("keyup", Ee, { passive: !0, capture: !0 }));
|
|
384
384
|
}
|
|
385
|
-
function
|
|
386
|
-
t.enabled === !1 || t.enablePan === !1 ||
|
|
385
|
+
function re(n) {
|
|
386
|
+
t.enabled === !1 || t.enablePan === !1 || Ke(n);
|
|
387
387
|
}
|
|
388
|
-
function
|
|
389
|
-
switch (
|
|
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
|
-
|
|
394
|
+
fe(n), o = i.TOUCH_ROTATE;
|
|
395
395
|
break;
|
|
396
396
|
case G.PAN:
|
|
397
397
|
if (t.enablePan === !1) return;
|
|
398
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
421
|
+
o !== i.NONE && t.dispatchEvent(ce);
|
|
422
422
|
}
|
|
423
|
-
function
|
|
424
|
-
switch (
|
|
423
|
+
function et(n) {
|
|
424
|
+
switch (Ne(n), o) {
|
|
425
425
|
case i.TOUCH_ROTATE:
|
|
426
426
|
if (t.enableRotate === !1) return;
|
|
427
|
-
|
|
427
|
+
xe(n), t.update();
|
|
428
428
|
break;
|
|
429
429
|
case i.TOUCH_PAN:
|
|
430
430
|
if (t.enablePan === !1) return;
|
|
431
|
-
|
|
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
|
|
445
|
+
function Ce(n) {
|
|
446
446
|
t.enabled !== !1 && n.preventDefault();
|
|
447
447
|
}
|
|
448
|
-
function
|
|
448
|
+
function tt(n) {
|
|
449
449
|
E.push(n.pointerId);
|
|
450
450
|
}
|
|
451
|
-
function
|
|
452
|
-
delete
|
|
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
|
|
460
|
-
let g =
|
|
461
|
-
g === void 0 && (g = new
|
|
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
|
|
465
|
+
return q[g];
|
|
466
466
|
}
|
|
467
|
-
t.domElement.addEventListener("contextmenu",
|
|
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
|
|
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
|
|
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 } =
|
|
482
|
-
this.camera = new
|
|
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
|
|
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 =
|
|
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
|
|
494
|
+
const e = new y.AmbientLight(16777215, 0.4);
|
|
495
495
|
this.scene.add(e);
|
|
496
|
-
const s = new
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 } =
|
|
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
|
|
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
|
|
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 (!
|
|
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) *
|
|
586
|
-
y: (Math.random() - 0.5) *
|
|
587
|
-
z: (Math.random() - 0.5) *
|
|
588
|
-
},
|
|
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:
|
|
597
|
+
position: i,
|
|
591
598
|
velocity: { x: 0, y: 0, z: 0 },
|
|
592
599
|
mass: 1
|
|
593
|
-
},
|
|
594
|
-
{ ...e, position:
|
|
600
|
+
}, a = this.nodeFactory.createNode(
|
|
601
|
+
{ ...e, position: i },
|
|
595
602
|
s
|
|
596
603
|
);
|
|
597
|
-
return this.sceneManager.add(
|
|
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
|
-
|
|
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 (!
|
|
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
|
|
868
|
-
const
|
|
869
|
-
for (let
|
|
870
|
-
const
|
|
871
|
-
let
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
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
|
|
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 =
|
|
896
|
-
if (
|
|
897
|
-
|
|
898
|
-
|
|
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
|
|
901
|
-
|
|
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),
|
|
911
|
-
e.velocity.x -= t / r *
|
|
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
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
|
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
|
|
1070
|
+
const f = { x: 0, y: 0, z: 0 };
|
|
995
1071
|
for (const b of e)
|
|
996
|
-
u += b.mass,
|
|
997
|
-
return u > 0 && (
|
|
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:
|
|
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
|
|
1010
|
-
c[
|
|
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
|
|
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
|
|
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
|
|
1027
|
-
p.push(
|
|
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 && (
|
|
1106
|
+
return x > 0 && (m.x /= x, m.y /= x, m.z /= x), {
|
|
1031
1107
|
bounds: s,
|
|
1032
1108
|
size: i,
|
|
1033
|
-
centerOfMass:
|
|
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
|
|
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
|
|
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
|
|
1233
|
+
for (let h = 0; h < c.data.length; h += 4) {
|
|
1158
1234
|
const p = (Math.random() - 0.5) * 5;
|
|
1159
|
-
c.data[
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
1328
|
+
side: y.FrontSide,
|
|
1253
1329
|
depthWrite: !0,
|
|
1254
|
-
blending:
|
|
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
|
|
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
|
|
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
|
|
1290
|
-
return r.needsUpdate = !0, new
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1430
|
-
const c = this.getDefaultMaterial().clone(),
|
|
1431
|
-
return
|
|
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
|
-
},
|
|
1438
|
-
line:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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] ?
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1542
|
-
new
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 = { ...
|
|
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,
|
|
2710
|
-
if (
|
|
2711
|
-
const p = Math.max(0, Math.min(1, ((e - o.x) * r + (s - o.y) * c) /
|
|
2712
|
-
if (Math.sqrt(u * u +
|
|
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
|
|
2731
|
-
let x = p.x -
|
|
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
|
|
2735
|
-
|
|
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),
|
|
2741
|
-
if (!c || !
|
|
2742
|
-
let p =
|
|
2743
|
-
|
|
2744
|
-
const
|
|
2745
|
-
c.vx += b, c.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
|
|
2764
|
-
t.beginPath(), t.arc(c,
|
|
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
|
|
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
|
-
|
|
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,
|
|
2798
|
-
r.addColorStop(0, `rgba(${Math.min(255, c + 60)}, ${Math.min(255,
|
|
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
|
|
2876
|
+
let m = s.label, u = e.measureText(m).width;
|
|
2801
2877
|
if (u > x) {
|
|
2802
|
-
for (; u > x &&
|
|
2803
|
-
|
|
2804
|
-
|
|
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(
|
|
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(),
|
|
2906
|
-
const p = performance.now() - c, x = Math.min(p / r, 1),
|
|
2907
|
-
this.transform.x = o + (t - o) *
|
|
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
|
-
|
|
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
|
|
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 = { ...
|
|
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 ??
|
|
2989
|
-
this.options.lodSegments ??
|
|
2990
|
-
this.options.defaultNodeColor ??
|
|
2991
|
-
), this.edgeFactory = new
|
|
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 ??
|
|
2994
|
-
this.options.edgeOpacity ??
|
|
2995
|
-
), this.sceneManager = new
|
|
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 ??
|
|
2998
|
-
this.options.enableLOD ??
|
|
2999
|
-
), this.frustumCuller = new
|
|
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 ??
|
|
3002
|
-
), this.nodeManager = new
|
|
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
|
|
3088
|
+
), this.rendererManager = new bt(
|
|
3013
3089
|
this.sceneManager,
|
|
3014
3090
|
() => this.onSimulate(),
|
|
3015
3091
|
() => this.onRender(),
|
|
3016
|
-
this.options.targetFPS ??
|
|
3017
|
-
), this.raycasterManager = new
|
|
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
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
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(
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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
|
-
},
|
|
3238
|
-
const
|
|
3239
|
-
o.position.x =
|
|
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
|
-
},
|
|
3258
|
-
x: c.x +
|
|
3259
|
-
y: c.y +
|
|
3260
|
-
z: c.z +
|
|
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,
|
|
3262
|
-
const
|
|
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
|
|
3289
|
-
const a = (
|
|
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),
|
|
3305
|
-
c &&
|
|
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
|
|
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
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
|
3614
|
+
function Dt(d = 30) {
|
|
3529
3615
|
const e = [], s = [];
|
|
3530
|
-
for (let i = 0; i <
|
|
3531
|
-
const o = i <
|
|
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:
|
|
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 <
|
|
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:
|
|
3634
|
+
relationship: ee[Math.floor(Math.random() * ee.length)]
|
|
3549
3635
|
});
|
|
3550
3636
|
}
|
|
3551
|
-
const t = Math.floor(
|
|
3637
|
+
const t = Math.floor(d * 0.5);
|
|
3552
3638
|
for (let i = 0; i < t; i++) {
|
|
3553
|
-
const o = Math.floor(Math.random() *
|
|
3554
|
-
let a = Math.floor(Math.random() *
|
|
3555
|
-
o === a && (a = (a + 1) %
|
|
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:
|
|
3648
|
+
relationship: ee[Math.floor(Math.random() * ee.length)]
|
|
3563
3649
|
});
|
|
3564
3650
|
}
|
|
3565
3651
|
return { nodes: e, edges: s };
|
|
3566
3652
|
}
|
|
3567
|
-
function
|
|
3568
|
-
const e = [], s = [], t = Math.ceil(
|
|
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 <
|
|
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 <
|
|
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
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3692
|
+
P as DEFAULT_OPTIONS,
|
|
3693
|
+
Ht as ForceGraph3D,
|
|
3694
|
+
X as LODLevel,
|
|
3609
3695
|
D as createEdgeKey,
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
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
|