force-3d-graph 1.0.1 → 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 +817 -510
- package/dist/force-3d-graph.js.map +1 -1
- package/dist/force-3d-graph.umd.cjs +180 -18
- 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
|
});
|
|
@@ -1785,6 +1797,13 @@ class Nt {
|
|
|
1785
1797
|
display: flex;
|
|
1786
1798
|
align-items: center;
|
|
1787
1799
|
gap: 10px;
|
|
1800
|
+
overflow: hidden;
|
|
1801
|
+
}
|
|
1802
|
+
.force-graph-panel .node-label-text {
|
|
1803
|
+
white-space: nowrap;
|
|
1804
|
+
overflow: hidden;
|
|
1805
|
+
text-overflow: ellipsis;
|
|
1806
|
+
flex: 1;
|
|
1788
1807
|
}
|
|
1789
1808
|
.force-graph-panel .color-dot {
|
|
1790
1809
|
width: 12px;
|
|
@@ -1809,6 +1828,11 @@ class Nt {
|
|
|
1809
1828
|
.force-graph-panel .info-value {
|
|
1810
1829
|
color: rgba(255, 255, 255, 0.95);
|
|
1811
1830
|
font-weight: 500;
|
|
1831
|
+
white-space: nowrap;
|
|
1832
|
+
overflow: hidden;
|
|
1833
|
+
text-overflow: ellipsis;
|
|
1834
|
+
max-width: 180px;
|
|
1835
|
+
text-align: right;
|
|
1812
1836
|
}
|
|
1813
1837
|
.force-graph-panel .neighbors-section {
|
|
1814
1838
|
margin-top: 16px;
|
|
@@ -1891,12 +1915,12 @@ class Nt {
|
|
|
1891
1915
|
|
|
1892
1916
|
<h2>
|
|
1893
1917
|
<span class="color-dot"></span>
|
|
1894
|
-
|
|
1918
|
+
<span class="node-label-text">${this.escapeHtml(e.label)}</span>
|
|
1895
1919
|
</h2>
|
|
1896
1920
|
|
|
1897
1921
|
<div class="info-row">
|
|
1898
1922
|
<span class="info-label">ID</span>
|
|
1899
|
-
<span class="info-value">${this.escapeHtml(e.id)}</span>
|
|
1923
|
+
<span class="info-value" title="${this.escapeHtml(e.id)}">${this.escapeHtml(e.id)}</span>
|
|
1900
1924
|
</div>
|
|
1901
1925
|
|
|
1902
1926
|
<div class="info-row">
|
|
@@ -1908,7 +1932,7 @@ class Nt {
|
|
|
1908
1932
|
<div class="neighbors-section">
|
|
1909
1933
|
<div class="neighbors-title">Connected To</div>
|
|
1910
1934
|
${s.slice(0, 5).map(
|
|
1911
|
-
(
|
|
1935
|
+
(n) => `<span class="neighbor-chip">${this.escapeHtml(n.label)}</span>`
|
|
1912
1936
|
).join("")}
|
|
1913
1937
|
${s.length > 5 ? `<span class="neighbor-chip">+${s.length - 5} more</span>` : ""}
|
|
1914
1938
|
</div>
|
|
@@ -1962,6 +1986,251 @@ class Nt {
|
|
|
1962
1986
|
this.panel && this.panel.parentNode && this.panel.parentNode.removeChild(this.panel), this.panel = null;
|
|
1963
1987
|
}
|
|
1964
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
|
+
}
|
|
1965
2234
|
class St {
|
|
1966
2235
|
constructor() {
|
|
1967
2236
|
r(this, "tooltip", null);
|
|
@@ -2008,14 +2277,14 @@ class St {
|
|
|
2008
2277
|
*/
|
|
2009
2278
|
positionTooltip(e, s) {
|
|
2010
2279
|
if (!this.tooltip) return;
|
|
2011
|
-
const t = this.tooltip.getBoundingClientRect(),
|
|
2280
|
+
const t = this.tooltip.getBoundingClientRect(), n = window.innerWidth, o = window.innerHeight;
|
|
2012
2281
|
let a = e + 15, l = s + 15;
|
|
2013
|
-
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`;
|
|
2014
2283
|
}
|
|
2015
2284
|
/**
|
|
2016
2285
|
* Shows the tooltip with edge info
|
|
2017
2286
|
*/
|
|
2018
|
-
show(e, s, t,
|
|
2287
|
+
show(e, s, t, n, o) {
|
|
2019
2288
|
if (!this.tooltip) return;
|
|
2020
2289
|
const a = e.relationship || "connected to";
|
|
2021
2290
|
this.tooltip.innerHTML = `
|
|
@@ -2030,7 +2299,7 @@ class St {
|
|
|
2030
2299
|
<span style="font-weight: 600; color: #ff9966;">${this.escapeHtml(t.label)}</span>
|
|
2031
2300
|
</div>
|
|
2032
2301
|
</div>
|
|
2033
|
-
`, this.positionTooltip(
|
|
2302
|
+
`, this.positionTooltip(n, o), this.tooltip.style.opacity = "1", this.tooltip.style.transform = "translateY(0)", this.visible = !0;
|
|
2034
2303
|
}
|
|
2035
2304
|
/**
|
|
2036
2305
|
* Updates tooltip position (called externally on mouse move)
|
|
@@ -2064,7 +2333,7 @@ class St {
|
|
|
2064
2333
|
this.tooltip && this.tooltip.parentNode && this.tooltip.parentNode.removeChild(this.tooltip), this.tooltip = null;
|
|
2065
2334
|
}
|
|
2066
2335
|
}
|
|
2067
|
-
class
|
|
2336
|
+
class kt {
|
|
2068
2337
|
constructor(e, s) {
|
|
2069
2338
|
r(this, "container");
|
|
2070
2339
|
r(this, "searchContainer", null);
|
|
@@ -2206,25 +2475,25 @@ class zt {
|
|
|
2206
2475
|
this.searchResults.innerHTML = '<div class="f3d-no-results">No results found</div>', this.searchResults.style.display = "block";
|
|
2207
2476
|
return;
|
|
2208
2477
|
}
|
|
2209
|
-
let
|
|
2210
|
-
s.length > 0 && (
|
|
2211
|
-
const a =
|
|
2212
|
-
|
|
2213
|
-
<div class="f3d-search-result-item" data-node-id="${this.escapeHtml(
|
|
2214
|
-
<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>
|
|
2215
2484
|
<div class="f3d-result-type">${this.escapeHtml(a)}</div>
|
|
2216
2485
|
</div>
|
|
2217
2486
|
`;
|
|
2218
|
-
}), s.length > 10 && (
|
|
2219
|
-
|
|
2220
|
-
<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)}">
|
|
2221
2490
|
<div class="f3d-result-label">${this.escapeHtml(a.label)} → ${this.escapeHtml(l.label)}</div>
|
|
2222
|
-
<div class="f3d-result-relationship">${this.escapeHtml(
|
|
2491
|
+
<div class="f3d-result-relationship">${this.escapeHtml(o.relationship || "connected")}</div>
|
|
2223
2492
|
</div>
|
|
2224
2493
|
`;
|
|
2225
|
-
}), t.length > 5 && (
|
|
2226
|
-
|
|
2227
|
-
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;
|
|
2228
2497
|
a && (this.onResultClick(a), this.searchResults && (this.searchResults.style.display = "none"), this.searchInput && this.searchInput.blur());
|
|
2229
2498
|
});
|
|
2230
2499
|
});
|
|
@@ -2258,6 +2527,7 @@ class Ot {
|
|
|
2258
2527
|
// Interaction
|
|
2259
2528
|
r(this, "raycasterManager");
|
|
2260
2529
|
r(this, "panelManager");
|
|
2530
|
+
r(this, "edgePanelManager");
|
|
2261
2531
|
r(this, "edgeTooltipManager");
|
|
2262
2532
|
r(this, "searchManager", null);
|
|
2263
2533
|
// Event system
|
|
@@ -2265,22 +2535,22 @@ class Ot {
|
|
|
2265
2535
|
// State
|
|
2266
2536
|
r(this, "initialized", !1);
|
|
2267
2537
|
r(this, "devControls", null);
|
|
2268
|
-
this.options = { ...
|
|
2538
|
+
this.options = { ...I, ...s }, this.container = ct(e), this.materialFactory = new xt(), this.nodeFactory = new vt(
|
|
2269
2539
|
this.materialFactory,
|
|
2270
|
-
this.options.nodeRadius ??
|
|
2271
|
-
this.options.lodSegments ??
|
|
2540
|
+
this.options.nodeRadius ?? I.nodeRadius,
|
|
2541
|
+
this.options.lodSegments ?? I.lodSegments
|
|
2272
2542
|
), this.edgeFactory = new Mt(
|
|
2273
2543
|
this.materialFactory,
|
|
2274
|
-
this.options.edgeColor ??
|
|
2275
|
-
this.options.edgeOpacity ??
|
|
2276
|
-
), 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(
|
|
2277
2547
|
this.sceneManager.camera,
|
|
2278
|
-
this.options.lodDistances ??
|
|
2279
|
-
this.options.enableLOD ??
|
|
2548
|
+
this.options.lodDistances ?? I.lodDistances,
|
|
2549
|
+
this.options.enableLOD ?? I.enableLOD
|
|
2280
2550
|
), this.frustumCuller = new Et(
|
|
2281
2551
|
this.sceneManager.camera,
|
|
2282
|
-
this.options.enableEdgeCulling ??
|
|
2283
|
-
), 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(
|
|
2284
2554
|
this.nodeManager.getAllNodes(),
|
|
2285
2555
|
this.edgeManager.getAllEdges(),
|
|
2286
2556
|
{
|
|
@@ -2294,8 +2564,12 @@ class Ot {
|
|
|
2294
2564
|
this.sceneManager,
|
|
2295
2565
|
() => this.onSimulate(),
|
|
2296
2566
|
() => this.onRender(),
|
|
2297
|
-
this.options.targetFPS ??
|
|
2298
|
-
), 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, {
|
|
2299
2573
|
placeholder: this.options.searchPlaceholder,
|
|
2300
2574
|
onSearch: (t) => ({
|
|
2301
2575
|
nodeResults: this.searchNodes(t),
|
|
@@ -2318,6 +2592,8 @@ class Ot {
|
|
|
2318
2592
|
this.expandNode(e, s);
|
|
2319
2593
|
}), this.options.panelTemplate && this.panelManager.setPanelTemplate(this.options.panelTemplate), this.options.panelStyles && this.panelManager.setPanelStyles(this.options.panelStyles), this.raycasterManager.setEdgeHoverCallback((e) => {
|
|
2320
2594
|
this.onEdgeHover(e);
|
|
2595
|
+
}), this.raycasterManager.setEdgeClickCallback((e) => {
|
|
2596
|
+
this.onEdgeClick(e);
|
|
2321
2597
|
});
|
|
2322
2598
|
}
|
|
2323
2599
|
/**
|
|
@@ -2326,8 +2602,8 @@ class Ot {
|
|
|
2326
2602
|
onEdgeHover(e) {
|
|
2327
2603
|
if (e) {
|
|
2328
2604
|
this.edgeManager.highlightEdge(e.edge.source, e.edge.target);
|
|
2329
|
-
const s = this.container.getBoundingClientRect(), t = s.left + s.width / 2,
|
|
2330
|
-
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);
|
|
2331
2607
|
} else
|
|
2332
2608
|
this.edgeManager.unhighlightCurrentEdge(), this.edgeTooltipManager.hide(), this.options.onEdgeHover && this.options.onEdgeHover(null, null, null), this.emit("edgeHover", null, null, null);
|
|
2333
2609
|
}
|
|
@@ -2335,9 +2611,16 @@ class Ot {
|
|
|
2335
2611
|
* Handles node click
|
|
2336
2612
|
*/
|
|
2337
2613
|
onNodeClick(e) {
|
|
2338
|
-
|
|
2614
|
+
this.edgePanelManager.hide();
|
|
2615
|
+
const t = this.edgeManager.getNeighborIds(e.id).map((n) => this.nodeManager.getNode(n)).filter((n) => n !== void 0);
|
|
2339
2616
|
this.options.showPanel !== !1 && this.panelManager.show(e, t), this.options.onNodeClick && this.options.onNodeClick(e), this.emit("nodeClick", e);
|
|
2340
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
|
+
}
|
|
2341
2624
|
/**
|
|
2342
2625
|
* Called every simulation step
|
|
2343
2626
|
*/
|
|
@@ -2369,7 +2652,7 @@ class Ot {
|
|
|
2369
2652
|
if (e.edges && Array.isArray(e.edges))
|
|
2370
2653
|
for (const s of e.edges)
|
|
2371
2654
|
this.addEdge(s);
|
|
2372
|
-
this.graphEngine = new
|
|
2655
|
+
this.graphEngine = new Le(
|
|
2373
2656
|
this.nodeManager.getAllNodes(),
|
|
2374
2657
|
this.edgeManager.getAllEdges(),
|
|
2375
2658
|
{
|
|
@@ -2433,20 +2716,20 @@ class Ot {
|
|
|
2433
2716
|
* @param fetchFn - Optional fetch function to override the default
|
|
2434
2717
|
*/
|
|
2435
2718
|
async expandNode(e, s = 1, t) {
|
|
2436
|
-
const
|
|
2437
|
-
if (!
|
|
2719
|
+
const n = t ?? this.options.onExpand;
|
|
2720
|
+
if (!n)
|
|
2438
2721
|
return console.warn("[ForceGraph3D] No expand callback provided"), !1;
|
|
2439
2722
|
try {
|
|
2440
|
-
const
|
|
2441
|
-
if (
|
|
2442
|
-
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)
|
|
2443
2726
|
this.addNode(a);
|
|
2444
|
-
if (
|
|
2445
|
-
for (const a of
|
|
2727
|
+
if (o.edges && Array.isArray(o.edges))
|
|
2728
|
+
for (const a of o.edges)
|
|
2446
2729
|
this.addEdge(a);
|
|
2447
|
-
return this.panelManager.hide(), this.emit("expand", e,
|
|
2448
|
-
} catch (
|
|
2449
|
-
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;
|
|
2450
2733
|
}
|
|
2451
2734
|
}
|
|
2452
2735
|
/**
|
|
@@ -2489,15 +2772,39 @@ class Ot {
|
|
|
2489
2772
|
console.warn(`[ForceGraph3D] Node "${e}" not found`);
|
|
2490
2773
|
return;
|
|
2491
2774
|
}
|
|
2492
|
-
const
|
|
2493
|
-
x:
|
|
2494
|
-
y:
|
|
2495
|
-
z:
|
|
2496
|
-
},
|
|
2497
|
-
const
|
|
2498
|
-
|
|
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);
|
|
2499
2782
|
};
|
|
2500
|
-
|
|
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();
|
|
2501
2808
|
}
|
|
2502
2809
|
/**
|
|
2503
2810
|
* Shows the info panel for a specific node
|
|
@@ -2518,28 +2825,28 @@ class Ot {
|
|
|
2518
2825
|
searchNodes(e) {
|
|
2519
2826
|
if (!e || e.trim() === "")
|
|
2520
2827
|
return [];
|
|
2521
|
-
const s = e.toLowerCase().trim(), t = this.nodeManager.getAllNodes(),
|
|
2522
|
-
return t.forEach((
|
|
2523
|
-
var
|
|
2524
|
-
const a = (
|
|
2525
|
-
(a || l ||
|
|
2526
|
-
}),
|
|
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;
|
|
2527
2834
|
}
|
|
2528
2835
|
/**
|
|
2529
2836
|
* Searches edges by relationship (case-insensitive)
|
|
2530
2837
|
* @returns Array of matching edges with source/target node info
|
|
2531
2838
|
*/
|
|
2532
2839
|
searchEdges(e) {
|
|
2533
|
-
var
|
|
2840
|
+
var o;
|
|
2534
2841
|
if (!e || e.trim() === "")
|
|
2535
2842
|
return [];
|
|
2536
|
-
const s = e.toLowerCase().trim(), t = this.edgeManager.getAllEdges(),
|
|
2843
|
+
const s = e.toLowerCase().trim(), t = this.edgeManager.getAllEdges(), n = [];
|
|
2537
2844
|
for (const a of t)
|
|
2538
|
-
if ((
|
|
2539
|
-
const
|
|
2540
|
-
|
|
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 });
|
|
2541
2848
|
}
|
|
2542
|
-
return
|
|
2849
|
+
return n;
|
|
2543
2850
|
}
|
|
2544
2851
|
/**
|
|
2545
2852
|
* Gets all nodes as an array
|
|
@@ -2571,7 +2878,7 @@ class Ot {
|
|
|
2571
2878
|
*/
|
|
2572
2879
|
emit(e, ...s) {
|
|
2573
2880
|
const t = this.eventCallbacks.get(e);
|
|
2574
|
-
t && t.forEach((
|
|
2881
|
+
t && t.forEach((n) => n(...s));
|
|
2575
2882
|
}
|
|
2576
2883
|
/**
|
|
2577
2884
|
* Sets physics parameters
|
|
@@ -2648,17 +2955,17 @@ class Ot {
|
|
|
2648
2955
|
`, this.container.appendChild(this.devControls);
|
|
2649
2956
|
const e = this.devControls.querySelector("#dev-repulsion"), s = this.devControls.querySelector("#dev-attraction"), t = this.devControls.querySelector("#dev-damping");
|
|
2650
2957
|
e == null || e.addEventListener("input", () => {
|
|
2651
|
-
const
|
|
2652
|
-
this.setPhysicsParams({ repulsionStrength:
|
|
2958
|
+
const n = parseFloat(e.value);
|
|
2959
|
+
this.setPhysicsParams({ repulsionStrength: n }), this.devControls.querySelector("#dev-repulsion-val").textContent = n.toString();
|
|
2653
2960
|
}), s == null || s.addEventListener("input", () => {
|
|
2654
|
-
const
|
|
2655
|
-
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);
|
|
2656
2963
|
}), t == null || t.addEventListener("input", () => {
|
|
2657
|
-
const
|
|
2658
|
-
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);
|
|
2659
2966
|
}), setInterval(() => {
|
|
2660
|
-
const
|
|
2661
|
-
|
|
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());
|
|
2662
2969
|
}, 500);
|
|
2663
2970
|
}
|
|
2664
2971
|
/**
|
|
@@ -2668,7 +2975,7 @@ class Ot {
|
|
|
2668
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;
|
|
2669
2976
|
}
|
|
2670
2977
|
}
|
|
2671
|
-
const
|
|
2978
|
+
const Oe = [
|
|
2672
2979
|
"Alpha",
|
|
2673
2980
|
"Beta",
|
|
2674
2981
|
"Gamma",
|
|
@@ -2699,7 +3006,7 @@ const ke = [
|
|
|
2699
3006
|
"Link",
|
|
2700
3007
|
"Point",
|
|
2701
3008
|
"Vertex"
|
|
2702
|
-
],
|
|
3009
|
+
], J = [
|
|
2703
3010
|
"connects to",
|
|
2704
3011
|
"links with",
|
|
2705
3012
|
"relates to",
|
|
@@ -2722,14 +3029,14 @@ const ke = [
|
|
|
2722
3029
|
16746564
|
|
2723
3030
|
// Darker tangerine
|
|
2724
3031
|
];
|
|
2725
|
-
function
|
|
3032
|
+
function It(c = 30) {
|
|
2726
3033
|
const e = [], s = [];
|
|
2727
|
-
for (let
|
|
2728
|
-
const
|
|
3034
|
+
for (let n = 0; n < c; n++) {
|
|
3035
|
+
const o = n < Oe.length ? Oe[n] : `Node ${n + 1}`;
|
|
2729
3036
|
e.push({
|
|
2730
|
-
id: `node-${
|
|
2731
|
-
label:
|
|
2732
|
-
color: Ie[
|
|
3037
|
+
id: `node-${n}`,
|
|
3038
|
+
label: o,
|
|
3039
|
+
color: Ie[n % Ie.length],
|
|
2733
3040
|
position: {
|
|
2734
3041
|
x: (Math.random() - 0.5) * 60,
|
|
2735
3042
|
y: (Math.random() - 0.5) * 60,
|
|
@@ -2737,43 +3044,43 @@ function kt(c = 30) {
|
|
|
2737
3044
|
}
|
|
2738
3045
|
});
|
|
2739
3046
|
}
|
|
2740
|
-
for (let
|
|
2741
|
-
const
|
|
3047
|
+
for (let n = 1; n < c; n++) {
|
|
3048
|
+
const o = Math.floor(Math.random() * n);
|
|
2742
3049
|
s.push({
|
|
2743
|
-
source: `node-${
|
|
2744
|
-
target: `node-${
|
|
2745
|
-
relationship:
|
|
3050
|
+
source: `node-${n}`,
|
|
3051
|
+
target: `node-${o}`,
|
|
3052
|
+
relationship: J[Math.floor(Math.random() * J.length)]
|
|
2746
3053
|
});
|
|
2747
3054
|
}
|
|
2748
3055
|
const t = Math.floor(c * 0.5);
|
|
2749
|
-
for (let
|
|
2750
|
-
const
|
|
3056
|
+
for (let n = 0; n < t; n++) {
|
|
3057
|
+
const o = Math.floor(Math.random() * c);
|
|
2751
3058
|
let a = Math.floor(Math.random() * c);
|
|
2752
|
-
|
|
2753
|
-
const l = `node-${
|
|
3059
|
+
o === a && (a = (a + 1) % c);
|
|
3060
|
+
const l = `node-${o}`, h = `node-${a}`;
|
|
2754
3061
|
s.some(
|
|
2755
|
-
(
|
|
3062
|
+
(u) => u.source === l && u.target === h || u.source === h && u.target === l
|
|
2756
3063
|
) || s.push({
|
|
2757
3064
|
source: l,
|
|
2758
|
-
target:
|
|
2759
|
-
relationship:
|
|
3065
|
+
target: h,
|
|
3066
|
+
relationship: J[Math.floor(Math.random() * J.length)]
|
|
2760
3067
|
});
|
|
2761
3068
|
}
|
|
2762
3069
|
return { nodes: e, edges: s };
|
|
2763
3070
|
}
|
|
2764
|
-
function
|
|
2765
|
-
const e = [], s = [], t = Math.ceil(c / 50),
|
|
2766
|
-
for (let
|
|
2767
|
-
|
|
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({
|
|
2768
3075
|
x: (Math.random() - 0.5) * 200,
|
|
2769
3076
|
y: (Math.random() - 0.5) * 200,
|
|
2770
3077
|
z: (Math.random() - 0.5) * 200
|
|
2771
3078
|
});
|
|
2772
|
-
for (let
|
|
2773
|
-
const a =
|
|
3079
|
+
for (let o = 0; o < c; o++) {
|
|
3080
|
+
const a = n[o % t];
|
|
2774
3081
|
e.push({
|
|
2775
|
-
id: `node-${
|
|
2776
|
-
label: `N${
|
|
3082
|
+
id: `node-${o}`,
|
|
3083
|
+
label: `N${o}`,
|
|
2777
3084
|
position: {
|
|
2778
3085
|
x: a.x + (Math.random() - 0.5) * 40,
|
|
2779
3086
|
y: a.y + (Math.random() - 0.5) * 40,
|
|
@@ -2781,16 +3088,16 @@ function It(c = 1e3) {
|
|
|
2781
3088
|
}
|
|
2782
3089
|
});
|
|
2783
3090
|
}
|
|
2784
|
-
for (let
|
|
2785
|
-
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));
|
|
2786
3093
|
s.push({
|
|
2787
|
-
source: `node-${
|
|
2788
|
-
target: `node-${Math.min(l,
|
|
3094
|
+
source: `node-${o}`,
|
|
3095
|
+
target: `node-${Math.min(l, o - 1)}`,
|
|
2789
3096
|
relationship: "links to"
|
|
2790
3097
|
});
|
|
2791
3098
|
}
|
|
2792
|
-
for (let
|
|
2793
|
-
const a =
|
|
3099
|
+
for (let o = 1; o < t; o++) {
|
|
3100
|
+
const a = o * 50, l = (o - 1) * 50 + Math.floor(Math.random() * 50);
|
|
2794
3101
|
s.push({
|
|
2795
3102
|
source: `node-${a}`,
|
|
2796
3103
|
target: `node-${l}`,
|
|
@@ -2800,12 +3107,12 @@ function It(c = 1e3) {
|
|
|
2800
3107
|
return { nodes: e, edges: s };
|
|
2801
3108
|
}
|
|
2802
3109
|
export {
|
|
2803
|
-
|
|
3110
|
+
I as DEFAULT_OPTIONS,
|
|
2804
3111
|
Ot as ForceGraph3D,
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
3112
|
+
X as LODLevel,
|
|
3113
|
+
A as createEdgeKey,
|
|
3114
|
+
Rt as generateLargeSampleData,
|
|
3115
|
+
It as generateSampleData,
|
|
2809
3116
|
Fe as validateEdgeData,
|
|
2810
3117
|
Re as validateNodeData
|
|
2811
3118
|
};
|