force-3d-graph 1.2.0 → 1.2.2
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 +448 -445
- package/dist/force-3d-graph.js.map +1 -1
- package/dist/force-3d-graph.umd.cjs +19 -19
- package/dist/force-3d-graph.umd.cjs.map +1 -1
- package/package.json +1 -1
package/dist/force-3d-graph.js
CHANGED
|
@@ -3,17 +3,18 @@ var it = (h, e, s) => e in h ? st(h, e, { enumerable: !0, configurable: !0, writ
|
|
|
3
3
|
var l = (h, e, s) => it(h, typeof e != "symbol" ? e + "" : e, s);
|
|
4
4
|
import * as m from "three";
|
|
5
5
|
import { EventDispatcher as ot, Vector3 as S, MOUSE as $, TOUCH as G, Spherical as Ne, Quaternion as Se, Vector2 as k, Ray as nt, Plane as at, MathUtils as rt } from "three";
|
|
6
|
-
const
|
|
6
|
+
const T = {
|
|
7
7
|
backgroundColor: 657930,
|
|
8
8
|
cameraPosition: { x: 0, y: 0, z: 80 },
|
|
9
9
|
cameraFov: 75,
|
|
10
|
-
repulsionStrength:
|
|
11
|
-
attractionStrength:
|
|
12
|
-
damping: 0.
|
|
13
|
-
useBarnesHut: !
|
|
14
|
-
//
|
|
10
|
+
repulsionStrength: 200,
|
|
11
|
+
attractionStrength: 8e-3,
|
|
12
|
+
damping: 0.95,
|
|
13
|
+
useBarnesHut: !0,
|
|
14
|
+
// Enabled by default for better performance
|
|
15
15
|
barnesHutTheta: 0.5,
|
|
16
|
-
defaultNodeColor:
|
|
16
|
+
defaultNodeColor: 16750950,
|
|
17
|
+
// Tangerine to match the premium glass material
|
|
17
18
|
nodeRadius: 2,
|
|
18
19
|
nodeSegments: 32,
|
|
19
20
|
enableLOD: !0,
|
|
@@ -91,14 +92,14 @@ class gt extends ot {
|
|
|
91
92
|
}, this.saveState = function() {
|
|
92
93
|
t.target0.copy(t.target), t.position0.copy(t.object.position), t.zoom0 = t.object.zoom;
|
|
93
94
|
}, this.reset = function() {
|
|
94
|
-
t.target.copy(t.target0), t.object.position.copy(t.position0), t.object.zoom = t.zoom0, t.object.updateProjectionMatrix(), t.dispatchEvent(ke), t.update(),
|
|
95
|
+
t.target.copy(t.target0), t.object.position.copy(t.position0), t.object.zoom = t.zoom0, t.object.updateProjectionMatrix(), t.dispatchEvent(ke), t.update(), o = i.NONE;
|
|
95
96
|
}, this.update = function() {
|
|
96
|
-
const n = new S(),
|
|
97
|
+
const n = new S(), g = new Se().setFromUnitVectors(e.up, new S(0, 1, 0)), v = g.clone().invert(), w = new S(), C = new Se(), F = new S(), z = 2 * Math.PI;
|
|
97
98
|
return function(tt = null) {
|
|
98
99
|
const Ce = t.object.position;
|
|
99
|
-
n.copy(Ce).sub(t.target), n.applyQuaternion(
|
|
100
|
-
let
|
|
101
|
-
isFinite(
|
|
100
|
+
n.copy(Ce).sub(t.target), n.applyQuaternion(g), r.setFromVector3(n), t.autoRotate && o === i.NONE && B(He(tt)), t.enableDamping ? (r.theta += c.theta * t.dampingFactor, r.phi += c.phi * t.dampingFactor) : (r.theta += c.theta, r.phi += c.phi);
|
|
101
|
+
let I = t.minAzimuthAngle, R = t.maxAzimuthAngle;
|
|
102
|
+
isFinite(I) && isFinite(R) && (I < -Math.PI ? I += z : I > Math.PI && (I -= z), R < -Math.PI ? R += z : R > Math.PI && (R -= z), I <= R ? r.theta = Math.max(I, Math.min(R, r.theta)) : r.theta = r.theta > (I + R) / 2 ? Math.max(I, r.theta) : Math.min(R, r.theta)), r.phi = Math.max(t.minPolarAngle, Math.min(t.maxPolarAngle, r.phi)), r.makeSafe(), t.enableDamping === !0 ? t.target.addScaledVector(p, t.dampingFactor) : t.target.add(p), t.target.sub(t.cursor), t.target.clampLength(t.minTargetRadius, t.maxTargetRadius), t.target.add(t.cursor), t.zoomToCursor && H || t.object.isOrthographicCamera ? r.radius = ie(r.radius) : r.radius = ie(r.radius * d), n.setFromSpherical(r), n.applyQuaternion(v), Ce.copy(t.target).add(n), t.object.lookAt(t.target), t.enableDamping === !0 ? (c.theta *= 1 - t.dampingFactor, c.phi *= 1 - t.dampingFactor, p.multiplyScalar(1 - t.dampingFactor)) : (c.set(0, 0, 0), p.set(0, 0, 0));
|
|
102
103
|
let ae = !1;
|
|
103
104
|
if (t.zoomToCursor && H) {
|
|
104
105
|
let X = null;
|
|
@@ -121,7 +122,7 @@ class gt extends ot {
|
|
|
121
122
|
}(), this.dispose = function() {
|
|
122
123
|
t.domElement.removeEventListener("contextmenu", we), t.domElement.removeEventListener("pointerdown", be), t.domElement.removeEventListener("pointercancel", K), t.domElement.removeEventListener("wheel", ve), t.domElement.removeEventListener("pointermove", oe), t.domElement.removeEventListener("pointerup", K), t._domElementKeyEvents !== null && (t._domElementKeyEvents.removeEventListener("keydown", ne), t._domElementKeyEvents = null);
|
|
123
124
|
};
|
|
124
|
-
const t = this,
|
|
125
|
+
const t = this, i = {
|
|
125
126
|
NONE: -1,
|
|
126
127
|
ROTATE: 0,
|
|
127
128
|
DOLLY: 1,
|
|
@@ -131,10 +132,10 @@ class gt extends ot {
|
|
|
131
132
|
TOUCH_DOLLY_PAN: 5,
|
|
132
133
|
TOUCH_DOLLY_ROTATE: 6
|
|
133
134
|
};
|
|
134
|
-
let
|
|
135
|
+
let o = i.NONE;
|
|
135
136
|
const a = 1e-6, r = new Ne(), c = new Ne();
|
|
136
137
|
let d = 1;
|
|
137
|
-
const
|
|
138
|
+
const p = new S(), x = new k(), f = new k(), u = new k(), y = new k(), b = new k(), M = new k(), N = new k(), O = new k(), L = new k(), Y = new S(), P = new k();
|
|
138
139
|
let H = !1;
|
|
139
140
|
const E = [], _ = {};
|
|
140
141
|
let ee = !1;
|
|
@@ -142,8 +143,8 @@ class gt extends ot {
|
|
|
142
143
|
return n !== null ? 2 * Math.PI / 60 * t.autoRotateSpeed * n : 2 * Math.PI / 60 / 60 * t.autoRotateSpeed;
|
|
143
144
|
}
|
|
144
145
|
function q(n) {
|
|
145
|
-
const
|
|
146
|
-
return Math.pow(0.95, t.zoomSpeed *
|
|
146
|
+
const g = Math.abs(n * 0.01);
|
|
147
|
+
return Math.pow(0.95, t.zoomSpeed * g);
|
|
147
148
|
}
|
|
148
149
|
function B(n) {
|
|
149
150
|
c.theta -= n;
|
|
@@ -153,24 +154,24 @@ class gt extends ot {
|
|
|
153
154
|
}
|
|
154
155
|
const le = function() {
|
|
155
156
|
const n = new S();
|
|
156
|
-
return function(
|
|
157
|
-
n.setFromMatrixColumn(w, 0), n.multiplyScalar(-
|
|
157
|
+
return function(v, w) {
|
|
158
|
+
n.setFromMatrixColumn(w, 0), n.multiplyScalar(-v), p.add(n);
|
|
158
159
|
};
|
|
159
160
|
}(), ce = function() {
|
|
160
161
|
const n = new S();
|
|
161
|
-
return function(
|
|
162
|
-
t.screenSpacePanning === !0 ? n.setFromMatrixColumn(w, 1) : (n.setFromMatrixColumn(w, 0), n.crossVectors(t.object.up, n)), n.multiplyScalar(
|
|
162
|
+
return function(v, w) {
|
|
163
|
+
t.screenSpacePanning === !0 ? n.setFromMatrixColumn(w, 1) : (n.setFromMatrixColumn(w, 0), n.crossVectors(t.object.up, n)), n.multiplyScalar(v), p.add(n);
|
|
163
164
|
};
|
|
164
165
|
}(), A = function() {
|
|
165
166
|
const n = new S();
|
|
166
|
-
return function(
|
|
167
|
+
return function(v, w) {
|
|
167
168
|
const C = t.domElement;
|
|
168
169
|
if (t.object.isPerspectiveCamera) {
|
|
169
170
|
const F = t.object.position;
|
|
170
171
|
n.copy(F).sub(t.target);
|
|
171
172
|
let z = n.length();
|
|
172
|
-
z *= Math.tan(t.object.fov / 2 * Math.PI / 180), le(2 *
|
|
173
|
-
} else t.object.isOrthographicCamera ? (le(
|
|
173
|
+
z *= Math.tan(t.object.fov / 2 * Math.PI / 180), le(2 * v * z / C.clientHeight, t.object.matrix), ce(2 * w * z / C.clientHeight, t.object.matrix);
|
|
174
|
+
} else t.object.isOrthographicCamera ? (le(v * (t.object.right - t.object.left) / t.object.zoom / C.clientWidth, t.object.matrix), ce(w * (t.object.top - t.object.bottom) / t.object.zoom / C.clientHeight, t.object.matrix)) : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."), t.enablePan = !1);
|
|
174
175
|
};
|
|
175
176
|
}();
|
|
176
177
|
function te(n) {
|
|
@@ -179,75 +180,75 @@ class gt extends ot {
|
|
|
179
180
|
function he(n) {
|
|
180
181
|
t.object.isPerspectiveCamera || t.object.isOrthographicCamera ? d *= n : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), t.enableZoom = !1);
|
|
181
182
|
}
|
|
182
|
-
function se(n,
|
|
183
|
+
function se(n, g) {
|
|
183
184
|
if (!t.zoomToCursor)
|
|
184
185
|
return;
|
|
185
186
|
H = !0;
|
|
186
|
-
const
|
|
187
|
+
const v = t.domElement.getBoundingClientRect(), w = n - v.left, C = g - v.top, F = v.width, z = v.height;
|
|
187
188
|
P.x = w / F * 2 - 1, P.y = -(C / z) * 2 + 1, Y.set(P.x, P.y, 1).unproject(t.object).sub(t.object.position).normalize();
|
|
188
189
|
}
|
|
189
190
|
function ie(n) {
|
|
190
191
|
return Math.max(t.minDistance, Math.min(t.maxDistance, n));
|
|
191
192
|
}
|
|
192
193
|
function de(n) {
|
|
193
|
-
|
|
194
|
+
x.set(n.clientX, n.clientY);
|
|
194
195
|
}
|
|
195
196
|
function De(n) {
|
|
196
197
|
se(n.clientX, n.clientX), N.set(n.clientX, n.clientY);
|
|
197
198
|
}
|
|
198
199
|
function pe(n) {
|
|
199
|
-
|
|
200
|
+
y.set(n.clientX, n.clientY);
|
|
200
201
|
}
|
|
201
202
|
function Ae(n) {
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
B(2 * Math.PI *
|
|
203
|
+
f.set(n.clientX, n.clientY), u.subVectors(f, x).multiplyScalar(t.rotateSpeed);
|
|
204
|
+
const g = t.domElement;
|
|
205
|
+
B(2 * Math.PI * u.x / g.clientHeight), W(2 * Math.PI * u.y / g.clientHeight), x.copy(f), t.update();
|
|
205
206
|
}
|
|
206
207
|
function je(n) {
|
|
207
|
-
O.set(n.clientX, n.clientY),
|
|
208
|
+
O.set(n.clientX, n.clientY), L.subVectors(O, N), L.y > 0 ? te(q(L.y)) : L.y < 0 && he(q(L.y)), N.copy(O), t.update();
|
|
208
209
|
}
|
|
209
210
|
function $e(n) {
|
|
210
|
-
|
|
211
|
+
b.set(n.clientX, n.clientY), M.subVectors(b, y).multiplyScalar(t.panSpeed), A(M.x, M.y), y.copy(b), t.update();
|
|
211
212
|
}
|
|
212
213
|
function Ge(n) {
|
|
213
214
|
se(n.clientX, n.clientY), n.deltaY < 0 ? he(q(n.deltaY)) : n.deltaY > 0 && te(q(n.deltaY)), t.update();
|
|
214
215
|
}
|
|
215
216
|
function Ye(n) {
|
|
216
|
-
let
|
|
217
|
+
let g = !1;
|
|
217
218
|
switch (n.code) {
|
|
218
219
|
case t.keys.UP:
|
|
219
|
-
n.ctrlKey || n.metaKey || n.shiftKey ? W(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(0, t.keyPanSpeed),
|
|
220
|
+
n.ctrlKey || n.metaKey || n.shiftKey ? W(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(0, t.keyPanSpeed), g = !0;
|
|
220
221
|
break;
|
|
221
222
|
case t.keys.BOTTOM:
|
|
222
|
-
n.ctrlKey || n.metaKey || n.shiftKey ? W(-2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(0, -t.keyPanSpeed),
|
|
223
|
+
n.ctrlKey || n.metaKey || n.shiftKey ? W(-2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(0, -t.keyPanSpeed), g = !0;
|
|
223
224
|
break;
|
|
224
225
|
case t.keys.LEFT:
|
|
225
|
-
n.ctrlKey || n.metaKey || n.shiftKey ? B(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(t.keyPanSpeed, 0),
|
|
226
|
+
n.ctrlKey || n.metaKey || n.shiftKey ? B(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(t.keyPanSpeed, 0), g = !0;
|
|
226
227
|
break;
|
|
227
228
|
case t.keys.RIGHT:
|
|
228
|
-
n.ctrlKey || n.metaKey || n.shiftKey ? B(-2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(-t.keyPanSpeed, 0),
|
|
229
|
+
n.ctrlKey || n.metaKey || n.shiftKey ? B(-2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(-t.keyPanSpeed, 0), g = !0;
|
|
229
230
|
break;
|
|
230
231
|
}
|
|
231
|
-
|
|
232
|
+
g && (n.preventDefault(), t.update());
|
|
232
233
|
}
|
|
233
234
|
function ge(n) {
|
|
234
235
|
if (E.length === 1)
|
|
235
|
-
|
|
236
|
+
x.set(n.pageX, n.pageY);
|
|
236
237
|
else {
|
|
237
|
-
const
|
|
238
|
-
|
|
238
|
+
const g = j(n), v = 0.5 * (n.pageX + g.x), w = 0.5 * (n.pageY + g.y);
|
|
239
|
+
x.set(v, w);
|
|
239
240
|
}
|
|
240
241
|
}
|
|
241
242
|
function ue(n) {
|
|
242
243
|
if (E.length === 1)
|
|
243
|
-
|
|
244
|
+
y.set(n.pageX, n.pageY);
|
|
244
245
|
else {
|
|
245
|
-
const
|
|
246
|
-
|
|
246
|
+
const g = j(n), v = 0.5 * (n.pageX + g.x), w = 0.5 * (n.pageY + g.y);
|
|
247
|
+
y.set(v, w);
|
|
247
248
|
}
|
|
248
249
|
}
|
|
249
250
|
function fe(n) {
|
|
250
|
-
const
|
|
251
|
+
const g = j(n), v = n.pageX - g.x, w = n.pageY - g.y, C = Math.sqrt(v * v + w * w);
|
|
251
252
|
N.set(0, C);
|
|
252
253
|
}
|
|
253
254
|
function Be(n) {
|
|
@@ -258,28 +259,28 @@ class gt extends ot {
|
|
|
258
259
|
}
|
|
259
260
|
function me(n) {
|
|
260
261
|
if (E.length == 1)
|
|
261
|
-
|
|
262
|
+
f.set(n.pageX, n.pageY);
|
|
262
263
|
else {
|
|
263
|
-
const
|
|
264
|
-
|
|
264
|
+
const v = j(n), w = 0.5 * (n.pageX + v.x), C = 0.5 * (n.pageY + v.y);
|
|
265
|
+
f.set(w, C);
|
|
265
266
|
}
|
|
266
|
-
|
|
267
|
-
const
|
|
268
|
-
B(2 * Math.PI *
|
|
267
|
+
u.subVectors(f, x).multiplyScalar(t.rotateSpeed);
|
|
268
|
+
const g = t.domElement;
|
|
269
|
+
B(2 * Math.PI * u.x / g.clientHeight), W(2 * Math.PI * u.y / g.clientHeight), x.copy(f);
|
|
269
270
|
}
|
|
270
271
|
function ye(n) {
|
|
271
272
|
if (E.length === 1)
|
|
272
|
-
|
|
273
|
+
b.set(n.pageX, n.pageY);
|
|
273
274
|
else {
|
|
274
|
-
const
|
|
275
|
-
|
|
275
|
+
const g = j(n), v = 0.5 * (n.pageX + g.x), w = 0.5 * (n.pageY + g.y);
|
|
276
|
+
b.set(v, w);
|
|
276
277
|
}
|
|
277
|
-
M.subVectors(
|
|
278
|
+
M.subVectors(b, y).multiplyScalar(t.panSpeed), A(M.x, M.y), y.copy(b);
|
|
278
279
|
}
|
|
279
280
|
function xe(n) {
|
|
280
|
-
const
|
|
281
|
-
O.set(0, C),
|
|
282
|
-
const F = (n.pageX +
|
|
281
|
+
const g = j(n), v = n.pageX - g.x, w = n.pageY - g.y, C = Math.sqrt(v * v + w * w);
|
|
282
|
+
O.set(0, C), L.set(0, Math.pow(O.y / N.y, t.zoomSpeed)), te(L.y), N.copy(O);
|
|
283
|
+
const F = (n.pageX + g.x) * 0.5, z = (n.pageY + g.y) * 0.5;
|
|
283
284
|
se(F, z);
|
|
284
285
|
}
|
|
285
286
|
function Xe(n) {
|
|
@@ -295,85 +296,85 @@ class gt extends ot {
|
|
|
295
296
|
t.enabled !== !1 && (n.pointerType === "touch" ? Qe(n) : _e(n));
|
|
296
297
|
}
|
|
297
298
|
function K(n) {
|
|
298
|
-
et(n), E.length === 0 && (t.domElement.releasePointerCapture(n.pointerId), t.domElement.removeEventListener("pointermove", oe), t.domElement.removeEventListener("pointerup", K)), t.dispatchEvent(Pe),
|
|
299
|
+
et(n), E.length === 0 && (t.domElement.releasePointerCapture(n.pointerId), t.domElement.removeEventListener("pointermove", oe), t.domElement.removeEventListener("pointerup", K)), t.dispatchEvent(Pe), o = i.NONE;
|
|
299
300
|
}
|
|
300
301
|
function Ue(n) {
|
|
301
|
-
let
|
|
302
|
+
let g;
|
|
302
303
|
switch (n.button) {
|
|
303
304
|
case 0:
|
|
304
|
-
|
|
305
|
+
g = t.mouseButtons.LEFT;
|
|
305
306
|
break;
|
|
306
307
|
case 1:
|
|
307
|
-
|
|
308
|
+
g = t.mouseButtons.MIDDLE;
|
|
308
309
|
break;
|
|
309
310
|
case 2:
|
|
310
|
-
|
|
311
|
+
g = t.mouseButtons.RIGHT;
|
|
311
312
|
break;
|
|
312
313
|
default:
|
|
313
|
-
|
|
314
|
+
g = -1;
|
|
314
315
|
}
|
|
315
|
-
switch (
|
|
316
|
+
switch (g) {
|
|
316
317
|
case $.DOLLY:
|
|
317
318
|
if (t.enableZoom === !1) return;
|
|
318
|
-
De(n),
|
|
319
|
+
De(n), o = i.DOLLY;
|
|
319
320
|
break;
|
|
320
321
|
case $.ROTATE:
|
|
321
322
|
if (n.ctrlKey || n.metaKey || n.shiftKey) {
|
|
322
323
|
if (t.enablePan === !1) return;
|
|
323
|
-
pe(n),
|
|
324
|
+
pe(n), o = i.PAN;
|
|
324
325
|
} else {
|
|
325
326
|
if (t.enableRotate === !1) return;
|
|
326
|
-
de(n),
|
|
327
|
+
de(n), o = i.ROTATE;
|
|
327
328
|
}
|
|
328
329
|
break;
|
|
329
330
|
case $.PAN:
|
|
330
331
|
if (n.ctrlKey || n.metaKey || n.shiftKey) {
|
|
331
332
|
if (t.enableRotate === !1) return;
|
|
332
|
-
de(n),
|
|
333
|
+
de(n), o = i.ROTATE;
|
|
333
334
|
} else {
|
|
334
335
|
if (t.enablePan === !1) return;
|
|
335
|
-
pe(n),
|
|
336
|
+
pe(n), o = i.PAN;
|
|
336
337
|
}
|
|
337
338
|
break;
|
|
338
339
|
default:
|
|
339
|
-
|
|
340
|
+
o = i.NONE;
|
|
340
341
|
}
|
|
341
|
-
|
|
342
|
+
o !== i.NONE && t.dispatchEvent(re);
|
|
342
343
|
}
|
|
343
344
|
function _e(n) {
|
|
344
|
-
switch (
|
|
345
|
-
case
|
|
345
|
+
switch (o) {
|
|
346
|
+
case i.ROTATE:
|
|
346
347
|
if (t.enableRotate === !1) return;
|
|
347
348
|
Ae(n);
|
|
348
349
|
break;
|
|
349
|
-
case
|
|
350
|
+
case i.DOLLY:
|
|
350
351
|
if (t.enableZoom === !1) return;
|
|
351
352
|
je(n);
|
|
352
353
|
break;
|
|
353
|
-
case
|
|
354
|
+
case i.PAN:
|
|
354
355
|
if (t.enablePan === !1) return;
|
|
355
356
|
$e(n);
|
|
356
357
|
break;
|
|
357
358
|
}
|
|
358
359
|
}
|
|
359
360
|
function ve(n) {
|
|
360
|
-
t.enabled === !1 || t.enableZoom === !1 ||
|
|
361
|
+
t.enabled === !1 || t.enableZoom === !1 || o !== i.NONE || (n.preventDefault(), t.dispatchEvent(re), Ge(qe(n)), t.dispatchEvent(Pe));
|
|
361
362
|
}
|
|
362
363
|
function qe(n) {
|
|
363
|
-
const
|
|
364
|
+
const g = n.deltaMode, v = {
|
|
364
365
|
clientX: n.clientX,
|
|
365
366
|
clientY: n.clientY,
|
|
366
367
|
deltaY: n.deltaY
|
|
367
368
|
};
|
|
368
|
-
switch (
|
|
369
|
+
switch (g) {
|
|
369
370
|
case 1:
|
|
370
|
-
|
|
371
|
+
v.deltaY *= 16;
|
|
371
372
|
break;
|
|
372
373
|
case 2:
|
|
373
|
-
|
|
374
|
+
v.deltaY *= 100;
|
|
374
375
|
break;
|
|
375
376
|
}
|
|
376
|
-
return n.ctrlKey && !ee && (
|
|
377
|
+
return n.ctrlKey && !ee && (v.deltaY *= 10), v;
|
|
377
378
|
}
|
|
378
379
|
function We(n) {
|
|
379
380
|
n.key === "Control" && (ee = !0, document.addEventListener("keyup", Me, { passive: !0, capture: !0 }));
|
|
@@ -390,55 +391,55 @@ class gt extends ot {
|
|
|
390
391
|
switch (t.touches.ONE) {
|
|
391
392
|
case G.ROTATE:
|
|
392
393
|
if (t.enableRotate === !1) return;
|
|
393
|
-
ge(n),
|
|
394
|
+
ge(n), o = i.TOUCH_ROTATE;
|
|
394
395
|
break;
|
|
395
396
|
case G.PAN:
|
|
396
397
|
if (t.enablePan === !1) return;
|
|
397
|
-
ue(n),
|
|
398
|
+
ue(n), o = i.TOUCH_PAN;
|
|
398
399
|
break;
|
|
399
400
|
default:
|
|
400
|
-
|
|
401
|
+
o = i.NONE;
|
|
401
402
|
}
|
|
402
403
|
break;
|
|
403
404
|
case 2:
|
|
404
405
|
switch (t.touches.TWO) {
|
|
405
406
|
case G.DOLLY_PAN:
|
|
406
407
|
if (t.enableZoom === !1 && t.enablePan === !1) return;
|
|
407
|
-
Be(n),
|
|
408
|
+
Be(n), o = i.TOUCH_DOLLY_PAN;
|
|
408
409
|
break;
|
|
409
410
|
case G.DOLLY_ROTATE:
|
|
410
411
|
if (t.enableZoom === !1 && t.enableRotate === !1) return;
|
|
411
|
-
Ke(n),
|
|
412
|
+
Ke(n), o = i.TOUCH_DOLLY_ROTATE;
|
|
412
413
|
break;
|
|
413
414
|
default:
|
|
414
|
-
|
|
415
|
+
o = i.NONE;
|
|
415
416
|
}
|
|
416
417
|
break;
|
|
417
418
|
default:
|
|
418
|
-
|
|
419
|
+
o = i.NONE;
|
|
419
420
|
}
|
|
420
|
-
|
|
421
|
+
o !== i.NONE && t.dispatchEvent(re);
|
|
421
422
|
}
|
|
422
423
|
function Qe(n) {
|
|
423
|
-
switch (Ee(n),
|
|
424
|
-
case
|
|
424
|
+
switch (Ee(n), o) {
|
|
425
|
+
case i.TOUCH_ROTATE:
|
|
425
426
|
if (t.enableRotate === !1) return;
|
|
426
427
|
me(n), t.update();
|
|
427
428
|
break;
|
|
428
|
-
case
|
|
429
|
+
case i.TOUCH_PAN:
|
|
429
430
|
if (t.enablePan === !1) return;
|
|
430
431
|
ye(n), t.update();
|
|
431
432
|
break;
|
|
432
|
-
case
|
|
433
|
+
case i.TOUCH_DOLLY_PAN:
|
|
433
434
|
if (t.enableZoom === !1 && t.enablePan === !1) return;
|
|
434
435
|
Xe(n), t.update();
|
|
435
436
|
break;
|
|
436
|
-
case
|
|
437
|
+
case i.TOUCH_DOLLY_ROTATE:
|
|
437
438
|
if (t.enableZoom === !1 && t.enableRotate === !1) return;
|
|
438
439
|
Ve(n), t.update();
|
|
439
440
|
break;
|
|
440
441
|
default:
|
|
441
|
-
|
|
442
|
+
o = i.NONE;
|
|
442
443
|
}
|
|
443
444
|
}
|
|
444
445
|
function we(n) {
|
|
@@ -449,19 +450,19 @@ class gt extends ot {
|
|
|
449
450
|
}
|
|
450
451
|
function et(n) {
|
|
451
452
|
delete _[n.pointerId];
|
|
452
|
-
for (let
|
|
453
|
-
if (E[
|
|
454
|
-
E.splice(
|
|
453
|
+
for (let g = 0; g < E.length; g++)
|
|
454
|
+
if (E[g] == n.pointerId) {
|
|
455
|
+
E.splice(g, 1);
|
|
455
456
|
return;
|
|
456
457
|
}
|
|
457
458
|
}
|
|
458
459
|
function Ee(n) {
|
|
459
|
-
let
|
|
460
|
-
|
|
460
|
+
let g = _[n.pointerId];
|
|
461
|
+
g === void 0 && (g = new k(), _[n.pointerId] = g), g.set(n.pageX, n.pageY);
|
|
461
462
|
}
|
|
462
463
|
function j(n) {
|
|
463
|
-
const
|
|
464
|
-
return _[
|
|
464
|
+
const g = n.pointerId === E[0] ? E[1] : E[0];
|
|
465
|
+
return _[g];
|
|
465
466
|
}
|
|
466
467
|
t.domElement.addEventListener("contextmenu", we), t.domElement.addEventListener("pointerdown", be), t.domElement.addEventListener("pointercancel", K), t.domElement.addEventListener("wheel", ve, { passive: !1 }), document.addEventListener("keydown", We, { passive: !0, capture: !0 }), this.update();
|
|
467
468
|
}
|
|
@@ -477,14 +478,14 @@ class ut {
|
|
|
477
478
|
this.container = e, this.scene = new m.Scene(), this.scene.background = new m.Color(
|
|
478
479
|
s.backgroundColor ?? 657930
|
|
479
480
|
);
|
|
480
|
-
const { width: t, height:
|
|
481
|
-
this.camera = new m.PerspectiveCamera(
|
|
481
|
+
const { width: t, height: i } = ze(e), o = s.cameraFov ?? 75;
|
|
482
|
+
this.camera = new m.PerspectiveCamera(o, t / i, 0.1, 2e3);
|
|
482
483
|
const a = s.cameraPosition ?? { x: 0, y: 0, z: 80 };
|
|
483
484
|
this.camera.position.set(a.x, a.y, a.z), this.renderer = new m.WebGLRenderer({
|
|
484
485
|
antialias: !0,
|
|
485
486
|
alpha: !0,
|
|
486
487
|
powerPreference: "high-performance"
|
|
487
|
-
}), this.renderer.setSize(t,
|
|
488
|
+
}), this.renderer.setSize(t, i), this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)), this.renderer.toneMapping = m.ACESFilmicToneMapping, this.renderer.toneMappingExposure = 1, this.renderer.shadowMap.enabled = !0, this.renderer.shadowMap.type = m.PCFSoftShadowMap, e.appendChild(this.renderer.domElement), this.controls = new gt(this.camera, this.renderer.domElement), this.controls.enableDamping = !0, this.controls.dampingFactor = 0.05, this.controls.rotateSpeed = 0.8, this.controls.zoomSpeed = 1.2, this.controls.minDistance = 10, this.controls.maxDistance = 500, this.setupLighting(), this.resizeHandler = this.onWindowResize.bind(this), window.addEventListener("resize", this.resizeHandler);
|
|
488
489
|
}
|
|
489
490
|
/**
|
|
490
491
|
* Sets up scene lighting for gradient glass on dark background
|
|
@@ -496,10 +497,10 @@ class ut {
|
|
|
496
497
|
s.position.set(50, 60, 40), s.castShadow = !0, s.shadow.mapSize.width = 1024, s.shadow.mapSize.height = 1024, this.scene.add(s);
|
|
497
498
|
const t = new m.DirectionalLight(16773344, 0.4);
|
|
498
499
|
t.position.set(-50, 30, -40), this.scene.add(t);
|
|
499
|
-
const
|
|
500
|
-
|
|
501
|
-
const
|
|
502
|
-
|
|
500
|
+
const i = new m.DirectionalLight(16777215, 0.3);
|
|
501
|
+
i.position.set(0, -30, -50), this.scene.add(i);
|
|
502
|
+
const o = new m.PointLight(16750950, 0.5, 150);
|
|
503
|
+
o.position.set(40, 20, 40), this.scene.add(o);
|
|
503
504
|
const a = new m.PointLight(16764057, 0.4, 150);
|
|
504
505
|
a.position.set(-40, -20, 40), this.scene.add(a);
|
|
505
506
|
const r = new m.PointLight(6724095, 0.2, 100);
|
|
@@ -584,16 +585,16 @@ class ft {
|
|
|
584
585
|
x: (Math.random() - 0.5) * 50,
|
|
585
586
|
y: (Math.random() - 0.5) * 50,
|
|
586
587
|
z: (Math.random() - 0.5) * 50
|
|
587
|
-
},
|
|
588
|
+
}, i = {
|
|
588
589
|
...e,
|
|
589
590
|
position: t,
|
|
590
591
|
velocity: { x: 0, y: 0, z: 0 },
|
|
591
592
|
mass: 1
|
|
592
|
-
},
|
|
593
|
+
}, o = this.nodeFactory.createNode(
|
|
593
594
|
{ ...e, position: t },
|
|
594
595
|
s
|
|
595
596
|
);
|
|
596
|
-
return this.sceneManager.add(
|
|
597
|
+
return this.sceneManager.add(o.group), this.nodes.set(e.id, i), this.nodeObjects.set(e.id, o), !0;
|
|
597
598
|
}
|
|
598
599
|
/**
|
|
599
600
|
* Removes a node from the graph
|
|
@@ -607,17 +608,17 @@ class ft {
|
|
|
607
608
|
* Updates a node's properties
|
|
608
609
|
*/
|
|
609
610
|
updateNode(e, s) {
|
|
610
|
-
const t = this.nodes.get(e),
|
|
611
|
-
return !t || !
|
|
612
|
-
|
|
611
|
+
const t = this.nodes.get(e), i = this.nodeObjects.get(e);
|
|
612
|
+
return !t || !i ? (console.warn(`[ForceGraph3D] Node "${e}" not found`), !1) : (s.label !== void 0 && (t.label = s.label, this.nodeFactory.updateNodeLabel(i, s.label)), s.color !== void 0 && (t.color = s.color, this.nodeFactory.updateNodeColor(i, s.color)), Object.keys(s).forEach((o) => {
|
|
613
|
+
o !== "id" && o !== "label" && o !== "color" && o !== "position" && (t[o] = s[o]);
|
|
613
614
|
}), !0);
|
|
614
615
|
}
|
|
615
616
|
/**
|
|
616
617
|
* Updates a node's position (called by physics engine)
|
|
617
618
|
*/
|
|
618
619
|
updateNodePosition(e, s) {
|
|
619
|
-
const t = this.nodes.get(e),
|
|
620
|
-
t &&
|
|
620
|
+
const t = this.nodes.get(e), i = this.nodeObjects.get(e);
|
|
621
|
+
t && i && (t.position = s, i.group.position.set(s.x, s.y, s.z));
|
|
621
622
|
}
|
|
622
623
|
/**
|
|
623
624
|
* Updates a node's LOD level
|
|
@@ -715,14 +716,14 @@ class mt {
|
|
|
715
716
|
const s = D(e.source, e.target);
|
|
716
717
|
if (this.edgeKeySet.has(s))
|
|
717
718
|
return console.warn(`[ForceGraph3D] Edge "${e.source}" -> "${e.target}" already exists`), !1;
|
|
718
|
-
const t = this.nodeManager.getNode(e.source),
|
|
719
|
+
const t = this.nodeManager.getNode(e.source), i = this.nodeManager.getNode(e.target), o = this.edgeFactory.createEdge(
|
|
719
720
|
e,
|
|
720
721
|
t,
|
|
721
|
-
|
|
722
|
+
i,
|
|
722
723
|
t.position,
|
|
723
|
-
|
|
724
|
+
i.position
|
|
724
725
|
);
|
|
725
|
-
return this.sceneManager.add(
|
|
726
|
+
return this.sceneManager.add(o.line), this.edges.push(e), this.edgeObjects.push(o), this.edgeKeySet.add(s), !0;
|
|
726
727
|
}
|
|
727
728
|
/**
|
|
728
729
|
* Removes an edge from the graph
|
|
@@ -732,13 +733,13 @@ class mt {
|
|
|
732
733
|
const t = D(e, s);
|
|
733
734
|
if (!this.edgeKeySet.has(t))
|
|
734
735
|
return !1;
|
|
735
|
-
const
|
|
736
|
+
const i = this.edges.findIndex(
|
|
736
737
|
(a) => D(a.source, a.target) === t
|
|
737
738
|
);
|
|
738
|
-
if (
|
|
739
|
+
if (i === -1)
|
|
739
740
|
return !1;
|
|
740
|
-
const
|
|
741
|
-
return this.sceneManager.remove(
|
|
741
|
+
const o = this.edgeObjects[i];
|
|
742
|
+
return this.sceneManager.remove(o.line), this.edgeFactory.disposeEdge(o), this.edges.splice(i, 1), this.edgeObjects.splice(i, 1), this.edgeKeySet.delete(t), this.highlightedEdgeKey === t && (this.highlightedEdgeKey = null), !0;
|
|
742
743
|
}
|
|
743
744
|
/**
|
|
744
745
|
* Highlights an edge
|
|
@@ -746,10 +747,10 @@ class mt {
|
|
|
746
747
|
highlightEdge(e, s) {
|
|
747
748
|
const t = D(e, s);
|
|
748
749
|
this.highlightedEdgeKey && this.highlightedEdgeKey !== t && this.unhighlightCurrentEdge();
|
|
749
|
-
const
|
|
750
|
-
(
|
|
750
|
+
const i = this.edges.findIndex(
|
|
751
|
+
(o) => D(o.source, o.target) === t
|
|
751
752
|
);
|
|
752
|
-
|
|
753
|
+
i !== -1 && (this.edgeFactory.highlightEdge(this.edgeObjects[i]), this.highlightedEdgeKey = t);
|
|
753
754
|
}
|
|
754
755
|
/**
|
|
755
756
|
* Unhighlights the currently highlighted edge
|
|
@@ -792,11 +793,11 @@ class mt {
|
|
|
792
793
|
*/
|
|
793
794
|
updateEdgePositions() {
|
|
794
795
|
this.edgeObjects.forEach((e, s) => {
|
|
795
|
-
const t = this.edges[s],
|
|
796
|
-
|
|
796
|
+
const t = this.edges[s], i = this.nodeManager.getNode(t.source), o = this.nodeManager.getNode(t.target);
|
|
797
|
+
i && o && this.edgeFactory.updateEdgePositions(
|
|
797
798
|
e,
|
|
798
|
-
|
|
799
|
-
|
|
799
|
+
i.position,
|
|
800
|
+
o.position
|
|
800
801
|
);
|
|
801
802
|
});
|
|
802
803
|
}
|
|
@@ -864,13 +865,13 @@ class Le {
|
|
|
864
865
|
calculateRepulsionBruteForce() {
|
|
865
866
|
const e = Array.from(this.nodes.values()), s = e.length;
|
|
866
867
|
for (let t = 0; t < s; t++) {
|
|
867
|
-
const
|
|
868
|
-
for (let
|
|
869
|
-
const a = e[
|
|
870
|
-
let
|
|
871
|
-
|
|
872
|
-
const
|
|
873
|
-
|
|
868
|
+
const i = e[t];
|
|
869
|
+
for (let o = t + 1; o < s; o++) {
|
|
870
|
+
const a = e[o], r = a.position.x - i.position.x, c = a.position.y - i.position.y, d = a.position.z - i.position.z;
|
|
871
|
+
let p = r * r + c * c + d * d;
|
|
872
|
+
p < 0.01 && (p = 0.01);
|
|
873
|
+
const x = Math.sqrt(p), f = this.repulsionStrength * this.alpha / p, u = r / x * f, y = c / x * f, b = d / x * f;
|
|
874
|
+
i.velocity.x -= u / i.mass, i.velocity.y -= y / i.mass, i.velocity.z -= b / i.mass, a.velocity.x += u / a.mass, a.velocity.y += y / a.mass, a.velocity.z += b / a.mass;
|
|
874
875
|
}
|
|
875
876
|
}
|
|
876
877
|
}
|
|
@@ -891,10 +892,10 @@ class Le {
|
|
|
891
892
|
return;
|
|
892
893
|
}
|
|
893
894
|
if (s.mass === 0) return;
|
|
894
|
-
const t = s.centerOfMass.x - e.position.x,
|
|
895
|
+
const t = s.centerOfMass.x - e.position.x, i = s.centerOfMass.y - e.position.y, o = s.centerOfMass.z - e.position.z, a = Math.sqrt(t * t + i * i + o * o);
|
|
895
896
|
if (s.size / a < this.barnesHutTheta) {
|
|
896
897
|
const r = Math.max(a * a, 0.01), c = this.repulsionStrength * this.alpha * s.mass / r;
|
|
897
|
-
e.velocity.x -= t / a * c / e.mass, e.velocity.y -=
|
|
898
|
+
e.velocity.x -= t / a * c / e.mass, e.velocity.y -= i / a * c / e.mass, e.velocity.z -= o / a * c / e.mass;
|
|
898
899
|
} else
|
|
899
900
|
for (const r of s.children)
|
|
900
901
|
r && this.calculateForceFromOctree(e, r);
|
|
@@ -903,11 +904,11 @@ class Le {
|
|
|
903
904
|
* Apply repulsion between two nodes
|
|
904
905
|
*/
|
|
905
906
|
applyRepulsionBetween(e, s) {
|
|
906
|
-
const t = s.position.x - e.position.x,
|
|
907
|
-
let a = t * t +
|
|
907
|
+
const t = s.position.x - e.position.x, i = s.position.y - e.position.y, o = s.position.z - e.position.z;
|
|
908
|
+
let a = t * t + i * i + o * o;
|
|
908
909
|
a < 0.01 && (a = 0.01);
|
|
909
910
|
const r = Math.sqrt(a), c = this.repulsionStrength * this.alpha / a;
|
|
910
|
-
e.velocity.x -= t / r * c / e.mass, e.velocity.y -=
|
|
911
|
+
e.velocity.x -= t / r * c / e.mass, e.velocity.y -= i / r * c / e.mass, e.velocity.z -= o / r * c / e.mass;
|
|
911
912
|
}
|
|
912
913
|
/**
|
|
913
914
|
* Calculate attraction forces along edges
|
|
@@ -916,10 +917,10 @@ class Le {
|
|
|
916
917
|
for (const e of this.edges) {
|
|
917
918
|
const s = this.nodes.get(e.source), t = this.nodes.get(e.target);
|
|
918
919
|
if (!s || !t) continue;
|
|
919
|
-
const
|
|
920
|
+
const i = t.position.x - s.position.x, o = t.position.y - s.position.y, a = t.position.z - s.position.z, r = Math.sqrt(i * i + o * o + a * a);
|
|
920
921
|
if (r < 0.01) continue;
|
|
921
|
-
const d = (r - 15) * this.attractionStrength * this.alpha,
|
|
922
|
-
s.velocity.x +=
|
|
922
|
+
const d = (r - 15) * this.attractionStrength * this.alpha, p = i / r * d, x = o / r * d, f = a / r * d;
|
|
923
|
+
s.velocity.x += p / s.mass, s.velocity.y += x / s.mass, s.velocity.z += f / s.mass, t.velocity.x -= p / t.mass, t.velocity.y -= x / t.mass, t.velocity.z -= f / t.mass;
|
|
923
924
|
}
|
|
924
925
|
}
|
|
925
926
|
/**
|
|
@@ -967,13 +968,13 @@ class yt {
|
|
|
967
968
|
max: { x: 100, y: 100, z: 100 }
|
|
968
969
|
};
|
|
969
970
|
const s = { x: 1 / 0, y: 1 / 0, z: 1 / 0 }, t = { x: -1 / 0, y: -1 / 0, z: -1 / 0 };
|
|
970
|
-
for (const
|
|
971
|
-
s.x = Math.min(s.x,
|
|
972
|
-
const
|
|
973
|
-
return s.x -=
|
|
971
|
+
for (const o of e)
|
|
972
|
+
s.x = Math.min(s.x, o.position.x), s.y = Math.min(s.y, o.position.y), s.z = Math.min(s.z, o.position.z), t.x = Math.max(t.x, o.position.x), t.y = Math.max(t.y, o.position.y), t.z = Math.max(t.z, o.position.z);
|
|
973
|
+
const i = 10;
|
|
974
|
+
return s.x -= i, s.y -= i, s.z -= i, t.x += i, t.y += i, t.z += i, { min: s, max: t };
|
|
974
975
|
}
|
|
975
976
|
buildTree(e, s, t = 0) {
|
|
976
|
-
const
|
|
977
|
+
const i = Math.max(
|
|
977
978
|
s.max.x - s.min.x,
|
|
978
979
|
s.max.y - s.min.y,
|
|
979
980
|
s.max.z - s.min.z
|
|
@@ -981,7 +982,7 @@ class yt {
|
|
|
981
982
|
if (e.length === 0)
|
|
982
983
|
return {
|
|
983
984
|
bounds: s,
|
|
984
|
-
size:
|
|
985
|
+
size: i,
|
|
985
986
|
centerOfMass: { x: 0, y: 0, z: 0 },
|
|
986
987
|
mass: 0,
|
|
987
988
|
isLeaf: !0,
|
|
@@ -989,56 +990,56 @@ class yt {
|
|
|
989
990
|
children: []
|
|
990
991
|
};
|
|
991
992
|
if (e.length === 1 || t > 20) {
|
|
992
|
-
let
|
|
993
|
-
const
|
|
994
|
-
for (const
|
|
995
|
-
|
|
996
|
-
return
|
|
993
|
+
let u = 0;
|
|
994
|
+
const y = { x: 0, y: 0, z: 0 };
|
|
995
|
+
for (const b of e)
|
|
996
|
+
u += b.mass, y.x += b.position.x * b.mass, y.y += b.position.y * b.mass, y.z += b.position.z * b.mass;
|
|
997
|
+
return u > 0 && (y.x /= u, y.y /= u, y.z /= u), {
|
|
997
998
|
bounds: s,
|
|
998
|
-
size:
|
|
999
|
-
centerOfMass:
|
|
1000
|
-
mass:
|
|
999
|
+
size: i,
|
|
1000
|
+
centerOfMass: y,
|
|
1001
|
+
mass: u,
|
|
1001
1002
|
isLeaf: !0,
|
|
1002
1003
|
node: e[0],
|
|
1003
1004
|
children: []
|
|
1004
1005
|
};
|
|
1005
1006
|
}
|
|
1006
|
-
const
|
|
1007
|
-
for (const
|
|
1008
|
-
const
|
|
1009
|
-
c[
|
|
1007
|
+
const o = (s.min.x + s.max.x) / 2, a = (s.min.y + s.max.y) / 2, r = (s.min.z + s.max.z) / 2, c = [[], [], [], [], [], [], [], []];
|
|
1008
|
+
for (const u of e) {
|
|
1009
|
+
const y = (u.position.x >= o ? 1 : 0) + (u.position.y >= a ? 2 : 0) + (u.position.z >= r ? 4 : 0);
|
|
1010
|
+
c[y].push(u);
|
|
1010
1011
|
}
|
|
1011
1012
|
const d = [
|
|
1012
|
-
{ min: { x: s.min.x, y: s.min.y, z: s.min.z }, max: { x:
|
|
1013
|
-
{ min: { x:
|
|
1014
|
-
{ min: { x: s.min.x, y: a, z: s.min.z }, max: { x:
|
|
1015
|
-
{ min: { x:
|
|
1016
|
-
{ min: { x: s.min.x, y: s.min.y, z: r }, max: { x:
|
|
1017
|
-
{ min: { x:
|
|
1018
|
-
{ min: { x: s.min.x, y: a, z: r }, max: { x:
|
|
1019
|
-
{ min: { x:
|
|
1020
|
-
],
|
|
1021
|
-
let
|
|
1022
|
-
const
|
|
1023
|
-
for (let
|
|
1024
|
-
if (c[
|
|
1025
|
-
const
|
|
1026
|
-
|
|
1013
|
+
{ min: { x: s.min.x, y: s.min.y, z: s.min.z }, max: { x: o, y: a, z: r } },
|
|
1014
|
+
{ min: { x: o, y: s.min.y, z: s.min.z }, max: { x: s.max.x, y: a, z: r } },
|
|
1015
|
+
{ min: { x: s.min.x, y: a, z: s.min.z }, max: { x: o, y: s.max.y, z: r } },
|
|
1016
|
+
{ min: { x: o, y: a, z: s.min.z }, max: { x: s.max.x, y: s.max.y, z: r } },
|
|
1017
|
+
{ min: { x: s.min.x, y: s.min.y, z: r }, max: { x: o, y: a, z: s.max.z } },
|
|
1018
|
+
{ min: { x: o, y: s.min.y, z: r }, max: { x: s.max.x, y: a, z: s.max.z } },
|
|
1019
|
+
{ min: { x: s.min.x, y: a, z: r }, max: { x: o, y: s.max.y, z: s.max.z } },
|
|
1020
|
+
{ min: { x: o, y: a, z: r }, max: { x: s.max.x, y: s.max.y, z: s.max.z } }
|
|
1021
|
+
], p = [];
|
|
1022
|
+
let x = 0;
|
|
1023
|
+
const f = { x: 0, y: 0, z: 0 };
|
|
1024
|
+
for (let u = 0; u < 8; u++)
|
|
1025
|
+
if (c[u].length > 0) {
|
|
1026
|
+
const y = this.buildTree(c[u], d[u], t + 1);
|
|
1027
|
+
p.push(y), x += y.mass, f.x += y.centerOfMass.x * y.mass, f.y += y.centerOfMass.y * y.mass, f.z += y.centerOfMass.z * y.mass;
|
|
1027
1028
|
} else
|
|
1028
|
-
|
|
1029
|
-
return
|
|
1029
|
+
p.push(null);
|
|
1030
|
+
return x > 0 && (f.x /= x, f.y /= x, f.z /= x), {
|
|
1030
1031
|
bounds: s,
|
|
1031
|
-
size:
|
|
1032
|
-
centerOfMass:
|
|
1033
|
-
mass:
|
|
1032
|
+
size: i,
|
|
1033
|
+
centerOfMass: f,
|
|
1034
|
+
mass: x,
|
|
1034
1035
|
isLeaf: !1,
|
|
1035
1036
|
node: null,
|
|
1036
|
-
children:
|
|
1037
|
+
children: p
|
|
1037
1038
|
};
|
|
1038
1039
|
}
|
|
1039
1040
|
}
|
|
1040
1041
|
class xt {
|
|
1041
|
-
constructor(e, s, t,
|
|
1042
|
+
constructor(e, s, t, i = 60) {
|
|
1042
1043
|
l(this, "sceneManager");
|
|
1043
1044
|
l(this, "animationId", null);
|
|
1044
1045
|
l(this, "isRunning", !1);
|
|
@@ -1063,7 +1064,7 @@ class xt {
|
|
|
1063
1064
|
const t = e - this.fpsStartTime;
|
|
1064
1065
|
t >= 1e3 && (this.currentFPS = this.frameCount / (t / 1e3), this.frameCount = 0, this.fpsStartTime = e), this.onSimulate(), this.onRender(), this.sceneManager.render();
|
|
1065
1066
|
});
|
|
1066
|
-
this.sceneManager = e, this.onSimulate = s, this.onRender = t, this.frameInterval = 1e3 /
|
|
1067
|
+
this.sceneManager = e, this.onSimulate = s, this.onRender = t, this.frameInterval = 1e3 / i;
|
|
1067
1068
|
}
|
|
1068
1069
|
/**
|
|
1069
1070
|
* Starts the animation loop
|
|
@@ -1140,10 +1141,10 @@ class bt {
|
|
|
1140
1141
|
{ colors: ["#2d1a1a", "#1a0a0a", "#0f0505"] }
|
|
1141
1142
|
// -z
|
|
1142
1143
|
];
|
|
1143
|
-
for (const
|
|
1144
|
-
const
|
|
1145
|
-
|
|
1146
|
-
const a =
|
|
1144
|
+
for (const i of t) {
|
|
1145
|
+
const o = document.createElement("canvas");
|
|
1146
|
+
o.width = 256, o.height = 256;
|
|
1147
|
+
const a = o.getContext("2d"), r = a.createRadialGradient(
|
|
1147
1148
|
256 / 2,
|
|
1148
1149
|
256 / 2,
|
|
1149
1150
|
0,
|
|
@@ -1151,17 +1152,17 @@ class bt {
|
|
|
1151
1152
|
256 / 2,
|
|
1152
1153
|
256 * 0.8
|
|
1153
1154
|
);
|
|
1154
|
-
r.addColorStop(0,
|
|
1155
|
+
r.addColorStop(0, i.colors[0]), r.addColorStop(0.5, i.colors[1]), r.addColorStop(1, i.colors[2]), a.fillStyle = r, a.fillRect(0, 0, 256, 256);
|
|
1155
1156
|
const c = a.getImageData(0, 0, 256, 256);
|
|
1156
1157
|
for (let d = 0; d < c.data.length; d += 4) {
|
|
1157
|
-
const
|
|
1158
|
-
c.data[d] = Math.min(255, Math.max(0, c.data[d] +
|
|
1158
|
+
const p = (Math.random() - 0.5) * 5;
|
|
1159
|
+
c.data[d] = Math.min(255, Math.max(0, c.data[d] + p)), c.data[d + 1] = Math.min(255, Math.max(0, c.data[d + 1] + p)), c.data[d + 2] = Math.min(255, Math.max(0, c.data[d + 2] + p));
|
|
1159
1160
|
}
|
|
1160
|
-
a.putImageData(c, 0, 0), s.push(
|
|
1161
|
+
a.putImageData(c, 0, 0), s.push(o);
|
|
1161
1162
|
}
|
|
1162
|
-
this.envMap = new m.CubeTexture(s.map((
|
|
1163
|
-
const
|
|
1164
|
-
return
|
|
1163
|
+
this.envMap = new m.CubeTexture(s.map((i) => {
|
|
1164
|
+
const o = new Image();
|
|
1165
|
+
return o.src = i.toDataURL(), o;
|
|
1165
1166
|
})), this.envMap.needsUpdate = !0;
|
|
1166
1167
|
}
|
|
1167
1168
|
/**
|
|
@@ -1178,9 +1179,9 @@ class bt {
|
|
|
1178
1179
|
const t = "glass-single";
|
|
1179
1180
|
if (this.materialCache.has(t))
|
|
1180
1181
|
return this.materialCache.get(t).clone();
|
|
1181
|
-
const
|
|
1182
|
+
const i = new m.Color(16750950), o = new m.ShaderMaterial({
|
|
1182
1183
|
uniforms: {
|
|
1183
|
-
uColor: { value:
|
|
1184
|
+
uColor: { value: i },
|
|
1184
1185
|
uEnvMap: { value: this.envMap },
|
|
1185
1186
|
uGlowColor: { value: new m.Color(16777215) },
|
|
1186
1187
|
uGlowIntensity: { value: 0.8 },
|
|
@@ -1252,7 +1253,7 @@ class bt {
|
|
|
1252
1253
|
depthWrite: !0,
|
|
1253
1254
|
blending: m.NormalBlending
|
|
1254
1255
|
});
|
|
1255
|
-
return this.materialCache.set(t,
|
|
1256
|
+
return this.materialCache.set(t, o), o.clone();
|
|
1256
1257
|
}
|
|
1257
1258
|
/**
|
|
1258
1259
|
* Creates material for edges (light color for dark background)
|
|
@@ -1281,10 +1282,10 @@ class bt {
|
|
|
1281
1282
|
* Creates a sprite material for labels (light text for dark background)
|
|
1282
1283
|
*/
|
|
1283
1284
|
createLabelMaterial(e, s = 24) {
|
|
1284
|
-
const t = document.createElement("canvas"),
|
|
1285
|
-
|
|
1286
|
-
const a =
|
|
1287
|
-
t.width = Math.max(128, a + 24), t.height = s + 20,
|
|
1285
|
+
const t = document.createElement("canvas"), i = t.getContext("2d");
|
|
1286
|
+
i.font = `600 ${s}px Inter, -apple-system, sans-serif`;
|
|
1287
|
+
const a = i.measureText(e).width;
|
|
1288
|
+
t.width = Math.max(128, a + 24), t.height = s + 20, i.clearRect(0, 0, t.width, t.height), i.font = `600 ${s}px Inter, -apple-system, sans-serif`, i.textAlign = "center", i.textBaseline = "middle", i.shadowColor = "rgba(0, 0, 0, 0.8)", i.shadowBlur = 4, i.shadowOffsetX = 1, i.shadowOffsetY = 1, i.fillStyle = "rgba(255, 255, 255, 0.95)", i.fillText(e, t.width / 2, t.height / 2);
|
|
1288
1289
|
const r = new m.CanvasTexture(t);
|
|
1289
1290
|
return r.needsUpdate = !0, new m.SpriteMaterial({
|
|
1290
1291
|
map: r,
|
|
@@ -1307,12 +1308,13 @@ class bt {
|
|
|
1307
1308
|
}
|
|
1308
1309
|
}
|
|
1309
1310
|
class vt {
|
|
1310
|
-
constructor(e, s = 2, t = [32, 16, 8]) {
|
|
1311
|
+
constructor(e, s = 2, t = [32, 16, 8], i = 16750950) {
|
|
1311
1312
|
l(this, "materialFactory");
|
|
1312
1313
|
l(this, "geometryCache", /* @__PURE__ */ new Map());
|
|
1313
1314
|
l(this, "nodeRadius");
|
|
1314
1315
|
l(this, "lodSegments");
|
|
1315
|
-
this
|
|
1316
|
+
l(this, "defaultNodeColor");
|
|
1317
|
+
this.materialFactory = e, this.nodeRadius = s, this.lodSegments = t, this.defaultNodeColor = i, this.initGeometryCache();
|
|
1316
1318
|
}
|
|
1317
1319
|
/**
|
|
1318
1320
|
* Pre-create geometries for each LOD level
|
|
@@ -1339,9 +1341,9 @@ class vt {
|
|
|
1339
1341
|
createNode(e, s = 0) {
|
|
1340
1342
|
const t = new m.Group();
|
|
1341
1343
|
t.name = `node-${e.id}`, t.userData = { nodeId: e.id, nodeData: e };
|
|
1342
|
-
const
|
|
1343
|
-
e.color ??
|
|
1344
|
-
), a = new m.Mesh(
|
|
1344
|
+
const i = this.getGeometry(s), o = this.materialFactory.createGlassMaterial(
|
|
1345
|
+
e.color ?? this.defaultNodeColor
|
|
1346
|
+
), a = new m.Mesh(i, o);
|
|
1345
1347
|
a.castShadow = !0, a.receiveShadow = !0, t.add(a);
|
|
1346
1348
|
const r = this.materialFactory.createLabelMaterial(e.label), c = new m.Sprite(r);
|
|
1347
1349
|
return c.position.y = this.nodeRadius + 1.5, c.scale.set(4, 1, 1), t.add(c), e.position && t.position.set(
|
|
@@ -1415,14 +1417,14 @@ class Mt {
|
|
|
1415
1417
|
/**
|
|
1416
1418
|
* Creates an edge line between two positions
|
|
1417
1419
|
*/
|
|
1418
|
-
createEdge(e, s, t,
|
|
1420
|
+
createEdge(e, s, t, i, o) {
|
|
1419
1421
|
const a = new m.BufferGeometry(), r = new Float32Array([
|
|
1420
|
-
o.x,
|
|
1421
|
-
o.y,
|
|
1422
|
-
o.z,
|
|
1423
1422
|
i.x,
|
|
1424
1423
|
i.y,
|
|
1425
|
-
i.z
|
|
1424
|
+
i.z,
|
|
1425
|
+
o.x,
|
|
1426
|
+
o.y,
|
|
1427
|
+
o.z
|
|
1426
1428
|
]);
|
|
1427
1429
|
a.setAttribute("position", new m.BufferAttribute(r, 3));
|
|
1428
1430
|
const c = this.getDefaultMaterial().clone(), d = new m.Line(a, c);
|
|
@@ -1454,8 +1456,8 @@ class Mt {
|
|
|
1454
1456
|
* Updates an edge's positions
|
|
1455
1457
|
*/
|
|
1456
1458
|
updateEdgePositions(e, s, t) {
|
|
1457
|
-
const
|
|
1458
|
-
|
|
1459
|
+
const i = e.line.geometry.attributes.position, o = i.array;
|
|
1460
|
+
o[0] = s.x, o[1] = s.y, o[2] = s.z, o[3] = t.x, o[4] = t.y, o[5] = t.z, i.needsUpdate = !0, e.line.geometry.computeBoundingSphere();
|
|
1459
1461
|
}
|
|
1460
1462
|
/**
|
|
1461
1463
|
* Disposes an edge's resources
|
|
@@ -1483,15 +1485,15 @@ class wt {
|
|
|
1483
1485
|
getLODLevel(e) {
|
|
1484
1486
|
if (!this.enabled)
|
|
1485
1487
|
return U.HIGH;
|
|
1486
|
-
const s = e.x - this.camera.position.x, t = e.y - this.camera.position.y,
|
|
1487
|
-
return
|
|
1488
|
+
const s = e.x - this.camera.position.x, t = e.y - this.camera.position.y, i = e.z - this.camera.position.z, o = Math.sqrt(s * s + t * t + i * i);
|
|
1489
|
+
return o < this.lodDistances[0] ? U.HIGH : o < this.lodDistances[1] ? U.MEDIUM : U.LOW;
|
|
1488
1490
|
}
|
|
1489
1491
|
/**
|
|
1490
1492
|
* Checks if a node should be visible based on distance
|
|
1491
1493
|
*/
|
|
1492
1494
|
shouldRenderNode(e, s = 500) {
|
|
1493
|
-
const t = e.x - this.camera.position.x,
|
|
1494
|
-
return Math.sqrt(t * t +
|
|
1495
|
+
const t = e.x - this.camera.position.x, i = e.y - this.camera.position.y, o = e.z - this.camera.position.z;
|
|
1496
|
+
return Math.sqrt(t * t + i * i + o * o) < s;
|
|
1495
1497
|
}
|
|
1496
1498
|
/**
|
|
1497
1499
|
* Sets the LOD distances
|
|
@@ -1547,14 +1549,14 @@ class Et {
|
|
|
1547
1549
|
*/
|
|
1548
1550
|
isLineVisible(e, s) {
|
|
1549
1551
|
if (!this.enabled) return !0;
|
|
1550
|
-
const t = new m.Vector3(e.x, e.y, e.z),
|
|
1551
|
-
if (this.frustum.containsPoint(t) || this.frustum.containsPoint(
|
|
1552
|
+
const t = new m.Vector3(e.x, e.y, e.z), i = new m.Vector3(s.x, s.y, s.z);
|
|
1553
|
+
if (this.frustum.containsPoint(t) || this.frustum.containsPoint(i))
|
|
1552
1554
|
return !0;
|
|
1553
|
-
const
|
|
1555
|
+
const o = new m.Vector3(
|
|
1554
1556
|
(e.x + s.x) / 2,
|
|
1555
1557
|
(e.y + s.y) / 2,
|
|
1556
1558
|
(e.z + s.z) / 2
|
|
1557
|
-
), a =
|
|
1559
|
+
), a = o.distanceTo(t), r = new m.Sphere(o, a);
|
|
1558
1560
|
return this.frustum.intersectsSphere(r);
|
|
1559
1561
|
}
|
|
1560
1562
|
/**
|
|
@@ -1578,7 +1580,7 @@ class Ct {
|
|
|
1578
1580
|
l(this, "hoveredEdgeKey", null);
|
|
1579
1581
|
l(this, "nodeObjects", []);
|
|
1580
1582
|
l(this, "edgeObjects", []);
|
|
1581
|
-
this.sceneManager = e, this.container = s, this.raycaster = new m.Raycaster(), this.raycaster.params.Line = { threshold:
|
|
1583
|
+
this.sceneManager = e, this.container = s, this.raycaster = new m.Raycaster(), this.raycaster.params.Line = { threshold: 1.5 }, this.mouse = new m.Vector2(), this.handleClick = this.handleClick.bind(this), this.handleMouseMove = this.handleMouseMove.bind(this), s.addEventListener("click", this.handleClick), s.addEventListener("mousemove", this.handleMouseMove);
|
|
1582
1584
|
}
|
|
1583
1585
|
/**
|
|
1584
1586
|
* Updates the list of node objects to raycast against
|
|
@@ -1637,23 +1639,23 @@ class Ct {
|
|
|
1637
1639
|
this.hoveredEdgeKey !== null && this.onEdgeHover && (this.hoveredEdgeKey = null, this.onEdgeHover(null)), this.container.style.cursor = "pointer";
|
|
1638
1640
|
return;
|
|
1639
1641
|
}
|
|
1640
|
-
const
|
|
1641
|
-
|
|
1642
|
+
const i = this.getIntersectedEdge(e), o = i ? `${i.edge.source}-${i.edge.target}` : null;
|
|
1643
|
+
o !== this.hoveredEdgeKey && (this.hoveredEdgeKey = o, this.onEdgeHover && this.onEdgeHover(i)), this.container.style.cursor = i ? "pointer" : "default";
|
|
1642
1644
|
}
|
|
1643
1645
|
/**
|
|
1644
1646
|
* Gets the intersected node from a mouse event
|
|
1645
1647
|
*/
|
|
1646
1648
|
getIntersectedNode(e) {
|
|
1647
|
-
var
|
|
1649
|
+
var i;
|
|
1648
1650
|
const s = this.container.getBoundingClientRect();
|
|
1649
1651
|
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);
|
|
1650
1652
|
const t = this.raycaster.intersectObjects(this.nodeObjects, !0);
|
|
1651
1653
|
if (t.length > 0) {
|
|
1652
|
-
let
|
|
1653
|
-
for (;
|
|
1654
|
-
if ((
|
|
1655
|
-
return
|
|
1656
|
-
|
|
1654
|
+
let o = t[0].object;
|
|
1655
|
+
for (; o; ) {
|
|
1656
|
+
if ((i = o.userData) != null && i.nodeData)
|
|
1657
|
+
return o.userData.nodeData;
|
|
1658
|
+
o = o.parent;
|
|
1657
1659
|
}
|
|
1658
1660
|
}
|
|
1659
1661
|
return null;
|
|
@@ -1666,13 +1668,13 @@ class Ct {
|
|
|
1666
1668
|
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);
|
|
1667
1669
|
const t = this.raycaster.intersectObjects(this.edgeObjects, !1);
|
|
1668
1670
|
if (t.length > 0) {
|
|
1669
|
-
const
|
|
1670
|
-
if (
|
|
1671
|
+
const i = t[0].object, o = i.userData;
|
|
1672
|
+
if (o != null && o.edge && (o != null && o.sourceNode) && (o != null && o.targetNode))
|
|
1671
1673
|
return {
|
|
1672
|
-
edge:
|
|
1673
|
-
sourceNode:
|
|
1674
|
-
targetNode:
|
|
1675
|
-
edgeLine:
|
|
1674
|
+
edge: o.edge,
|
|
1675
|
+
sourceNode: o.sourceNode,
|
|
1676
|
+
targetNode: o.targetNode,
|
|
1677
|
+
edgeLine: i
|
|
1676
1678
|
};
|
|
1677
1679
|
}
|
|
1678
1680
|
return null;
|
|
@@ -1681,14 +1683,14 @@ class Ct {
|
|
|
1681
1683
|
* Performs a raycast and returns the intersected node ID
|
|
1682
1684
|
*/
|
|
1683
1685
|
getIntersectedNodeId(e, s) {
|
|
1684
|
-
var
|
|
1686
|
+
var o;
|
|
1685
1687
|
const t = this.container.getBoundingClientRect();
|
|
1686
1688
|
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);
|
|
1687
|
-
const
|
|
1688
|
-
if (
|
|
1689
|
-
let a =
|
|
1689
|
+
const i = this.raycaster.intersectObjects(this.nodeObjects, !0);
|
|
1690
|
+
if (i.length > 0) {
|
|
1691
|
+
let a = i[0].object;
|
|
1690
1692
|
for (; a; ) {
|
|
1691
|
-
if ((
|
|
1693
|
+
if ((o = a.userData) != null && o.nodeId)
|
|
1692
1694
|
return a.userData.nodeId;
|
|
1693
1695
|
a = a.parent;
|
|
1694
1696
|
}
|
|
@@ -1772,10 +1774,10 @@ class Nt {
|
|
|
1772
1774
|
this.currentNodeId = e.id;
|
|
1773
1775
|
let t;
|
|
1774
1776
|
this.panelTemplate ? t = this.panelTemplate(e, s) : t = this.generateDefaultContent(e, s), this.panel.innerHTML = t;
|
|
1775
|
-
const
|
|
1776
|
-
|
|
1777
|
+
const i = this.panel.querySelector('[data-action="expand"]'), o = this.panel.querySelector("[data-depth-select]");
|
|
1778
|
+
i && this.onExpand && i.addEventListener("click", () => {
|
|
1777
1779
|
if (this.currentNodeId) {
|
|
1778
|
-
const r =
|
|
1780
|
+
const r = o ? parseInt(o.value, 10) : 1;
|
|
1779
1781
|
this.onExpand(this.currentNodeId, r);
|
|
1780
1782
|
}
|
|
1781
1783
|
});
|
|
@@ -1934,7 +1936,7 @@ class Nt {
|
|
|
1934
1936
|
<div class="neighbors-section">
|
|
1935
1937
|
<div class="neighbors-title">Connected To</div>
|
|
1936
1938
|
${s.slice(0, 5).map(
|
|
1937
|
-
(
|
|
1939
|
+
(i) => `<span class="neighbor-chip">${this.escapeHtml(i.label)}</span>`
|
|
1938
1940
|
).join("")}
|
|
1939
1941
|
${s.length > 5 ? `<span class="neighbor-chip">+${s.length - 5} more</span>` : ""}
|
|
1940
1942
|
</div>
|
|
@@ -2052,10 +2054,10 @@ class St {
|
|
|
2052
2054
|
show(e, s, t) {
|
|
2053
2055
|
if (!this.panel) return;
|
|
2054
2056
|
this.currentEdgeKey = `${e.source}-${e.target}`;
|
|
2055
|
-
let
|
|
2056
|
-
this.panelTemplate ?
|
|
2057
|
-
const
|
|
2058
|
-
|
|
2057
|
+
let i;
|
|
2058
|
+
this.panelTemplate ? i = this.panelTemplate(e, s, t) : i = this.generateDefaultContent(e, s, t), this.panel.innerHTML = i;
|
|
2059
|
+
const o = this.panel.querySelector('[data-action="close"]');
|
|
2060
|
+
o && o.addEventListener("click", () => {
|
|
2059
2061
|
this.hide(), this.onClose && this.onClose();
|
|
2060
2062
|
});
|
|
2061
2063
|
const a = this.panel.querySelector('[data-action="goto-source"]');
|
|
@@ -2071,7 +2073,7 @@ class St {
|
|
|
2071
2073
|
* Generates default panel content
|
|
2072
2074
|
*/
|
|
2073
2075
|
generateDefaultContent(e, s, t) {
|
|
2074
|
-
const
|
|
2076
|
+
const i = s.color ? `#${s.color.toString(16).padStart(6, "0")}` : "#ff9966", o = t.color ? `#${t.color.toString(16).padStart(6, "0")}` : "#ff9966", a = e.relationship || "connected to";
|
|
2075
2077
|
return `
|
|
2076
2078
|
<style>
|
|
2077
2079
|
.force-graph-edge-panel .panel-header {
|
|
@@ -2181,7 +2183,7 @@ class St {
|
|
|
2181
2183
|
<div class="node-card" data-action="goto-source" title="Click to focus on ${this.escapeHtml(s.label)}">
|
|
2182
2184
|
<div class="node-type">Source</div>
|
|
2183
2185
|
<div class="node-card-header">
|
|
2184
|
-
<span class="color-dot" style="background: ${
|
|
2186
|
+
<span class="color-dot" style="background: ${i}; box-shadow: 0 0 8px ${i}80;"></span>
|
|
2185
2187
|
<span class="node-label">${this.escapeHtml(s.label)}</span>
|
|
2186
2188
|
</div>
|
|
2187
2189
|
</div>
|
|
@@ -2191,7 +2193,7 @@ class St {
|
|
|
2191
2193
|
<div class="node-card" data-action="goto-target" title="Click to focus on ${this.escapeHtml(t.label)}">
|
|
2192
2194
|
<div class="node-type">Target</div>
|
|
2193
2195
|
<div class="node-card-header">
|
|
2194
|
-
<span class="color-dot" style="background: ${
|
|
2196
|
+
<span class="color-dot" style="background: ${o}; box-shadow: 0 0 8px ${o}80;"></span>
|
|
2195
2197
|
<span class="node-label">${this.escapeHtml(t.label)}</span>
|
|
2196
2198
|
</div>
|
|
2197
2199
|
</div>
|
|
@@ -2279,14 +2281,14 @@ class zt {
|
|
|
2279
2281
|
*/
|
|
2280
2282
|
positionTooltip(e, s) {
|
|
2281
2283
|
if (!this.tooltip) return;
|
|
2282
|
-
const t = this.tooltip.getBoundingClientRect(),
|
|
2284
|
+
const t = this.tooltip.getBoundingClientRect(), i = window.innerWidth, o = window.innerHeight;
|
|
2283
2285
|
let a = e + 15, r = s + 15;
|
|
2284
|
-
a + t.width >
|
|
2286
|
+
a + t.width > i - 10 && (a = e - t.width - 15), r + t.height > o - 10 && (r = s - t.height - 15), a < 10 && (a = 10), r < 10 && (r = 10), this.tooltip.style.left = `${a}px`, this.tooltip.style.top = `${r}px`;
|
|
2285
2287
|
}
|
|
2286
2288
|
/**
|
|
2287
2289
|
* Shows the tooltip with edge info
|
|
2288
2290
|
*/
|
|
2289
|
-
show(e, s, t,
|
|
2291
|
+
show(e, s, t, i, o) {
|
|
2290
2292
|
if (!this.tooltip) return;
|
|
2291
2293
|
const a = e.relationship || "connected to";
|
|
2292
2294
|
this.tooltip.innerHTML = `
|
|
@@ -2301,7 +2303,7 @@ class zt {
|
|
|
2301
2303
|
<span style="font-weight: 600; color: #ff9966;">${this.escapeHtml(t.label)}</span>
|
|
2302
2304
|
</div>
|
|
2303
2305
|
</div>
|
|
2304
|
-
`, this.positionTooltip(
|
|
2306
|
+
`, this.positionTooltip(i, o), this.tooltip.style.opacity = "1", this.tooltip.style.transform = "translateY(0)", this.visible = !0;
|
|
2305
2307
|
}
|
|
2306
2308
|
/**
|
|
2307
2309
|
* Updates tooltip position (called externally on mouse move)
|
|
@@ -2478,25 +2480,25 @@ class kt {
|
|
|
2478
2480
|
this.searchResults.innerHTML = '<div class="f3d-no-results">No results found</div>', this.searchResults.style.display = "block";
|
|
2479
2481
|
return;
|
|
2480
2482
|
}
|
|
2481
|
-
let
|
|
2482
|
-
s.length > 0 && (
|
|
2483
|
-
const a =
|
|
2484
|
-
|
|
2485
|
-
<div class="f3d-search-result-item" data-node-id="${this.escapeHtml(
|
|
2486
|
-
<div class="f3d-result-label">${this.escapeHtml(
|
|
2483
|
+
let i = "";
|
|
2484
|
+
s.length > 0 && (i += '<div class="f3d-search-section-header">Nodes</div>', s.slice(0, 10).forEach((o) => {
|
|
2485
|
+
const a = o.type || "Node";
|
|
2486
|
+
i += `
|
|
2487
|
+
<div class="f3d-search-result-item" data-node-id="${this.escapeHtml(o.id)}">
|
|
2488
|
+
<div class="f3d-result-label">${this.escapeHtml(o.label)}</div>
|
|
2487
2489
|
<div class="f3d-result-type">${this.escapeHtml(a)}</div>
|
|
2488
2490
|
</div>
|
|
2489
2491
|
`;
|
|
2490
|
-
}), s.length > 10 && (
|
|
2491
|
-
|
|
2492
|
-
<div class="f3d-search-result-item" data-node-id="${this.escapeHtml(
|
|
2492
|
+
}), s.length > 10 && (i += `<div class="f3d-no-results">+ ${s.length - 10} more nodes</div>`)), t.length > 0 && (i += '<div class="f3d-search-section-header">Relationships</div>', t.slice(0, 5).forEach(({ edge: o, sourceNode: a, targetNode: r }) => {
|
|
2493
|
+
i += `
|
|
2494
|
+
<div class="f3d-search-result-item" data-node-id="${this.escapeHtml(o.source)}">
|
|
2493
2495
|
<div class="f3d-result-label">${this.escapeHtml(a.label)} → ${this.escapeHtml(r.label)}</div>
|
|
2494
|
-
<div class="f3d-result-relationship">${this.escapeHtml(
|
|
2496
|
+
<div class="f3d-result-relationship">${this.escapeHtml(o.relationship || "connected")}</div>
|
|
2495
2497
|
</div>
|
|
2496
2498
|
`;
|
|
2497
|
-
}), t.length > 5 && (
|
|
2498
|
-
|
|
2499
|
-
const a =
|
|
2499
|
+
}), t.length > 5 && (i += `<div class="f3d-no-results">+ ${t.length - 5} more relationships</div>`)), this.searchResults.innerHTML = i, this.searchResults.style.display = "block", this.searchResults.querySelectorAll(".f3d-search-result-item").forEach((o) => {
|
|
2500
|
+
o.addEventListener("click", () => {
|
|
2501
|
+
const a = o.dataset.nodeId;
|
|
2500
2502
|
a && (this.onResultClick(a), this.searchResults && (this.searchResults.style.display = "none"), this.searchInput && this.searchInput.blur());
|
|
2501
2503
|
});
|
|
2502
2504
|
});
|
|
@@ -2607,8 +2609,8 @@ const Tt = {
|
|
|
2607
2609
|
nodeRadius: 24,
|
|
2608
2610
|
edgeColor: "rgba(255, 255, 255, 0.15)",
|
|
2609
2611
|
edgeOpacity: 0.4,
|
|
2610
|
-
repulsionStrength:
|
|
2611
|
-
//
|
|
2612
|
+
repulsionStrength: 5e3,
|
|
2613
|
+
// Strong repulsion for spread out layout
|
|
2612
2614
|
attractionStrength: 1e-3,
|
|
2613
2615
|
// Very low attraction
|
|
2614
2616
|
damping: 0.85
|
|
@@ -2654,31 +2656,31 @@ class Lt {
|
|
|
2654
2656
|
setupInteractions() {
|
|
2655
2657
|
this.canvas.addEventListener("wheel", (e) => {
|
|
2656
2658
|
e.preventDefault();
|
|
2657
|
-
const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left,
|
|
2658
|
-
this.transform.x = t - (t - this.transform.x) * r, this.transform.y =
|
|
2659
|
+
const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, o = e.deltaY > 0 ? 0.9 : 1.1, a = Math.max(0.1, Math.min(5, this.transform.scale * o)), r = a / this.transform.scale;
|
|
2660
|
+
this.transform.x = t - (t - this.transform.x) * r, this.transform.y = i - (i - this.transform.y) * r, this.transform.scale = a;
|
|
2659
2661
|
}), this.canvas.addEventListener("mousedown", (e) => {
|
|
2660
|
-
const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left,
|
|
2662
|
+
const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, o = this.screenToWorld(t, i), a = this.findNodeAt(o.x, o.y);
|
|
2661
2663
|
this.dragStartPos = { x: e.clientX, y: e.clientY }, a ? (this.isDragging = !0, this.draggedNode = a, this.canvas.style.cursor = "grabbing", this.isSimulating = !0) : (this.isPanning = !0, this.canvas.style.cursor = "grabbing"), this.lastMousePos = { x: e.clientX, y: e.clientY };
|
|
2662
2664
|
}), this.canvas.addEventListener("mousemove", (e) => {
|
|
2663
|
-
const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left,
|
|
2665
|
+
const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, o = this.screenToWorld(t, i);
|
|
2664
2666
|
if (this.isDragging && this.draggedNode)
|
|
2665
|
-
this.draggedNode.x =
|
|
2667
|
+
this.draggedNode.x = o.x, this.draggedNode.y = o.y, this.draggedNode.vx = 0, this.draggedNode.vy = 0;
|
|
2666
2668
|
else if (this.isPanning) {
|
|
2667
2669
|
const a = e.clientX - this.lastMousePos.x, r = e.clientY - this.lastMousePos.y;
|
|
2668
2670
|
this.transform.x += a, this.transform.y += r, this.lastMousePos = { x: e.clientX, y: e.clientY };
|
|
2669
2671
|
} else {
|
|
2670
|
-
const a = this.findNodeAt(
|
|
2672
|
+
const a = this.findNodeAt(o.x, o.y);
|
|
2671
2673
|
if (a !== this.hoveredNode && (this.hoveredNode = a, a ? (this.hoveredEdge && (this.hoveredEdge = null, this.options.onEdgeHover && this.options.onEdgeHover(null)), this.canvas.style.cursor = "pointer", this.options.onNodeHover && this.options.onNodeHover(a.data)) : this.options.onNodeHover && this.options.onNodeHover(null)), !a) {
|
|
2672
|
-
const r = this.findEdgeAt(
|
|
2674
|
+
const r = this.findEdgeAt(o.x, o.y);
|
|
2673
2675
|
r !== this.hoveredEdge && (this.hoveredEdge = r, this.canvas.style.cursor = r ? "pointer" : "grab", this.options.onEdgeHover && this.options.onEdgeHover(r ? r.data : null, e));
|
|
2674
2676
|
}
|
|
2675
2677
|
}
|
|
2676
2678
|
}), this.canvas.addEventListener("mouseup", (e) => {
|
|
2677
|
-
const s = Math.abs(e.clientX - this.dragStartPos.x), t = Math.abs(e.clientY - this.dragStartPos.y),
|
|
2679
|
+
const s = Math.abs(e.clientX - this.dragStartPos.x), t = Math.abs(e.clientY - this.dragStartPos.y), i = s < 5 && t < 5;
|
|
2678
2680
|
if (this.isDragging && this.draggedNode)
|
|
2679
|
-
|
|
2680
|
-
else if (
|
|
2681
|
-
const
|
|
2681
|
+
i && this.options.onNodeClick && (this.selectedNode = this.draggedNode, this.options.onNodeClick(this.draggedNode.data));
|
|
2682
|
+
else if (i) {
|
|
2683
|
+
const o = this.canvas.getBoundingClientRect(), a = this.screenToWorld(e.clientX - o.left, e.clientY - o.top), r = this.findEdgeAt(a.x, a.y);
|
|
2682
2684
|
r && this.options.onEdgeClick && this.options.onEdgeClick(r.data);
|
|
2683
2685
|
}
|
|
2684
2686
|
this.isDragging = !1, this.isPanning = !1, this.draggedNode = null, this.canvas.style.cursor = this.hoveredNode ? "pointer" : "grab";
|
|
@@ -2694,21 +2696,21 @@ class Lt {
|
|
|
2694
2696
|
}
|
|
2695
2697
|
findNodeAt(e, s) {
|
|
2696
2698
|
for (const t of this.nodes.values()) {
|
|
2697
|
-
const
|
|
2698
|
-
if (Math.sqrt(
|
|
2699
|
+
const i = t.x - e, o = t.y - s;
|
|
2700
|
+
if (Math.sqrt(i * i + o * o) < t.radius)
|
|
2699
2701
|
return t;
|
|
2700
2702
|
}
|
|
2701
2703
|
return null;
|
|
2702
2704
|
}
|
|
2703
2705
|
findEdgeAt(e, s) {
|
|
2704
|
-
for (const
|
|
2705
|
-
const
|
|
2706
|
-
if (!
|
|
2707
|
-
const r = a.x -
|
|
2706
|
+
for (const i of this.edges) {
|
|
2707
|
+
const o = this.nodes.get(i.source), a = this.nodes.get(i.target);
|
|
2708
|
+
if (!o || !a) continue;
|
|
2709
|
+
const r = a.x - o.x, c = a.y - o.y, d = r * r + c * c;
|
|
2708
2710
|
if (d === 0) continue;
|
|
2709
|
-
const
|
|
2710
|
-
if (Math.sqrt(
|
|
2711
|
-
return
|
|
2711
|
+
const p = Math.max(0, Math.min(1, ((e - o.x) * r + (s - o.y) * c) / d)), x = o.x + p * r, f = o.y + p * c, u = e - x, y = s - f;
|
|
2712
|
+
if (Math.sqrt(u * u + y * y) < 12)
|
|
2713
|
+
return i;
|
|
2712
2714
|
}
|
|
2713
2715
|
return null;
|
|
2714
2716
|
}
|
|
@@ -2721,87 +2723,87 @@ class Lt {
|
|
|
2721
2723
|
simulate() {
|
|
2722
2724
|
const e = Array.from(this.nodes.values()), s = e.length;
|
|
2723
2725
|
if (s === 0) return;
|
|
2724
|
-
const t = 60,
|
|
2725
|
-
let
|
|
2726
|
+
const t = 60, i = 5;
|
|
2727
|
+
let o = 0;
|
|
2726
2728
|
for (let r = 0; r < s; r++)
|
|
2727
2729
|
for (let c = r + 1; c < s; c++) {
|
|
2728
|
-
const d = e[r],
|
|
2729
|
-
let
|
|
2730
|
-
if (
|
|
2731
|
-
|
|
2732
|
-
const
|
|
2733
|
-
d.vx -=
|
|
2730
|
+
const d = e[r], p = e[c];
|
|
2731
|
+
let x = p.x - d.x, f = p.y - d.y, u = Math.sqrt(x * x + f * f);
|
|
2732
|
+
if (u < t * 3) {
|
|
2733
|
+
u < 1 && (u = 1);
|
|
2734
|
+
const y = this.options.repulsionStrength / (u * u), b = x / u * y, M = f / u * y;
|
|
2735
|
+
d.vx -= b, d.vy -= M, p.vx += b, p.vy += M;
|
|
2734
2736
|
}
|
|
2735
2737
|
}
|
|
2736
2738
|
const a = 80;
|
|
2737
2739
|
for (const r of this.edges) {
|
|
2738
2740
|
const c = this.nodes.get(r.source), d = this.nodes.get(r.target);
|
|
2739
2741
|
if (!c || !d) continue;
|
|
2740
|
-
let
|
|
2741
|
-
|
|
2742
|
-
const
|
|
2743
|
-
c.vx +=
|
|
2742
|
+
let p = d.x - c.x, x = d.y - c.y, f = Math.sqrt(p * p + x * x);
|
|
2743
|
+
f < 1 && (f = 1);
|
|
2744
|
+
const y = (f - a) * this.options.attractionStrength, b = p / f * y, M = x / f * y;
|
|
2745
|
+
c.vx += b, c.vy += M, d.vx -= b, d.vy -= M;
|
|
2744
2746
|
}
|
|
2745
2747
|
for (const r of e) {
|
|
2746
2748
|
if (this.draggedNode === r) continue;
|
|
2747
2749
|
r.vx *= this.options.damping, r.vy *= this.options.damping;
|
|
2748
2750
|
const c = Math.sqrt(r.vx * r.vx + r.vy * r.vy);
|
|
2749
|
-
c >
|
|
2751
|
+
c > i && (r.vx = r.vx / c * i, r.vy = r.vy / c * i), r.x += r.vx, r.y += r.vy, o += r.vx * r.vx + r.vy * r.vy;
|
|
2750
2752
|
}
|
|
2751
|
-
|
|
2753
|
+
o < 0.01 && !this.draggedNode && (this.isSimulating = !1);
|
|
2752
2754
|
}
|
|
2753
2755
|
render() {
|
|
2754
2756
|
const e = this.ctx, s = this.canvas.width / (window.devicePixelRatio || 1), t = this.canvas.height / (window.devicePixelRatio || 1);
|
|
2755
2757
|
e.fillStyle = this.options.backgroundColor, e.fillRect(0, 0, s, t), this.renderGrid(s, t), e.save(), e.translate(this.transform.x, this.transform.y), e.scale(this.transform.scale, this.transform.scale), this.renderEdges(), this.renderNodes(), e.restore();
|
|
2756
2758
|
}
|
|
2757
2759
|
renderGrid(e, s) {
|
|
2758
|
-
const t = this.ctx,
|
|
2760
|
+
const t = this.ctx, i = 40 * this.transform.scale, o = 1.5, a = this.transform.x % i, r = this.transform.y % i;
|
|
2759
2761
|
t.fillStyle = this.options.gridColor;
|
|
2760
|
-
for (let c = a; c < e; c +=
|
|
2761
|
-
for (let d = r; d < s; d +=
|
|
2762
|
-
t.beginPath(), t.arc(c, d,
|
|
2762
|
+
for (let c = a; c < e; c += i)
|
|
2763
|
+
for (let d = r; d < s; d += i)
|
|
2764
|
+
t.beginPath(), t.arc(c, d, o, 0, Math.PI * 2), t.fill();
|
|
2763
2765
|
}
|
|
2764
2766
|
renderEdges() {
|
|
2765
2767
|
const e = this.ctx;
|
|
2766
2768
|
for (const s of this.edges) {
|
|
2767
|
-
const t = this.nodes.get(s.source),
|
|
2768
|
-
if (!t || !
|
|
2769
|
-
const
|
|
2770
|
-
|
|
2769
|
+
const t = this.nodes.get(s.source), i = this.nodes.get(s.target);
|
|
2770
|
+
if (!t || !i) continue;
|
|
2771
|
+
const o = s === this.hoveredEdge, a = e.createLinearGradient(t.x, t.y, i.x, i.y);
|
|
2772
|
+
o ? (a.addColorStop(0, "rgba(255, 153, 102, 0.8)"), a.addColorStop(0.5, "rgba(255, 255, 255, 0.5)"), a.addColorStop(1, "rgba(102, 153, 255, 0.8)"), e.lineWidth = 3) : (a.addColorStop(0, "rgba(255, 153, 102, 0.3)"), a.addColorStop(0.5, "rgba(255, 255, 255, 0.15)"), a.addColorStop(1, "rgba(102, 153, 255, 0.3)"), e.lineWidth = 1.5), e.beginPath(), e.moveTo(t.x, t.y), e.lineTo(i.x, i.y), e.strokeStyle = a, e.stroke();
|
|
2771
2773
|
}
|
|
2772
2774
|
}
|
|
2773
2775
|
renderNodes() {
|
|
2774
2776
|
const e = this.ctx;
|
|
2775
2777
|
for (const s of this.nodes.values()) {
|
|
2776
|
-
const t = s === this.hoveredNode,
|
|
2777
|
-
if (t || o) {
|
|
2778
|
-
const
|
|
2778
|
+
const t = s === this.hoveredNode, i = s === this.selectedNode, o = this.hoveredEdge && (s.data.id === this.hoveredEdge.source || s.data.id === this.hoveredEdge.target), a = s.radius * (t ? 1.1 : 1);
|
|
2779
|
+
if (t || i || o) {
|
|
2780
|
+
const y = e.createRadialGradient(
|
|
2779
2781
|
s.x,
|
|
2780
2782
|
s.y,
|
|
2781
|
-
|
|
2783
|
+
a * 0.5,
|
|
2782
2784
|
s.x,
|
|
2783
2785
|
s.y,
|
|
2784
|
-
|
|
2785
|
-
);
|
|
2786
|
-
|
|
2786
|
+
a * 2
|
|
2787
|
+
), b = t || i ? 0.4 : 0.25;
|
|
2788
|
+
y.addColorStop(0, `rgba(255, 153, 102, ${b})`), y.addColorStop(1, "rgba(255, 153, 102, 0)"), e.fillStyle = y, e.beginPath(), e.arc(s.x, s.y, a * 2, 0, Math.PI * 2), e.fill();
|
|
2787
2789
|
}
|
|
2788
|
-
const
|
|
2789
|
-
s.x -
|
|
2790
|
-
s.y -
|
|
2790
|
+
const r = e.createRadialGradient(
|
|
2791
|
+
s.x - a * 0.3,
|
|
2792
|
+
s.y - a * 0.3,
|
|
2791
2793
|
0,
|
|
2792
2794
|
s.x,
|
|
2793
2795
|
s.y,
|
|
2794
|
-
|
|
2795
|
-
),
|
|
2796
|
-
|
|
2797
|
-
const
|
|
2798
|
-
let
|
|
2799
|
-
if (
|
|
2800
|
-
for (;
|
|
2801
|
-
|
|
2802
|
-
|
|
2796
|
+
a
|
|
2797
|
+
), c = s.color >> 16 & 255, d = s.color >> 8 & 255, p = s.color & 255;
|
|
2798
|
+
r.addColorStop(0, `rgba(${Math.min(255, c + 60)}, ${Math.min(255, d + 60)}, ${Math.min(255, p + 60)}, 0.95)`), r.addColorStop(0.7, `rgba(${c}, ${d}, ${p}, 0.9)`), r.addColorStop(1, `rgba(${Math.max(0, c - 40)}, ${Math.max(0, d - 40)}, ${Math.max(0, p - 40)}, 0.85)`), e.beginPath(), e.arc(s.x, s.y, a, 0, Math.PI * 2), e.fillStyle = r, e.fill(), e.strokeStyle = "rgba(255, 255, 255, 0.2)", e.lineWidth = 1, e.stroke(), e.beginPath(), e.arc(s.x - a * 0.25, s.y - a * 0.25, a * 0.3, 0, Math.PI * 2), e.fillStyle = "rgba(255, 255, 255, 0.15)", e.fill(), e.fillStyle = "white", e.font = "600 11px Inter, -apple-system, BlinkMacSystemFont, sans-serif", e.textAlign = "center", e.textBaseline = "middle";
|
|
2799
|
+
const x = a * 1.6;
|
|
2800
|
+
let f = s.label, u = e.measureText(f).width;
|
|
2801
|
+
if (u > x) {
|
|
2802
|
+
for (; u > x && f.length > 3; )
|
|
2803
|
+
f = f.slice(0, -1), u = e.measureText(f + "...").width;
|
|
2804
|
+
f += "...";
|
|
2803
2805
|
}
|
|
2804
|
-
e.shadowColor = "rgba(0, 0, 0, 0.5)", e.shadowBlur = 3, e.fillText(
|
|
2806
|
+
e.shadowColor = "rgba(0, 0, 0, 0.5)", e.shadowBlur = 3, e.fillText(f, s.x, s.y), e.shadowBlur = 0;
|
|
2805
2807
|
}
|
|
2806
2808
|
}
|
|
2807
2809
|
/**
|
|
@@ -2809,14 +2811,14 @@ class Lt {
|
|
|
2809
2811
|
*/
|
|
2810
2812
|
setData(e) {
|
|
2811
2813
|
this.nodes.clear(), this.edges = [], this.nodeIdToIndex.clear(), e.nodes.forEach((s, t) => {
|
|
2812
|
-
const
|
|
2814
|
+
const i = s.position || {
|
|
2813
2815
|
x: (Math.random() - 0.5) * 300,
|
|
2814
2816
|
y: (Math.random() - 0.5) * 300
|
|
2815
|
-
},
|
|
2817
|
+
}, o = {
|
|
2816
2818
|
id: s.id,
|
|
2817
2819
|
label: s.label,
|
|
2818
|
-
x:
|
|
2819
|
-
y:
|
|
2820
|
+
x: i.x,
|
|
2821
|
+
y: i.y,
|
|
2820
2822
|
vx: 0,
|
|
2821
2823
|
vy: 0,
|
|
2822
2824
|
color: s.color || 16750950,
|
|
@@ -2824,7 +2826,7 @@ class Lt {
|
|
|
2824
2826
|
radius: this.options.nodeRadius,
|
|
2825
2827
|
data: s
|
|
2826
2828
|
};
|
|
2827
|
-
this.nodes.set(s.id,
|
|
2829
|
+
this.nodes.set(s.id, o), this.nodeIdToIndex.set(s.id, t);
|
|
2828
2830
|
}), this.edges = e.edges.map((s) => ({
|
|
2829
2831
|
source: s.source,
|
|
2830
2832
|
target: s.target,
|
|
@@ -2900,9 +2902,9 @@ class Lt {
|
|
|
2900
2902
|
focusOnNode(e) {
|
|
2901
2903
|
const s = this.nodes.get(e);
|
|
2902
2904
|
if (!s) return;
|
|
2903
|
-
const t = this.canvas.width / 2 / (window.devicePixelRatio || 1) - s.x * this.transform.scale,
|
|
2904
|
-
const
|
|
2905
|
-
this.transform.x =
|
|
2905
|
+
const t = this.canvas.width / 2 / (window.devicePixelRatio || 1) - s.x * this.transform.scale, i = this.canvas.height / 2 / (window.devicePixelRatio || 1) - s.y * this.transform.scale, o = this.transform.x, a = this.transform.y, r = 500, c = performance.now(), d = () => {
|
|
2906
|
+
const p = performance.now() - c, x = Math.min(p / r, 1), f = 1 - Math.pow(1 - x, 3);
|
|
2907
|
+
this.transform.x = o + (t - o) * f, this.transform.y = a + (i - a) * f, x < 1 ? requestAnimationFrame(d) : this.selectedNode = s;
|
|
2906
2908
|
};
|
|
2907
2909
|
d();
|
|
2908
2910
|
}
|
|
@@ -2911,8 +2913,8 @@ class Lt {
|
|
|
2911
2913
|
*/
|
|
2912
2914
|
syncFrom3D(e) {
|
|
2913
2915
|
e.forEach((s, t) => {
|
|
2914
|
-
const
|
|
2915
|
-
|
|
2916
|
+
const i = this.nodes.get(t);
|
|
2917
|
+
i && (i.x = s.position.x * 3, i.y = s.position.y * 3, i.vx = 0, i.vy = 0);
|
|
2916
2918
|
}), this.isSimulating = !1;
|
|
2917
2919
|
}
|
|
2918
2920
|
/**
|
|
@@ -2981,21 +2983,22 @@ class Ft {
|
|
|
2981
2983
|
l(this, "devControls", null);
|
|
2982
2984
|
l(this, "viewMode", "3d");
|
|
2983
2985
|
l(this, "graphData", null);
|
|
2984
|
-
this.options = { ...
|
|
2986
|
+
this.options = { ...T, ...s }, this.container = ct(e), this.materialFactory = new bt(), this.nodeFactory = new vt(
|
|
2985
2987
|
this.materialFactory,
|
|
2986
|
-
this.options.nodeRadius ??
|
|
2987
|
-
this.options.lodSegments ??
|
|
2988
|
+
this.options.nodeRadius ?? T.nodeRadius,
|
|
2989
|
+
this.options.lodSegments ?? T.lodSegments,
|
|
2990
|
+
this.options.defaultNodeColor ?? T.defaultNodeColor
|
|
2988
2991
|
), this.edgeFactory = new Mt(
|
|
2989
2992
|
this.materialFactory,
|
|
2990
|
-
this.options.edgeColor ??
|
|
2991
|
-
this.options.edgeOpacity ??
|
|
2993
|
+
this.options.edgeColor ?? T.edgeColor,
|
|
2994
|
+
this.options.edgeOpacity ?? T.edgeOpacity
|
|
2992
2995
|
), this.sceneManager = new ut(this.container, this.options), this.lodManager = new wt(
|
|
2993
2996
|
this.sceneManager.camera,
|
|
2994
|
-
this.options.lodDistances ??
|
|
2995
|
-
this.options.enableLOD ??
|
|
2997
|
+
this.options.lodDistances ?? T.lodDistances,
|
|
2998
|
+
this.options.enableLOD ?? T.enableLOD
|
|
2996
2999
|
), this.frustumCuller = new Et(
|
|
2997
3000
|
this.sceneManager.camera,
|
|
2998
|
-
this.options.enableEdgeCulling ??
|
|
3001
|
+
this.options.enableEdgeCulling ?? T.enableEdgeCulling
|
|
2999
3002
|
), this.nodeManager = new ft(this.sceneManager, this.nodeFactory), this.edgeManager = new mt(this.sceneManager, this.nodeManager, this.edgeFactory), this.graphEngine = new Le(
|
|
3000
3003
|
this.nodeManager.getAllNodes(),
|
|
3001
3004
|
this.edgeManager.getAllEdges(),
|
|
@@ -3010,7 +3013,7 @@ class Ft {
|
|
|
3010
3013
|
this.sceneManager,
|
|
3011
3014
|
() => this.onSimulate(),
|
|
3012
3015
|
() => this.onRender(),
|
|
3013
|
-
this.options.targetFPS ??
|
|
3016
|
+
this.options.targetFPS ?? T.targetFPS
|
|
3014
3017
|
), this.raycasterManager = new Ct(this.sceneManager, this.container), this.panelManager = new Nt(this.container), this.edgePanelManager = new St(this.container), this.edgeTooltipManager = new zt(), this.edgePanelManager.setNodeClickCallback((t) => {
|
|
3015
3018
|
this.edgePanelManager.hide(), this.focusOnNode(t), setTimeout(() => {
|
|
3016
3019
|
this.showNodePanel(t);
|
|
@@ -3053,8 +3056,8 @@ class Ft {
|
|
|
3053
3056
|
onEdgeHover(e) {
|
|
3054
3057
|
if (e) {
|
|
3055
3058
|
this.edgeManager.highlightEdge(e.edge.source, e.edge.target);
|
|
3056
|
-
const s = this.container.getBoundingClientRect(), t = s.left + s.width / 2,
|
|
3057
|
-
this.edgeTooltipManager.show(e.edge, e.sourceNode, e.targetNode, t,
|
|
3059
|
+
const s = this.container.getBoundingClientRect(), t = s.left + s.width / 2, i = s.top + s.height / 2;
|
|
3060
|
+
this.edgeTooltipManager.show(e.edge, e.sourceNode, e.targetNode, t, i), this.options.onEdgeHover && this.options.onEdgeHover(e.edge, e.sourceNode, e.targetNode), this.emit("edgeHover", e.edge, e.sourceNode, e.targetNode);
|
|
3058
3061
|
} else
|
|
3059
3062
|
this.edgeManager.unhighlightCurrentEdge(), this.edgeTooltipManager.hide(), this.options.onEdgeHover && this.options.onEdgeHover(null, null, null), this.emit("edgeHover", null, null, null);
|
|
3060
3063
|
}
|
|
@@ -3063,7 +3066,7 @@ class Ft {
|
|
|
3063
3066
|
*/
|
|
3064
3067
|
onNodeClick(e) {
|
|
3065
3068
|
this.edgePanelManager.hide();
|
|
3066
|
-
const t = this.edgeManager.getNeighborIds(e.id).map((
|
|
3069
|
+
const t = this.edgeManager.getNeighborIds(e.id).map((i) => this.nodeManager.getNode(i)).filter((i) => i !== void 0);
|
|
3067
3070
|
this.options.showPanel !== !1 && this.panelManager.show(e, t), this.options.onNodeClick && this.options.onNodeClick(e), this.emit("nodeClick", e);
|
|
3068
3071
|
}
|
|
3069
3072
|
/**
|
|
@@ -3167,20 +3170,20 @@ class Ft {
|
|
|
3167
3170
|
* @param fetchFn - Optional fetch function to override the default
|
|
3168
3171
|
*/
|
|
3169
3172
|
async expandNode(e, s = 1, t) {
|
|
3170
|
-
const
|
|
3171
|
-
if (!
|
|
3173
|
+
const i = t ?? this.options.onExpand;
|
|
3174
|
+
if (!i)
|
|
3172
3175
|
return console.warn("[ForceGraph3D] No expand callback provided"), !1;
|
|
3173
3176
|
try {
|
|
3174
|
-
const
|
|
3175
|
-
if (
|
|
3176
|
-
for (const a of
|
|
3177
|
+
const o = await i(e, s);
|
|
3178
|
+
if (o.nodes && Array.isArray(o.nodes))
|
|
3179
|
+
for (const a of o.nodes)
|
|
3177
3180
|
this.addNode(a);
|
|
3178
|
-
if (
|
|
3179
|
-
for (const a of
|
|
3181
|
+
if (o.edges && Array.isArray(o.edges))
|
|
3182
|
+
for (const a of o.edges)
|
|
3180
3183
|
this.addEdge(a);
|
|
3181
|
-
return this.panelManager.hide(), this.emit("expand", e,
|
|
3182
|
-
} catch (
|
|
3183
|
-
return console.error("[ForceGraph3D] Error expanding node:",
|
|
3184
|
+
return this.panelManager.hide(), this.emit("expand", e, o), !0;
|
|
3185
|
+
} catch (o) {
|
|
3186
|
+
return console.error("[ForceGraph3D] Error expanding node:", o), !1;
|
|
3184
3187
|
}
|
|
3185
3188
|
}
|
|
3186
3189
|
/**
|
|
@@ -3227,37 +3230,37 @@ class Ft {
|
|
|
3227
3230
|
console.warn(`[ForceGraph3D] Node "${e}" not found`);
|
|
3228
3231
|
return;
|
|
3229
3232
|
}
|
|
3230
|
-
const
|
|
3231
|
-
x:
|
|
3232
|
-
y:
|
|
3233
|
-
z:
|
|
3234
|
-
}, d = { x:
|
|
3235
|
-
const
|
|
3236
|
-
|
|
3233
|
+
const i = t.position, o = this.sceneManager.camera, a = this.sceneManager.controls, r = o.position.clone().sub(a.target).normalize(), c = {
|
|
3234
|
+
x: i.x + r.x * s,
|
|
3235
|
+
y: i.y + r.y * s,
|
|
3236
|
+
z: i.z + r.z * s
|
|
3237
|
+
}, d = { x: o.position.x, y: o.position.y, z: o.position.z }, p = { x: a.target.x, y: a.target.y, z: a.target.z }, x = 800, f = performance.now(), u = () => {
|
|
3238
|
+
const y = performance.now() - f, b = Math.min(y / x, 1), M = 1 - Math.pow(1 - b, 3);
|
|
3239
|
+
o.position.x = d.x + (c.x - d.x) * M, o.position.y = d.y + (c.y - d.y) * M, o.position.z = d.z + (c.z - d.z) * M, a.target.x = p.x + (i.x - p.x) * M, a.target.y = p.y + (i.y - p.y) * M, a.target.z = p.z + (i.z - p.z) * M, a.update(), b < 1 && requestAnimationFrame(u);
|
|
3237
3240
|
};
|
|
3238
|
-
|
|
3241
|
+
u();
|
|
3239
3242
|
}
|
|
3240
3243
|
/**
|
|
3241
3244
|
* Focuses the camera on an edge (both source and target nodes) with smooth animation
|
|
3242
3245
|
* Camera targets the midpoint and zooms out enough to see both nodes
|
|
3243
3246
|
*/
|
|
3244
3247
|
focusOnEdge(e, s, t = 1.5) {
|
|
3245
|
-
const
|
|
3246
|
-
if (!
|
|
3248
|
+
const i = this.nodeManager.getNode(e), o = this.nodeManager.getNode(s);
|
|
3249
|
+
if (!i || !o) {
|
|
3247
3250
|
console.warn(`[ForceGraph3D] Could not find nodes for edge "${e}" -> "${s}"`);
|
|
3248
3251
|
return;
|
|
3249
3252
|
}
|
|
3250
3253
|
const a = this.sceneManager.camera, r = this.sceneManager.controls, c = {
|
|
3251
|
-
x: (
|
|
3252
|
-
y: (
|
|
3253
|
-
z: (
|
|
3254
|
-
}, d =
|
|
3255
|
-
x: c.x +
|
|
3256
|
-
y: c.y +
|
|
3257
|
-
z: c.z +
|
|
3258
|
-
}, M = { x: a.position.x, y: a.position.y, z: a.position.z }, N = { x: r.target.x, y: r.target.y, z: r.target.z }, O = 800,
|
|
3259
|
-
const P = performance.now() -
|
|
3260
|
-
a.position.x = M.x + (
|
|
3254
|
+
x: (i.position.x + o.position.x) / 2,
|
|
3255
|
+
y: (i.position.y + o.position.y) / 2,
|
|
3256
|
+
z: (i.position.z + o.position.z) / 2
|
|
3257
|
+
}, d = o.position.x - i.position.x, p = o.position.y - i.position.y, x = o.position.z - i.position.z, f = Math.sqrt(d * d + p * p + x * x), u = Math.max(f * t, 40), y = a.position.clone().sub(r.target).normalize(), b = {
|
|
3258
|
+
x: c.x + y.x * u,
|
|
3259
|
+
y: c.y + y.y * u,
|
|
3260
|
+
z: c.z + y.z * u
|
|
3261
|
+
}, M = { x: a.position.x, y: a.position.y, z: a.position.z }, N = { x: r.target.x, y: r.target.y, z: r.target.z }, O = 800, L = performance.now(), Y = () => {
|
|
3262
|
+
const P = performance.now() - L, H = Math.min(P / O, 1), E = 1 - Math.pow(1 - H, 3);
|
|
3263
|
+
a.position.x = M.x + (b.x - M.x) * E, a.position.y = M.y + (b.y - M.y) * E, a.position.z = M.z + (b.z - M.z) * E, r.target.x = N.x + (c.x - N.x) * E, r.target.y = N.y + (c.y - N.y) * E, r.target.z = N.z + (c.z - N.z) * E, r.update(), H < 1 && requestAnimationFrame(Y);
|
|
3261
3264
|
};
|
|
3262
3265
|
Y();
|
|
3263
3266
|
}
|
|
@@ -3280,28 +3283,28 @@ class Ft {
|
|
|
3280
3283
|
searchNodes(e) {
|
|
3281
3284
|
if (!e || e.trim() === "")
|
|
3282
3285
|
return [];
|
|
3283
|
-
const s = e.toLowerCase().trim(), t = this.nodeManager.getAllNodes(),
|
|
3284
|
-
return t.forEach((
|
|
3285
|
-
var d,
|
|
3286
|
-
const a = (d =
|
|
3287
|
-
(a || r || c) &&
|
|
3288
|
-
}),
|
|
3286
|
+
const s = e.toLowerCase().trim(), t = this.nodeManager.getAllNodes(), i = [];
|
|
3287
|
+
return t.forEach((o) => {
|
|
3288
|
+
var d, p, x;
|
|
3289
|
+
const a = (d = o.label) == null ? void 0 : d.toLowerCase().includes(s), r = (p = o.id) == null ? void 0 : p.toLowerCase().includes(s), c = (x = o.type) == null ? void 0 : x.toLowerCase().includes(s);
|
|
3290
|
+
(a || r || c) && i.push(o);
|
|
3291
|
+
}), i;
|
|
3289
3292
|
}
|
|
3290
3293
|
/**
|
|
3291
3294
|
* Searches edges by relationship (case-insensitive)
|
|
3292
3295
|
* @returns Array of matching edges with source/target node info
|
|
3293
3296
|
*/
|
|
3294
3297
|
searchEdges(e) {
|
|
3295
|
-
var
|
|
3298
|
+
var o;
|
|
3296
3299
|
if (!e || e.trim() === "")
|
|
3297
3300
|
return [];
|
|
3298
|
-
const s = e.toLowerCase().trim(), t = this.edgeManager.getAllEdges(),
|
|
3301
|
+
const s = e.toLowerCase().trim(), t = this.edgeManager.getAllEdges(), i = [];
|
|
3299
3302
|
for (const a of t)
|
|
3300
|
-
if ((
|
|
3303
|
+
if ((o = a.relationship) == null ? void 0 : o.toLowerCase().includes(s)) {
|
|
3301
3304
|
const c = this.nodeManager.getNode(a.source), d = this.nodeManager.getNode(a.target);
|
|
3302
|
-
c && d &&
|
|
3305
|
+
c && d && i.push({ edge: a, sourceNode: c, targetNode: d });
|
|
3303
3306
|
}
|
|
3304
|
-
return
|
|
3307
|
+
return i;
|
|
3305
3308
|
}
|
|
3306
3309
|
/**
|
|
3307
3310
|
* Gets all nodes as an array
|
|
@@ -3343,11 +3346,11 @@ class Ft {
|
|
|
3343
3346
|
},
|
|
3344
3347
|
onEdgeHover: (s, t) => {
|
|
3345
3348
|
if (s && t) {
|
|
3346
|
-
const
|
|
3347
|
-
|
|
3349
|
+
const i = this.nodeManager.getNode(s.source), o = this.nodeManager.getNode(s.target);
|
|
3350
|
+
i && o && this.edgeTooltipManager.show(
|
|
3348
3351
|
s,
|
|
3349
|
-
o,
|
|
3350
3352
|
i,
|
|
3353
|
+
o,
|
|
3351
3354
|
t.clientX,
|
|
3352
3355
|
t.clientY
|
|
3353
3356
|
);
|
|
@@ -3355,8 +3358,8 @@ class Ft {
|
|
|
3355
3358
|
this.edgeTooltipManager.hide();
|
|
3356
3359
|
},
|
|
3357
3360
|
onEdgeClick: (s) => {
|
|
3358
|
-
const t = this.nodeManager.getNode(s.source),
|
|
3359
|
-
t &&
|
|
3361
|
+
const t = this.nodeManager.getNode(s.source), i = this.nodeManager.getNode(s.target);
|
|
3362
|
+
t && i && this.edgePanelManager.show(s, t, i);
|
|
3360
3363
|
}
|
|
3361
3364
|
}), this.graphData && (this.forceGraph2D.setData(this.graphData), this.forceGraph2D.syncFrom3D(this.nodeManager.getAllNodes())))) : (this.forceGraph2D && this.forceGraph2D.hide(), this.sceneManager.renderer.domElement.style.display = "block", this.rendererManager.start()), this.emit("viewChange", e));
|
|
3362
3365
|
}
|
|
@@ -3371,7 +3374,7 @@ class Ft {
|
|
|
3371
3374
|
*/
|
|
3372
3375
|
emit(e, ...s) {
|
|
3373
3376
|
const t = this.eventCallbacks.get(e);
|
|
3374
|
-
t && t.forEach((
|
|
3377
|
+
t && t.forEach((i) => i(...s));
|
|
3375
3378
|
}
|
|
3376
3379
|
/**
|
|
3377
3380
|
* Sets physics parameters for both 3D and 2D views
|
|
@@ -3448,17 +3451,17 @@ class Ft {
|
|
|
3448
3451
|
`, this.container.appendChild(this.devControls);
|
|
3449
3452
|
const e = this.devControls.querySelector("#dev-repulsion"), s = this.devControls.querySelector("#dev-attraction"), t = this.devControls.querySelector("#dev-damping");
|
|
3450
3453
|
e == null || e.addEventListener("input", () => {
|
|
3451
|
-
const
|
|
3452
|
-
this.setPhysicsParams({ repulsionStrength:
|
|
3454
|
+
const i = parseFloat(e.value);
|
|
3455
|
+
this.setPhysicsParams({ repulsionStrength: i }), this.devControls.querySelector("#dev-repulsion-val").textContent = i.toString();
|
|
3453
3456
|
}), s == null || s.addEventListener("input", () => {
|
|
3454
|
-
const
|
|
3455
|
-
this.setPhysicsParams({ attractionStrength:
|
|
3457
|
+
const i = parseFloat(s.value) / 1e3;
|
|
3458
|
+
this.setPhysicsParams({ attractionStrength: i }), this.devControls.querySelector("#dev-attraction-val").textContent = i.toFixed(3);
|
|
3456
3459
|
}), t == null || t.addEventListener("input", () => {
|
|
3457
|
-
const
|
|
3458
|
-
this.setPhysicsParams({ damping:
|
|
3460
|
+
const i = parseFloat(t.value) / 100;
|
|
3461
|
+
this.setPhysicsParams({ damping: i }), this.devControls.querySelector("#dev-damping-val").textContent = i.toFixed(2);
|
|
3459
3462
|
}), setInterval(() => {
|
|
3460
|
-
const
|
|
3461
|
-
|
|
3463
|
+
const i = this.devControls.querySelector("#dev-node-count"), o = this.devControls.querySelector("#dev-edge-count"), a = this.devControls.querySelector("#dev-fps");
|
|
3464
|
+
i && (i.textContent = this.getNodeCount().toString()), o && (o.textContent = this.getEdgeCount().toString()), a && (a.textContent = this.rendererManager.getFPS().toString());
|
|
3462
3465
|
}, 500);
|
|
3463
3466
|
}
|
|
3464
3467
|
/**
|
|
@@ -3524,12 +3527,12 @@ const Ie = [
|
|
|
3524
3527
|
];
|
|
3525
3528
|
function Ht(h = 30) {
|
|
3526
3529
|
const e = [], s = [];
|
|
3527
|
-
for (let
|
|
3528
|
-
const
|
|
3530
|
+
for (let i = 0; i < h; i++) {
|
|
3531
|
+
const o = i < Ie.length ? Ie[i] : `Node ${i + 1}`;
|
|
3529
3532
|
e.push({
|
|
3530
|
-
id: `node-${
|
|
3531
|
-
label:
|
|
3532
|
-
color: Re[
|
|
3533
|
+
id: `node-${i}`,
|
|
3534
|
+
label: o,
|
|
3535
|
+
color: Re[i % Re.length],
|
|
3533
3536
|
position: {
|
|
3534
3537
|
x: (Math.random() - 0.5) * 60,
|
|
3535
3538
|
y: (Math.random() - 0.5) * 60,
|
|
@@ -3537,22 +3540,22 @@ function Ht(h = 30) {
|
|
|
3537
3540
|
}
|
|
3538
3541
|
});
|
|
3539
3542
|
}
|
|
3540
|
-
for (let
|
|
3541
|
-
const
|
|
3543
|
+
for (let i = 1; i < h; i++) {
|
|
3544
|
+
const o = Math.floor(Math.random() * i);
|
|
3542
3545
|
s.push({
|
|
3543
|
-
source: `node-${
|
|
3544
|
-
target: `node-${
|
|
3546
|
+
source: `node-${i}`,
|
|
3547
|
+
target: `node-${o}`,
|
|
3545
3548
|
relationship: J[Math.floor(Math.random() * J.length)]
|
|
3546
3549
|
});
|
|
3547
3550
|
}
|
|
3548
3551
|
const t = Math.floor(h * 0.5);
|
|
3549
|
-
for (let
|
|
3550
|
-
const
|
|
3552
|
+
for (let i = 0; i < t; i++) {
|
|
3553
|
+
const o = Math.floor(Math.random() * h);
|
|
3551
3554
|
let a = Math.floor(Math.random() * h);
|
|
3552
|
-
|
|
3553
|
-
const r = `node-${
|
|
3555
|
+
o === a && (a = (a + 1) % h);
|
|
3556
|
+
const r = `node-${o}`, c = `node-${a}`;
|
|
3554
3557
|
s.some(
|
|
3555
|
-
(
|
|
3558
|
+
(p) => p.source === r && p.target === c || p.source === c && p.target === r
|
|
3556
3559
|
) || s.push({
|
|
3557
3560
|
source: r,
|
|
3558
3561
|
target: c,
|
|
@@ -3562,18 +3565,18 @@ function Ht(h = 30) {
|
|
|
3562
3565
|
return { nodes: e, edges: s };
|
|
3563
3566
|
}
|
|
3564
3567
|
function Dt(h = 1e3) {
|
|
3565
|
-
const e = [], s = [], t = Math.ceil(h / 50),
|
|
3566
|
-
for (let
|
|
3567
|
-
|
|
3568
|
+
const e = [], s = [], t = Math.ceil(h / 50), i = [];
|
|
3569
|
+
for (let o = 0; o < t; o++)
|
|
3570
|
+
i.push({
|
|
3568
3571
|
x: (Math.random() - 0.5) * 200,
|
|
3569
3572
|
y: (Math.random() - 0.5) * 200,
|
|
3570
3573
|
z: (Math.random() - 0.5) * 200
|
|
3571
3574
|
});
|
|
3572
|
-
for (let
|
|
3573
|
-
const a = o
|
|
3575
|
+
for (let o = 0; o < h; o++) {
|
|
3576
|
+
const a = i[o % t];
|
|
3574
3577
|
e.push({
|
|
3575
|
-
id: `node-${
|
|
3576
|
-
label: `N${
|
|
3578
|
+
id: `node-${o}`,
|
|
3579
|
+
label: `N${o}`,
|
|
3577
3580
|
position: {
|
|
3578
3581
|
x: a.x + (Math.random() - 0.5) * 40,
|
|
3579
3582
|
y: a.y + (Math.random() - 0.5) * 40,
|
|
@@ -3581,16 +3584,16 @@ function Dt(h = 1e3) {
|
|
|
3581
3584
|
}
|
|
3582
3585
|
});
|
|
3583
3586
|
}
|
|
3584
|
-
for (let
|
|
3585
|
-
const a = Math.floor(
|
|
3587
|
+
for (let o = 1; o < h; o++) {
|
|
3588
|
+
const a = Math.floor(o / 50) * 50, r = a === 0 ? Math.floor(Math.random() * o) : a + Math.floor(Math.random() * Math.min(o - a, 50));
|
|
3586
3589
|
s.push({
|
|
3587
|
-
source: `node-${
|
|
3588
|
-
target: `node-${Math.min(r,
|
|
3590
|
+
source: `node-${o}`,
|
|
3591
|
+
target: `node-${Math.min(r, o - 1)}`,
|
|
3589
3592
|
relationship: "links to"
|
|
3590
3593
|
});
|
|
3591
3594
|
}
|
|
3592
|
-
for (let
|
|
3593
|
-
const a =
|
|
3595
|
+
for (let o = 1; o < t; o++) {
|
|
3596
|
+
const a = o * 50, r = (o - 1) * 50 + Math.floor(Math.random() * 50);
|
|
3594
3597
|
s.push({
|
|
3595
3598
|
source: `node-${a}`,
|
|
3596
3599
|
target: `node-${r}`,
|
|
@@ -3600,7 +3603,7 @@ function Dt(h = 1e3) {
|
|
|
3600
3603
|
return { nodes: e, edges: s };
|
|
3601
3604
|
}
|
|
3602
3605
|
export {
|
|
3603
|
-
|
|
3606
|
+
T as DEFAULT_OPTIONS,
|
|
3604
3607
|
Ft as ForceGraph3D,
|
|
3605
3608
|
U as LODLevel,
|
|
3606
3609
|
D as createEdgeKey,
|