force-3d-graph 1.0.2 → 1.0.3
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 +803 -508
- package/dist/force-3d-graph.js.map +1 -1
- package/dist/force-3d-graph.umd.cjs +162 -12
- package/dist/force-3d-graph.umd.cjs.map +1 -1
- package/dist/index.d.ts +11 -1
- package/package.json +1 -1
package/dist/force-3d-graph.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
var st = Object.defineProperty;
|
|
2
|
-
var
|
|
3
|
-
var r = (c, e, s) =>
|
|
2
|
+
var nt = (c, e, s) => e in c ? st(c, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : c[e] = s;
|
|
3
|
+
var r = (c, e, s) => nt(c, typeof e != "symbol" ? e + "" : e, s);
|
|
4
4
|
import * as p from "three";
|
|
5
|
-
import { EventDispatcher as
|
|
6
|
-
const
|
|
5
|
+
import { EventDispatcher as ot, Vector3 as N, MOUSE as $, TOUCH as K, Spherical as ze, Quaternion as Ne, Vector2 as k, Ray as it, Plane as at, MathUtils as rt } from "three";
|
|
6
|
+
const I = {
|
|
7
7
|
backgroundColor: 657930,
|
|
8
8
|
cameraPosition: { x: 0, y: 0, z: 80 },
|
|
9
9
|
cameraFov: 75,
|
|
@@ -28,7 +28,7 @@ const L = {
|
|
|
28
28
|
targetFPS: 60,
|
|
29
29
|
maxVisibleNodes: 1e4
|
|
30
30
|
};
|
|
31
|
-
var
|
|
31
|
+
var X = /* @__PURE__ */ ((c) => (c[c.HIGH = 0] = "HIGH", c[c.MEDIUM = 1] = "MEDIUM", c[c.LOW = 2] = "LOW", c))(X || {});
|
|
32
32
|
function lt() {
|
|
33
33
|
const c = document.createElement("div");
|
|
34
34
|
return c.id = "force-graph-3d-container", c.style.cssText = `
|
|
@@ -43,7 +43,7 @@ function lt() {
|
|
|
43
43
|
function ct(c) {
|
|
44
44
|
return c && c instanceof HTMLElement ? c : (console.warn("[ForceGraph3D] No container provided, creating one automatically"), lt());
|
|
45
45
|
}
|
|
46
|
-
function
|
|
46
|
+
function Se(c) {
|
|
47
47
|
const e = c.getBoundingClientRect();
|
|
48
48
|
return {
|
|
49
49
|
width: e.width || window.innerWidth,
|
|
@@ -70,56 +70,56 @@ function dt(c) {
|
|
|
70
70
|
const e = c;
|
|
71
71
|
return typeof e.x == "number" && typeof e.y == "number" && typeof e.z == "number";
|
|
72
72
|
}
|
|
73
|
-
function
|
|
73
|
+
function A(c, e) {
|
|
74
74
|
return c === e ? `${c}-${e}` : c < e ? `${c}-${e}` : `${e}-${c}`;
|
|
75
75
|
}
|
|
76
|
-
const
|
|
77
|
-
class
|
|
76
|
+
const ke = { type: "change" }, re = { type: "start" }, Te = { type: "end" }, Q = new it(), Pe = new at(), pt = Math.cos(70 * rt.DEG2RAD);
|
|
77
|
+
class gt extends ot {
|
|
78
78
|
constructor(e, s) {
|
|
79
|
-
super(), this.object = e, this.domElement = s, this.domElement.style.touchAction = "none", this.enabled = !0, this.target = new N(), this.cursor = new N(), 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:
|
|
79
|
+
super(), this.object = e, this.domElement = s, this.domElement.style.touchAction = "none", this.enabled = !0, this.target = new N(), this.cursor = new N(), 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: K.ROTATE, TWO: K.DOLLY_PAN }, this.target0 = this.target.clone(), this.position0 = this.object.position.clone(), this.zoom0 = this.object.zoom, this._domElementKeyEvents = null, this.getPolarAngle = function() {
|
|
80
80
|
return l.phi;
|
|
81
81
|
}, this.getAzimuthalAngle = function() {
|
|
82
82
|
return l.theta;
|
|
83
83
|
}, this.getDistance = function() {
|
|
84
84
|
return this.object.position.distanceTo(this.target);
|
|
85
|
-
}, this.listenToKeyEvents = function(
|
|
86
|
-
|
|
85
|
+
}, this.listenToKeyEvents = function(i) {
|
|
86
|
+
i.addEventListener("keydown", ie), this._domElementKeyEvents = i;
|
|
87
87
|
}, this.stopListenToKeyEvents = function() {
|
|
88
|
-
this._domElementKeyEvents.removeEventListener("keydown",
|
|
88
|
+
this._domElementKeyEvents.removeEventListener("keydown", ie), this._domElementKeyEvents = null;
|
|
89
89
|
}, this.saveState = function() {
|
|
90
90
|
t.target0.copy(t.target), t.position0.copy(t.object.position), t.zoom0 = t.object.zoom;
|
|
91
91
|
}, this.reset = function() {
|
|
92
|
-
t.target.copy(t.target0), t.object.position.copy(t.position0), t.object.zoom = t.zoom0, t.object.updateProjectionMatrix(), t.dispatchEvent(
|
|
92
|
+
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 = n.NONE;
|
|
93
93
|
}, this.update = function() {
|
|
94
|
-
const
|
|
94
|
+
const i = new N(), d = new Ne().setFromUnitVectors(e.up, new N(0, 1, 0)), y = d.clone().invert(), v = new N(), C = new Ne(), F = new N(), S = 2 * Math.PI;
|
|
95
95
|
return function(tt = null) {
|
|
96
96
|
const Ce = t.object.position;
|
|
97
|
-
|
|
98
|
-
let
|
|
99
|
-
isFinite(
|
|
100
|
-
let
|
|
101
|
-
if (t.zoomToCursor &&
|
|
102
|
-
let
|
|
97
|
+
i.copy(Ce).sub(t.target), i.applyQuaternion(d), l.setFromVector3(i), t.autoRotate && o === n.NONE && G(He(tt)), t.enableDamping ? (l.theta += h.theta * t.dampingFactor, l.phi += h.phi * t.dampingFactor) : (l.theta += h.theta, l.phi += h.phi);
|
|
98
|
+
let L = t.minAzimuthAngle, O = t.maxAzimuthAngle;
|
|
99
|
+
isFinite(L) && isFinite(O) && (L < -Math.PI ? L += S : L > Math.PI && (L -= S), O < -Math.PI ? O += S : O > Math.PI && (O -= S), L <= O ? l.theta = Math.max(L, Math.min(O, l.theta)) : l.theta = l.theta > (L + O) / 2 ? Math.max(L, l.theta) : Math.min(O, l.theta)), l.phi = Math.max(t.minPolarAngle, Math.min(t.maxPolarAngle, l.phi)), l.makeSafe(), t.enableDamping === !0 ? t.target.addScaledVector(u, t.dampingFactor) : t.target.add(u), t.target.sub(t.cursor), t.target.clampLength(t.minTargetRadius, t.maxTargetRadius), t.target.add(t.cursor), t.zoomToCursor && H || t.object.isOrthographicCamera ? l.radius = ne(l.radius) : l.radius = ne(l.radius * g), i.setFromSpherical(l), i.applyQuaternion(y), Ce.copy(t.target).add(i), t.object.lookAt(t.target), t.enableDamping === !0 ? (h.theta *= 1 - t.dampingFactor, h.phi *= 1 - t.dampingFactor, u.multiplyScalar(1 - t.dampingFactor)) : (h.set(0, 0, 0), u.set(0, 0, 0));
|
|
100
|
+
let ae = !1;
|
|
101
|
+
if (t.zoomToCursor && H) {
|
|
102
|
+
let U = null;
|
|
103
103
|
if (t.object.isPerspectiveCamera) {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
t.object.position.addScaledVector(
|
|
104
|
+
const _ = i.length();
|
|
105
|
+
U = ne(_ * g);
|
|
106
|
+
const Z = _ - U;
|
|
107
|
+
t.object.position.addScaledVector(Y, Z), t.object.updateMatrixWorld();
|
|
108
108
|
} else if (t.object.isOrthographicCamera) {
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
109
|
+
const _ = new N(T.x, T.y, 0);
|
|
110
|
+
_.unproject(t.object), t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom / g)), t.object.updateProjectionMatrix(), ae = !0;
|
|
111
|
+
const Z = new N(T.x, T.y, 0);
|
|
112
|
+
Z.unproject(t.object), t.object.position.sub(Z).add(_), t.object.updateMatrixWorld(), U = i.length();
|
|
113
113
|
} else
|
|
114
114
|
console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."), t.zoomToCursor = !1;
|
|
115
|
-
|
|
116
|
-
} else t.object.isOrthographicCamera && (t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom /
|
|
117
|
-
return
|
|
115
|
+
U !== null && (this.screenSpacePanning ? t.target.set(0, 0, -1).transformDirection(t.object.matrix).multiplyScalar(U).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) : (Pe.setFromNormalAndCoplanarPoint(t.object.up, t.target), Q.intersectPlane(Pe, t.target))));
|
|
116
|
+
} else t.object.isOrthographicCamera && (t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom / g)), t.object.updateProjectionMatrix(), ae = !0);
|
|
117
|
+
return g = 1, H = !1, ae || v.distanceToSquared(t.object.position) > a || 8 * (1 - C.dot(t.object.quaternion)) > a || F.distanceToSquared(t.target) > 0 ? (t.dispatchEvent(ke), v.copy(t.object.position), C.copy(t.object.quaternion), F.copy(t.target), !0) : !1;
|
|
118
118
|
};
|
|
119
119
|
}(), this.dispose = function() {
|
|
120
|
-
t.domElement.removeEventListener("contextmenu", we), t.domElement.removeEventListener("pointerdown", xe), t.domElement.removeEventListener("pointercancel",
|
|
120
|
+
t.domElement.removeEventListener("contextmenu", we), t.domElement.removeEventListener("pointerdown", xe), t.domElement.removeEventListener("pointercancel", B), t.domElement.removeEventListener("wheel", ve), t.domElement.removeEventListener("pointermove", oe), t.domElement.removeEventListener("pointerup", B), t._domElementKeyEvents !== null && (t._domElementKeyEvents.removeEventListener("keydown", ie), t._domElementKeyEvents = null);
|
|
121
121
|
};
|
|
122
|
-
const t = this,
|
|
122
|
+
const t = this, n = {
|
|
123
123
|
NONE: -1,
|
|
124
124
|
ROTATE: 0,
|
|
125
125
|
DOLLY: 1,
|
|
@@ -129,342 +129,342 @@ class ut extends nt {
|
|
|
129
129
|
TOUCH_DOLLY_PAN: 5,
|
|
130
130
|
TOUCH_DOLLY_ROTATE: 6
|
|
131
131
|
};
|
|
132
|
-
let
|
|
133
|
-
const a = 1e-6, l = new
|
|
134
|
-
let
|
|
135
|
-
const
|
|
136
|
-
let
|
|
137
|
-
const
|
|
138
|
-
let
|
|
139
|
-
function He(
|
|
140
|
-
return
|
|
132
|
+
let o = n.NONE;
|
|
133
|
+
const a = 1e-6, l = new ze(), h = new ze();
|
|
134
|
+
let g = 1;
|
|
135
|
+
const u = new N(), b = new k(), x = new k(), f = new k(), m = new k(), M = new k(), E = new k(), z = new k(), R = new k(), P = new k(), Y = new N(), T = new k();
|
|
136
|
+
let H = !1;
|
|
137
|
+
const w = [], q = {};
|
|
138
|
+
let ee = !1;
|
|
139
|
+
function He(i) {
|
|
140
|
+
return i !== null ? 2 * Math.PI / 60 * t.autoRotateSpeed * i : 2 * Math.PI / 60 / 60 * t.autoRotateSpeed;
|
|
141
141
|
}
|
|
142
|
-
function
|
|
143
|
-
const
|
|
144
|
-
return Math.pow(0.95, t.zoomSpeed *
|
|
142
|
+
function V(i) {
|
|
143
|
+
const d = Math.abs(i * 0.01);
|
|
144
|
+
return Math.pow(0.95, t.zoomSpeed * d);
|
|
145
145
|
}
|
|
146
|
-
function
|
|
147
|
-
|
|
146
|
+
function G(i) {
|
|
147
|
+
h.theta -= i;
|
|
148
148
|
}
|
|
149
|
-
function W(
|
|
150
|
-
|
|
149
|
+
function W(i) {
|
|
150
|
+
h.phi -= i;
|
|
151
151
|
}
|
|
152
152
|
const le = function() {
|
|
153
|
-
const
|
|
154
|
-
return function(
|
|
155
|
-
|
|
153
|
+
const i = new N();
|
|
154
|
+
return function(y, v) {
|
|
155
|
+
i.setFromMatrixColumn(v, 0), i.multiplyScalar(-y), u.add(i);
|
|
156
156
|
};
|
|
157
157
|
}(), ce = function() {
|
|
158
|
-
const
|
|
159
|
-
return function(
|
|
160
|
-
t.screenSpacePanning === !0 ?
|
|
158
|
+
const i = new N();
|
|
159
|
+
return function(y, v) {
|
|
160
|
+
t.screenSpacePanning === !0 ? i.setFromMatrixColumn(v, 1) : (i.setFromMatrixColumn(v, 0), i.crossVectors(t.object.up, i)), i.multiplyScalar(y), u.add(i);
|
|
161
161
|
};
|
|
162
|
-
}(),
|
|
163
|
-
const
|
|
164
|
-
return function(
|
|
165
|
-
const
|
|
162
|
+
}(), j = function() {
|
|
163
|
+
const i = new N();
|
|
164
|
+
return function(y, v) {
|
|
165
|
+
const C = t.domElement;
|
|
166
166
|
if (t.object.isPerspectiveCamera) {
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
let S =
|
|
170
|
-
S *= Math.tan(t.object.fov / 2 * Math.PI / 180), le(2 *
|
|
171
|
-
} else t.object.isOrthographicCamera ? (le(
|
|
167
|
+
const F = t.object.position;
|
|
168
|
+
i.copy(F).sub(t.target);
|
|
169
|
+
let S = i.length();
|
|
170
|
+
S *= Math.tan(t.object.fov / 2 * Math.PI / 180), le(2 * y * S / C.clientHeight, t.object.matrix), ce(2 * v * S / C.clientHeight, t.object.matrix);
|
|
171
|
+
} else t.object.isOrthographicCamera ? (le(y * (t.object.right - t.object.left) / t.object.zoom / C.clientWidth, t.object.matrix), ce(v * (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);
|
|
172
172
|
};
|
|
173
173
|
}();
|
|
174
|
-
function
|
|
175
|
-
t.object.isPerspectiveCamera || t.object.isOrthographicCamera ?
|
|
174
|
+
function te(i) {
|
|
175
|
+
t.object.isPerspectiveCamera || t.object.isOrthographicCamera ? g /= i : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), t.enableZoom = !1);
|
|
176
176
|
}
|
|
177
|
-
function he(
|
|
178
|
-
t.object.isPerspectiveCamera || t.object.isOrthographicCamera ?
|
|
177
|
+
function he(i) {
|
|
178
|
+
t.object.isPerspectiveCamera || t.object.isOrthographicCamera ? g *= i : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), t.enableZoom = !1);
|
|
179
179
|
}
|
|
180
|
-
function
|
|
180
|
+
function se(i, d) {
|
|
181
181
|
if (!t.zoomToCursor)
|
|
182
182
|
return;
|
|
183
|
-
|
|
184
|
-
const
|
|
185
|
-
|
|
183
|
+
H = !0;
|
|
184
|
+
const y = t.domElement.getBoundingClientRect(), v = i - y.left, C = d - y.top, F = y.width, S = y.height;
|
|
185
|
+
T.x = v / F * 2 - 1, T.y = -(C / S) * 2 + 1, Y.set(T.x, T.y, 1).unproject(t.object).sub(t.object.position).normalize();
|
|
186
186
|
}
|
|
187
|
-
function
|
|
188
|
-
return Math.max(t.minDistance, Math.min(t.maxDistance,
|
|
187
|
+
function ne(i) {
|
|
188
|
+
return Math.max(t.minDistance, Math.min(t.maxDistance, i));
|
|
189
189
|
}
|
|
190
|
-
function de(
|
|
191
|
-
b.set(
|
|
190
|
+
function de(i) {
|
|
191
|
+
b.set(i.clientX, i.clientY);
|
|
192
192
|
}
|
|
193
|
-
function Ae(
|
|
194
|
-
|
|
193
|
+
function Ae(i) {
|
|
194
|
+
se(i.clientX, i.clientX), z.set(i.clientX, i.clientY);
|
|
195
195
|
}
|
|
196
|
-
function pe(
|
|
197
|
-
|
|
196
|
+
function pe(i) {
|
|
197
|
+
m.set(i.clientX, i.clientY);
|
|
198
198
|
}
|
|
199
|
-
function je(
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
|
|
199
|
+
function je(i) {
|
|
200
|
+
x.set(i.clientX, i.clientY), f.subVectors(x, b).multiplyScalar(t.rotateSpeed);
|
|
201
|
+
const d = t.domElement;
|
|
202
|
+
G(2 * Math.PI * f.x / d.clientHeight), W(2 * Math.PI * f.y / d.clientHeight), b.copy(x), t.update();
|
|
203
203
|
}
|
|
204
|
-
function De(
|
|
205
|
-
|
|
204
|
+
function De(i) {
|
|
205
|
+
R.set(i.clientX, i.clientY), P.subVectors(R, z), P.y > 0 ? te(V(P.y)) : P.y < 0 && he(V(P.y)), z.copy(R), t.update();
|
|
206
206
|
}
|
|
207
|
-
function $e(
|
|
208
|
-
M.set(
|
|
207
|
+
function $e(i) {
|
|
208
|
+
M.set(i.clientX, i.clientY), E.subVectors(M, m).multiplyScalar(t.panSpeed), j(E.x, E.y), m.copy(M), t.update();
|
|
209
209
|
}
|
|
210
|
-
function Ke(
|
|
211
|
-
|
|
210
|
+
function Ke(i) {
|
|
211
|
+
se(i.clientX, i.clientY), i.deltaY < 0 ? he(V(i.deltaY)) : i.deltaY > 0 && te(V(i.deltaY)), t.update();
|
|
212
212
|
}
|
|
213
|
-
function
|
|
214
|
-
let
|
|
215
|
-
switch (
|
|
213
|
+
function Ye(i) {
|
|
214
|
+
let d = !1;
|
|
215
|
+
switch (i.code) {
|
|
216
216
|
case t.keys.UP:
|
|
217
|
-
|
|
217
|
+
i.ctrlKey || i.metaKey || i.shiftKey ? W(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : j(0, t.keyPanSpeed), d = !0;
|
|
218
218
|
break;
|
|
219
219
|
case t.keys.BOTTOM:
|
|
220
|
-
|
|
220
|
+
i.ctrlKey || i.metaKey || i.shiftKey ? W(-2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : j(0, -t.keyPanSpeed), d = !0;
|
|
221
221
|
break;
|
|
222
222
|
case t.keys.LEFT:
|
|
223
|
-
|
|
223
|
+
i.ctrlKey || i.metaKey || i.shiftKey ? G(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : j(t.keyPanSpeed, 0), d = !0;
|
|
224
224
|
break;
|
|
225
225
|
case t.keys.RIGHT:
|
|
226
|
-
|
|
226
|
+
i.ctrlKey || i.metaKey || i.shiftKey ? G(-2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : j(-t.keyPanSpeed, 0), d = !0;
|
|
227
227
|
break;
|
|
228
228
|
}
|
|
229
|
-
|
|
229
|
+
d && (i.preventDefault(), t.update());
|
|
230
230
|
}
|
|
231
|
-
function
|
|
232
|
-
if (
|
|
233
|
-
b.set(
|
|
231
|
+
function ge(i) {
|
|
232
|
+
if (w.length === 1)
|
|
233
|
+
b.set(i.pageX, i.pageY);
|
|
234
234
|
else {
|
|
235
|
-
const
|
|
236
|
-
b.set(
|
|
235
|
+
const d = D(i), y = 0.5 * (i.pageX + d.x), v = 0.5 * (i.pageY + d.y);
|
|
236
|
+
b.set(y, v);
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
|
-
function
|
|
240
|
-
if (
|
|
241
|
-
|
|
239
|
+
function ue(i) {
|
|
240
|
+
if (w.length === 1)
|
|
241
|
+
m.set(i.pageX, i.pageY);
|
|
242
242
|
else {
|
|
243
|
-
const
|
|
244
|
-
|
|
243
|
+
const d = D(i), y = 0.5 * (i.pageX + d.x), v = 0.5 * (i.pageY + d.y);
|
|
244
|
+
m.set(y, v);
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
|
-
function me(
|
|
248
|
-
const
|
|
249
|
-
|
|
247
|
+
function me(i) {
|
|
248
|
+
const d = D(i), y = i.pageX - d.x, v = i.pageY - d.y, C = Math.sqrt(y * y + v * v);
|
|
249
|
+
z.set(0, C);
|
|
250
250
|
}
|
|
251
|
-
function
|
|
252
|
-
t.enableZoom && me(
|
|
251
|
+
function Ge(i) {
|
|
252
|
+
t.enableZoom && me(i), t.enablePan && ue(i);
|
|
253
253
|
}
|
|
254
|
-
function Be(
|
|
255
|
-
t.enableZoom && me(
|
|
254
|
+
function Be(i) {
|
|
255
|
+
t.enableZoom && me(i), t.enableRotate && ge(i);
|
|
256
256
|
}
|
|
257
|
-
function fe(
|
|
258
|
-
if (
|
|
259
|
-
|
|
257
|
+
function fe(i) {
|
|
258
|
+
if (w.length == 1)
|
|
259
|
+
x.set(i.pageX, i.pageY);
|
|
260
260
|
else {
|
|
261
|
-
const
|
|
262
|
-
|
|
261
|
+
const y = D(i), v = 0.5 * (i.pageX + y.x), C = 0.5 * (i.pageY + y.y);
|
|
262
|
+
x.set(v, C);
|
|
263
263
|
}
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
|
|
264
|
+
f.subVectors(x, b).multiplyScalar(t.rotateSpeed);
|
|
265
|
+
const d = t.domElement;
|
|
266
|
+
G(2 * Math.PI * f.x / d.clientHeight), W(2 * Math.PI * f.y / d.clientHeight), b.copy(x);
|
|
267
267
|
}
|
|
268
|
-
function ye(
|
|
269
|
-
if (
|
|
270
|
-
M.set(
|
|
268
|
+
function ye(i) {
|
|
269
|
+
if (w.length === 1)
|
|
270
|
+
M.set(i.pageX, i.pageY);
|
|
271
271
|
else {
|
|
272
|
-
const
|
|
273
|
-
M.set(
|
|
272
|
+
const d = D(i), y = 0.5 * (i.pageX + d.x), v = 0.5 * (i.pageY + d.y);
|
|
273
|
+
M.set(y, v);
|
|
274
274
|
}
|
|
275
|
-
|
|
275
|
+
E.subVectors(M, m).multiplyScalar(t.panSpeed), j(E.x, E.y), m.copy(M);
|
|
276
276
|
}
|
|
277
|
-
function be(
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
const
|
|
281
|
-
|
|
277
|
+
function be(i) {
|
|
278
|
+
const d = D(i), y = i.pageX - d.x, v = i.pageY - d.y, C = Math.sqrt(y * y + v * v);
|
|
279
|
+
R.set(0, C), P.set(0, Math.pow(R.y / z.y, t.zoomSpeed)), te(P.y), z.copy(R);
|
|
280
|
+
const F = (i.pageX + d.x) * 0.5, S = (i.pageY + d.y) * 0.5;
|
|
281
|
+
se(F, S);
|
|
282
282
|
}
|
|
283
|
-
function Ue(
|
|
284
|
-
t.enableZoom && be(
|
|
283
|
+
function Ue(i) {
|
|
284
|
+
t.enableZoom && be(i), t.enablePan && ye(i);
|
|
285
285
|
}
|
|
286
|
-
function _e(
|
|
287
|
-
t.enableZoom && be(
|
|
286
|
+
function _e(i) {
|
|
287
|
+
t.enableZoom && be(i), t.enableRotate && fe(i);
|
|
288
288
|
}
|
|
289
|
-
function xe(
|
|
290
|
-
t.enabled !== !1 && (
|
|
289
|
+
function xe(i) {
|
|
290
|
+
t.enabled !== !1 && (w.length === 0 && (t.domElement.setPointerCapture(i.pointerId), t.domElement.addEventListener("pointermove", oe), t.domElement.addEventListener("pointerup", B)), Je(i), i.pointerType === "touch" ? Ze(i) : Xe(i));
|
|
291
291
|
}
|
|
292
|
-
function
|
|
293
|
-
t.enabled !== !1 && (
|
|
292
|
+
function oe(i) {
|
|
293
|
+
t.enabled !== !1 && (i.pointerType === "touch" ? Qe(i) : qe(i));
|
|
294
294
|
}
|
|
295
|
-
function
|
|
296
|
-
et(
|
|
295
|
+
function B(i) {
|
|
296
|
+
et(i), w.length === 0 && (t.domElement.releasePointerCapture(i.pointerId), t.domElement.removeEventListener("pointermove", oe), t.domElement.removeEventListener("pointerup", B)), t.dispatchEvent(Te), o = n.NONE;
|
|
297
297
|
}
|
|
298
|
-
function
|
|
299
|
-
let
|
|
300
|
-
switch (
|
|
298
|
+
function Xe(i) {
|
|
299
|
+
let d;
|
|
300
|
+
switch (i.button) {
|
|
301
301
|
case 0:
|
|
302
|
-
|
|
302
|
+
d = t.mouseButtons.LEFT;
|
|
303
303
|
break;
|
|
304
304
|
case 1:
|
|
305
|
-
|
|
305
|
+
d = t.mouseButtons.MIDDLE;
|
|
306
306
|
break;
|
|
307
307
|
case 2:
|
|
308
|
-
|
|
308
|
+
d = t.mouseButtons.RIGHT;
|
|
309
309
|
break;
|
|
310
310
|
default:
|
|
311
|
-
|
|
311
|
+
d = -1;
|
|
312
312
|
}
|
|
313
|
-
switch (
|
|
314
|
-
case
|
|
313
|
+
switch (d) {
|
|
314
|
+
case $.DOLLY:
|
|
315
315
|
if (t.enableZoom === !1) return;
|
|
316
|
-
Ae(
|
|
316
|
+
Ae(i), o = n.DOLLY;
|
|
317
317
|
break;
|
|
318
|
-
case
|
|
319
|
-
if (
|
|
318
|
+
case $.ROTATE:
|
|
319
|
+
if (i.ctrlKey || i.metaKey || i.shiftKey) {
|
|
320
320
|
if (t.enablePan === !1) return;
|
|
321
|
-
pe(
|
|
321
|
+
pe(i), o = n.PAN;
|
|
322
322
|
} else {
|
|
323
323
|
if (t.enableRotate === !1) return;
|
|
324
|
-
de(
|
|
324
|
+
de(i), o = n.ROTATE;
|
|
325
325
|
}
|
|
326
326
|
break;
|
|
327
|
-
case
|
|
328
|
-
if (
|
|
327
|
+
case $.PAN:
|
|
328
|
+
if (i.ctrlKey || i.metaKey || i.shiftKey) {
|
|
329
329
|
if (t.enableRotate === !1) return;
|
|
330
|
-
de(
|
|
330
|
+
de(i), o = n.ROTATE;
|
|
331
331
|
} else {
|
|
332
332
|
if (t.enablePan === !1) return;
|
|
333
|
-
pe(
|
|
333
|
+
pe(i), o = n.PAN;
|
|
334
334
|
}
|
|
335
335
|
break;
|
|
336
336
|
default:
|
|
337
|
-
|
|
337
|
+
o = n.NONE;
|
|
338
338
|
}
|
|
339
|
-
|
|
339
|
+
o !== n.NONE && t.dispatchEvent(re);
|
|
340
340
|
}
|
|
341
|
-
function
|
|
342
|
-
switch (
|
|
343
|
-
case
|
|
341
|
+
function qe(i) {
|
|
342
|
+
switch (o) {
|
|
343
|
+
case n.ROTATE:
|
|
344
344
|
if (t.enableRotate === !1) return;
|
|
345
|
-
je(
|
|
345
|
+
je(i);
|
|
346
346
|
break;
|
|
347
|
-
case
|
|
347
|
+
case n.DOLLY:
|
|
348
348
|
if (t.enableZoom === !1) return;
|
|
349
|
-
De(
|
|
349
|
+
De(i);
|
|
350
350
|
break;
|
|
351
|
-
case
|
|
351
|
+
case n.PAN:
|
|
352
352
|
if (t.enablePan === !1) return;
|
|
353
|
-
$e(
|
|
353
|
+
$e(i);
|
|
354
354
|
break;
|
|
355
355
|
}
|
|
356
356
|
}
|
|
357
|
-
function ve(
|
|
358
|
-
t.enabled === !1 || t.enableZoom === !1 ||
|
|
357
|
+
function ve(i) {
|
|
358
|
+
t.enabled === !1 || t.enableZoom === !1 || o !== n.NONE || (i.preventDefault(), t.dispatchEvent(re), Ke(Ve(i)), t.dispatchEvent(Te));
|
|
359
359
|
}
|
|
360
|
-
function
|
|
361
|
-
const
|
|
362
|
-
clientX:
|
|
363
|
-
clientY:
|
|
364
|
-
deltaY:
|
|
360
|
+
function Ve(i) {
|
|
361
|
+
const d = i.deltaMode, y = {
|
|
362
|
+
clientX: i.clientX,
|
|
363
|
+
clientY: i.clientY,
|
|
364
|
+
deltaY: i.deltaY
|
|
365
365
|
};
|
|
366
|
-
switch (
|
|
366
|
+
switch (d) {
|
|
367
367
|
case 1:
|
|
368
|
-
|
|
368
|
+
y.deltaY *= 16;
|
|
369
369
|
break;
|
|
370
370
|
case 2:
|
|
371
|
-
|
|
371
|
+
y.deltaY *= 100;
|
|
372
372
|
break;
|
|
373
373
|
}
|
|
374
|
-
return
|
|
374
|
+
return i.ctrlKey && !ee && (y.deltaY *= 10), y;
|
|
375
375
|
}
|
|
376
|
-
function
|
|
377
|
-
|
|
376
|
+
function We(i) {
|
|
377
|
+
i.key === "Control" && (ee = !0, document.addEventListener("keyup", Me, { passive: !0, capture: !0 }));
|
|
378
378
|
}
|
|
379
|
-
function Me(
|
|
380
|
-
|
|
379
|
+
function Me(i) {
|
|
380
|
+
i.key === "Control" && (ee = !1, document.removeEventListener("keyup", Me, { passive: !0, capture: !0 }));
|
|
381
381
|
}
|
|
382
|
-
function
|
|
383
|
-
t.enabled === !1 || t.enablePan === !1 ||
|
|
382
|
+
function ie(i) {
|
|
383
|
+
t.enabled === !1 || t.enablePan === !1 || Ye(i);
|
|
384
384
|
}
|
|
385
|
-
function Ze(
|
|
386
|
-
switch (Ee(
|
|
385
|
+
function Ze(i) {
|
|
386
|
+
switch (Ee(i), w.length) {
|
|
387
387
|
case 1:
|
|
388
388
|
switch (t.touches.ONE) {
|
|
389
|
-
case
|
|
389
|
+
case K.ROTATE:
|
|
390
390
|
if (t.enableRotate === !1) return;
|
|
391
|
-
|
|
391
|
+
ge(i), o = n.TOUCH_ROTATE;
|
|
392
392
|
break;
|
|
393
|
-
case
|
|
393
|
+
case K.PAN:
|
|
394
394
|
if (t.enablePan === !1) return;
|
|
395
|
-
|
|
395
|
+
ue(i), o = n.TOUCH_PAN;
|
|
396
396
|
break;
|
|
397
397
|
default:
|
|
398
|
-
|
|
398
|
+
o = n.NONE;
|
|
399
399
|
}
|
|
400
400
|
break;
|
|
401
401
|
case 2:
|
|
402
402
|
switch (t.touches.TWO) {
|
|
403
|
-
case
|
|
403
|
+
case K.DOLLY_PAN:
|
|
404
404
|
if (t.enableZoom === !1 && t.enablePan === !1) return;
|
|
405
|
-
|
|
405
|
+
Ge(i), o = n.TOUCH_DOLLY_PAN;
|
|
406
406
|
break;
|
|
407
|
-
case
|
|
407
|
+
case K.DOLLY_ROTATE:
|
|
408
408
|
if (t.enableZoom === !1 && t.enableRotate === !1) return;
|
|
409
|
-
Be(
|
|
409
|
+
Be(i), o = n.TOUCH_DOLLY_ROTATE;
|
|
410
410
|
break;
|
|
411
411
|
default:
|
|
412
|
-
|
|
412
|
+
o = n.NONE;
|
|
413
413
|
}
|
|
414
414
|
break;
|
|
415
415
|
default:
|
|
416
|
-
|
|
416
|
+
o = n.NONE;
|
|
417
417
|
}
|
|
418
|
-
|
|
418
|
+
o !== n.NONE && t.dispatchEvent(re);
|
|
419
419
|
}
|
|
420
|
-
function Qe(
|
|
421
|
-
switch (Ee(
|
|
422
|
-
case
|
|
420
|
+
function Qe(i) {
|
|
421
|
+
switch (Ee(i), o) {
|
|
422
|
+
case n.TOUCH_ROTATE:
|
|
423
423
|
if (t.enableRotate === !1) return;
|
|
424
|
-
fe(
|
|
424
|
+
fe(i), t.update();
|
|
425
425
|
break;
|
|
426
|
-
case
|
|
426
|
+
case n.TOUCH_PAN:
|
|
427
427
|
if (t.enablePan === !1) return;
|
|
428
|
-
ye(
|
|
428
|
+
ye(i), t.update();
|
|
429
429
|
break;
|
|
430
|
-
case
|
|
430
|
+
case n.TOUCH_DOLLY_PAN:
|
|
431
431
|
if (t.enableZoom === !1 && t.enablePan === !1) return;
|
|
432
|
-
Ue(
|
|
432
|
+
Ue(i), t.update();
|
|
433
433
|
break;
|
|
434
|
-
case
|
|
434
|
+
case n.TOUCH_DOLLY_ROTATE:
|
|
435
435
|
if (t.enableZoom === !1 && t.enableRotate === !1) return;
|
|
436
|
-
_e(
|
|
436
|
+
_e(i), t.update();
|
|
437
437
|
break;
|
|
438
438
|
default:
|
|
439
|
-
|
|
439
|
+
o = n.NONE;
|
|
440
440
|
}
|
|
441
441
|
}
|
|
442
|
-
function we(
|
|
443
|
-
t.enabled !== !1 &&
|
|
442
|
+
function we(i) {
|
|
443
|
+
t.enabled !== !1 && i.preventDefault();
|
|
444
444
|
}
|
|
445
|
-
function Je(
|
|
446
|
-
|
|
445
|
+
function Je(i) {
|
|
446
|
+
w.push(i.pointerId);
|
|
447
447
|
}
|
|
448
|
-
function et(
|
|
449
|
-
delete
|
|
450
|
-
for (let
|
|
451
|
-
if (
|
|
452
|
-
|
|
448
|
+
function et(i) {
|
|
449
|
+
delete q[i.pointerId];
|
|
450
|
+
for (let d = 0; d < w.length; d++)
|
|
451
|
+
if (w[d] == i.pointerId) {
|
|
452
|
+
w.splice(d, 1);
|
|
453
453
|
return;
|
|
454
454
|
}
|
|
455
455
|
}
|
|
456
|
-
function Ee(
|
|
457
|
-
let
|
|
458
|
-
|
|
456
|
+
function Ee(i) {
|
|
457
|
+
let d = q[i.pointerId];
|
|
458
|
+
d === void 0 && (d = new k(), q[i.pointerId] = d), d.set(i.pageX, i.pageY);
|
|
459
459
|
}
|
|
460
|
-
function
|
|
461
|
-
const
|
|
462
|
-
return
|
|
460
|
+
function D(i) {
|
|
461
|
+
const d = i.pointerId === w[0] ? w[1] : w[0];
|
|
462
|
+
return q[d];
|
|
463
463
|
}
|
|
464
|
-
t.domElement.addEventListener("contextmenu", we), t.domElement.addEventListener("pointerdown", xe), t.domElement.addEventListener("pointercancel",
|
|
464
|
+
t.domElement.addEventListener("contextmenu", we), t.domElement.addEventListener("pointerdown", xe), t.domElement.addEventListener("pointercancel", B), t.domElement.addEventListener("wheel", ve, { passive: !1 }), document.addEventListener("keydown", We, { passive: !0, capture: !0 }), this.update();
|
|
465
465
|
}
|
|
466
466
|
}
|
|
467
|
-
class
|
|
467
|
+
class ut {
|
|
468
468
|
constructor(e, s) {
|
|
469
469
|
r(this, "scene");
|
|
470
470
|
r(this, "camera");
|
|
@@ -475,14 +475,14 @@ class gt {
|
|
|
475
475
|
this.container = e, this.scene = new p.Scene(), this.scene.background = new p.Color(
|
|
476
476
|
s.backgroundColor ?? 657930
|
|
477
477
|
);
|
|
478
|
-
const { width: t, height:
|
|
479
|
-
this.camera = new p.PerspectiveCamera(
|
|
478
|
+
const { width: t, height: n } = Se(e), o = s.cameraFov ?? 75;
|
|
479
|
+
this.camera = new p.PerspectiveCamera(o, t / n, 0.1, 2e3);
|
|
480
480
|
const a = s.cameraPosition ?? { x: 0, y: 0, z: 80 };
|
|
481
481
|
this.camera.position.set(a.x, a.y, a.z), this.renderer = new p.WebGLRenderer({
|
|
482
482
|
antialias: !0,
|
|
483
483
|
alpha: !0,
|
|
484
484
|
powerPreference: "high-performance"
|
|
485
|
-
}), this.renderer.setSize(t,
|
|
485
|
+
}), this.renderer.setSize(t, n), this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)), this.renderer.toneMapping = p.ACESFilmicToneMapping, this.renderer.toneMappingExposure = 1, this.renderer.shadowMap.enabled = !0, this.renderer.shadowMap.type = p.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);
|
|
486
486
|
}
|
|
487
487
|
/**
|
|
488
488
|
* Sets up scene lighting for gradient glass on dark background
|
|
@@ -494,10 +494,10 @@ class gt {
|
|
|
494
494
|
s.position.set(50, 60, 40), s.castShadow = !0, s.shadow.mapSize.width = 1024, s.shadow.mapSize.height = 1024, this.scene.add(s);
|
|
495
495
|
const t = new p.DirectionalLight(16773344, 0.4);
|
|
496
496
|
t.position.set(-50, 30, -40), this.scene.add(t);
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
const
|
|
500
|
-
|
|
497
|
+
const n = new p.DirectionalLight(16777215, 0.3);
|
|
498
|
+
n.position.set(0, -30, -50), this.scene.add(n);
|
|
499
|
+
const o = new p.PointLight(16750950, 0.5, 150);
|
|
500
|
+
o.position.set(40, 20, 40), this.scene.add(o);
|
|
501
501
|
const a = new p.PointLight(16764057, 0.4, 150);
|
|
502
502
|
a.position.set(-40, -20, 40), this.scene.add(a);
|
|
503
503
|
const l = new p.PointLight(6724095, 0.2, 100);
|
|
@@ -507,7 +507,7 @@ class gt {
|
|
|
507
507
|
* Handle window resize
|
|
508
508
|
*/
|
|
509
509
|
onWindowResize() {
|
|
510
|
-
const { width: e, height: s } =
|
|
510
|
+
const { width: e, height: s } = Se(this.container);
|
|
511
511
|
this.camera.aspect = e / s, this.camera.updateProjectionMatrix(), this.renderer.setSize(e, s);
|
|
512
512
|
}
|
|
513
513
|
/**
|
|
@@ -582,16 +582,16 @@ class mt {
|
|
|
582
582
|
x: (Math.random() - 0.5) * 50,
|
|
583
583
|
y: (Math.random() - 0.5) * 50,
|
|
584
584
|
z: (Math.random() - 0.5) * 50
|
|
585
|
-
},
|
|
585
|
+
}, n = {
|
|
586
586
|
...e,
|
|
587
587
|
position: t,
|
|
588
588
|
velocity: { x: 0, y: 0, z: 0 },
|
|
589
589
|
mass: 1
|
|
590
|
-
},
|
|
590
|
+
}, o = this.nodeFactory.createNode(
|
|
591
591
|
{ ...e, position: t },
|
|
592
592
|
s
|
|
593
593
|
);
|
|
594
|
-
return this.sceneManager.add(
|
|
594
|
+
return this.sceneManager.add(o.group), this.nodes.set(e.id, n), this.nodeObjects.set(e.id, o), !0;
|
|
595
595
|
}
|
|
596
596
|
/**
|
|
597
597
|
* Removes a node from the graph
|
|
@@ -605,17 +605,17 @@ class mt {
|
|
|
605
605
|
* Updates a node's properties
|
|
606
606
|
*/
|
|
607
607
|
updateNode(e, s) {
|
|
608
|
-
const t = this.nodes.get(e),
|
|
609
|
-
return !t || !
|
|
610
|
-
|
|
608
|
+
const t = this.nodes.get(e), n = this.nodeObjects.get(e);
|
|
609
|
+
return !t || !n ? (console.warn(`[ForceGraph3D] Node "${e}" not found`), !1) : (s.label !== void 0 && (t.label = s.label, this.nodeFactory.updateNodeLabel(n, s.label)), s.color !== void 0 && (t.color = s.color, this.nodeFactory.updateNodeColor(n, s.color)), Object.keys(s).forEach((o) => {
|
|
610
|
+
o !== "id" && o !== "label" && o !== "color" && o !== "position" && (t[o] = s[o]);
|
|
611
611
|
}), !0);
|
|
612
612
|
}
|
|
613
613
|
/**
|
|
614
614
|
* Updates a node's position (called by physics engine)
|
|
615
615
|
*/
|
|
616
616
|
updateNodePosition(e, s) {
|
|
617
|
-
const t = this.nodes.get(e),
|
|
618
|
-
t &&
|
|
617
|
+
const t = this.nodes.get(e), n = this.nodeObjects.get(e);
|
|
618
|
+
t && n && (t.position = s, n.group.position.set(s.x, s.y, s.z));
|
|
619
619
|
}
|
|
620
620
|
/**
|
|
621
621
|
* Updates a node's LOD level
|
|
@@ -696,7 +696,7 @@ class ft {
|
|
|
696
696
|
* Checks if an edge exists
|
|
697
697
|
*/
|
|
698
698
|
hasEdge(e, s) {
|
|
699
|
-
const t =
|
|
699
|
+
const t = A(e, s);
|
|
700
700
|
return this.edgeKeySet.has(t);
|
|
701
701
|
}
|
|
702
702
|
/**
|
|
@@ -710,44 +710,44 @@ class ft {
|
|
|
710
710
|
return console.warn(`[ForceGraph3D] Source node "${e.source}" does not exist`), !1;
|
|
711
711
|
if (!this.nodeManager.hasNode(e.target))
|
|
712
712
|
return console.warn(`[ForceGraph3D] Target node "${e.target}" does not exist`), !1;
|
|
713
|
-
const s =
|
|
713
|
+
const s = A(e.source, e.target);
|
|
714
714
|
if (this.edgeKeySet.has(s))
|
|
715
715
|
return console.warn(`[ForceGraph3D] Edge "${e.source}" -> "${e.target}" already exists`), !1;
|
|
716
|
-
const t = this.nodeManager.getNode(e.source),
|
|
716
|
+
const t = this.nodeManager.getNode(e.source), n = this.nodeManager.getNode(e.target), o = this.edgeFactory.createEdge(
|
|
717
717
|
e,
|
|
718
718
|
t,
|
|
719
|
-
|
|
719
|
+
n,
|
|
720
720
|
t.position,
|
|
721
|
-
|
|
721
|
+
n.position
|
|
722
722
|
);
|
|
723
|
-
return this.sceneManager.add(
|
|
723
|
+
return this.sceneManager.add(o.line), this.edges.push(e), this.edgeObjects.push(o), this.edgeKeySet.add(s), !0;
|
|
724
724
|
}
|
|
725
725
|
/**
|
|
726
726
|
* Removes an edge from the graph
|
|
727
727
|
* @returns true if removed, false if not found
|
|
728
728
|
*/
|
|
729
729
|
removeEdge(e, s) {
|
|
730
|
-
const t =
|
|
730
|
+
const t = A(e, s);
|
|
731
731
|
if (!this.edgeKeySet.has(t))
|
|
732
732
|
return !1;
|
|
733
|
-
const
|
|
734
|
-
(a) =>
|
|
733
|
+
const n = this.edges.findIndex(
|
|
734
|
+
(a) => A(a.source, a.target) === t
|
|
735
735
|
);
|
|
736
|
-
if (
|
|
736
|
+
if (n === -1)
|
|
737
737
|
return !1;
|
|
738
|
-
const
|
|
739
|
-
return this.sceneManager.remove(
|
|
738
|
+
const o = this.edgeObjects[n];
|
|
739
|
+
return this.sceneManager.remove(o.line), this.edgeFactory.disposeEdge(o), this.edges.splice(n, 1), this.edgeObjects.splice(n, 1), this.edgeKeySet.delete(t), this.highlightedEdgeKey === t && (this.highlightedEdgeKey = null), !0;
|
|
740
740
|
}
|
|
741
741
|
/**
|
|
742
742
|
* Highlights an edge
|
|
743
743
|
*/
|
|
744
744
|
highlightEdge(e, s) {
|
|
745
|
-
const t =
|
|
745
|
+
const t = A(e, s);
|
|
746
746
|
this.highlightedEdgeKey && this.highlightedEdgeKey !== t && this.unhighlightCurrentEdge();
|
|
747
|
-
const
|
|
748
|
-
(
|
|
747
|
+
const n = this.edges.findIndex(
|
|
748
|
+
(o) => A(o.source, o.target) === t
|
|
749
749
|
);
|
|
750
|
-
|
|
750
|
+
n !== -1 && (this.edgeFactory.highlightEdge(this.edgeObjects[n]), this.highlightedEdgeKey = t);
|
|
751
751
|
}
|
|
752
752
|
/**
|
|
753
753
|
* Unhighlights the currently highlighted edge
|
|
@@ -755,7 +755,7 @@ class ft {
|
|
|
755
755
|
unhighlightCurrentEdge() {
|
|
756
756
|
if (!this.highlightedEdgeKey) return;
|
|
757
757
|
const e = this.edges.findIndex(
|
|
758
|
-
(s) =>
|
|
758
|
+
(s) => A(s.source, s.target) === this.highlightedEdgeKey
|
|
759
759
|
);
|
|
760
760
|
e !== -1 && this.edgeFactory.unhighlightEdge(this.edgeObjects[e]), this.highlightedEdgeKey = null;
|
|
761
761
|
}
|
|
@@ -790,11 +790,11 @@ class ft {
|
|
|
790
790
|
*/
|
|
791
791
|
updateEdgePositions() {
|
|
792
792
|
this.edgeObjects.forEach((e, s) => {
|
|
793
|
-
const t = this.edges[s],
|
|
794
|
-
|
|
793
|
+
const t = this.edges[s], n = this.nodeManager.getNode(t.source), o = this.nodeManager.getNode(t.target);
|
|
794
|
+
n && o && this.edgeFactory.updateEdgePositions(
|
|
795
795
|
e,
|
|
796
|
-
|
|
797
|
-
|
|
796
|
+
n.position,
|
|
797
|
+
o.position
|
|
798
798
|
);
|
|
799
799
|
});
|
|
800
800
|
}
|
|
@@ -831,7 +831,7 @@ class ft {
|
|
|
831
831
|
this.clear();
|
|
832
832
|
}
|
|
833
833
|
}
|
|
834
|
-
class
|
|
834
|
+
class Le {
|
|
835
835
|
constructor(e, s, t = {}) {
|
|
836
836
|
r(this, "nodes");
|
|
837
837
|
r(this, "edges");
|
|
@@ -862,13 +862,13 @@ class Oe {
|
|
|
862
862
|
calculateRepulsionBruteForce() {
|
|
863
863
|
const e = Array.from(this.nodes.values()), s = e.length;
|
|
864
864
|
for (let t = 0; t < s; t++) {
|
|
865
|
-
const
|
|
866
|
-
for (let
|
|
867
|
-
const a = e[
|
|
868
|
-
let
|
|
869
|
-
|
|
870
|
-
const b = Math.sqrt(
|
|
871
|
-
|
|
865
|
+
const n = e[t];
|
|
866
|
+
for (let o = t + 1; o < s; o++) {
|
|
867
|
+
const a = e[o], l = a.position.x - n.position.x, h = a.position.y - n.position.y, g = a.position.z - n.position.z;
|
|
868
|
+
let u = l * l + h * h + g * g;
|
|
869
|
+
u < 0.01 && (u = 0.01);
|
|
870
|
+
const b = Math.sqrt(u), x = this.repulsionStrength * this.alpha / u, f = l / b * x, m = h / b * x, M = g / b * x;
|
|
871
|
+
n.velocity.x -= f / n.mass, n.velocity.y -= m / n.mass, n.velocity.z -= M / n.mass, a.velocity.x += f / a.mass, a.velocity.y += m / a.mass, a.velocity.z += M / a.mass;
|
|
872
872
|
}
|
|
873
873
|
}
|
|
874
874
|
}
|
|
@@ -889,10 +889,10 @@ class Oe {
|
|
|
889
889
|
return;
|
|
890
890
|
}
|
|
891
891
|
if (s.mass === 0) return;
|
|
892
|
-
const t = s.centerOfMass.x - e.position.x,
|
|
892
|
+
const t = s.centerOfMass.x - e.position.x, n = s.centerOfMass.y - e.position.y, o = s.centerOfMass.z - e.position.z, a = Math.sqrt(t * t + n * n + o * o);
|
|
893
893
|
if (s.size / a < this.barnesHutTheta) {
|
|
894
|
-
const l = Math.max(a * a, 0.01),
|
|
895
|
-
e.velocity.x -= t / a *
|
|
894
|
+
const l = Math.max(a * a, 0.01), h = this.repulsionStrength * this.alpha * s.mass / l;
|
|
895
|
+
e.velocity.x -= t / a * h / e.mass, e.velocity.y -= n / a * h / e.mass, e.velocity.z -= o / a * h / e.mass;
|
|
896
896
|
} else
|
|
897
897
|
for (const l of s.children)
|
|
898
898
|
l && this.calculateForceFromOctree(e, l);
|
|
@@ -901,11 +901,11 @@ class Oe {
|
|
|
901
901
|
* Apply repulsion between two nodes
|
|
902
902
|
*/
|
|
903
903
|
applyRepulsionBetween(e, s) {
|
|
904
|
-
const t = s.position.x - e.position.x,
|
|
905
|
-
let a = t * t +
|
|
904
|
+
const t = s.position.x - e.position.x, n = s.position.y - e.position.y, o = s.position.z - e.position.z;
|
|
905
|
+
let a = t * t + n * n + o * o;
|
|
906
906
|
a < 0.01 && (a = 0.01);
|
|
907
|
-
const l = Math.sqrt(a),
|
|
908
|
-
e.velocity.x -= t / l *
|
|
907
|
+
const l = Math.sqrt(a), h = this.repulsionStrength * this.alpha / a;
|
|
908
|
+
e.velocity.x -= t / l * h / e.mass, e.velocity.y -= n / l * h / e.mass, e.velocity.z -= o / l * h / e.mass;
|
|
909
909
|
}
|
|
910
910
|
/**
|
|
911
911
|
* Calculate attraction forces along edges
|
|
@@ -914,10 +914,10 @@ class Oe {
|
|
|
914
914
|
for (const e of this.edges) {
|
|
915
915
|
const s = this.nodes.get(e.source), t = this.nodes.get(e.target);
|
|
916
916
|
if (!s || !t) continue;
|
|
917
|
-
const
|
|
917
|
+
const n = t.position.x - s.position.x, o = t.position.y - s.position.y, a = t.position.z - s.position.z, l = Math.sqrt(n * n + o * o + a * a);
|
|
918
918
|
if (l < 0.01) continue;
|
|
919
|
-
const
|
|
920
|
-
s.velocity.x +=
|
|
919
|
+
const g = (l - 15) * this.attractionStrength * this.alpha, u = n / l * g, b = o / l * g, x = a / l * g;
|
|
920
|
+
s.velocity.x += u / s.mass, s.velocity.y += b / s.mass, s.velocity.z += x / s.mass, t.velocity.x -= u / t.mass, t.velocity.y -= b / t.mass, t.velocity.z -= x / t.mass;
|
|
921
921
|
}
|
|
922
922
|
}
|
|
923
923
|
/**
|
|
@@ -965,13 +965,13 @@ class yt {
|
|
|
965
965
|
max: { x: 100, y: 100, z: 100 }
|
|
966
966
|
};
|
|
967
967
|
const s = { x: 1 / 0, y: 1 / 0, z: 1 / 0 }, t = { x: -1 / 0, y: -1 / 0, z: -1 / 0 };
|
|
968
|
-
for (const
|
|
969
|
-
s.x = Math.min(s.x,
|
|
970
|
-
const
|
|
971
|
-
return s.x -=
|
|
968
|
+
for (const o of e)
|
|
969
|
+
s.x = Math.min(s.x, o.position.x), s.y = Math.min(s.y, o.position.y), s.z = Math.min(s.z, o.position.z), t.x = Math.max(t.x, o.position.x), t.y = Math.max(t.y, o.position.y), t.z = Math.max(t.z, o.position.z);
|
|
970
|
+
const n = 10;
|
|
971
|
+
return s.x -= n, s.y -= n, s.z -= n, t.x += n, t.y += n, t.z += n, { min: s, max: t };
|
|
972
972
|
}
|
|
973
973
|
buildTree(e, s, t = 0) {
|
|
974
|
-
const
|
|
974
|
+
const n = Math.max(
|
|
975
975
|
s.max.x - s.min.x,
|
|
976
976
|
s.max.y - s.min.y,
|
|
977
977
|
s.max.z - s.min.z
|
|
@@ -979,7 +979,7 @@ class yt {
|
|
|
979
979
|
if (e.length === 0)
|
|
980
980
|
return {
|
|
981
981
|
bounds: s,
|
|
982
|
-
size:
|
|
982
|
+
size: n,
|
|
983
983
|
centerOfMass: { x: 0, y: 0, z: 0 },
|
|
984
984
|
mass: 0,
|
|
985
985
|
isLeaf: !0,
|
|
@@ -987,56 +987,56 @@ class yt {
|
|
|
987
987
|
children: []
|
|
988
988
|
};
|
|
989
989
|
if (e.length === 1 || t > 20) {
|
|
990
|
-
let
|
|
991
|
-
const
|
|
990
|
+
let f = 0;
|
|
991
|
+
const m = { x: 0, y: 0, z: 0 };
|
|
992
992
|
for (const M of e)
|
|
993
|
-
|
|
994
|
-
return
|
|
993
|
+
f += M.mass, m.x += M.position.x * M.mass, m.y += M.position.y * M.mass, m.z += M.position.z * M.mass;
|
|
994
|
+
return f > 0 && (m.x /= f, m.y /= f, m.z /= f), {
|
|
995
995
|
bounds: s,
|
|
996
|
-
size:
|
|
997
|
-
centerOfMass:
|
|
998
|
-
mass:
|
|
996
|
+
size: n,
|
|
997
|
+
centerOfMass: m,
|
|
998
|
+
mass: f,
|
|
999
999
|
isLeaf: !0,
|
|
1000
1000
|
node: e[0],
|
|
1001
1001
|
children: []
|
|
1002
1002
|
};
|
|
1003
1003
|
}
|
|
1004
|
-
const
|
|
1005
|
-
for (const
|
|
1006
|
-
const
|
|
1007
|
-
|
|
1004
|
+
const o = (s.min.x + s.max.x) / 2, a = (s.min.y + s.max.y) / 2, l = (s.min.z + s.max.z) / 2, h = [[], [], [], [], [], [], [], []];
|
|
1005
|
+
for (const f of e) {
|
|
1006
|
+
const m = (f.position.x >= o ? 1 : 0) + (f.position.y >= a ? 2 : 0) + (f.position.z >= l ? 4 : 0);
|
|
1007
|
+
h[m].push(f);
|
|
1008
1008
|
}
|
|
1009
|
-
const
|
|
1010
|
-
{ min: { x: s.min.x, y: s.min.y, z: s.min.z }, max: { x:
|
|
1011
|
-
{ min: { x:
|
|
1012
|
-
{ min: { x: s.min.x, y: a, z: s.min.z }, max: { x:
|
|
1013
|
-
{ min: { x:
|
|
1014
|
-
{ min: { x: s.min.x, y: s.min.y, z: l }, max: { x:
|
|
1015
|
-
{ min: { x:
|
|
1016
|
-
{ min: { x: s.min.x, y: a, z: l }, max: { x:
|
|
1017
|
-
{ min: { x:
|
|
1018
|
-
],
|
|
1009
|
+
const g = [
|
|
1010
|
+
{ min: { x: s.min.x, y: s.min.y, z: s.min.z }, max: { x: o, y: a, z: l } },
|
|
1011
|
+
{ min: { x: o, y: s.min.y, z: s.min.z }, max: { x: s.max.x, y: a, z: l } },
|
|
1012
|
+
{ min: { x: s.min.x, y: a, z: s.min.z }, max: { x: o, y: s.max.y, z: l } },
|
|
1013
|
+
{ min: { x: o, y: a, z: s.min.z }, max: { x: s.max.x, y: s.max.y, z: l } },
|
|
1014
|
+
{ min: { x: s.min.x, y: s.min.y, z: l }, max: { x: o, y: a, z: s.max.z } },
|
|
1015
|
+
{ min: { x: o, y: s.min.y, z: l }, max: { x: s.max.x, y: a, z: s.max.z } },
|
|
1016
|
+
{ min: { x: s.min.x, y: a, z: l }, max: { x: o, y: s.max.y, z: s.max.z } },
|
|
1017
|
+
{ min: { x: o, y: a, z: l }, max: { x: s.max.x, y: s.max.y, z: s.max.z } }
|
|
1018
|
+
], u = [];
|
|
1019
1019
|
let b = 0;
|
|
1020
|
-
const
|
|
1021
|
-
for (let
|
|
1022
|
-
if (
|
|
1023
|
-
const
|
|
1024
|
-
|
|
1020
|
+
const x = { x: 0, y: 0, z: 0 };
|
|
1021
|
+
for (let f = 0; f < 8; f++)
|
|
1022
|
+
if (h[f].length > 0) {
|
|
1023
|
+
const m = this.buildTree(h[f], g[f], t + 1);
|
|
1024
|
+
u.push(m), b += m.mass, x.x += m.centerOfMass.x * m.mass, x.y += m.centerOfMass.y * m.mass, x.z += m.centerOfMass.z * m.mass;
|
|
1025
1025
|
} else
|
|
1026
|
-
|
|
1027
|
-
return b > 0 && (
|
|
1026
|
+
u.push(null);
|
|
1027
|
+
return b > 0 && (x.x /= b, x.y /= b, x.z /= b), {
|
|
1028
1028
|
bounds: s,
|
|
1029
|
-
size:
|
|
1030
|
-
centerOfMass:
|
|
1029
|
+
size: n,
|
|
1030
|
+
centerOfMass: x,
|
|
1031
1031
|
mass: b,
|
|
1032
1032
|
isLeaf: !1,
|
|
1033
1033
|
node: null,
|
|
1034
|
-
children:
|
|
1034
|
+
children: u
|
|
1035
1035
|
};
|
|
1036
1036
|
}
|
|
1037
1037
|
}
|
|
1038
1038
|
class bt {
|
|
1039
|
-
constructor(e, s, t,
|
|
1039
|
+
constructor(e, s, t, n = 60) {
|
|
1040
1040
|
r(this, "sceneManager");
|
|
1041
1041
|
r(this, "animationId", null);
|
|
1042
1042
|
r(this, "isRunning", !1);
|
|
@@ -1061,7 +1061,7 @@ class bt {
|
|
|
1061
1061
|
const t = e - this.fpsStartTime;
|
|
1062
1062
|
t >= 1e3 && (this.currentFPS = this.frameCount / (t / 1e3), this.frameCount = 0, this.fpsStartTime = e), this.onSimulate(), this.onRender(), this.sceneManager.render();
|
|
1063
1063
|
});
|
|
1064
|
-
this.sceneManager = e, this.onSimulate = s, this.onRender = t, this.frameInterval = 1e3 /
|
|
1064
|
+
this.sceneManager = e, this.onSimulate = s, this.onRender = t, this.frameInterval = 1e3 / n;
|
|
1065
1065
|
}
|
|
1066
1066
|
/**
|
|
1067
1067
|
* Starts the animation loop
|
|
@@ -1138,10 +1138,10 @@ class xt {
|
|
|
1138
1138
|
{ colors: ["#2d1a1a", "#1a0a0a", "#0f0505"] }
|
|
1139
1139
|
// -z
|
|
1140
1140
|
];
|
|
1141
|
-
for (const
|
|
1142
|
-
const
|
|
1143
|
-
|
|
1144
|
-
const a =
|
|
1141
|
+
for (const n of t) {
|
|
1142
|
+
const o = document.createElement("canvas");
|
|
1143
|
+
o.width = 256, o.height = 256;
|
|
1144
|
+
const a = o.getContext("2d"), l = a.createRadialGradient(
|
|
1145
1145
|
256 / 2,
|
|
1146
1146
|
256 / 2,
|
|
1147
1147
|
0,
|
|
@@ -1149,17 +1149,17 @@ class xt {
|
|
|
1149
1149
|
256 / 2,
|
|
1150
1150
|
256 * 0.8
|
|
1151
1151
|
);
|
|
1152
|
-
l.addColorStop(0,
|
|
1153
|
-
const
|
|
1154
|
-
for (let
|
|
1155
|
-
const
|
|
1156
|
-
|
|
1152
|
+
l.addColorStop(0, n.colors[0]), l.addColorStop(0.5, n.colors[1]), l.addColorStop(1, n.colors[2]), a.fillStyle = l, a.fillRect(0, 0, 256, 256);
|
|
1153
|
+
const h = a.getImageData(0, 0, 256, 256);
|
|
1154
|
+
for (let g = 0; g < h.data.length; g += 4) {
|
|
1155
|
+
const u = (Math.random() - 0.5) * 5;
|
|
1156
|
+
h.data[g] = Math.min(255, Math.max(0, h.data[g] + u)), h.data[g + 1] = Math.min(255, Math.max(0, h.data[g + 1] + u)), h.data[g + 2] = Math.min(255, Math.max(0, h.data[g + 2] + u));
|
|
1157
1157
|
}
|
|
1158
|
-
a.putImageData(
|
|
1158
|
+
a.putImageData(h, 0, 0), s.push(o);
|
|
1159
1159
|
}
|
|
1160
|
-
this.envMap = new p.CubeTexture(s.map((
|
|
1161
|
-
const
|
|
1162
|
-
return
|
|
1160
|
+
this.envMap = new p.CubeTexture(s.map((n) => {
|
|
1161
|
+
const o = new Image();
|
|
1162
|
+
return o.src = n.toDataURL(), o;
|
|
1163
1163
|
})), this.envMap.needsUpdate = !0;
|
|
1164
1164
|
}
|
|
1165
1165
|
/**
|
|
@@ -1176,9 +1176,9 @@ class xt {
|
|
|
1176
1176
|
const t = "glass-single";
|
|
1177
1177
|
if (this.materialCache.has(t))
|
|
1178
1178
|
return this.materialCache.get(t).clone();
|
|
1179
|
-
const
|
|
1179
|
+
const n = new p.Color(16750950), o = new p.ShaderMaterial({
|
|
1180
1180
|
uniforms: {
|
|
1181
|
-
uColor: { value:
|
|
1181
|
+
uColor: { value: n },
|
|
1182
1182
|
uEnvMap: { value: this.envMap },
|
|
1183
1183
|
uGlowColor: { value: new p.Color(16777215) },
|
|
1184
1184
|
uGlowIntensity: { value: 0.8 },
|
|
@@ -1250,7 +1250,7 @@ class xt {
|
|
|
1250
1250
|
depthWrite: !0,
|
|
1251
1251
|
blending: p.NormalBlending
|
|
1252
1252
|
});
|
|
1253
|
-
return this.materialCache.set(t,
|
|
1253
|
+
return this.materialCache.set(t, o), o.clone();
|
|
1254
1254
|
}
|
|
1255
1255
|
/**
|
|
1256
1256
|
* Creates material for edges (light color for dark background)
|
|
@@ -1279,10 +1279,10 @@ class xt {
|
|
|
1279
1279
|
* Creates a sprite material for labels (light text for dark background)
|
|
1280
1280
|
*/
|
|
1281
1281
|
createLabelMaterial(e, s = 24) {
|
|
1282
|
-
const t = document.createElement("canvas"),
|
|
1283
|
-
|
|
1284
|
-
const a =
|
|
1285
|
-
t.width = Math.max(128, a + 24), t.height = s + 20,
|
|
1282
|
+
const t = document.createElement("canvas"), n = t.getContext("2d");
|
|
1283
|
+
n.font = `600 ${s}px Inter, -apple-system, sans-serif`;
|
|
1284
|
+
const a = n.measureText(e).width;
|
|
1285
|
+
t.width = Math.max(128, a + 24), t.height = s + 20, n.clearRect(0, 0, t.width, t.height), n.font = `600 ${s}px Inter, -apple-system, sans-serif`, n.textAlign = "center", n.textBaseline = "middle", n.shadowColor = "rgba(0, 0, 0, 0.8)", n.shadowBlur = 4, n.shadowOffsetX = 1, n.shadowOffsetY = 1, n.fillStyle = "rgba(255, 255, 255, 0.95)", n.fillText(e, t.width / 2, t.height / 2);
|
|
1286
1286
|
const l = new p.CanvasTexture(t);
|
|
1287
1287
|
return l.needsUpdate = !0, new p.SpriteMaterial({
|
|
1288
1288
|
map: l,
|
|
@@ -1337,19 +1337,19 @@ class vt {
|
|
|
1337
1337
|
createNode(e, s = 0) {
|
|
1338
1338
|
const t = new p.Group();
|
|
1339
1339
|
t.name = `node-${e.id}`, t.userData = { nodeId: e.id, nodeData: e };
|
|
1340
|
-
const
|
|
1340
|
+
const n = this.getGeometry(s), o = this.materialFactory.createGlassMaterial(
|
|
1341
1341
|
e.color ?? 4886754
|
|
1342
|
-
), a = new p.Mesh(
|
|
1342
|
+
), a = new p.Mesh(n, o);
|
|
1343
1343
|
a.castShadow = !0, a.receiveShadow = !0, t.add(a);
|
|
1344
|
-
const l = this.materialFactory.createLabelMaterial(e.label),
|
|
1345
|
-
return
|
|
1344
|
+
const l = this.materialFactory.createLabelMaterial(e.label), h = new p.Sprite(l);
|
|
1345
|
+
return h.position.y = this.nodeRadius + 1.5, h.scale.set(4, 1, 1), t.add(h), e.position && t.position.set(
|
|
1346
1346
|
e.position.x,
|
|
1347
1347
|
e.position.y,
|
|
1348
1348
|
e.position.z
|
|
1349
1349
|
), {
|
|
1350
1350
|
group: t,
|
|
1351
1351
|
sphere: a,
|
|
1352
|
-
label:
|
|
1352
|
+
label: h,
|
|
1353
1353
|
lodLevel: s
|
|
1354
1354
|
};
|
|
1355
1355
|
}
|
|
@@ -1413,25 +1413,25 @@ class Mt {
|
|
|
1413
1413
|
/**
|
|
1414
1414
|
* Creates an edge line between two positions
|
|
1415
1415
|
*/
|
|
1416
|
-
createEdge(e, s, t,
|
|
1416
|
+
createEdge(e, s, t, n, o) {
|
|
1417
1417
|
const a = new p.BufferGeometry(), l = new Float32Array([
|
|
1418
|
-
i.x,
|
|
1419
|
-
i.y,
|
|
1420
|
-
i.z,
|
|
1421
1418
|
n.x,
|
|
1422
1419
|
n.y,
|
|
1423
|
-
n.z
|
|
1420
|
+
n.z,
|
|
1421
|
+
o.x,
|
|
1422
|
+
o.y,
|
|
1423
|
+
o.z
|
|
1424
1424
|
]);
|
|
1425
1425
|
a.setAttribute("position", new p.BufferAttribute(l, 3));
|
|
1426
|
-
const
|
|
1427
|
-
return
|
|
1426
|
+
const h = this.getDefaultMaterial().clone(), g = new p.Line(a, h);
|
|
1427
|
+
return g.name = `edge-${e.source}-${e.target}`, g.userData = {
|
|
1428
1428
|
source: e.source,
|
|
1429
1429
|
target: e.target,
|
|
1430
1430
|
edge: e,
|
|
1431
1431
|
sourceNode: s,
|
|
1432
1432
|
targetNode: t
|
|
1433
|
-
},
|
|
1434
|
-
line:
|
|
1433
|
+
}, g.frustumCulled = !0, {
|
|
1434
|
+
line: g,
|
|
1435
1435
|
source: e.source,
|
|
1436
1436
|
target: e.target
|
|
1437
1437
|
};
|
|
@@ -1452,8 +1452,8 @@ class Mt {
|
|
|
1452
1452
|
* Updates an edge's positions
|
|
1453
1453
|
*/
|
|
1454
1454
|
updateEdgePositions(e, s, t) {
|
|
1455
|
-
const
|
|
1456
|
-
|
|
1455
|
+
const n = e.line.geometry.attributes.position, o = n.array;
|
|
1456
|
+
o[0] = s.x, o[1] = s.y, o[2] = s.z, o[3] = t.x, o[4] = t.y, o[5] = t.z, n.needsUpdate = !0, e.line.geometry.computeBoundingSphere();
|
|
1457
1457
|
}
|
|
1458
1458
|
/**
|
|
1459
1459
|
* Disposes an edge's resources
|
|
@@ -1480,16 +1480,16 @@ class wt {
|
|
|
1480
1480
|
*/
|
|
1481
1481
|
getLODLevel(e) {
|
|
1482
1482
|
if (!this.enabled)
|
|
1483
|
-
return
|
|
1484
|
-
const s = e.x - this.camera.position.x, t = e.y - this.camera.position.y,
|
|
1485
|
-
return
|
|
1483
|
+
return X.HIGH;
|
|
1484
|
+
const s = e.x - this.camera.position.x, t = e.y - this.camera.position.y, n = e.z - this.camera.position.z, o = Math.sqrt(s * s + t * t + n * n);
|
|
1485
|
+
return o < this.lodDistances[0] ? X.HIGH : o < this.lodDistances[1] ? X.MEDIUM : X.LOW;
|
|
1486
1486
|
}
|
|
1487
1487
|
/**
|
|
1488
1488
|
* Checks if a node should be visible based on distance
|
|
1489
1489
|
*/
|
|
1490
1490
|
shouldRenderNode(e, s = 500) {
|
|
1491
|
-
const t = e.x - this.camera.position.x,
|
|
1492
|
-
return Math.sqrt(t * t +
|
|
1491
|
+
const t = e.x - this.camera.position.x, n = e.y - this.camera.position.y, o = e.z - this.camera.position.z;
|
|
1492
|
+
return Math.sqrt(t * t + n * n + o * o) < s;
|
|
1493
1493
|
}
|
|
1494
1494
|
/**
|
|
1495
1495
|
* Sets the LOD distances
|
|
@@ -1545,14 +1545,14 @@ class Et {
|
|
|
1545
1545
|
*/
|
|
1546
1546
|
isLineVisible(e, s) {
|
|
1547
1547
|
if (!this.enabled) return !0;
|
|
1548
|
-
const t = new p.Vector3(e.x, e.y, e.z),
|
|
1549
|
-
if (this.frustum.containsPoint(t) || this.frustum.containsPoint(
|
|
1548
|
+
const t = new p.Vector3(e.x, e.y, e.z), n = new p.Vector3(s.x, s.y, s.z);
|
|
1549
|
+
if (this.frustum.containsPoint(t) || this.frustum.containsPoint(n))
|
|
1550
1550
|
return !0;
|
|
1551
|
-
const
|
|
1551
|
+
const o = new p.Vector3(
|
|
1552
1552
|
(e.x + s.x) / 2,
|
|
1553
1553
|
(e.y + s.y) / 2,
|
|
1554
1554
|
(e.z + s.z) / 2
|
|
1555
|
-
), a =
|
|
1555
|
+
), a = o.distanceTo(t), l = new p.Sphere(o, a);
|
|
1556
1556
|
return this.frustum.intersectsSphere(l);
|
|
1557
1557
|
}
|
|
1558
1558
|
/**
|
|
@@ -1571,6 +1571,7 @@ class Ct {
|
|
|
1571
1571
|
r(this, "onNodeClick", null);
|
|
1572
1572
|
r(this, "onNodeHover", null);
|
|
1573
1573
|
r(this, "onEdgeHover", null);
|
|
1574
|
+
r(this, "onEdgeClick", null);
|
|
1574
1575
|
r(this, "hoveredNodeId", null);
|
|
1575
1576
|
r(this, "hoveredEdgeKey", null);
|
|
1576
1577
|
r(this, "nodeObjects", []);
|
|
@@ -1607,12 +1608,23 @@ class Ct {
|
|
|
1607
1608
|
setEdgeHoverCallback(e) {
|
|
1608
1609
|
this.onEdgeHover = e;
|
|
1609
1610
|
}
|
|
1611
|
+
/**
|
|
1612
|
+
* Sets the edge click callback
|
|
1613
|
+
*/
|
|
1614
|
+
setEdgeClickCallback(e) {
|
|
1615
|
+
this.onEdgeClick = e;
|
|
1616
|
+
}
|
|
1610
1617
|
/**
|
|
1611
1618
|
* Handles click events
|
|
1612
1619
|
*/
|
|
1613
1620
|
handleClick(e) {
|
|
1614
1621
|
const s = this.getIntersectedNode(e);
|
|
1615
|
-
s && this.onNodeClick
|
|
1622
|
+
if (s && this.onNodeClick) {
|
|
1623
|
+
this.onNodeClick(s);
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1626
|
+
const t = this.getIntersectedEdge(e);
|
|
1627
|
+
t && this.onEdgeClick && this.onEdgeClick(t);
|
|
1616
1628
|
}
|
|
1617
1629
|
/**
|
|
1618
1630
|
* Handles mouse move events for hover detection
|
|
@@ -1623,23 +1635,23 @@ class Ct {
|
|
|
1623
1635
|
this.hoveredEdgeKey !== null && this.onEdgeHover && (this.hoveredEdgeKey = null, this.onEdgeHover(null)), this.container.style.cursor = "pointer";
|
|
1624
1636
|
return;
|
|
1625
1637
|
}
|
|
1626
|
-
const
|
|
1627
|
-
|
|
1638
|
+
const n = this.getIntersectedEdge(e), o = n ? `${n.edge.source}-${n.edge.target}` : null;
|
|
1639
|
+
o !== this.hoveredEdgeKey && (this.hoveredEdgeKey = o, this.onEdgeHover && this.onEdgeHover(n)), this.container.style.cursor = n ? "pointer" : "default";
|
|
1628
1640
|
}
|
|
1629
1641
|
/**
|
|
1630
1642
|
* Gets the intersected node from a mouse event
|
|
1631
1643
|
*/
|
|
1632
1644
|
getIntersectedNode(e) {
|
|
1633
|
-
var
|
|
1645
|
+
var n;
|
|
1634
1646
|
const s = this.container.getBoundingClientRect();
|
|
1635
1647
|
this.mouse.x = (e.clientX - s.left) / s.width * 2 - 1, this.mouse.y = -((e.clientY - s.top) / s.height) * 2 + 1, this.raycaster.setFromCamera(this.mouse, this.sceneManager.camera);
|
|
1636
1648
|
const t = this.raycaster.intersectObjects(this.nodeObjects, !0);
|
|
1637
1649
|
if (t.length > 0) {
|
|
1638
|
-
let
|
|
1639
|
-
for (;
|
|
1640
|
-
if ((
|
|
1641
|
-
return
|
|
1642
|
-
|
|
1650
|
+
let o = t[0].object;
|
|
1651
|
+
for (; o; ) {
|
|
1652
|
+
if ((n = o.userData) != null && n.nodeData)
|
|
1653
|
+
return o.userData.nodeData;
|
|
1654
|
+
o = o.parent;
|
|
1643
1655
|
}
|
|
1644
1656
|
}
|
|
1645
1657
|
return null;
|
|
@@ -1652,13 +1664,13 @@ class Ct {
|
|
|
1652
1664
|
this.mouse.x = (e.clientX - s.left) / s.width * 2 - 1, this.mouse.y = -((e.clientY - s.top) / s.height) * 2 + 1, this.raycaster.setFromCamera(this.mouse, this.sceneManager.camera);
|
|
1653
1665
|
const t = this.raycaster.intersectObjects(this.edgeObjects, !1);
|
|
1654
1666
|
if (t.length > 0) {
|
|
1655
|
-
const
|
|
1656
|
-
if (
|
|
1667
|
+
const n = t[0].object, o = n.userData;
|
|
1668
|
+
if (o != null && o.edge && (o != null && o.sourceNode) && (o != null && o.targetNode))
|
|
1657
1669
|
return {
|
|
1658
|
-
edge:
|
|
1659
|
-
sourceNode:
|
|
1660
|
-
targetNode:
|
|
1661
|
-
edgeLine:
|
|
1670
|
+
edge: o.edge,
|
|
1671
|
+
sourceNode: o.sourceNode,
|
|
1672
|
+
targetNode: o.targetNode,
|
|
1673
|
+
edgeLine: n
|
|
1662
1674
|
};
|
|
1663
1675
|
}
|
|
1664
1676
|
return null;
|
|
@@ -1667,14 +1679,14 @@ class Ct {
|
|
|
1667
1679
|
* Performs a raycast and returns the intersected node ID
|
|
1668
1680
|
*/
|
|
1669
1681
|
getIntersectedNodeId(e, s) {
|
|
1670
|
-
var
|
|
1682
|
+
var o;
|
|
1671
1683
|
const t = this.container.getBoundingClientRect();
|
|
1672
1684
|
this.mouse.x = (e - t.left) / t.width * 2 - 1, this.mouse.y = -((s - t.top) / t.height) * 2 + 1, this.raycaster.setFromCamera(this.mouse, this.sceneManager.camera);
|
|
1673
|
-
const
|
|
1674
|
-
if (
|
|
1675
|
-
let a =
|
|
1685
|
+
const n = this.raycaster.intersectObjects(this.nodeObjects, !0);
|
|
1686
|
+
if (n.length > 0) {
|
|
1687
|
+
let a = n[0].object;
|
|
1676
1688
|
for (; a; ) {
|
|
1677
|
-
if ((
|
|
1689
|
+
if ((o = a.userData) != null && o.nodeId)
|
|
1678
1690
|
return a.userData.nodeId;
|
|
1679
1691
|
a = a.parent;
|
|
1680
1692
|
}
|
|
@@ -1688,7 +1700,7 @@ class Ct {
|
|
|
1688
1700
|
this.container.removeEventListener("click", this.handleClick), this.container.removeEventListener("mousemove", this.handleMouseMove);
|
|
1689
1701
|
}
|
|
1690
1702
|
}
|
|
1691
|
-
class
|
|
1703
|
+
class zt {
|
|
1692
1704
|
constructor(e) {
|
|
1693
1705
|
r(this, "container");
|
|
1694
1706
|
r(this, "panel", null);
|
|
@@ -1758,10 +1770,10 @@ class Nt {
|
|
|
1758
1770
|
this.currentNodeId = e.id;
|
|
1759
1771
|
let t;
|
|
1760
1772
|
this.panelTemplate ? t = this.panelTemplate(e, s) : t = this.generateDefaultContent(e, s), this.panel.innerHTML = t;
|
|
1761
|
-
const
|
|
1762
|
-
|
|
1773
|
+
const n = this.panel.querySelector('[data-action="expand"]'), o = this.panel.querySelector("[data-depth-select]");
|
|
1774
|
+
n && this.onExpand && n.addEventListener("click", () => {
|
|
1763
1775
|
if (this.currentNodeId) {
|
|
1764
|
-
const l =
|
|
1776
|
+
const l = o ? parseInt(o.value, 10) : 1;
|
|
1765
1777
|
this.onExpand(this.currentNodeId, l);
|
|
1766
1778
|
}
|
|
1767
1779
|
});
|
|
@@ -1920,7 +1932,7 @@ class Nt {
|
|
|
1920
1932
|
<div class="neighbors-section">
|
|
1921
1933
|
<div class="neighbors-title">Connected To</div>
|
|
1922
1934
|
${s.slice(0, 5).map(
|
|
1923
|
-
(
|
|
1935
|
+
(n) => `<span class="neighbor-chip">${this.escapeHtml(n.label)}</span>`
|
|
1924
1936
|
).join("")}
|
|
1925
1937
|
${s.length > 5 ? `<span class="neighbor-chip">+${s.length - 5} more</span>` : ""}
|
|
1926
1938
|
</div>
|
|
@@ -1974,6 +1986,251 @@ class Nt {
|
|
|
1974
1986
|
this.panel && this.panel.parentNode && this.panel.parentNode.removeChild(this.panel), this.panel = null;
|
|
1975
1987
|
}
|
|
1976
1988
|
}
|
|
1989
|
+
class Nt {
|
|
1990
|
+
constructor(e) {
|
|
1991
|
+
r(this, "container");
|
|
1992
|
+
r(this, "panel", null);
|
|
1993
|
+
r(this, "currentEdgeKey", null);
|
|
1994
|
+
r(this, "visible", !1);
|
|
1995
|
+
r(this, "panelTemplate", null);
|
|
1996
|
+
r(this, "onClose", null);
|
|
1997
|
+
r(this, "onNodeClick", null);
|
|
1998
|
+
this.container = e, this.createPanel();
|
|
1999
|
+
}
|
|
2000
|
+
/**
|
|
2001
|
+
* Creates the panel element
|
|
2002
|
+
*/
|
|
2003
|
+
createPanel() {
|
|
2004
|
+
this.panel = document.createElement("div"), this.panel.className = "force-graph-edge-panel", this.panel.style.cssText = `
|
|
2005
|
+
position: absolute;
|
|
2006
|
+
right: 20px;
|
|
2007
|
+
top: 50%;
|
|
2008
|
+
transform: translateY(-50%);
|
|
2009
|
+
width: 300px;
|
|
2010
|
+
max-height: 80vh;
|
|
2011
|
+
overflow-y: auto;
|
|
2012
|
+
background: rgba(15, 15, 25, 0.85);
|
|
2013
|
+
backdrop-filter: blur(20px);
|
|
2014
|
+
-webkit-backdrop-filter: blur(20px);
|
|
2015
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
2016
|
+
border-radius: 16px;
|
|
2017
|
+
padding: 24px;
|
|
2018
|
+
color: white;
|
|
2019
|
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
2020
|
+
box-shadow:
|
|
2021
|
+
0 8px 32px rgba(0, 0, 0, 0.4),
|
|
2022
|
+
inset 0 0 0 1px rgba(255, 255, 255, 0.05);
|
|
2023
|
+
z-index: 1000;
|
|
2024
|
+
opacity: 0;
|
|
2025
|
+
pointer-events: none;
|
|
2026
|
+
transition: opacity 0.3s ease, transform 0.3s ease;
|
|
2027
|
+
`, this.container.appendChild(this.panel);
|
|
2028
|
+
}
|
|
2029
|
+
/**
|
|
2030
|
+
* Sets the panel template function
|
|
2031
|
+
*/
|
|
2032
|
+
setPanelTemplate(e) {
|
|
2033
|
+
this.panelTemplate = e;
|
|
2034
|
+
}
|
|
2035
|
+
/**
|
|
2036
|
+
* Sets the close callback
|
|
2037
|
+
*/
|
|
2038
|
+
setCloseCallback(e) {
|
|
2039
|
+
this.onClose = e;
|
|
2040
|
+
}
|
|
2041
|
+
/**
|
|
2042
|
+
* Sets the node click callback (for navigating to nodes from edge panel)
|
|
2043
|
+
*/
|
|
2044
|
+
setNodeClickCallback(e) {
|
|
2045
|
+
this.onNodeClick = e;
|
|
2046
|
+
}
|
|
2047
|
+
/**
|
|
2048
|
+
* Shows the panel with edge/relationship information
|
|
2049
|
+
*/
|
|
2050
|
+
show(e, s, t) {
|
|
2051
|
+
if (!this.panel) return;
|
|
2052
|
+
this.currentEdgeKey = `${e.source}-${e.target}`;
|
|
2053
|
+
let n;
|
|
2054
|
+
this.panelTemplate ? n = this.panelTemplate(e, s, t) : n = this.generateDefaultContent(e, s, t), this.panel.innerHTML = n;
|
|
2055
|
+
const o = this.panel.querySelector('[data-action="close"]');
|
|
2056
|
+
o && o.addEventListener("click", () => {
|
|
2057
|
+
this.hide(), this.onClose && this.onClose();
|
|
2058
|
+
});
|
|
2059
|
+
const a = this.panel.querySelector('[data-action="goto-source"]');
|
|
2060
|
+
a && this.onNodeClick && a.addEventListener("click", () => {
|
|
2061
|
+
this.onNodeClick && this.onNodeClick(e.source);
|
|
2062
|
+
});
|
|
2063
|
+
const l = this.panel.querySelector('[data-action="goto-target"]');
|
|
2064
|
+
l && this.onNodeClick && l.addEventListener("click", () => {
|
|
2065
|
+
this.onNodeClick && this.onNodeClick(e.target);
|
|
2066
|
+
}), this.panel.style.opacity = "1", this.panel.style.pointerEvents = "auto", this.panel.style.transform = "translateY(-50%) translateX(0)", this.visible = !0;
|
|
2067
|
+
}
|
|
2068
|
+
/**
|
|
2069
|
+
* Generates default panel content
|
|
2070
|
+
*/
|
|
2071
|
+
generateDefaultContent(e, s, t) {
|
|
2072
|
+
const n = s.color ? `#${s.color.toString(16).padStart(6, "0")}` : "#ff9966", o = t.color ? `#${t.color.toString(16).padStart(6, "0")}` : "#ff9966", a = e.relationship || "connected to";
|
|
2073
|
+
return `
|
|
2074
|
+
<style>
|
|
2075
|
+
.force-graph-edge-panel .panel-header {
|
|
2076
|
+
display: flex;
|
|
2077
|
+
align-items: center;
|
|
2078
|
+
justify-content: space-between;
|
|
2079
|
+
margin-bottom: 20px;
|
|
2080
|
+
}
|
|
2081
|
+
.force-graph-edge-panel .panel-title {
|
|
2082
|
+
font-size: 14px;
|
|
2083
|
+
text-transform: uppercase;
|
|
2084
|
+
letter-spacing: 1px;
|
|
2085
|
+
color: rgba(255, 255, 255, 0.6);
|
|
2086
|
+
margin: 0;
|
|
2087
|
+
}
|
|
2088
|
+
.force-graph-edge-panel .relationship-section {
|
|
2089
|
+
background: rgba(255, 255, 255, 0.05);
|
|
2090
|
+
border-radius: 12px;
|
|
2091
|
+
padding: 16px;
|
|
2092
|
+
text-align: center;
|
|
2093
|
+
margin-bottom: 20px;
|
|
2094
|
+
}
|
|
2095
|
+
.force-graph-edge-panel .relationship-label {
|
|
2096
|
+
font-size: 18px;
|
|
2097
|
+
font-weight: 600;
|
|
2098
|
+
color: #a78bfa;
|
|
2099
|
+
letter-spacing: 0.5px;
|
|
2100
|
+
}
|
|
2101
|
+
.force-graph-edge-panel .node-card {
|
|
2102
|
+
background: rgba(255, 255, 255, 0.05);
|
|
2103
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
2104
|
+
border-radius: 12px;
|
|
2105
|
+
padding: 14px;
|
|
2106
|
+
margin-bottom: 12px;
|
|
2107
|
+
cursor: pointer;
|
|
2108
|
+
transition: all 0.2s ease;
|
|
2109
|
+
}
|
|
2110
|
+
.force-graph-edge-panel .node-card:hover {
|
|
2111
|
+
background: rgba(255, 255, 255, 0.1);
|
|
2112
|
+
border-color: rgba(255, 255, 255, 0.2);
|
|
2113
|
+
transform: translateX(4px);
|
|
2114
|
+
}
|
|
2115
|
+
.force-graph-edge-panel .node-card-header {
|
|
2116
|
+
display: flex;
|
|
2117
|
+
align-items: center;
|
|
2118
|
+
gap: 10px;
|
|
2119
|
+
margin-bottom: 6px;
|
|
2120
|
+
}
|
|
2121
|
+
.force-graph-edge-panel .node-type {
|
|
2122
|
+
font-size: 10px;
|
|
2123
|
+
text-transform: uppercase;
|
|
2124
|
+
letter-spacing: 1px;
|
|
2125
|
+
color: rgba(255, 255, 255, 0.5);
|
|
2126
|
+
}
|
|
2127
|
+
.force-graph-edge-panel .color-dot {
|
|
2128
|
+
width: 10px;
|
|
2129
|
+
height: 10px;
|
|
2130
|
+
border-radius: 50%;
|
|
2131
|
+
flex-shrink: 0;
|
|
2132
|
+
}
|
|
2133
|
+
.force-graph-edge-panel .node-label {
|
|
2134
|
+
font-size: 15px;
|
|
2135
|
+
font-weight: 500;
|
|
2136
|
+
color: rgba(255, 255, 255, 0.95);
|
|
2137
|
+
white-space: nowrap;
|
|
2138
|
+
overflow: hidden;
|
|
2139
|
+
text-overflow: ellipsis;
|
|
2140
|
+
}
|
|
2141
|
+
.force-graph-edge-panel .connection-arrow {
|
|
2142
|
+
text-align: center;
|
|
2143
|
+
color: rgba(255, 255, 255, 0.4);
|
|
2144
|
+
font-size: 18px;
|
|
2145
|
+
margin: 8px 0;
|
|
2146
|
+
}
|
|
2147
|
+
.force-graph-edge-panel .btn-close {
|
|
2148
|
+
width: 100%;
|
|
2149
|
+
padding: 12px 16px;
|
|
2150
|
+
border: none;
|
|
2151
|
+
border-radius: 8px;
|
|
2152
|
+
font-size: 13px;
|
|
2153
|
+
font-weight: 500;
|
|
2154
|
+
cursor: pointer;
|
|
2155
|
+
transition: all 0.2s ease;
|
|
2156
|
+
background: rgba(255, 255, 255, 0.1);
|
|
2157
|
+
color: rgba(255, 255, 255, 0.8);
|
|
2158
|
+
margin-top: 16px;
|
|
2159
|
+
}
|
|
2160
|
+
.force-graph-edge-panel .btn-close:hover {
|
|
2161
|
+
background: rgba(255, 255, 255, 0.15);
|
|
2162
|
+
}
|
|
2163
|
+
.force-graph-edge-panel .hint-text {
|
|
2164
|
+
font-size: 11px;
|
|
2165
|
+
color: rgba(255, 255, 255, 0.4);
|
|
2166
|
+
text-align: center;
|
|
2167
|
+
margin-top: 8px;
|
|
2168
|
+
}
|
|
2169
|
+
</style>
|
|
2170
|
+
|
|
2171
|
+
<div class="panel-header">
|
|
2172
|
+
<h3 class="panel-title">Relationship</h3>
|
|
2173
|
+
</div>
|
|
2174
|
+
|
|
2175
|
+
<div class="relationship-section">
|
|
2176
|
+
<span class="relationship-label">${this.escapeHtml(a)}</span>
|
|
2177
|
+
</div>
|
|
2178
|
+
|
|
2179
|
+
<div class="node-card" data-action="goto-source" title="Click to focus on ${this.escapeHtml(s.label)}">
|
|
2180
|
+
<div class="node-type">Source</div>
|
|
2181
|
+
<div class="node-card-header">
|
|
2182
|
+
<span class="color-dot" style="background: ${n}; box-shadow: 0 0 8px ${n}80;"></span>
|
|
2183
|
+
<span class="node-label">${this.escapeHtml(s.label)}</span>
|
|
2184
|
+
</div>
|
|
2185
|
+
</div>
|
|
2186
|
+
|
|
2187
|
+
<div class="connection-arrow">↓</div>
|
|
2188
|
+
|
|
2189
|
+
<div class="node-card" data-action="goto-target" title="Click to focus on ${this.escapeHtml(t.label)}">
|
|
2190
|
+
<div class="node-type">Target</div>
|
|
2191
|
+
<div class="node-card-header">
|
|
2192
|
+
<span class="color-dot" style="background: ${o}; box-shadow: 0 0 8px ${o}80;"></span>
|
|
2193
|
+
<span class="node-label">${this.escapeHtml(t.label)}</span>
|
|
2194
|
+
</div>
|
|
2195
|
+
</div>
|
|
2196
|
+
|
|
2197
|
+
<p class="hint-text">Click on a node to focus on it</p>
|
|
2198
|
+
|
|
2199
|
+
<button class="btn-close" data-action="close">Close</button>
|
|
2200
|
+
`;
|
|
2201
|
+
}
|
|
2202
|
+
/**
|
|
2203
|
+
* Escapes HTML to prevent XSS
|
|
2204
|
+
*/
|
|
2205
|
+
escapeHtml(e) {
|
|
2206
|
+
const s = document.createElement("div");
|
|
2207
|
+
return s.textContent = e, s.innerHTML;
|
|
2208
|
+
}
|
|
2209
|
+
/**
|
|
2210
|
+
* Hides the panel
|
|
2211
|
+
*/
|
|
2212
|
+
hide() {
|
|
2213
|
+
this.panel && (this.panel.style.opacity = "0", this.panel.style.pointerEvents = "none", this.panel.style.transform = "translateY(-50%) translateX(20px)", this.visible = !1, this.currentEdgeKey = null);
|
|
2214
|
+
}
|
|
2215
|
+
/**
|
|
2216
|
+
* Checks if the panel is visible
|
|
2217
|
+
*/
|
|
2218
|
+
isVisible() {
|
|
2219
|
+
return this.visible;
|
|
2220
|
+
}
|
|
2221
|
+
/**
|
|
2222
|
+
* Gets the currently displayed edge key
|
|
2223
|
+
*/
|
|
2224
|
+
getCurrentEdgeKey() {
|
|
2225
|
+
return this.currentEdgeKey;
|
|
2226
|
+
}
|
|
2227
|
+
/**
|
|
2228
|
+
* Dispose the panel
|
|
2229
|
+
*/
|
|
2230
|
+
dispose() {
|
|
2231
|
+
this.panel && this.panel.parentNode && this.panel.parentNode.removeChild(this.panel), this.panel = null;
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
1977
2234
|
class St {
|
|
1978
2235
|
constructor() {
|
|
1979
2236
|
r(this, "tooltip", null);
|
|
@@ -2020,14 +2277,14 @@ class St {
|
|
|
2020
2277
|
*/
|
|
2021
2278
|
positionTooltip(e, s) {
|
|
2022
2279
|
if (!this.tooltip) return;
|
|
2023
|
-
const t = this.tooltip.getBoundingClientRect(),
|
|
2280
|
+
const t = this.tooltip.getBoundingClientRect(), n = window.innerWidth, o = window.innerHeight;
|
|
2024
2281
|
let a = e + 15, l = s + 15;
|
|
2025
|
-
a + t.width >
|
|
2282
|
+
a + t.width > n - 10 && (a = e - t.width - 15), l + t.height > o - 10 && (l = s - t.height - 15), a < 10 && (a = 10), l < 10 && (l = 10), this.tooltip.style.left = `${a}px`, this.tooltip.style.top = `${l}px`;
|
|
2026
2283
|
}
|
|
2027
2284
|
/**
|
|
2028
2285
|
* Shows the tooltip with edge info
|
|
2029
2286
|
*/
|
|
2030
|
-
show(e, s, t,
|
|
2287
|
+
show(e, s, t, n, o) {
|
|
2031
2288
|
if (!this.tooltip) return;
|
|
2032
2289
|
const a = e.relationship || "connected to";
|
|
2033
2290
|
this.tooltip.innerHTML = `
|
|
@@ -2042,7 +2299,7 @@ class St {
|
|
|
2042
2299
|
<span style="font-weight: 600; color: #ff9966;">${this.escapeHtml(t.label)}</span>
|
|
2043
2300
|
</div>
|
|
2044
2301
|
</div>
|
|
2045
|
-
`, this.positionTooltip(
|
|
2302
|
+
`, this.positionTooltip(n, o), this.tooltip.style.opacity = "1", this.tooltip.style.transform = "translateY(0)", this.visible = !0;
|
|
2046
2303
|
}
|
|
2047
2304
|
/**
|
|
2048
2305
|
* Updates tooltip position (called externally on mouse move)
|
|
@@ -2076,7 +2333,7 @@ class St {
|
|
|
2076
2333
|
this.tooltip && this.tooltip.parentNode && this.tooltip.parentNode.removeChild(this.tooltip), this.tooltip = null;
|
|
2077
2334
|
}
|
|
2078
2335
|
}
|
|
2079
|
-
class
|
|
2336
|
+
class kt {
|
|
2080
2337
|
constructor(e, s) {
|
|
2081
2338
|
r(this, "container");
|
|
2082
2339
|
r(this, "searchContainer", null);
|
|
@@ -2218,25 +2475,25 @@ class zt {
|
|
|
2218
2475
|
this.searchResults.innerHTML = '<div class="f3d-no-results">No results found</div>', this.searchResults.style.display = "block";
|
|
2219
2476
|
return;
|
|
2220
2477
|
}
|
|
2221
|
-
let
|
|
2222
|
-
s.length > 0 && (
|
|
2223
|
-
const a =
|
|
2224
|
-
|
|
2225
|
-
<div class="f3d-search-result-item" data-node-id="${this.escapeHtml(
|
|
2226
|
-
<div class="f3d-result-label">${this.escapeHtml(
|
|
2478
|
+
let n = "";
|
|
2479
|
+
s.length > 0 && (n += '<div class="f3d-search-section-header">Nodes</div>', s.slice(0, 10).forEach((o) => {
|
|
2480
|
+
const a = o.type || "Node";
|
|
2481
|
+
n += `
|
|
2482
|
+
<div class="f3d-search-result-item" data-node-id="${this.escapeHtml(o.id)}">
|
|
2483
|
+
<div class="f3d-result-label">${this.escapeHtml(o.label)}</div>
|
|
2227
2484
|
<div class="f3d-result-type">${this.escapeHtml(a)}</div>
|
|
2228
2485
|
</div>
|
|
2229
2486
|
`;
|
|
2230
|
-
}), s.length > 10 && (
|
|
2231
|
-
|
|
2232
|
-
<div class="f3d-search-result-item" data-node-id="${this.escapeHtml(
|
|
2487
|
+
}), s.length > 10 && (n += `<div class="f3d-no-results">+ ${s.length - 10} more nodes</div>`)), t.length > 0 && (n += '<div class="f3d-search-section-header">Relationships</div>', t.slice(0, 5).forEach(({ edge: o, sourceNode: a, targetNode: l }) => {
|
|
2488
|
+
n += `
|
|
2489
|
+
<div class="f3d-search-result-item" data-node-id="${this.escapeHtml(o.source)}">
|
|
2233
2490
|
<div class="f3d-result-label">${this.escapeHtml(a.label)} → ${this.escapeHtml(l.label)}</div>
|
|
2234
|
-
<div class="f3d-result-relationship">${this.escapeHtml(
|
|
2491
|
+
<div class="f3d-result-relationship">${this.escapeHtml(o.relationship || "connected")}</div>
|
|
2235
2492
|
</div>
|
|
2236
2493
|
`;
|
|
2237
|
-
}), t.length > 5 && (
|
|
2238
|
-
|
|
2239
|
-
const a =
|
|
2494
|
+
}), t.length > 5 && (n += `<div class="f3d-no-results">+ ${t.length - 5} more relationships</div>`)), this.searchResults.innerHTML = n, this.searchResults.style.display = "block", this.searchResults.querySelectorAll(".f3d-search-result-item").forEach((o) => {
|
|
2495
|
+
o.addEventListener("click", () => {
|
|
2496
|
+
const a = o.dataset.nodeId;
|
|
2240
2497
|
a && (this.onResultClick(a), this.searchResults && (this.searchResults.style.display = "none"), this.searchInput && this.searchInput.blur());
|
|
2241
2498
|
});
|
|
2242
2499
|
});
|
|
@@ -2270,6 +2527,7 @@ class Ot {
|
|
|
2270
2527
|
// Interaction
|
|
2271
2528
|
r(this, "raycasterManager");
|
|
2272
2529
|
r(this, "panelManager");
|
|
2530
|
+
r(this, "edgePanelManager");
|
|
2273
2531
|
r(this, "edgeTooltipManager");
|
|
2274
2532
|
r(this, "searchManager", null);
|
|
2275
2533
|
// Event system
|
|
@@ -2277,22 +2535,22 @@ class Ot {
|
|
|
2277
2535
|
// State
|
|
2278
2536
|
r(this, "initialized", !1);
|
|
2279
2537
|
r(this, "devControls", null);
|
|
2280
|
-
this.options = { ...
|
|
2538
|
+
this.options = { ...I, ...s }, this.container = ct(e), this.materialFactory = new xt(), this.nodeFactory = new vt(
|
|
2281
2539
|
this.materialFactory,
|
|
2282
|
-
this.options.nodeRadius ??
|
|
2283
|
-
this.options.lodSegments ??
|
|
2540
|
+
this.options.nodeRadius ?? I.nodeRadius,
|
|
2541
|
+
this.options.lodSegments ?? I.lodSegments
|
|
2284
2542
|
), this.edgeFactory = new Mt(
|
|
2285
2543
|
this.materialFactory,
|
|
2286
|
-
this.options.edgeColor ??
|
|
2287
|
-
this.options.edgeOpacity ??
|
|
2288
|
-
), this.sceneManager = new
|
|
2544
|
+
this.options.edgeColor ?? I.edgeColor,
|
|
2545
|
+
this.options.edgeOpacity ?? I.edgeOpacity
|
|
2546
|
+
), this.sceneManager = new ut(this.container, this.options), this.lodManager = new wt(
|
|
2289
2547
|
this.sceneManager.camera,
|
|
2290
|
-
this.options.lodDistances ??
|
|
2291
|
-
this.options.enableLOD ??
|
|
2548
|
+
this.options.lodDistances ?? I.lodDistances,
|
|
2549
|
+
this.options.enableLOD ?? I.enableLOD
|
|
2292
2550
|
), this.frustumCuller = new Et(
|
|
2293
2551
|
this.sceneManager.camera,
|
|
2294
|
-
this.options.enableEdgeCulling ??
|
|
2295
|
-
), this.nodeManager = new mt(this.sceneManager, this.nodeFactory), this.edgeManager = new ft(this.sceneManager, this.nodeManager, this.edgeFactory), this.graphEngine = new
|
|
2552
|
+
this.options.enableEdgeCulling ?? I.enableEdgeCulling
|
|
2553
|
+
), this.nodeManager = new mt(this.sceneManager, this.nodeFactory), this.edgeManager = new ft(this.sceneManager, this.nodeManager, this.edgeFactory), this.graphEngine = new Le(
|
|
2296
2554
|
this.nodeManager.getAllNodes(),
|
|
2297
2555
|
this.edgeManager.getAllEdges(),
|
|
2298
2556
|
{
|
|
@@ -2306,8 +2564,12 @@ class Ot {
|
|
|
2306
2564
|
this.sceneManager,
|
|
2307
2565
|
() => this.onSimulate(),
|
|
2308
2566
|
() => this.onRender(),
|
|
2309
|
-
this.options.targetFPS ??
|
|
2310
|
-
), this.raycasterManager = new Ct(this.sceneManager, this.container), this.panelManager = new
|
|
2567
|
+
this.options.targetFPS ?? I.targetFPS
|
|
2568
|
+
), this.raycasterManager = new Ct(this.sceneManager, this.container), this.panelManager = new zt(this.container), this.edgePanelManager = new Nt(this.container), this.edgeTooltipManager = new St(), this.edgePanelManager.setNodeClickCallback((t) => {
|
|
2569
|
+
this.edgePanelManager.hide(), this.focusOnNode(t), setTimeout(() => {
|
|
2570
|
+
this.showNodePanel(t);
|
|
2571
|
+
}, 400);
|
|
2572
|
+
}), this.options.showSearch !== !1 && (this.searchManager = new kt(this.container, {
|
|
2311
2573
|
placeholder: this.options.searchPlaceholder,
|
|
2312
2574
|
onSearch: (t) => ({
|
|
2313
2575
|
nodeResults: this.searchNodes(t),
|
|
@@ -2330,6 +2592,8 @@ class Ot {
|
|
|
2330
2592
|
this.expandNode(e, s);
|
|
2331
2593
|
}), this.options.panelTemplate && this.panelManager.setPanelTemplate(this.options.panelTemplate), this.options.panelStyles && this.panelManager.setPanelStyles(this.options.panelStyles), this.raycasterManager.setEdgeHoverCallback((e) => {
|
|
2332
2594
|
this.onEdgeHover(e);
|
|
2595
|
+
}), this.raycasterManager.setEdgeClickCallback((e) => {
|
|
2596
|
+
this.onEdgeClick(e);
|
|
2333
2597
|
});
|
|
2334
2598
|
}
|
|
2335
2599
|
/**
|
|
@@ -2338,8 +2602,8 @@ class Ot {
|
|
|
2338
2602
|
onEdgeHover(e) {
|
|
2339
2603
|
if (e) {
|
|
2340
2604
|
this.edgeManager.highlightEdge(e.edge.source, e.edge.target);
|
|
2341
|
-
const s = this.container.getBoundingClientRect(), t = s.left + s.width / 2,
|
|
2342
|
-
this.edgeTooltipManager.show(e.edge, e.sourceNode, e.targetNode, t,
|
|
2605
|
+
const s = this.container.getBoundingClientRect(), t = s.left + s.width / 2, n = s.top + s.height / 2;
|
|
2606
|
+
this.edgeTooltipManager.show(e.edge, e.sourceNode, e.targetNode, t, n), this.options.onEdgeHover && this.options.onEdgeHover(e.edge, e.sourceNode, e.targetNode), this.emit("edgeHover", e.edge, e.sourceNode, e.targetNode);
|
|
2343
2607
|
} else
|
|
2344
2608
|
this.edgeManager.unhighlightCurrentEdge(), this.edgeTooltipManager.hide(), this.options.onEdgeHover && this.options.onEdgeHover(null, null, null), this.emit("edgeHover", null, null, null);
|
|
2345
2609
|
}
|
|
@@ -2347,9 +2611,16 @@ class Ot {
|
|
|
2347
2611
|
* Handles node click
|
|
2348
2612
|
*/
|
|
2349
2613
|
onNodeClick(e) {
|
|
2350
|
-
|
|
2614
|
+
this.edgePanelManager.hide();
|
|
2615
|
+
const t = this.edgeManager.getNeighborIds(e.id).map((n) => this.nodeManager.getNode(n)).filter((n) => n !== void 0);
|
|
2351
2616
|
this.options.showPanel !== !1 && this.panelManager.show(e, t), this.options.onNodeClick && this.options.onNodeClick(e), this.emit("nodeClick", e);
|
|
2352
2617
|
}
|
|
2618
|
+
/**
|
|
2619
|
+
* Handles edge click
|
|
2620
|
+
*/
|
|
2621
|
+
onEdgeClick(e) {
|
|
2622
|
+
this.panelManager.hide(), this.edgeTooltipManager.hide(), this.edgeManager.highlightEdge(e.edge.source, e.edge.target), this.edgePanelManager.show(e.edge, e.sourceNode, e.targetNode), this.focusOnEdge(e.edge.source, e.edge.target), this.emit("edgeClick", e.edge, e.sourceNode, e.targetNode);
|
|
2623
|
+
}
|
|
2353
2624
|
/**
|
|
2354
2625
|
* Called every simulation step
|
|
2355
2626
|
*/
|
|
@@ -2381,7 +2652,7 @@ class Ot {
|
|
|
2381
2652
|
if (e.edges && Array.isArray(e.edges))
|
|
2382
2653
|
for (const s of e.edges)
|
|
2383
2654
|
this.addEdge(s);
|
|
2384
|
-
this.graphEngine = new
|
|
2655
|
+
this.graphEngine = new Le(
|
|
2385
2656
|
this.nodeManager.getAllNodes(),
|
|
2386
2657
|
this.edgeManager.getAllEdges(),
|
|
2387
2658
|
{
|
|
@@ -2445,20 +2716,20 @@ class Ot {
|
|
|
2445
2716
|
* @param fetchFn - Optional fetch function to override the default
|
|
2446
2717
|
*/
|
|
2447
2718
|
async expandNode(e, s = 1, t) {
|
|
2448
|
-
const
|
|
2449
|
-
if (!
|
|
2719
|
+
const n = t ?? this.options.onExpand;
|
|
2720
|
+
if (!n)
|
|
2450
2721
|
return console.warn("[ForceGraph3D] No expand callback provided"), !1;
|
|
2451
2722
|
try {
|
|
2452
|
-
const
|
|
2453
|
-
if (
|
|
2454
|
-
for (const a of
|
|
2723
|
+
const o = await n(e, s);
|
|
2724
|
+
if (o.nodes && Array.isArray(o.nodes))
|
|
2725
|
+
for (const a of o.nodes)
|
|
2455
2726
|
this.addNode(a);
|
|
2456
|
-
if (
|
|
2457
|
-
for (const a of
|
|
2727
|
+
if (o.edges && Array.isArray(o.edges))
|
|
2728
|
+
for (const a of o.edges)
|
|
2458
2729
|
this.addEdge(a);
|
|
2459
|
-
return this.panelManager.hide(), this.emit("expand", e,
|
|
2460
|
-
} catch (
|
|
2461
|
-
return console.error("[ForceGraph3D] Error expanding node:",
|
|
2730
|
+
return this.panelManager.hide(), this.emit("expand", e, o), !0;
|
|
2731
|
+
} catch (o) {
|
|
2732
|
+
return console.error("[ForceGraph3D] Error expanding node:", o), !1;
|
|
2462
2733
|
}
|
|
2463
2734
|
}
|
|
2464
2735
|
/**
|
|
@@ -2501,15 +2772,39 @@ class Ot {
|
|
|
2501
2772
|
console.warn(`[ForceGraph3D] Node "${e}" not found`);
|
|
2502
2773
|
return;
|
|
2503
2774
|
}
|
|
2504
|
-
const
|
|
2505
|
-
x:
|
|
2506
|
-
y:
|
|
2507
|
-
z:
|
|
2508
|
-
},
|
|
2509
|
-
const
|
|
2510
|
-
|
|
2775
|
+
const n = t.position, o = this.sceneManager.camera, a = this.sceneManager.controls, l = o.position.clone().sub(a.target).normalize(), h = {
|
|
2776
|
+
x: n.x + l.x * s,
|
|
2777
|
+
y: n.y + l.y * s,
|
|
2778
|
+
z: n.z + l.z * s
|
|
2779
|
+
}, g = { x: o.position.x, y: o.position.y, z: o.position.z }, u = { x: a.target.x, y: a.target.y, z: a.target.z }, b = 800, x = performance.now(), f = () => {
|
|
2780
|
+
const m = performance.now() - x, M = Math.min(m / b, 1), E = 1 - Math.pow(1 - M, 3);
|
|
2781
|
+
o.position.x = g.x + (h.x - g.x) * E, o.position.y = g.y + (h.y - g.y) * E, o.position.z = g.z + (h.z - g.z) * E, a.target.x = u.x + (n.x - u.x) * E, a.target.y = u.y + (n.y - u.y) * E, a.target.z = u.z + (n.z - u.z) * E, a.update(), M < 1 && requestAnimationFrame(f);
|
|
2511
2782
|
};
|
|
2512
|
-
|
|
2783
|
+
f();
|
|
2784
|
+
}
|
|
2785
|
+
/**
|
|
2786
|
+
* Focuses the camera on an edge (both source and target nodes) with smooth animation
|
|
2787
|
+
* Camera targets the midpoint and zooms out enough to see both nodes
|
|
2788
|
+
*/
|
|
2789
|
+
focusOnEdge(e, s, t = 1.5) {
|
|
2790
|
+
const n = this.nodeManager.getNode(e), o = this.nodeManager.getNode(s);
|
|
2791
|
+
if (!n || !o) {
|
|
2792
|
+
console.warn(`[ForceGraph3D] Could not find nodes for edge "${e}" -> "${s}"`);
|
|
2793
|
+
return;
|
|
2794
|
+
}
|
|
2795
|
+
const a = this.sceneManager.camera, l = this.sceneManager.controls, h = {
|
|
2796
|
+
x: (n.position.x + o.position.x) / 2,
|
|
2797
|
+
y: (n.position.y + o.position.y) / 2,
|
|
2798
|
+
z: (n.position.z + o.position.z) / 2
|
|
2799
|
+
}, g = o.position.x - n.position.x, u = o.position.y - n.position.y, b = o.position.z - n.position.z, x = Math.sqrt(g * g + u * u + b * b), f = Math.max(x * t, 40), m = a.position.clone().sub(l.target).normalize(), M = {
|
|
2800
|
+
x: h.x + m.x * f,
|
|
2801
|
+
y: h.y + m.y * f,
|
|
2802
|
+
z: h.z + m.z * f
|
|
2803
|
+
}, E = { x: a.position.x, y: a.position.y, z: a.position.z }, z = { x: l.target.x, y: l.target.y, z: l.target.z }, R = 800, P = performance.now(), Y = () => {
|
|
2804
|
+
const T = performance.now() - P, H = Math.min(T / R, 1), w = 1 - Math.pow(1 - H, 3);
|
|
2805
|
+
a.position.x = E.x + (M.x - E.x) * w, a.position.y = E.y + (M.y - E.y) * w, a.position.z = E.z + (M.z - E.z) * w, l.target.x = z.x + (h.x - z.x) * w, l.target.y = z.y + (h.y - z.y) * w, l.target.z = z.z + (h.z - z.z) * w, l.update(), H < 1 && requestAnimationFrame(Y);
|
|
2806
|
+
};
|
|
2807
|
+
Y();
|
|
2513
2808
|
}
|
|
2514
2809
|
/**
|
|
2515
2810
|
* Shows the info panel for a specific node
|
|
@@ -2530,28 +2825,28 @@ class Ot {
|
|
|
2530
2825
|
searchNodes(e) {
|
|
2531
2826
|
if (!e || e.trim() === "")
|
|
2532
2827
|
return [];
|
|
2533
|
-
const s = e.toLowerCase().trim(), t = this.nodeManager.getAllNodes(),
|
|
2534
|
-
return t.forEach((
|
|
2535
|
-
var
|
|
2536
|
-
const a = (
|
|
2537
|
-
(a || l ||
|
|
2538
|
-
}),
|
|
2828
|
+
const s = e.toLowerCase().trim(), t = this.nodeManager.getAllNodes(), n = [];
|
|
2829
|
+
return t.forEach((o) => {
|
|
2830
|
+
var g, u, b;
|
|
2831
|
+
const a = (g = o.label) == null ? void 0 : g.toLowerCase().includes(s), l = (u = o.id) == null ? void 0 : u.toLowerCase().includes(s), h = (b = o.type) == null ? void 0 : b.toLowerCase().includes(s);
|
|
2832
|
+
(a || l || h) && n.push(o);
|
|
2833
|
+
}), n;
|
|
2539
2834
|
}
|
|
2540
2835
|
/**
|
|
2541
2836
|
* Searches edges by relationship (case-insensitive)
|
|
2542
2837
|
* @returns Array of matching edges with source/target node info
|
|
2543
2838
|
*/
|
|
2544
2839
|
searchEdges(e) {
|
|
2545
|
-
var
|
|
2840
|
+
var o;
|
|
2546
2841
|
if (!e || e.trim() === "")
|
|
2547
2842
|
return [];
|
|
2548
|
-
const s = e.toLowerCase().trim(), t = this.edgeManager.getAllEdges(),
|
|
2843
|
+
const s = e.toLowerCase().trim(), t = this.edgeManager.getAllEdges(), n = [];
|
|
2549
2844
|
for (const a of t)
|
|
2550
|
-
if ((
|
|
2551
|
-
const
|
|
2552
|
-
|
|
2845
|
+
if ((o = a.relationship) == null ? void 0 : o.toLowerCase().includes(s)) {
|
|
2846
|
+
const h = this.nodeManager.getNode(a.source), g = this.nodeManager.getNode(a.target);
|
|
2847
|
+
h && g && n.push({ edge: a, sourceNode: h, targetNode: g });
|
|
2553
2848
|
}
|
|
2554
|
-
return
|
|
2849
|
+
return n;
|
|
2555
2850
|
}
|
|
2556
2851
|
/**
|
|
2557
2852
|
* Gets all nodes as an array
|
|
@@ -2583,7 +2878,7 @@ class Ot {
|
|
|
2583
2878
|
*/
|
|
2584
2879
|
emit(e, ...s) {
|
|
2585
2880
|
const t = this.eventCallbacks.get(e);
|
|
2586
|
-
t && t.forEach((
|
|
2881
|
+
t && t.forEach((n) => n(...s));
|
|
2587
2882
|
}
|
|
2588
2883
|
/**
|
|
2589
2884
|
* Sets physics parameters
|
|
@@ -2660,17 +2955,17 @@ class Ot {
|
|
|
2660
2955
|
`, this.container.appendChild(this.devControls);
|
|
2661
2956
|
const e = this.devControls.querySelector("#dev-repulsion"), s = this.devControls.querySelector("#dev-attraction"), t = this.devControls.querySelector("#dev-damping");
|
|
2662
2957
|
e == null || e.addEventListener("input", () => {
|
|
2663
|
-
const
|
|
2664
|
-
this.setPhysicsParams({ repulsionStrength:
|
|
2958
|
+
const n = parseFloat(e.value);
|
|
2959
|
+
this.setPhysicsParams({ repulsionStrength: n }), this.devControls.querySelector("#dev-repulsion-val").textContent = n.toString();
|
|
2665
2960
|
}), s == null || s.addEventListener("input", () => {
|
|
2666
|
-
const
|
|
2667
|
-
this.setPhysicsParams({ attractionStrength:
|
|
2961
|
+
const n = parseFloat(s.value) / 1e3;
|
|
2962
|
+
this.setPhysicsParams({ attractionStrength: n }), this.devControls.querySelector("#dev-attraction-val").textContent = n.toFixed(3);
|
|
2668
2963
|
}), t == null || t.addEventListener("input", () => {
|
|
2669
|
-
const
|
|
2670
|
-
this.setPhysicsParams({ damping:
|
|
2964
|
+
const n = parseFloat(t.value) / 100;
|
|
2965
|
+
this.setPhysicsParams({ damping: n }), this.devControls.querySelector("#dev-damping-val").textContent = n.toFixed(2);
|
|
2671
2966
|
}), setInterval(() => {
|
|
2672
|
-
const
|
|
2673
|
-
|
|
2967
|
+
const n = this.devControls.querySelector("#dev-node-count"), o = this.devControls.querySelector("#dev-edge-count"), a = this.devControls.querySelector("#dev-fps");
|
|
2968
|
+
n && (n.textContent = this.getNodeCount().toString()), o && (o.textContent = this.getEdgeCount().toString()), a && (a.textContent = this.rendererManager.getFPS().toString());
|
|
2674
2969
|
}, 500);
|
|
2675
2970
|
}
|
|
2676
2971
|
/**
|
|
@@ -2680,7 +2975,7 @@ class Ot {
|
|
|
2680
2975
|
this.rendererManager.dispose(), this.panelManager.dispose(), this.raycasterManager.dispose(), this.edgeTooltipManager.dispose(), this.searchManager && this.searchManager.dispose(), this.edgeManager.dispose(), this.nodeManager.dispose(), this.nodeFactory.dispose(), this.materialFactory.dispose(), this.sceneManager.dispose(), this.devControls && this.devControls.parentNode && this.devControls.parentNode.removeChild(this.devControls), this.eventCallbacks.clear(), this.initialized = !1;
|
|
2681
2976
|
}
|
|
2682
2977
|
}
|
|
2683
|
-
const
|
|
2978
|
+
const Oe = [
|
|
2684
2979
|
"Alpha",
|
|
2685
2980
|
"Beta",
|
|
2686
2981
|
"Gamma",
|
|
@@ -2711,7 +3006,7 @@ const ke = [
|
|
|
2711
3006
|
"Link",
|
|
2712
3007
|
"Point",
|
|
2713
3008
|
"Vertex"
|
|
2714
|
-
],
|
|
3009
|
+
], J = [
|
|
2715
3010
|
"connects to",
|
|
2716
3011
|
"links with",
|
|
2717
3012
|
"relates to",
|
|
@@ -2734,14 +3029,14 @@ const ke = [
|
|
|
2734
3029
|
16746564
|
|
2735
3030
|
// Darker tangerine
|
|
2736
3031
|
];
|
|
2737
|
-
function
|
|
3032
|
+
function It(c = 30) {
|
|
2738
3033
|
const e = [], s = [];
|
|
2739
|
-
for (let
|
|
2740
|
-
const
|
|
3034
|
+
for (let n = 0; n < c; n++) {
|
|
3035
|
+
const o = n < Oe.length ? Oe[n] : `Node ${n + 1}`;
|
|
2741
3036
|
e.push({
|
|
2742
|
-
id: `node-${
|
|
2743
|
-
label:
|
|
2744
|
-
color: Ie[
|
|
3037
|
+
id: `node-${n}`,
|
|
3038
|
+
label: o,
|
|
3039
|
+
color: Ie[n % Ie.length],
|
|
2745
3040
|
position: {
|
|
2746
3041
|
x: (Math.random() - 0.5) * 60,
|
|
2747
3042
|
y: (Math.random() - 0.5) * 60,
|
|
@@ -2749,43 +3044,43 @@ function kt(c = 30) {
|
|
|
2749
3044
|
}
|
|
2750
3045
|
});
|
|
2751
3046
|
}
|
|
2752
|
-
for (let
|
|
2753
|
-
const
|
|
3047
|
+
for (let n = 1; n < c; n++) {
|
|
3048
|
+
const o = Math.floor(Math.random() * n);
|
|
2754
3049
|
s.push({
|
|
2755
|
-
source: `node-${
|
|
2756
|
-
target: `node-${
|
|
2757
|
-
relationship:
|
|
3050
|
+
source: `node-${n}`,
|
|
3051
|
+
target: `node-${o}`,
|
|
3052
|
+
relationship: J[Math.floor(Math.random() * J.length)]
|
|
2758
3053
|
});
|
|
2759
3054
|
}
|
|
2760
3055
|
const t = Math.floor(c * 0.5);
|
|
2761
|
-
for (let
|
|
2762
|
-
const
|
|
3056
|
+
for (let n = 0; n < t; n++) {
|
|
3057
|
+
const o = Math.floor(Math.random() * c);
|
|
2763
3058
|
let a = Math.floor(Math.random() * c);
|
|
2764
|
-
|
|
2765
|
-
const l = `node-${
|
|
3059
|
+
o === a && (a = (a + 1) % c);
|
|
3060
|
+
const l = `node-${o}`, h = `node-${a}`;
|
|
2766
3061
|
s.some(
|
|
2767
|
-
(
|
|
3062
|
+
(u) => u.source === l && u.target === h || u.source === h && u.target === l
|
|
2768
3063
|
) || s.push({
|
|
2769
3064
|
source: l,
|
|
2770
|
-
target:
|
|
2771
|
-
relationship:
|
|
3065
|
+
target: h,
|
|
3066
|
+
relationship: J[Math.floor(Math.random() * J.length)]
|
|
2772
3067
|
});
|
|
2773
3068
|
}
|
|
2774
3069
|
return { nodes: e, edges: s };
|
|
2775
3070
|
}
|
|
2776
|
-
function
|
|
2777
|
-
const e = [], s = [], t = Math.ceil(c / 50),
|
|
2778
|
-
for (let
|
|
2779
|
-
|
|
3071
|
+
function Rt(c = 1e3) {
|
|
3072
|
+
const e = [], s = [], t = Math.ceil(c / 50), n = [];
|
|
3073
|
+
for (let o = 0; o < t; o++)
|
|
3074
|
+
n.push({
|
|
2780
3075
|
x: (Math.random() - 0.5) * 200,
|
|
2781
3076
|
y: (Math.random() - 0.5) * 200,
|
|
2782
3077
|
z: (Math.random() - 0.5) * 200
|
|
2783
3078
|
});
|
|
2784
|
-
for (let
|
|
2785
|
-
const a =
|
|
3079
|
+
for (let o = 0; o < c; o++) {
|
|
3080
|
+
const a = n[o % t];
|
|
2786
3081
|
e.push({
|
|
2787
|
-
id: `node-${
|
|
2788
|
-
label: `N${
|
|
3082
|
+
id: `node-${o}`,
|
|
3083
|
+
label: `N${o}`,
|
|
2789
3084
|
position: {
|
|
2790
3085
|
x: a.x + (Math.random() - 0.5) * 40,
|
|
2791
3086
|
y: a.y + (Math.random() - 0.5) * 40,
|
|
@@ -2793,16 +3088,16 @@ function It(c = 1e3) {
|
|
|
2793
3088
|
}
|
|
2794
3089
|
});
|
|
2795
3090
|
}
|
|
2796
|
-
for (let
|
|
2797
|
-
const a = Math.floor(
|
|
3091
|
+
for (let o = 1; o < c; o++) {
|
|
3092
|
+
const a = Math.floor(o / 50) * 50, l = a === 0 ? Math.floor(Math.random() * o) : a + Math.floor(Math.random() * Math.min(o - a, 50));
|
|
2798
3093
|
s.push({
|
|
2799
|
-
source: `node-${
|
|
2800
|
-
target: `node-${Math.min(l,
|
|
3094
|
+
source: `node-${o}`,
|
|
3095
|
+
target: `node-${Math.min(l, o - 1)}`,
|
|
2801
3096
|
relationship: "links to"
|
|
2802
3097
|
});
|
|
2803
3098
|
}
|
|
2804
|
-
for (let
|
|
2805
|
-
const a =
|
|
3099
|
+
for (let o = 1; o < t; o++) {
|
|
3100
|
+
const a = o * 50, l = (o - 1) * 50 + Math.floor(Math.random() * 50);
|
|
2806
3101
|
s.push({
|
|
2807
3102
|
source: `node-${a}`,
|
|
2808
3103
|
target: `node-${l}`,
|
|
@@ -2812,12 +3107,12 @@ function It(c = 1e3) {
|
|
|
2812
3107
|
return { nodes: e, edges: s };
|
|
2813
3108
|
}
|
|
2814
3109
|
export {
|
|
2815
|
-
|
|
3110
|
+
I as DEFAULT_OPTIONS,
|
|
2816
3111
|
Ot as ForceGraph3D,
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
3112
|
+
X as LODLevel,
|
|
3113
|
+
A as createEdgeKey,
|
|
3114
|
+
Rt as generateLargeSampleData,
|
|
3115
|
+
It as generateSampleData,
|
|
2821
3116
|
Fe as validateEdgeData,
|
|
2822
3117
|
Re as validateNodeData
|
|
2823
3118
|
};
|