force-3d-graph 1.3.6 → 1.3.8
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 +784 -653
- package/dist/force-3d-graph.js.map +1 -1
- package/dist/force-3d-graph.umd.cjs +144 -111
- package/dist/force-3d-graph.umd.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/force-3d-graph.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var l = (
|
|
4
|
-
import * as
|
|
5
|
-
import { EventDispatcher as
|
|
1
|
+
var it = Object.defineProperty;
|
|
2
|
+
var ot = (d, e, s) => e in d ? it(d, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : d[e] = s;
|
|
3
|
+
var l = (d, e, s) => ot(d, typeof e != "symbol" ? e + "" : e, s);
|
|
4
|
+
import * as x from "three";
|
|
5
|
+
import { EventDispatcher as nt, Vector3 as S, MOUSE as j, TOUCH as $, Spherical as Se, Quaternion as ze, Vector2 as k, Ray as at, Plane as rt, MathUtils as lt } from "three";
|
|
6
6
|
const P = {
|
|
7
7
|
backgroundColor: 657930,
|
|
8
8
|
cameraPosition: { x: 0, y: 0, z: 80 },
|
|
@@ -32,96 +32,96 @@ const P = {
|
|
|
32
32
|
targetFPS: 60,
|
|
33
33
|
maxVisibleNodes: 1e4
|
|
34
34
|
};
|
|
35
|
-
var
|
|
36
|
-
function
|
|
37
|
-
const
|
|
38
|
-
return
|
|
35
|
+
var _ = /* @__PURE__ */ ((d) => (d[d.HIGH = 0] = "HIGH", d[d.MEDIUM = 1] = "MEDIUM", d[d.LOW = 2] = "LOW", d))(_ || {});
|
|
36
|
+
function ct() {
|
|
37
|
+
const d = document.createElement("div");
|
|
38
|
+
return d.id = "force-graph-3d-container", d.style.cssText = `
|
|
39
39
|
width: 100%;
|
|
40
40
|
height: 100%;
|
|
41
41
|
position: absolute;
|
|
42
42
|
top: 0;
|
|
43
43
|
left: 0;
|
|
44
44
|
overflow: hidden;
|
|
45
|
-
`, document.body.appendChild(
|
|
45
|
+
`, document.body.appendChild(d), d;
|
|
46
46
|
}
|
|
47
|
-
function ht(
|
|
48
|
-
return
|
|
47
|
+
function ht(d) {
|
|
48
|
+
return d && d instanceof HTMLElement ? d : (console.warn("[ForceGraph3D] No container provided, creating one automatically"), ct());
|
|
49
49
|
}
|
|
50
|
-
function
|
|
51
|
-
const e =
|
|
50
|
+
function ke(d) {
|
|
51
|
+
const e = d.getBoundingClientRect();
|
|
52
52
|
return {
|
|
53
53
|
width: e.width || window.innerWidth,
|
|
54
54
|
height: e.height || window.innerHeight
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
|
-
function
|
|
58
|
-
if (!
|
|
57
|
+
function Fe(d) {
|
|
58
|
+
if (!d || typeof d != "object")
|
|
59
59
|
return console.warn("[ForceGraph3D] Invalid node: must be an object"), !1;
|
|
60
|
-
const e =
|
|
61
|
-
return typeof e.id != "string" || e.id.trim() === "" ? (console.warn("[ForceGraph3D] Invalid node: id must be a non-empty string"), !1) : typeof e.label != "string" ? (console.warn("[ForceGraph3D] Invalid node: label must be a string"), !1) : e.color !== void 0 && typeof e.color != "number" ? (console.warn("[ForceGraph3D] Invalid node: color must be a number (hex)"), !1) : e.position !== void 0 && !
|
|
60
|
+
const e = d;
|
|
61
|
+
return typeof e.id != "string" || e.id.trim() === "" ? (console.warn("[ForceGraph3D] Invalid node: id must be a non-empty string"), !1) : typeof e.label != "string" ? (console.warn("[ForceGraph3D] Invalid node: label must be a string"), !1) : e.color !== void 0 && typeof e.color != "number" ? (console.warn("[ForceGraph3D] Invalid node: color must be a number (hex)"), !1) : e.position !== void 0 && !pt(e.position) ? (console.warn("[ForceGraph3D] Invalid node: position must have x, y, z numbers"), !1) : !0;
|
|
62
62
|
}
|
|
63
|
-
function
|
|
64
|
-
if (!
|
|
63
|
+
function De(d) {
|
|
64
|
+
if (!d || typeof d != "object")
|
|
65
65
|
return console.warn("[ForceGraph3D] Invalid edge: must be an object"), !1;
|
|
66
|
-
const e =
|
|
66
|
+
const e = d;
|
|
67
67
|
return typeof e.source != "string" || e.source.trim() === "" ? (console.warn("[ForceGraph3D] Invalid edge: source must be a non-empty string"), !1) : typeof e.target != "string" || e.target.trim() === "" ? (console.warn("[ForceGraph3D] Invalid edge: target must be a non-empty string"), !1) : !0;
|
|
68
68
|
}
|
|
69
|
-
function
|
|
70
|
-
return typeof
|
|
69
|
+
function dt(d) {
|
|
70
|
+
return typeof d != "string" || d.trim() === "" ? (console.warn("[ForceGraph3D] Invalid node ID: must be a non-empty string"), !1) : !0;
|
|
71
71
|
}
|
|
72
|
-
function
|
|
73
|
-
if (!
|
|
74
|
-
const e =
|
|
72
|
+
function pt(d) {
|
|
73
|
+
if (!d || typeof d != "object") return !1;
|
|
74
|
+
const e = d;
|
|
75
75
|
return typeof e.x == "number" && typeof e.y == "number" && typeof e.z == "number";
|
|
76
76
|
}
|
|
77
|
-
function
|
|
78
|
-
return
|
|
77
|
+
function Dt(d, e) {
|
|
78
|
+
return d === e ? `${d}-${e}` : d < e ? `${d}-${e}` : `${e}-${d}`;
|
|
79
79
|
}
|
|
80
|
-
const
|
|
81
|
-
class
|
|
80
|
+
const Te = { type: "change" }, le = { type: "start" }, Pe = { type: "end" }, Q = new at(), Re = new rt(), gt = Math.cos(70 * lt.DEG2RAD);
|
|
81
|
+
class ut extends nt {
|
|
82
82
|
constructor(e, s) {
|
|
83
|
-
super(), this.object = e, this.domElement = s, this.domElement.style.touchAction = "none", this.enabled = !0, this.target = new S(), this.cursor = new S(), this.minDistance = 0, this.maxDistance = 1 / 0, this.minZoom = 0, this.maxZoom = 1 / 0, this.minTargetRadius = 0, this.maxTargetRadius = 1 / 0, this.minPolarAngle = 0, this.maxPolarAngle = Math.PI, this.minAzimuthAngle = -1 / 0, this.maxAzimuthAngle = 1 / 0, this.enableDamping = !1, this.dampingFactor = 0.05, this.enableZoom = !0, this.zoomSpeed = 1, this.enableRotate = !0, this.rotateSpeed = 1, this.enablePan = !0, this.panSpeed = 1, this.screenSpacePanning = !0, this.keyPanSpeed = 7, this.zoomToCursor = !1, this.autoRotate = !1, this.autoRotateSpeed = 2, this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" }, this.mouseButtons = { LEFT:
|
|
83
|
+
super(), this.object = e, this.domElement = s, this.domElement.style.touchAction = "none", this.enabled = !0, this.target = new S(), this.cursor = new S(), this.minDistance = 0, this.maxDistance = 1 / 0, this.minZoom = 0, this.maxZoom = 1 / 0, this.minTargetRadius = 0, this.maxTargetRadius = 1 / 0, this.minPolarAngle = 0, this.maxPolarAngle = Math.PI, this.minAzimuthAngle = -1 / 0, this.maxAzimuthAngle = 1 / 0, this.enableDamping = !1, this.dampingFactor = 0.05, this.enableZoom = !0, this.zoomSpeed = 1, this.enableRotate = !0, this.rotateSpeed = 1, this.enablePan = !0, this.panSpeed = 1, this.screenSpacePanning = !0, this.keyPanSpeed = 7, this.zoomToCursor = !1, this.autoRotate = !1, this.autoRotateSpeed = 2, this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" }, this.mouseButtons = { LEFT: j.ROTATE, MIDDLE: j.DOLLY, RIGHT: j.PAN }, this.touches = { ONE: $.ROTATE, TWO: $.DOLLY_PAN }, this.target0 = this.target.clone(), this.position0 = this.object.position.clone(), this.zoom0 = this.object.zoom, this._domElementKeyEvents = null, this.getPolarAngle = function() {
|
|
84
84
|
return r.phi;
|
|
85
85
|
}, this.getAzimuthalAngle = function() {
|
|
86
86
|
return r.theta;
|
|
87
87
|
}, this.getDistance = function() {
|
|
88
88
|
return this.object.position.distanceTo(this.target);
|
|
89
|
-
}, this.listenToKeyEvents = function(
|
|
90
|
-
|
|
89
|
+
}, this.listenToKeyEvents = function(a) {
|
|
90
|
+
a.addEventListener("keydown", ae), this._domElementKeyEvents = a;
|
|
91
91
|
}, this.stopListenToKeyEvents = function() {
|
|
92
|
-
this._domElementKeyEvents.removeEventListener("keydown",
|
|
92
|
+
this._domElementKeyEvents.removeEventListener("keydown", ae), this._domElementKeyEvents = null;
|
|
93
93
|
}, this.saveState = function() {
|
|
94
94
|
t.target0.copy(t.target), t.position0.copy(t.object.position), t.zoom0 = t.object.zoom;
|
|
95
95
|
}, this.reset = function() {
|
|
96
|
-
t.target.copy(t.target0), t.object.position.copy(t.position0), t.object.zoom = t.zoom0, t.object.updateProjectionMatrix(), t.dispatchEvent(
|
|
96
|
+
t.target.copy(t.target0), t.object.position.copy(t.position0), t.object.zoom = t.zoom0, t.object.updateProjectionMatrix(), t.dispatchEvent(Te), t.update(), o = i.NONE;
|
|
97
97
|
}, this.update = function() {
|
|
98
|
-
const
|
|
99
|
-
return function(
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
let
|
|
103
|
-
isFinite(
|
|
104
|
-
let
|
|
98
|
+
const a = new S(), g = new ze().setFromUnitVectors(e.up, new S(0, 1, 0)), v = g.clone().invert(), M = new S(), C = new ze(), F = new S(), z = 2 * Math.PI;
|
|
99
|
+
return function(st = null) {
|
|
100
|
+
const Ne = t.object.position;
|
|
101
|
+
a.copy(Ne).sub(t.target), a.applyQuaternion(g), r.setFromVector3(a), t.autoRotate && o === i.NONE && Y(He(st)), t.enableDamping ? (r.theta += h.theta * t.dampingFactor, r.phi += h.phi * t.dampingFactor) : (r.theta += h.theta, r.phi += h.phi);
|
|
102
|
+
let L = t.minAzimuthAngle, I = t.maxAzimuthAngle;
|
|
103
|
+
isFinite(L) && isFinite(I) && (L < -Math.PI ? L += z : L > Math.PI && (L -= z), I < -Math.PI ? I += z : I > Math.PI && (I -= z), L <= I ? r.theta = Math.max(L, Math.min(I, r.theta)) : r.theta = r.theta > (L + I) / 2 ? Math.max(L, r.theta) : Math.min(I, 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 && D || t.object.isOrthographicCamera ? r.radius = oe(r.radius) : r.radius = oe(r.radius * c), a.setFromSpherical(r), a.applyQuaternion(v), Ne.copy(t.target).add(a), t.object.lookAt(t.target), t.enableDamping === !0 ? (h.theta *= 1 - t.dampingFactor, h.phi *= 1 - t.dampingFactor, p.multiplyScalar(1 - t.dampingFactor)) : (h.set(0, 0, 0), p.set(0, 0, 0));
|
|
104
|
+
let re = !1;
|
|
105
105
|
if (t.zoomToCursor && D) {
|
|
106
|
-
let
|
|
106
|
+
let K = null;
|
|
107
107
|
if (t.object.isPerspectiveCamera) {
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
t.object.position.addScaledVector(
|
|
108
|
+
const U = a.length();
|
|
109
|
+
K = oe(U * c);
|
|
110
|
+
const Z = U - K;
|
|
111
|
+
t.object.position.addScaledVector(G, Z), t.object.updateMatrixWorld();
|
|
112
112
|
} else if (t.object.isOrthographicCamera) {
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
|
|
113
|
+
const U = new S(T.x, T.y, 0);
|
|
114
|
+
U.unproject(t.object), t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom / c)), t.object.updateProjectionMatrix(), re = !0;
|
|
115
|
+
const Z = new S(T.x, T.y, 0);
|
|
116
|
+
Z.unproject(t.object), t.object.position.sub(Z).add(U), t.object.updateMatrixWorld(), K = a.length();
|
|
117
117
|
} else
|
|
118
118
|
console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."), t.zoomToCursor = !1;
|
|
119
|
-
|
|
120
|
-
} else t.object.isOrthographicCamera && (t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom /
|
|
121
|
-
return
|
|
119
|
+
K !== null && (this.screenSpacePanning ? t.target.set(0, 0, -1).transformDirection(t.object.matrix).multiplyScalar(K).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)) < gt ? e.lookAt(t.target) : (Re.setFromNormalAndCoplanarPoint(t.object.up, t.target), Q.intersectPlane(Re, t.target))));
|
|
120
|
+
} else t.object.isOrthographicCamera && (t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom / c)), t.object.updateProjectionMatrix(), re = !0);
|
|
121
|
+
return c = 1, D = !1, re || M.distanceToSquared(t.object.position) > n || 8 * (1 - C.dot(t.object.quaternion)) > n || F.distanceToSquared(t.target) > 0 ? (t.dispatchEvent(Te), M.copy(t.object.position), C.copy(t.object.quaternion), F.copy(t.target), !0) : !1;
|
|
122
122
|
};
|
|
123
123
|
}(), this.dispose = function() {
|
|
124
|
-
t.domElement.removeEventListener("contextmenu",
|
|
124
|
+
t.domElement.removeEventListener("contextmenu", Ee), t.domElement.removeEventListener("pointerdown", ve), t.domElement.removeEventListener("pointercancel", B), t.domElement.removeEventListener("wheel", we), t.domElement.removeEventListener("pointermove", ne), t.domElement.removeEventListener("pointerup", B), t._domElementKeyEvents !== null && (t._domElementKeyEvents.removeEventListener("keydown", ae), t._domElementKeyEvents = null);
|
|
125
125
|
};
|
|
126
126
|
const t = this, i = {
|
|
127
127
|
NONE: -1,
|
|
@@ -134,174 +134,174 @@ class ft extends at {
|
|
|
134
134
|
TOUCH_DOLLY_ROTATE: 6
|
|
135
135
|
};
|
|
136
136
|
let o = i.NONE;
|
|
137
|
-
const
|
|
138
|
-
let
|
|
139
|
-
const p = new S(),
|
|
137
|
+
const n = 1e-6, r = new Se(), h = new Se();
|
|
138
|
+
let c = 1;
|
|
139
|
+
const p = new S(), f = new k(), m = new k(), u = new k(), y = new k(), b = new k(), w = new k(), N = new k(), O = new k(), R = new k(), G = new S(), T = new k();
|
|
140
140
|
let D = !1;
|
|
141
|
-
const E = [],
|
|
142
|
-
let
|
|
143
|
-
function
|
|
144
|
-
return
|
|
141
|
+
const E = [], V = {};
|
|
142
|
+
let te = !1;
|
|
143
|
+
function He(a) {
|
|
144
|
+
return a !== null ? 2 * Math.PI / 60 * t.autoRotateSpeed * a : 2 * Math.PI / 60 / 60 * t.autoRotateSpeed;
|
|
145
145
|
}
|
|
146
|
-
function
|
|
147
|
-
const g = Math.abs(
|
|
146
|
+
function q(a) {
|
|
147
|
+
const g = Math.abs(a * 0.01);
|
|
148
148
|
return Math.pow(0.95, t.zoomSpeed * g);
|
|
149
149
|
}
|
|
150
|
-
function
|
|
151
|
-
|
|
150
|
+
function Y(a) {
|
|
151
|
+
h.theta -= a;
|
|
152
152
|
}
|
|
153
|
-
function
|
|
154
|
-
|
|
153
|
+
function W(a) {
|
|
154
|
+
h.phi -= a;
|
|
155
155
|
}
|
|
156
|
-
const
|
|
157
|
-
const
|
|
158
|
-
return function(v,
|
|
159
|
-
|
|
156
|
+
const ce = function() {
|
|
157
|
+
const a = new S();
|
|
158
|
+
return function(v, M) {
|
|
159
|
+
a.setFromMatrixColumn(M, 0), a.multiplyScalar(-v), p.add(a);
|
|
160
160
|
};
|
|
161
161
|
}(), he = function() {
|
|
162
|
-
const
|
|
163
|
-
return function(v,
|
|
164
|
-
t.screenSpacePanning === !0 ?
|
|
162
|
+
const a = new S();
|
|
163
|
+
return function(v, M) {
|
|
164
|
+
t.screenSpacePanning === !0 ? a.setFromMatrixColumn(M, 1) : (a.setFromMatrixColumn(M, 0), a.crossVectors(t.object.up, a)), a.multiplyScalar(v), p.add(a);
|
|
165
165
|
};
|
|
166
|
-
}(),
|
|
167
|
-
const
|
|
168
|
-
return function(v,
|
|
166
|
+
}(), H = function() {
|
|
167
|
+
const a = new S();
|
|
168
|
+
return function(v, M) {
|
|
169
169
|
const C = t.domElement;
|
|
170
170
|
if (t.object.isPerspectiveCamera) {
|
|
171
171
|
const F = t.object.position;
|
|
172
|
-
|
|
173
|
-
let z =
|
|
174
|
-
z *= Math.tan(t.object.fov / 2 * Math.PI / 180),
|
|
175
|
-
} else t.object.isOrthographicCamera ? (
|
|
172
|
+
a.copy(F).sub(t.target);
|
|
173
|
+
let z = a.length();
|
|
174
|
+
z *= Math.tan(t.object.fov / 2 * Math.PI / 180), ce(2 * v * z / C.clientHeight, t.object.matrix), he(2 * M * z / C.clientHeight, t.object.matrix);
|
|
175
|
+
} else t.object.isOrthographicCamera ? (ce(v * (t.object.right - t.object.left) / t.object.zoom / C.clientWidth, t.object.matrix), he(M * (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);
|
|
176
176
|
};
|
|
177
177
|
}();
|
|
178
|
-
function
|
|
179
|
-
t.object.isPerspectiveCamera || t.object.isOrthographicCamera ?
|
|
178
|
+
function se(a) {
|
|
179
|
+
t.object.isPerspectiveCamera || t.object.isOrthographicCamera ? c /= a : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), t.enableZoom = !1);
|
|
180
180
|
}
|
|
181
|
-
function
|
|
182
|
-
t.object.isPerspectiveCamera || t.object.isOrthographicCamera ?
|
|
181
|
+
function de(a) {
|
|
182
|
+
t.object.isPerspectiveCamera || t.object.isOrthographicCamera ? c *= a : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), t.enableZoom = !1);
|
|
183
183
|
}
|
|
184
|
-
function
|
|
184
|
+
function ie(a, g) {
|
|
185
185
|
if (!t.zoomToCursor)
|
|
186
186
|
return;
|
|
187
187
|
D = !0;
|
|
188
|
-
const v = t.domElement.getBoundingClientRect(),
|
|
189
|
-
T.x =
|
|
188
|
+
const v = t.domElement.getBoundingClientRect(), M = a - v.left, C = g - v.top, F = v.width, z = v.height;
|
|
189
|
+
T.x = M / F * 2 - 1, T.y = -(C / z) * 2 + 1, G.set(T.x, T.y, 1).unproject(t.object).sub(t.object.position).normalize();
|
|
190
190
|
}
|
|
191
|
-
function
|
|
192
|
-
return Math.max(t.minDistance, Math.min(t.maxDistance,
|
|
191
|
+
function oe(a) {
|
|
192
|
+
return Math.max(t.minDistance, Math.min(t.maxDistance, a));
|
|
193
193
|
}
|
|
194
|
-
function
|
|
195
|
-
|
|
194
|
+
function pe(a) {
|
|
195
|
+
f.set(a.clientX, a.clientY);
|
|
196
196
|
}
|
|
197
|
-
function
|
|
198
|
-
|
|
197
|
+
function Ae(a) {
|
|
198
|
+
ie(a.clientX, a.clientX), N.set(a.clientX, a.clientY);
|
|
199
199
|
}
|
|
200
|
-
function
|
|
201
|
-
|
|
200
|
+
function ge(a) {
|
|
201
|
+
y.set(a.clientX, a.clientY);
|
|
202
202
|
}
|
|
203
|
-
function
|
|
204
|
-
m.set(
|
|
203
|
+
function je(a) {
|
|
204
|
+
m.set(a.clientX, a.clientY), u.subVectors(m, f).multiplyScalar(t.rotateSpeed);
|
|
205
205
|
const g = t.domElement;
|
|
206
|
-
|
|
206
|
+
Y(2 * Math.PI * u.x / g.clientHeight), W(2 * Math.PI * u.y / g.clientHeight), f.copy(m), t.update();
|
|
207
207
|
}
|
|
208
|
-
function
|
|
209
|
-
O.set(
|
|
208
|
+
function $e(a) {
|
|
209
|
+
O.set(a.clientX, a.clientY), R.subVectors(O, N), R.y > 0 ? se(q(R.y)) : R.y < 0 && de(q(R.y)), N.copy(O), t.update();
|
|
210
210
|
}
|
|
211
|
-
function
|
|
212
|
-
b.set(
|
|
211
|
+
function Ge(a) {
|
|
212
|
+
b.set(a.clientX, a.clientY), w.subVectors(b, y).multiplyScalar(t.panSpeed), H(w.x, w.y), y.copy(b), t.update();
|
|
213
213
|
}
|
|
214
|
-
function
|
|
215
|
-
|
|
214
|
+
function Ye(a) {
|
|
215
|
+
ie(a.clientX, a.clientY), a.deltaY < 0 ? de(q(a.deltaY)) : a.deltaY > 0 && se(q(a.deltaY)), t.update();
|
|
216
216
|
}
|
|
217
|
-
function
|
|
217
|
+
function Be(a) {
|
|
218
218
|
let g = !1;
|
|
219
|
-
switch (
|
|
219
|
+
switch (a.code) {
|
|
220
220
|
case t.keys.UP:
|
|
221
|
-
|
|
221
|
+
a.ctrlKey || a.metaKey || a.shiftKey ? W(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : H(0, t.keyPanSpeed), g = !0;
|
|
222
222
|
break;
|
|
223
223
|
case t.keys.BOTTOM:
|
|
224
|
-
|
|
224
|
+
a.ctrlKey || a.metaKey || a.shiftKey ? W(-2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : H(0, -t.keyPanSpeed), g = !0;
|
|
225
225
|
break;
|
|
226
226
|
case t.keys.LEFT:
|
|
227
|
-
|
|
227
|
+
a.ctrlKey || a.metaKey || a.shiftKey ? Y(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : H(t.keyPanSpeed, 0), g = !0;
|
|
228
228
|
break;
|
|
229
229
|
case t.keys.RIGHT:
|
|
230
|
-
|
|
230
|
+
a.ctrlKey || a.metaKey || a.shiftKey ? Y(-2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : H(-t.keyPanSpeed, 0), g = !0;
|
|
231
231
|
break;
|
|
232
232
|
}
|
|
233
|
-
g && (
|
|
233
|
+
g && (a.preventDefault(), t.update());
|
|
234
234
|
}
|
|
235
|
-
function
|
|
235
|
+
function ue(a) {
|
|
236
236
|
if (E.length === 1)
|
|
237
|
-
|
|
237
|
+
f.set(a.pageX, a.pageY);
|
|
238
238
|
else {
|
|
239
|
-
const g =
|
|
240
|
-
|
|
239
|
+
const g = A(a), v = 0.5 * (a.pageX + g.x), M = 0.5 * (a.pageY + g.y);
|
|
240
|
+
f.set(v, M);
|
|
241
241
|
}
|
|
242
242
|
}
|
|
243
|
-
function
|
|
243
|
+
function fe(a) {
|
|
244
244
|
if (E.length === 1)
|
|
245
|
-
|
|
245
|
+
y.set(a.pageX, a.pageY);
|
|
246
246
|
else {
|
|
247
|
-
const g =
|
|
248
|
-
|
|
247
|
+
const g = A(a), v = 0.5 * (a.pageX + g.x), M = 0.5 * (a.pageY + g.y);
|
|
248
|
+
y.set(v, M);
|
|
249
249
|
}
|
|
250
250
|
}
|
|
251
|
-
function
|
|
252
|
-
const g =
|
|
251
|
+
function me(a) {
|
|
252
|
+
const g = A(a), v = a.pageX - g.x, M = a.pageY - g.y, C = Math.sqrt(v * v + M * M);
|
|
253
253
|
N.set(0, C);
|
|
254
254
|
}
|
|
255
|
-
function
|
|
256
|
-
t.enableZoom &&
|
|
255
|
+
function Ke(a) {
|
|
256
|
+
t.enableZoom && me(a), t.enablePan && fe(a);
|
|
257
257
|
}
|
|
258
|
-
function
|
|
259
|
-
t.enableZoom &&
|
|
258
|
+
function Ue(a) {
|
|
259
|
+
t.enableZoom && me(a), t.enableRotate && ue(a);
|
|
260
260
|
}
|
|
261
|
-
function
|
|
261
|
+
function ye(a) {
|
|
262
262
|
if (E.length == 1)
|
|
263
|
-
m.set(
|
|
263
|
+
m.set(a.pageX, a.pageY);
|
|
264
264
|
else {
|
|
265
|
-
const v =
|
|
266
|
-
m.set(
|
|
265
|
+
const v = A(a), M = 0.5 * (a.pageX + v.x), C = 0.5 * (a.pageY + v.y);
|
|
266
|
+
m.set(M, C);
|
|
267
267
|
}
|
|
268
|
-
u.subVectors(m,
|
|
268
|
+
u.subVectors(m, f).multiplyScalar(t.rotateSpeed);
|
|
269
269
|
const g = t.domElement;
|
|
270
|
-
|
|
270
|
+
Y(2 * Math.PI * u.x / g.clientHeight), W(2 * Math.PI * u.y / g.clientHeight), f.copy(m);
|
|
271
271
|
}
|
|
272
|
-
function
|
|
272
|
+
function xe(a) {
|
|
273
273
|
if (E.length === 1)
|
|
274
|
-
b.set(
|
|
274
|
+
b.set(a.pageX, a.pageY);
|
|
275
275
|
else {
|
|
276
|
-
const g =
|
|
277
|
-
b.set(v,
|
|
276
|
+
const g = A(a), v = 0.5 * (a.pageX + g.x), M = 0.5 * (a.pageY + g.y);
|
|
277
|
+
b.set(v, M);
|
|
278
278
|
}
|
|
279
|
-
|
|
279
|
+
w.subVectors(b, y).multiplyScalar(t.panSpeed), H(w.x, w.y), y.copy(b);
|
|
280
280
|
}
|
|
281
|
-
function
|
|
282
|
-
const g =
|
|
283
|
-
O.set(0, C),
|
|
284
|
-
const F = (
|
|
285
|
-
|
|
281
|
+
function be(a) {
|
|
282
|
+
const g = A(a), v = a.pageX - g.x, M = a.pageY - g.y, C = Math.sqrt(v * v + M * M);
|
|
283
|
+
O.set(0, C), R.set(0, Math.pow(O.y / N.y, t.zoomSpeed)), se(R.y), N.copy(O);
|
|
284
|
+
const F = (a.pageX + g.x) * 0.5, z = (a.pageY + g.y) * 0.5;
|
|
285
|
+
ie(F, z);
|
|
286
286
|
}
|
|
287
|
-
function
|
|
288
|
-
t.enableZoom &&
|
|
287
|
+
function _e(a) {
|
|
288
|
+
t.enableZoom && be(a), t.enablePan && xe(a);
|
|
289
289
|
}
|
|
290
|
-
function
|
|
291
|
-
t.enableZoom &&
|
|
290
|
+
function Xe(a) {
|
|
291
|
+
t.enableZoom && be(a), t.enableRotate && ye(a);
|
|
292
292
|
}
|
|
293
|
-
function
|
|
294
|
-
t.enabled !== !1 && (E.length === 0 && (t.domElement.setPointerCapture(
|
|
293
|
+
function ve(a) {
|
|
294
|
+
t.enabled !== !1 && (E.length === 0 && (t.domElement.setPointerCapture(a.pointerId), t.domElement.addEventListener("pointermove", ne), t.domElement.addEventListener("pointerup", B)), et(a), a.pointerType === "touch" ? Qe(a) : Ve(a));
|
|
295
295
|
}
|
|
296
|
-
function
|
|
297
|
-
t.enabled !== !1 && (
|
|
296
|
+
function ne(a) {
|
|
297
|
+
t.enabled !== !1 && (a.pointerType === "touch" ? Je(a) : qe(a));
|
|
298
298
|
}
|
|
299
|
-
function
|
|
300
|
-
|
|
299
|
+
function B(a) {
|
|
300
|
+
tt(a), E.length === 0 && (t.domElement.releasePointerCapture(a.pointerId), t.domElement.removeEventListener("pointermove", ne), t.domElement.removeEventListener("pointerup", B)), t.dispatchEvent(Pe), o = i.NONE;
|
|
301
301
|
}
|
|
302
|
-
function
|
|
302
|
+
function Ve(a) {
|
|
303
303
|
let g;
|
|
304
|
-
switch (
|
|
304
|
+
switch (a.button) {
|
|
305
305
|
case 0:
|
|
306
306
|
g = t.mouseButtons.LEFT;
|
|
307
307
|
break;
|
|
@@ -315,57 +315,57 @@ class ft extends at {
|
|
|
315
315
|
g = -1;
|
|
316
316
|
}
|
|
317
317
|
switch (g) {
|
|
318
|
-
case
|
|
318
|
+
case j.DOLLY:
|
|
319
319
|
if (t.enableZoom === !1) return;
|
|
320
|
-
|
|
320
|
+
Ae(a), o = i.DOLLY;
|
|
321
321
|
break;
|
|
322
|
-
case
|
|
323
|
-
if (
|
|
322
|
+
case j.ROTATE:
|
|
323
|
+
if (a.ctrlKey || a.metaKey || a.shiftKey) {
|
|
324
324
|
if (t.enablePan === !1) return;
|
|
325
|
-
|
|
325
|
+
ge(a), o = i.PAN;
|
|
326
326
|
} else {
|
|
327
327
|
if (t.enableRotate === !1) return;
|
|
328
|
-
|
|
328
|
+
pe(a), o = i.ROTATE;
|
|
329
329
|
}
|
|
330
330
|
break;
|
|
331
|
-
case
|
|
332
|
-
if (
|
|
331
|
+
case j.PAN:
|
|
332
|
+
if (a.ctrlKey || a.metaKey || a.shiftKey) {
|
|
333
333
|
if (t.enableRotate === !1) return;
|
|
334
|
-
|
|
334
|
+
pe(a), o = i.ROTATE;
|
|
335
335
|
} else {
|
|
336
336
|
if (t.enablePan === !1) return;
|
|
337
|
-
|
|
337
|
+
ge(a), o = i.PAN;
|
|
338
338
|
}
|
|
339
339
|
break;
|
|
340
340
|
default:
|
|
341
341
|
o = i.NONE;
|
|
342
342
|
}
|
|
343
|
-
o !== i.NONE && t.dispatchEvent(
|
|
343
|
+
o !== i.NONE && t.dispatchEvent(le);
|
|
344
344
|
}
|
|
345
|
-
function
|
|
345
|
+
function qe(a) {
|
|
346
346
|
switch (o) {
|
|
347
347
|
case i.ROTATE:
|
|
348
348
|
if (t.enableRotate === !1) return;
|
|
349
|
-
|
|
349
|
+
je(a);
|
|
350
350
|
break;
|
|
351
351
|
case i.DOLLY:
|
|
352
352
|
if (t.enableZoom === !1) return;
|
|
353
|
-
|
|
353
|
+
$e(a);
|
|
354
354
|
break;
|
|
355
355
|
case i.PAN:
|
|
356
356
|
if (t.enablePan === !1) return;
|
|
357
|
-
|
|
357
|
+
Ge(a);
|
|
358
358
|
break;
|
|
359
359
|
}
|
|
360
360
|
}
|
|
361
|
-
function we(
|
|
362
|
-
t.enabled === !1 || t.enableZoom === !1 || o !== i.NONE || (
|
|
361
|
+
function we(a) {
|
|
362
|
+
t.enabled === !1 || t.enableZoom === !1 || o !== i.NONE || (a.preventDefault(), t.dispatchEvent(le), Ye(We(a)), t.dispatchEvent(Pe));
|
|
363
363
|
}
|
|
364
|
-
function
|
|
365
|
-
const g =
|
|
366
|
-
clientX:
|
|
367
|
-
clientY:
|
|
368
|
-
deltaY:
|
|
364
|
+
function We(a) {
|
|
365
|
+
const g = a.deltaMode, v = {
|
|
366
|
+
clientX: a.clientX,
|
|
367
|
+
clientY: a.clientY,
|
|
368
|
+
deltaY: a.deltaY
|
|
369
369
|
};
|
|
370
370
|
switch (g) {
|
|
371
371
|
case 1:
|
|
@@ -375,28 +375,28 @@ class ft extends at {
|
|
|
375
375
|
v.deltaY *= 100;
|
|
376
376
|
break;
|
|
377
377
|
}
|
|
378
|
-
return
|
|
378
|
+
return a.ctrlKey && !te && (v.deltaY *= 10), v;
|
|
379
379
|
}
|
|
380
|
-
function
|
|
381
|
-
|
|
380
|
+
function Ze(a) {
|
|
381
|
+
a.key === "Control" && (te = !0, document.addEventListener("keyup", Me, { passive: !0, capture: !0 }));
|
|
382
382
|
}
|
|
383
|
-
function
|
|
384
|
-
|
|
383
|
+
function Me(a) {
|
|
384
|
+
a.key === "Control" && (te = !1, document.removeEventListener("keyup", Me, { passive: !0, capture: !0 }));
|
|
385
385
|
}
|
|
386
|
-
function
|
|
387
|
-
t.enabled === !1 || t.enablePan === !1 ||
|
|
386
|
+
function ae(a) {
|
|
387
|
+
t.enabled === !1 || t.enablePan === !1 || Be(a);
|
|
388
388
|
}
|
|
389
|
-
function
|
|
390
|
-
switch (
|
|
389
|
+
function Qe(a) {
|
|
390
|
+
switch (Ce(a), E.length) {
|
|
391
391
|
case 1:
|
|
392
392
|
switch (t.touches.ONE) {
|
|
393
|
-
case
|
|
393
|
+
case $.ROTATE:
|
|
394
394
|
if (t.enableRotate === !1) return;
|
|
395
|
-
|
|
395
|
+
ue(a), o = i.TOUCH_ROTATE;
|
|
396
396
|
break;
|
|
397
|
-
case
|
|
397
|
+
case $.PAN:
|
|
398
398
|
if (t.enablePan === !1) return;
|
|
399
|
-
|
|
399
|
+
fe(a), o = i.TOUCH_PAN;
|
|
400
400
|
break;
|
|
401
401
|
default:
|
|
402
402
|
o = i.NONE;
|
|
@@ -404,13 +404,13 @@ class ft extends at {
|
|
|
404
404
|
break;
|
|
405
405
|
case 2:
|
|
406
406
|
switch (t.touches.TWO) {
|
|
407
|
-
case
|
|
407
|
+
case $.DOLLY_PAN:
|
|
408
408
|
if (t.enableZoom === !1 && t.enablePan === !1) return;
|
|
409
|
-
|
|
409
|
+
Ke(a), o = i.TOUCH_DOLLY_PAN;
|
|
410
410
|
break;
|
|
411
|
-
case
|
|
411
|
+
case $.DOLLY_ROTATE:
|
|
412
412
|
if (t.enableZoom === !1 && t.enableRotate === !1) return;
|
|
413
|
-
|
|
413
|
+
Ue(a), o = i.TOUCH_DOLLY_ROTATE;
|
|
414
414
|
break;
|
|
415
415
|
default:
|
|
416
416
|
o = i.NONE;
|
|
@@ -419,56 +419,56 @@ class ft extends at {
|
|
|
419
419
|
default:
|
|
420
420
|
o = i.NONE;
|
|
421
421
|
}
|
|
422
|
-
o !== i.NONE && t.dispatchEvent(
|
|
422
|
+
o !== i.NONE && t.dispatchEvent(le);
|
|
423
423
|
}
|
|
424
|
-
function
|
|
425
|
-
switch (
|
|
424
|
+
function Je(a) {
|
|
425
|
+
switch (Ce(a), o) {
|
|
426
426
|
case i.TOUCH_ROTATE:
|
|
427
427
|
if (t.enableRotate === !1) return;
|
|
428
|
-
|
|
428
|
+
ye(a), t.update();
|
|
429
429
|
break;
|
|
430
430
|
case i.TOUCH_PAN:
|
|
431
431
|
if (t.enablePan === !1) return;
|
|
432
|
-
|
|
432
|
+
xe(a), t.update();
|
|
433
433
|
break;
|
|
434
434
|
case i.TOUCH_DOLLY_PAN:
|
|
435
435
|
if (t.enableZoom === !1 && t.enablePan === !1) return;
|
|
436
|
-
|
|
436
|
+
_e(a), t.update();
|
|
437
437
|
break;
|
|
438
438
|
case i.TOUCH_DOLLY_ROTATE:
|
|
439
439
|
if (t.enableZoom === !1 && t.enableRotate === !1) return;
|
|
440
|
-
|
|
440
|
+
Xe(a), t.update();
|
|
441
441
|
break;
|
|
442
442
|
default:
|
|
443
443
|
o = i.NONE;
|
|
444
444
|
}
|
|
445
445
|
}
|
|
446
|
-
function
|
|
447
|
-
t.enabled !== !1 &&
|
|
446
|
+
function Ee(a) {
|
|
447
|
+
t.enabled !== !1 && a.preventDefault();
|
|
448
448
|
}
|
|
449
|
-
function
|
|
450
|
-
E.push(
|
|
449
|
+
function et(a) {
|
|
450
|
+
E.push(a.pointerId);
|
|
451
451
|
}
|
|
452
|
-
function
|
|
453
|
-
delete
|
|
452
|
+
function tt(a) {
|
|
453
|
+
delete V[a.pointerId];
|
|
454
454
|
for (let g = 0; g < E.length; g++)
|
|
455
|
-
if (E[g] ==
|
|
455
|
+
if (E[g] == a.pointerId) {
|
|
456
456
|
E.splice(g, 1);
|
|
457
457
|
return;
|
|
458
458
|
}
|
|
459
459
|
}
|
|
460
|
-
function
|
|
461
|
-
let g =
|
|
462
|
-
g === void 0 && (g = new k(),
|
|
460
|
+
function Ce(a) {
|
|
461
|
+
let g = V[a.pointerId];
|
|
462
|
+
g === void 0 && (g = new k(), V[a.pointerId] = g), g.set(a.pageX, a.pageY);
|
|
463
463
|
}
|
|
464
|
-
function
|
|
465
|
-
const g =
|
|
466
|
-
return
|
|
464
|
+
function A(a) {
|
|
465
|
+
const g = a.pointerId === E[0] ? E[1] : E[0];
|
|
466
|
+
return V[g];
|
|
467
467
|
}
|
|
468
|
-
t.domElement.addEventListener("contextmenu",
|
|
468
|
+
t.domElement.addEventListener("contextmenu", Ee), t.domElement.addEventListener("pointerdown", ve), t.domElement.addEventListener("pointercancel", B), t.domElement.addEventListener("wheel", we, { passive: !1 }), document.addEventListener("keydown", Ze, { passive: !0, capture: !0 }), this.update();
|
|
469
469
|
}
|
|
470
470
|
}
|
|
471
|
-
class
|
|
471
|
+
class ft {
|
|
472
472
|
constructor(e, s) {
|
|
473
473
|
l(this, "scene");
|
|
474
474
|
l(this, "camera");
|
|
@@ -476,42 +476,42 @@ class mt {
|
|
|
476
476
|
l(this, "controls");
|
|
477
477
|
l(this, "container");
|
|
478
478
|
l(this, "resizeHandler");
|
|
479
|
-
this.container = e, this.scene = new
|
|
479
|
+
this.container = e, this.scene = new x.Scene(), this.scene.background = new x.Color(
|
|
480
480
|
s.backgroundColor ?? 657930
|
|
481
481
|
);
|
|
482
|
-
const { width: t, height: i } =
|
|
483
|
-
this.camera = new
|
|
484
|
-
const
|
|
485
|
-
this.camera.position.set(
|
|
482
|
+
const { width: t, height: i } = ke(e), o = s.cameraFov ?? 75;
|
|
483
|
+
this.camera = new x.PerspectiveCamera(o, t / i, 0.1, 2e3);
|
|
484
|
+
const n = s.cameraPosition ?? { x: 0, y: 0, z: 80 };
|
|
485
|
+
this.camera.position.set(n.x, n.y, n.z), this.renderer = new x.WebGLRenderer({
|
|
486
486
|
antialias: !0,
|
|
487
487
|
alpha: !0,
|
|
488
488
|
powerPreference: "high-performance"
|
|
489
|
-
}), this.renderer.setSize(t, i), this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)), this.renderer.toneMapping =
|
|
489
|
+
}), this.renderer.setSize(t, i), this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)), this.renderer.toneMapping = x.ACESFilmicToneMapping, this.renderer.toneMappingExposure = 1, this.renderer.shadowMap.enabled = !0, this.renderer.shadowMap.type = x.PCFSoftShadowMap, e.appendChild(this.renderer.domElement), this.controls = new ut(this.camera, this.renderer.domElement), this.controls.enableDamping = !0, this.controls.dampingFactor = 0.05, this.controls.rotateSpeed = 0.8, this.controls.zoomSpeed = 1.2, this.controls.minDistance = 10, this.controls.maxDistance = 2e3, this.setupLighting(), this.resizeHandler = this.onWindowResize.bind(this), window.addEventListener("resize", this.resizeHandler);
|
|
490
490
|
}
|
|
491
491
|
/**
|
|
492
492
|
* Sets up scene lighting for gradient glass on dark background
|
|
493
493
|
*/
|
|
494
494
|
setupLighting() {
|
|
495
|
-
const e = new
|
|
495
|
+
const e = new x.AmbientLight(16777215, 0.4);
|
|
496
496
|
this.scene.add(e);
|
|
497
|
-
const s = new
|
|
497
|
+
const s = new x.DirectionalLight(16777215, 0.9);
|
|
498
498
|
s.position.set(50, 60, 40), s.castShadow = !0, s.shadow.mapSize.width = 1024, s.shadow.mapSize.height = 1024, this.scene.add(s);
|
|
499
|
-
const t = new
|
|
499
|
+
const t = new x.DirectionalLight(16773344, 0.4);
|
|
500
500
|
t.position.set(-50, 30, -40), this.scene.add(t);
|
|
501
|
-
const i = new
|
|
501
|
+
const i = new x.DirectionalLight(16777215, 0.3);
|
|
502
502
|
i.position.set(0, -30, -50), this.scene.add(i);
|
|
503
|
-
const o = new
|
|
503
|
+
const o = new x.PointLight(16750950, 0.5, 150);
|
|
504
504
|
o.position.set(40, 20, 40), this.scene.add(o);
|
|
505
|
-
const
|
|
506
|
-
|
|
507
|
-
const r = new
|
|
505
|
+
const n = new x.PointLight(16764057, 0.4, 150);
|
|
506
|
+
n.position.set(-40, -20, 40), this.scene.add(n);
|
|
507
|
+
const r = new x.PointLight(6724095, 0.2, 100);
|
|
508
508
|
r.position.set(0, 40, -40), this.scene.add(r);
|
|
509
509
|
}
|
|
510
510
|
/**
|
|
511
511
|
* Handle window resize
|
|
512
512
|
*/
|
|
513
513
|
onWindowResize() {
|
|
514
|
-
const { width: e, height: s } =
|
|
514
|
+
const { width: e, height: s } = ke(this.container);
|
|
515
515
|
this.camera.aspect = e / s, this.camera.updateProjectionMatrix(), this.renderer.setSize(e, s);
|
|
516
516
|
}
|
|
517
517
|
/**
|
|
@@ -546,7 +546,7 @@ class mt {
|
|
|
546
546
|
* Gets the camera's forward direction
|
|
547
547
|
*/
|
|
548
548
|
getCameraDirection() {
|
|
549
|
-
const e = new
|
|
549
|
+
const e = new x.Vector3();
|
|
550
550
|
return this.camera.getWorldDirection(e), e;
|
|
551
551
|
}
|
|
552
552
|
/**
|
|
@@ -559,7 +559,7 @@ class mt {
|
|
|
559
559
|
}
|
|
560
560
|
}
|
|
561
561
|
}
|
|
562
|
-
const
|
|
562
|
+
const X = class X {
|
|
563
563
|
constructor(e, s) {
|
|
564
564
|
l(this, "sceneManager");
|
|
565
565
|
l(this, "nodeFactory");
|
|
@@ -578,18 +578,18 @@ const V = class V {
|
|
|
578
578
|
* Call this before adding nodes in bulk.
|
|
579
579
|
*/
|
|
580
580
|
static setExpectedNodeCount(e) {
|
|
581
|
-
|
|
581
|
+
X.expectedNodeCount = e;
|
|
582
582
|
}
|
|
583
583
|
/**
|
|
584
584
|
* Adds a node to the graph
|
|
585
585
|
* @returns true if added, false if node already exists or invalid
|
|
586
586
|
*/
|
|
587
587
|
addNode(e, s = 0) {
|
|
588
|
-
if (!
|
|
588
|
+
if (!Fe(e))
|
|
589
589
|
return !1;
|
|
590
590
|
if (this.nodes.has(e.id))
|
|
591
591
|
return console.warn(`[ForceGraph3D] Node with id "${e.id}" already exists`), !1;
|
|
592
|
-
const t = Math.max(50, Math.cbrt(
|
|
592
|
+
const t = Math.max(50, Math.cbrt(X.expectedNodeCount) * 10), i = e.position ?? {
|
|
593
593
|
x: (Math.random() - 0.5) * t,
|
|
594
594
|
y: (Math.random() - 0.5) * t,
|
|
595
595
|
z: (Math.random() - 0.5) * t
|
|
@@ -598,11 +598,11 @@ const V = class V {
|
|
|
598
598
|
position: i,
|
|
599
599
|
velocity: { x: 0, y: 0, z: 0 },
|
|
600
600
|
mass: 1
|
|
601
|
-
},
|
|
601
|
+
}, n = this.nodeFactory.createNode(
|
|
602
602
|
{ ...e, position: i },
|
|
603
603
|
s
|
|
604
604
|
);
|
|
605
|
-
return this.sceneManager.add(
|
|
605
|
+
return this.sceneManager.add(n.group), this.nodes.set(e.id, o), this.nodeObjects.set(e.id, n), !0;
|
|
606
606
|
}
|
|
607
607
|
/**
|
|
608
608
|
* Removes a node from the graph
|
|
@@ -693,16 +693,23 @@ const V = class V {
|
|
|
693
693
|
}
|
|
694
694
|
};
|
|
695
695
|
// Scale spawn volume with expected graph size
|
|
696
|
-
l(
|
|
697
|
-
let
|
|
698
|
-
class
|
|
696
|
+
l(X, "expectedNodeCount", 100);
|
|
697
|
+
let ee = X;
|
|
698
|
+
class mt {
|
|
699
699
|
constructor(e, s, t) {
|
|
700
700
|
l(this, "sceneManager");
|
|
701
701
|
l(this, "nodeManager");
|
|
702
702
|
l(this, "edgeFactory");
|
|
703
|
+
// Full relationship list (includes duplicates between same pair)
|
|
703
704
|
l(this, "edges", []);
|
|
705
|
+
// One visual line per directed pair (source -> target)
|
|
704
706
|
l(this, "edgeObjects", []);
|
|
707
|
+
// Tracks which directed pairs currently have at least one relationship
|
|
705
708
|
l(this, "edgeKeySet", /* @__PURE__ */ new Set());
|
|
709
|
+
// Maps directed pair key to the relationship list for that pair
|
|
710
|
+
l(this, "edgeGroups", /* @__PURE__ */ new Map());
|
|
711
|
+
// Maps directed pair key to the corresponding visual line
|
|
712
|
+
l(this, "edgeObjectMap", /* @__PURE__ */ new Map());
|
|
706
713
|
l(this, "highlightedEdgeKey", null);
|
|
707
714
|
this.sceneManager = e, this.nodeManager = s, this.edgeFactory = t;
|
|
708
715
|
}
|
|
@@ -710,68 +717,92 @@ class yt {
|
|
|
710
717
|
* Checks if an edge exists
|
|
711
718
|
*/
|
|
712
719
|
hasEdge(e, s) {
|
|
713
|
-
const t =
|
|
720
|
+
const t = this.createDirectedEdgeKey(e, s);
|
|
714
721
|
return this.edgeKeySet.has(t);
|
|
715
722
|
}
|
|
716
723
|
/**
|
|
717
724
|
* Adds an edge to the graph
|
|
718
|
-
* @returns true if added, false if
|
|
725
|
+
* @returns true if added, false if invalid or nodes don't exist
|
|
719
726
|
*/
|
|
720
727
|
addEdge(e) {
|
|
721
|
-
if (!
|
|
728
|
+
if (!De(e))
|
|
722
729
|
return !1;
|
|
723
730
|
if (!this.nodeManager.hasNode(e.source))
|
|
724
731
|
return console.warn(`[ForceGraph3D] Source node "${e.source}" does not exist`), !1;
|
|
725
732
|
if (!this.nodeManager.hasNode(e.target))
|
|
726
733
|
return console.warn(`[ForceGraph3D] Target node "${e.target}" does not exist`), !1;
|
|
727
|
-
const s =
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
734
|
+
const s = this.nodeManager.getNode(e.source), t = this.nodeManager.getNode(e.target), i = this.createDirectedEdgeKey(e.source, e.target);
|
|
735
|
+
this.edges.push(e);
|
|
736
|
+
const o = this.edgeGroups.get(i);
|
|
737
|
+
if (o) {
|
|
738
|
+
o.push(e);
|
|
739
|
+
const r = this.edgeObjectMap.get(i);
|
|
740
|
+
return r && this.updateEdgeUserData(r, o, s, t), !0;
|
|
741
|
+
}
|
|
742
|
+
const n = this.edgeFactory.createEdge(
|
|
731
743
|
e,
|
|
744
|
+
s,
|
|
732
745
|
t,
|
|
733
|
-
|
|
734
|
-
t.position
|
|
735
|
-
i.position
|
|
746
|
+
s.position,
|
|
747
|
+
t.position
|
|
736
748
|
);
|
|
737
|
-
return this.sceneManager.add(
|
|
749
|
+
return this.sceneManager.add(n.line), this.edgeGroups.set(i, [e]), this.edgeObjectMap.set(i, n), this.edgeObjects.push(n), this.edgeKeySet.add(i), this.updateEdgeUserData(n, [e], s, t), !0;
|
|
738
750
|
}
|
|
739
751
|
/**
|
|
740
752
|
* Removes an edge from the graph
|
|
753
|
+
* Removes one relationship instance for source -> target.
|
|
741
754
|
* @returns true if removed, false if not found
|
|
742
755
|
*/
|
|
743
756
|
removeEdge(e, s) {
|
|
744
|
-
const t =
|
|
757
|
+
const t = this.createDirectedEdgeKey(e, s);
|
|
745
758
|
if (!this.edgeKeySet.has(t))
|
|
746
759
|
return !1;
|
|
747
760
|
const i = this.edges.findIndex(
|
|
748
|
-
(
|
|
761
|
+
(c) => c.source === e && c.target === s
|
|
749
762
|
);
|
|
750
763
|
if (i === -1)
|
|
751
764
|
return !1;
|
|
752
|
-
const o = this.
|
|
753
|
-
|
|
765
|
+
const o = this.edges[i];
|
|
766
|
+
this.edges.splice(i, 1);
|
|
767
|
+
const n = this.edgeGroups.get(t);
|
|
768
|
+
if (!n)
|
|
769
|
+
return !0;
|
|
770
|
+
const r = n.findIndex((c) => c === o);
|
|
771
|
+
if (r !== -1)
|
|
772
|
+
n.splice(r, 1);
|
|
773
|
+
else {
|
|
774
|
+
const c = n.findIndex((p) => p.source === e && p.target === s);
|
|
775
|
+
c !== -1 && n.splice(c, 1);
|
|
776
|
+
}
|
|
777
|
+
const h = this.edgeObjectMap.get(t);
|
|
778
|
+
if (!h)
|
|
779
|
+
return !0;
|
|
780
|
+
if (n.length === 0) {
|
|
781
|
+
this.sceneManager.remove(h.line), this.edgeFactory.disposeEdge(h);
|
|
782
|
+
const c = this.edgeObjects.findIndex((p) => p === h);
|
|
783
|
+
c !== -1 && this.edgeObjects.splice(c, 1), this.edgeGroups.delete(t), this.edgeObjectMap.delete(t), this.edgeKeySet.delete(t), this.highlightedEdgeKey === t && (this.highlightedEdgeKey = null);
|
|
784
|
+
} else {
|
|
785
|
+
const c = this.nodeManager.getNode(e), p = this.nodeManager.getNode(s);
|
|
786
|
+
c && p && this.updateEdgeUserData(h, n, c, p);
|
|
787
|
+
}
|
|
788
|
+
return !0;
|
|
754
789
|
}
|
|
755
790
|
/**
|
|
756
791
|
* Highlights an edge
|
|
757
792
|
*/
|
|
758
793
|
highlightEdge(e, s) {
|
|
759
|
-
const t =
|
|
794
|
+
const t = this.createDirectedEdgeKey(e, s);
|
|
760
795
|
this.highlightedEdgeKey && this.highlightedEdgeKey !== t && this.unhighlightCurrentEdge();
|
|
761
|
-
const i = this.
|
|
762
|
-
|
|
763
|
-
);
|
|
764
|
-
i !== -1 && (this.edgeFactory.highlightEdge(this.edgeObjects[i]), this.highlightedEdgeKey = t);
|
|
796
|
+
const i = this.edgeObjectMap.get(t);
|
|
797
|
+
i && (this.edgeFactory.highlightEdge(i), this.highlightedEdgeKey = t);
|
|
765
798
|
}
|
|
766
799
|
/**
|
|
767
800
|
* Unhighlights the currently highlighted edge
|
|
768
801
|
*/
|
|
769
802
|
unhighlightCurrentEdge() {
|
|
770
803
|
if (!this.highlightedEdgeKey) return;
|
|
771
|
-
const e = this.
|
|
772
|
-
|
|
773
|
-
);
|
|
774
|
-
e !== -1 && this.edgeFactory.unhighlightEdge(this.edgeObjects[e]), this.highlightedEdgeKey = null;
|
|
804
|
+
const e = this.edgeObjectMap.get(this.highlightedEdgeKey);
|
|
805
|
+
e && this.edgeFactory.unhighlightEdge(e), this.highlightedEdgeKey = null;
|
|
775
806
|
}
|
|
776
807
|
/**
|
|
777
808
|
* Removes all edges connected to a node
|
|
@@ -803,12 +834,12 @@ class yt {
|
|
|
803
834
|
* Updates all edge positions based on current node positions
|
|
804
835
|
*/
|
|
805
836
|
updateEdgePositions() {
|
|
806
|
-
this.edgeObjects.forEach((e
|
|
807
|
-
const
|
|
808
|
-
|
|
837
|
+
this.edgeObjects.forEach((e) => {
|
|
838
|
+
const s = this.nodeManager.getNode(e.source), t = this.nodeManager.getNode(e.target);
|
|
839
|
+
s && t && this.edgeFactory.updateEdgePositions(
|
|
809
840
|
e,
|
|
810
|
-
|
|
811
|
-
|
|
841
|
+
s.position,
|
|
842
|
+
t.position
|
|
812
843
|
);
|
|
813
844
|
});
|
|
814
845
|
}
|
|
@@ -836,7 +867,29 @@ class yt {
|
|
|
836
867
|
clear() {
|
|
837
868
|
this.edgeObjects.forEach((e) => {
|
|
838
869
|
this.sceneManager.remove(e.line), this.edgeFactory.disposeEdge(e);
|
|
839
|
-
}), this.edges = [], this.edgeObjects = [], this.edgeKeySet.clear(), this.highlightedEdgeKey = null;
|
|
870
|
+
}), this.edges = [], this.edgeObjects = [], this.edgeKeySet.clear(), this.edgeGroups.clear(), this.edgeObjectMap.clear(), this.highlightedEdgeKey = null;
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* Creates a directed key (source -> target)
|
|
874
|
+
*/
|
|
875
|
+
createDirectedEdgeKey(e, s) {
|
|
876
|
+
return `${e}->${s}`;
|
|
877
|
+
}
|
|
878
|
+
/**
|
|
879
|
+
* Syncs relationship metadata to the line for hover/click UI
|
|
880
|
+
*/
|
|
881
|
+
updateEdgeUserData(e, s, t, i) {
|
|
882
|
+
const o = s[0];
|
|
883
|
+
e.line.userData = {
|
|
884
|
+
...e.line.userData,
|
|
885
|
+
source: e.source,
|
|
886
|
+
target: e.target,
|
|
887
|
+
edge: o,
|
|
888
|
+
relationships: [...s],
|
|
889
|
+
relationshipCount: s.length,
|
|
890
|
+
sourceNode: t,
|
|
891
|
+
targetNode: i
|
|
892
|
+
};
|
|
840
893
|
}
|
|
841
894
|
/**
|
|
842
895
|
* Dispose resources
|
|
@@ -845,7 +898,7 @@ class yt {
|
|
|
845
898
|
this.clear();
|
|
846
899
|
}
|
|
847
900
|
}
|
|
848
|
-
class
|
|
901
|
+
class Le {
|
|
849
902
|
constructor(e, s, t = {}) {
|
|
850
903
|
l(this, "nodes");
|
|
851
904
|
l(this, "edges");
|
|
@@ -885,8 +938,8 @@ class Ie {
|
|
|
885
938
|
let s = 0, t = null;
|
|
886
939
|
for (const [i, o] of e) {
|
|
887
940
|
o > s && (s = o, t = i);
|
|
888
|
-
const
|
|
889
|
-
|
|
941
|
+
const n = this.nodes.get(i);
|
|
942
|
+
n && (n.mass = 1 + Math.log2(1 + o));
|
|
890
943
|
}
|
|
891
944
|
if (console.log(`[ForceGraph3D] Hub detected: id="${t}", degree=${s}, threshold=10`), t && s > 10) {
|
|
892
945
|
this.pinnedNodeId = t;
|
|
@@ -918,13 +971,13 @@ class Ie {
|
|
|
918
971
|
const e = Array.from(this.nodes.values()), s = e.length, t = this.getEffectiveRepulsion();
|
|
919
972
|
for (let i = 0; i < s; i++) {
|
|
920
973
|
const o = e[i];
|
|
921
|
-
for (let
|
|
922
|
-
const r = e[
|
|
923
|
-
let
|
|
924
|
-
if (
|
|
925
|
-
|
|
926
|
-
const m = Math.sqrt(
|
|
927
|
-
o.velocity.x -=
|
|
974
|
+
for (let n = i + 1; n < s; n++) {
|
|
975
|
+
const r = e[n], h = r.position.x - o.position.x, c = r.position.y - o.position.y, p = r.position.z - o.position.z;
|
|
976
|
+
let f = h * h + c * c + p * p;
|
|
977
|
+
if (f > this.REPULSION_CUTOFF_SQ) continue;
|
|
978
|
+
f < 0.01 && (f = 0.01);
|
|
979
|
+
const m = Math.sqrt(f), u = t * this.alpha / f, y = h / m * u, b = c / m * u, w = p / m * u;
|
|
980
|
+
o.velocity.x -= y / o.mass, o.velocity.y -= b / o.mass, o.velocity.z -= w / o.mass, r.velocity.x += y / r.mass, r.velocity.y += b / r.mass, r.velocity.z += w / r.mass;
|
|
928
981
|
}
|
|
929
982
|
}
|
|
930
983
|
}
|
|
@@ -932,7 +985,7 @@ class Ie {
|
|
|
932
985
|
* Barnes-Hut approximation - O(n log n)
|
|
933
986
|
*/
|
|
934
987
|
calculateRepulsionBarnesHut() {
|
|
935
|
-
const e = Array.from(this.nodes.values()), s = new
|
|
988
|
+
const e = Array.from(this.nodes.values()), s = new yt(e);
|
|
936
989
|
for (const t of e)
|
|
937
990
|
this.calculateForceFromOctree(t, s.root);
|
|
938
991
|
}
|
|
@@ -945,26 +998,26 @@ class Ie {
|
|
|
945
998
|
return;
|
|
946
999
|
}
|
|
947
1000
|
if (s.mass === 0) return;
|
|
948
|
-
const t = s.centerOfMass.x - e.position.x, i = s.centerOfMass.y - e.position.y, o = s.centerOfMass.z - e.position.z,
|
|
949
|
-
if (
|
|
950
|
-
const r = Math.sqrt(
|
|
1001
|
+
const t = s.centerOfMass.x - e.position.x, i = s.centerOfMass.y - e.position.y, o = s.centerOfMass.z - e.position.z, n = t * t + i * i + o * o;
|
|
1002
|
+
if (n > this.REPULSION_CUTOFF_SQ) return;
|
|
1003
|
+
const r = Math.sqrt(n), h = this.getEffectiveRepulsion();
|
|
951
1004
|
if (r > 0 && s.size / r < this.barnesHutTheta) {
|
|
952
|
-
const
|
|
1005
|
+
const c = Math.max(n, 0.01), p = h * this.alpha * s.mass / c;
|
|
953
1006
|
e.velocity.x -= t / r * p / e.mass, e.velocity.y -= i / r * p / e.mass, e.velocity.z -= o / r * p / e.mass;
|
|
954
1007
|
} else
|
|
955
|
-
for (const
|
|
956
|
-
|
|
1008
|
+
for (const c of s.children)
|
|
1009
|
+
c && this.calculateForceFromOctree(e, c);
|
|
957
1010
|
}
|
|
958
1011
|
/**
|
|
959
1012
|
* Apply repulsion between two nodes (with cutoff)
|
|
960
1013
|
*/
|
|
961
1014
|
applyRepulsionBetween(e, s) {
|
|
962
1015
|
const t = s.position.x - e.position.x, i = s.position.y - e.position.y, o = s.position.z - e.position.z;
|
|
963
|
-
let
|
|
964
|
-
if (
|
|
965
|
-
|
|
966
|
-
const r = Math.sqrt(
|
|
967
|
-
e.velocity.x -= t / r *
|
|
1016
|
+
let n = t * t + i * i + o * o;
|
|
1017
|
+
if (n > this.REPULSION_CUTOFF_SQ) return;
|
|
1018
|
+
n < 0.01 && (n = 0.01);
|
|
1019
|
+
const r = Math.sqrt(n), c = this.getEffectiveRepulsion() * this.alpha / n;
|
|
1020
|
+
e.velocity.x -= t / r * c / e.mass, e.velocity.y -= i / r * c / e.mass, e.velocity.z -= o / r * c / e.mass;
|
|
968
1021
|
}
|
|
969
1022
|
/**
|
|
970
1023
|
* Calculate attraction forces along edges
|
|
@@ -974,10 +1027,10 @@ class Ie {
|
|
|
974
1027
|
for (const t of this.edges) {
|
|
975
1028
|
const i = this.nodes.get(t.source), o = this.nodes.get(t.target);
|
|
976
1029
|
if (!i || !o) continue;
|
|
977
|
-
const
|
|
978
|
-
if (
|
|
979
|
-
const
|
|
980
|
-
i.velocity.x += m / i.mass, i.velocity.y += u / i.mass, i.velocity.z +=
|
|
1030
|
+
const n = o.position.x - i.position.x, r = o.position.y - i.position.y, h = o.position.z - i.position.z, c = Math.sqrt(n * n + r * r + h * h);
|
|
1031
|
+
if (c < 0.01) continue;
|
|
1032
|
+
const f = (c - 15) * this.attractionStrength * s * this.alpha, m = n / c * f, u = r / c * f, y = h / c * f;
|
|
1033
|
+
i.velocity.x += m / i.mass, i.velocity.y += u / i.mass, i.velocity.z += y / i.mass, o.velocity.x -= m / o.mass, o.velocity.y -= u / o.mass, o.velocity.z -= y / o.mass;
|
|
981
1034
|
}
|
|
982
1035
|
}
|
|
983
1036
|
/**
|
|
@@ -1034,7 +1087,7 @@ class Ie {
|
|
|
1034
1087
|
e.repulsionStrength !== void 0 && (this.repulsionStrength = e.repulsionStrength), e.attractionStrength !== void 0 && (this.attractionStrength = e.attractionStrength), e.damping !== void 0 && (this.damping = e.damping);
|
|
1035
1088
|
}
|
|
1036
1089
|
}
|
|
1037
|
-
class
|
|
1090
|
+
class yt {
|
|
1038
1091
|
constructor(e) {
|
|
1039
1092
|
l(this, "root");
|
|
1040
1093
|
const s = this.calculateBounds(e);
|
|
@@ -1070,54 +1123,54 @@ class xt {
|
|
|
1070
1123
|
};
|
|
1071
1124
|
if (e.length === 1 || t > 20) {
|
|
1072
1125
|
let u = 0;
|
|
1073
|
-
const
|
|
1126
|
+
const y = { x: 0, y: 0, z: 0 };
|
|
1074
1127
|
for (const b of e)
|
|
1075
|
-
u += b.mass,
|
|
1076
|
-
return u > 0 && (
|
|
1128
|
+
u += b.mass, y.x += b.position.x * b.mass, y.y += b.position.y * b.mass, y.z += b.position.z * b.mass;
|
|
1129
|
+
return u > 0 && (y.x /= u, y.y /= u, y.z /= u), {
|
|
1077
1130
|
bounds: s,
|
|
1078
1131
|
size: i,
|
|
1079
|
-
centerOfMass:
|
|
1132
|
+
centerOfMass: y,
|
|
1080
1133
|
mass: u,
|
|
1081
1134
|
isLeaf: !0,
|
|
1082
1135
|
node: e[0],
|
|
1083
1136
|
children: []
|
|
1084
1137
|
};
|
|
1085
1138
|
}
|
|
1086
|
-
const o = (s.min.x + s.max.x) / 2,
|
|
1139
|
+
const o = (s.min.x + s.max.x) / 2, n = (s.min.y + s.max.y) / 2, r = (s.min.z + s.max.z) / 2, h = [[], [], [], [], [], [], [], []];
|
|
1087
1140
|
for (const u of e) {
|
|
1088
|
-
const
|
|
1089
|
-
|
|
1090
|
-
}
|
|
1091
|
-
const
|
|
1092
|
-
{ min: { x: s.min.x, y: s.min.y, z: s.min.z }, max: { x: o, y:
|
|
1093
|
-
{ min: { x: o, y: s.min.y, z: s.min.z }, max: { x: s.max.x, y:
|
|
1094
|
-
{ min: { x: s.min.x, y:
|
|
1095
|
-
{ min: { x: o, y:
|
|
1096
|
-
{ min: { x: s.min.x, y: s.min.y, z: r }, max: { x: o, y:
|
|
1097
|
-
{ min: { x: o, y: s.min.y, z: r }, max: { x: s.max.x, y:
|
|
1098
|
-
{ min: { x: s.min.x, y:
|
|
1099
|
-
{ min: { x: o, y:
|
|
1141
|
+
const y = (u.position.x >= o ? 1 : 0) + (u.position.y >= n ? 2 : 0) + (u.position.z >= r ? 4 : 0);
|
|
1142
|
+
h[y].push(u);
|
|
1143
|
+
}
|
|
1144
|
+
const c = [
|
|
1145
|
+
{ min: { x: s.min.x, y: s.min.y, z: s.min.z }, max: { x: o, y: n, z: r } },
|
|
1146
|
+
{ min: { x: o, y: s.min.y, z: s.min.z }, max: { x: s.max.x, y: n, z: r } },
|
|
1147
|
+
{ min: { x: s.min.x, y: n, z: s.min.z }, max: { x: o, y: s.max.y, z: r } },
|
|
1148
|
+
{ min: { x: o, y: n, z: s.min.z }, max: { x: s.max.x, y: s.max.y, z: r } },
|
|
1149
|
+
{ min: { x: s.min.x, y: s.min.y, z: r }, max: { x: o, y: n, z: s.max.z } },
|
|
1150
|
+
{ min: { x: o, y: s.min.y, z: r }, max: { x: s.max.x, y: n, z: s.max.z } },
|
|
1151
|
+
{ min: { x: s.min.x, y: n, z: r }, max: { x: o, y: s.max.y, z: s.max.z } },
|
|
1152
|
+
{ min: { x: o, y: n, z: r }, max: { x: s.max.x, y: s.max.y, z: s.max.z } }
|
|
1100
1153
|
], p = [];
|
|
1101
|
-
let
|
|
1154
|
+
let f = 0;
|
|
1102
1155
|
const m = { x: 0, y: 0, z: 0 };
|
|
1103
1156
|
for (let u = 0; u < 8; u++)
|
|
1104
|
-
if (
|
|
1105
|
-
const
|
|
1106
|
-
p.push(
|
|
1157
|
+
if (h[u].length > 0) {
|
|
1158
|
+
const y = this.buildTree(h[u], c[u], t + 1);
|
|
1159
|
+
p.push(y), f += y.mass, m.x += y.centerOfMass.x * y.mass, m.y += y.centerOfMass.y * y.mass, m.z += y.centerOfMass.z * y.mass;
|
|
1107
1160
|
} else
|
|
1108
1161
|
p.push(null);
|
|
1109
|
-
return
|
|
1162
|
+
return f > 0 && (m.x /= f, m.y /= f, m.z /= f), {
|
|
1110
1163
|
bounds: s,
|
|
1111
1164
|
size: i,
|
|
1112
1165
|
centerOfMass: m,
|
|
1113
|
-
mass:
|
|
1166
|
+
mass: f,
|
|
1114
1167
|
isLeaf: !1,
|
|
1115
1168
|
node: null,
|
|
1116
1169
|
children: p
|
|
1117
1170
|
};
|
|
1118
1171
|
}
|
|
1119
1172
|
}
|
|
1120
|
-
class
|
|
1173
|
+
class xt {
|
|
1121
1174
|
constructor(e, s, t, i = 60) {
|
|
1122
1175
|
l(this, "sceneManager");
|
|
1123
1176
|
l(this, "animationId", null);
|
|
@@ -1182,7 +1235,7 @@ class bt {
|
|
|
1182
1235
|
this.stop();
|
|
1183
1236
|
}
|
|
1184
1237
|
}
|
|
1185
|
-
class
|
|
1238
|
+
class bt {
|
|
1186
1239
|
constructor() {
|
|
1187
1240
|
l(this, "envMap", null);
|
|
1188
1241
|
l(this, "materialCache", /* @__PURE__ */ new Map());
|
|
@@ -1223,7 +1276,7 @@ class vt {
|
|
|
1223
1276
|
for (const i of t) {
|
|
1224
1277
|
const o = document.createElement("canvas");
|
|
1225
1278
|
o.width = 256, o.height = 256;
|
|
1226
|
-
const
|
|
1279
|
+
const n = o.getContext("2d"), r = n.createRadialGradient(
|
|
1227
1280
|
256 / 2,
|
|
1228
1281
|
256 / 2,
|
|
1229
1282
|
0,
|
|
@@ -1231,15 +1284,15 @@ class vt {
|
|
|
1231
1284
|
256 / 2,
|
|
1232
1285
|
256 * 0.8
|
|
1233
1286
|
);
|
|
1234
|
-
r.addColorStop(0, i.colors[0]), r.addColorStop(0.5, i.colors[1]), r.addColorStop(1, i.colors[2]),
|
|
1235
|
-
const
|
|
1236
|
-
for (let
|
|
1287
|
+
r.addColorStop(0, i.colors[0]), r.addColorStop(0.5, i.colors[1]), r.addColorStop(1, i.colors[2]), n.fillStyle = r, n.fillRect(0, 0, 256, 256);
|
|
1288
|
+
const h = n.getImageData(0, 0, 256, 256);
|
|
1289
|
+
for (let c = 0; c < h.data.length; c += 4) {
|
|
1237
1290
|
const p = (Math.random() - 0.5) * 5;
|
|
1238
|
-
|
|
1291
|
+
h.data[c] = Math.min(255, Math.max(0, h.data[c] + p)), h.data[c + 1] = Math.min(255, Math.max(0, h.data[c + 1] + p)), h.data[c + 2] = Math.min(255, Math.max(0, h.data[c + 2] + p));
|
|
1239
1292
|
}
|
|
1240
|
-
|
|
1293
|
+
n.putImageData(h, 0, 0), s.push(o);
|
|
1241
1294
|
}
|
|
1242
|
-
this.envMap = new
|
|
1295
|
+
this.envMap = new x.CubeTexture(s.map((i) => {
|
|
1243
1296
|
const o = new Image();
|
|
1244
1297
|
return o.src = i.toDataURL(), o;
|
|
1245
1298
|
})), this.envMap.needsUpdate = !0;
|
|
@@ -1258,11 +1311,11 @@ class vt {
|
|
|
1258
1311
|
const t = "glass-single";
|
|
1259
1312
|
if (this.materialCache.has(t))
|
|
1260
1313
|
return this.materialCache.get(t).clone();
|
|
1261
|
-
const i = new
|
|
1314
|
+
const i = new x.Color(16750950), o = new x.ShaderMaterial({
|
|
1262
1315
|
uniforms: {
|
|
1263
1316
|
uColor: { value: i },
|
|
1264
1317
|
uEnvMap: { value: this.envMap },
|
|
1265
|
-
uGlowColor: { value: new
|
|
1318
|
+
uGlowColor: { value: new x.Color(16777215) },
|
|
1266
1319
|
uGlowIntensity: { value: 0.8 },
|
|
1267
1320
|
uReflectivity: { value: 0.4 },
|
|
1268
1321
|
uFresnelPower: { value: 2.5 }
|
|
@@ -1328,9 +1381,9 @@ class vt {
|
|
|
1328
1381
|
}
|
|
1329
1382
|
`,
|
|
1330
1383
|
transparent: !0,
|
|
1331
|
-
side:
|
|
1384
|
+
side: x.FrontSide,
|
|
1332
1385
|
depthWrite: !0,
|
|
1333
|
-
blending:
|
|
1386
|
+
blending: x.NormalBlending
|
|
1334
1387
|
});
|
|
1335
1388
|
return this.materialCache.set(t, o), o.clone();
|
|
1336
1389
|
}
|
|
@@ -1338,7 +1391,7 @@ class vt {
|
|
|
1338
1391
|
* Creates material for edges (light color for dark background)
|
|
1339
1392
|
*/
|
|
1340
1393
|
createEdgeMaterial(e = 6710886, s = 0.4) {
|
|
1341
|
-
return new
|
|
1394
|
+
return new x.LineBasicMaterial({
|
|
1342
1395
|
color: e,
|
|
1343
1396
|
transparent: !0,
|
|
1344
1397
|
opacity: s,
|
|
@@ -1349,7 +1402,7 @@ class vt {
|
|
|
1349
1402
|
* Creates highlighted edge material
|
|
1350
1403
|
*/
|
|
1351
1404
|
createHighlightedEdgeMaterial() {
|
|
1352
|
-
return new
|
|
1405
|
+
return new x.LineBasicMaterial({
|
|
1353
1406
|
color: 16750950,
|
|
1354
1407
|
// Tangerine highlight
|
|
1355
1408
|
transparent: !1,
|
|
@@ -1363,10 +1416,10 @@ class vt {
|
|
|
1363
1416
|
createLabelMaterial(e, s = 24) {
|
|
1364
1417
|
const t = document.createElement("canvas"), i = t.getContext("2d");
|
|
1365
1418
|
i.font = `600 ${s}px Inter, -apple-system, sans-serif`;
|
|
1366
|
-
const
|
|
1367
|
-
t.width = Math.max(128,
|
|
1368
|
-
const r = new
|
|
1369
|
-
return r.needsUpdate = !0, new
|
|
1419
|
+
const n = i.measureText(e).width;
|
|
1420
|
+
t.width = Math.max(128, n + 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);
|
|
1421
|
+
const r = new x.CanvasTexture(t);
|
|
1422
|
+
return r.needsUpdate = !0, new x.SpriteMaterial({
|
|
1370
1423
|
map: r,
|
|
1371
1424
|
transparent: !0,
|
|
1372
1425
|
depthTest: !1,
|
|
@@ -1386,7 +1439,7 @@ class vt {
|
|
|
1386
1439
|
this.materialCache.forEach((e) => e.dispose()), this.materialCache.clear(), this.envMap && this.envMap.dispose();
|
|
1387
1440
|
}
|
|
1388
1441
|
}
|
|
1389
|
-
class
|
|
1442
|
+
class vt {
|
|
1390
1443
|
constructor(e, s = 2, t = [32, 16, 8], i = 16750950) {
|
|
1391
1444
|
l(this, "materialFactory");
|
|
1392
1445
|
l(this, "geometryCache", /* @__PURE__ */ new Map());
|
|
@@ -1403,7 +1456,7 @@ class Mt {
|
|
|
1403
1456
|
const t = `lod-${s}`;
|
|
1404
1457
|
this.geometryCache.set(
|
|
1405
1458
|
t,
|
|
1406
|
-
new
|
|
1459
|
+
new x.SphereGeometry(this.nodeRadius, e, e)
|
|
1407
1460
|
);
|
|
1408
1461
|
});
|
|
1409
1462
|
}
|
|
@@ -1418,21 +1471,21 @@ class Mt {
|
|
|
1418
1471
|
* Creates a node visual (glass ball + label)
|
|
1419
1472
|
*/
|
|
1420
1473
|
createNode(e, s = 0) {
|
|
1421
|
-
const t = new
|
|
1474
|
+
const t = new x.Group();
|
|
1422
1475
|
t.name = `node-${e.id}`, t.userData = { nodeId: e.id, nodeData: e };
|
|
1423
1476
|
const i = this.getGeometry(s), o = this.materialFactory.createGlassMaterial(
|
|
1424
1477
|
e.color ?? this.defaultNodeColor
|
|
1425
|
-
),
|
|
1426
|
-
|
|
1427
|
-
const r = this.materialFactory.createLabelMaterial(e.label),
|
|
1428
|
-
return
|
|
1478
|
+
), n = new x.Mesh(i, o);
|
|
1479
|
+
n.castShadow = !0, n.receiveShadow = !0, t.add(n);
|
|
1480
|
+
const r = this.materialFactory.createLabelMaterial(e.label), h = new x.Sprite(r);
|
|
1481
|
+
return h.position.y = this.nodeRadius + 1.5, h.scale.set(4, 1, 1), t.add(h), e.position && t.position.set(
|
|
1429
1482
|
e.position.x,
|
|
1430
1483
|
e.position.y,
|
|
1431
1484
|
e.position.z
|
|
1432
1485
|
), {
|
|
1433
1486
|
group: t,
|
|
1434
|
-
sphere:
|
|
1435
|
-
label:
|
|
1487
|
+
sphere: n,
|
|
1488
|
+
label: h,
|
|
1436
1489
|
lodLevel: s
|
|
1437
1490
|
};
|
|
1438
1491
|
}
|
|
@@ -1448,19 +1501,19 @@ class Mt {
|
|
|
1448
1501
|
* Updates the color of a node
|
|
1449
1502
|
*/
|
|
1450
1503
|
updateNodeColor(e, s) {
|
|
1451
|
-
e.sphere.material instanceof
|
|
1504
|
+
e.sphere.material instanceof x.Material && e.sphere.material.dispose(), e.sphere.material = this.materialFactory.createGlassMaterial(s);
|
|
1452
1505
|
}
|
|
1453
1506
|
/**
|
|
1454
1507
|
* Updates the label of a node
|
|
1455
1508
|
*/
|
|
1456
1509
|
updateNodeLabel(e, s) {
|
|
1457
|
-
e.label.material instanceof
|
|
1510
|
+
e.label.material instanceof x.SpriteMaterial && (e.label.material.map && e.label.material.map.dispose(), e.label.material.dispose()), e.label.material = this.materialFactory.createLabelMaterial(s);
|
|
1458
1511
|
}
|
|
1459
1512
|
/**
|
|
1460
1513
|
* Disposes a node's resources
|
|
1461
1514
|
*/
|
|
1462
1515
|
disposeNode(e) {
|
|
1463
|
-
e.sphere.material instanceof
|
|
1516
|
+
e.sphere.material instanceof x.Material && e.sphere.material.dispose(), e.label.material instanceof x.SpriteMaterial && (e.label.material.map && e.label.material.map.dispose(), e.label.material.dispose());
|
|
1464
1517
|
}
|
|
1465
1518
|
/**
|
|
1466
1519
|
* Dispose factory resources
|
|
@@ -1497,7 +1550,7 @@ class wt {
|
|
|
1497
1550
|
* Creates an edge line between two positions
|
|
1498
1551
|
*/
|
|
1499
1552
|
createEdge(e, s, t, i, o) {
|
|
1500
|
-
const
|
|
1553
|
+
const n = new x.BufferGeometry(), r = new Float32Array([
|
|
1501
1554
|
i.x,
|
|
1502
1555
|
i.y,
|
|
1503
1556
|
i.z,
|
|
@@ -1505,16 +1558,16 @@ class wt {
|
|
|
1505
1558
|
o.y,
|
|
1506
1559
|
o.z
|
|
1507
1560
|
]);
|
|
1508
|
-
|
|
1509
|
-
const
|
|
1510
|
-
return
|
|
1561
|
+
n.setAttribute("position", new x.BufferAttribute(r, 3));
|
|
1562
|
+
const h = this.getDefaultMaterial().clone(), c = new x.Line(n, h);
|
|
1563
|
+
return c.name = `edge-${e.source}-${e.target}`, c.userData = {
|
|
1511
1564
|
source: e.source,
|
|
1512
1565
|
target: e.target,
|
|
1513
1566
|
edge: e,
|
|
1514
1567
|
sourceNode: s,
|
|
1515
1568
|
targetNode: t
|
|
1516
|
-
},
|
|
1517
|
-
line:
|
|
1569
|
+
}, c.frustumCulled = !0, {
|
|
1570
|
+
line: c,
|
|
1518
1571
|
source: e.source,
|
|
1519
1572
|
target: e.target
|
|
1520
1573
|
};
|
|
@@ -1523,13 +1576,13 @@ class wt {
|
|
|
1523
1576
|
* Highlights an edge
|
|
1524
1577
|
*/
|
|
1525
1578
|
highlightEdge(e) {
|
|
1526
|
-
e.line.material instanceof
|
|
1579
|
+
e.line.material instanceof x.Material && e.line.material.dispose(), e.line.material = this.getHighlightMaterial().clone();
|
|
1527
1580
|
}
|
|
1528
1581
|
/**
|
|
1529
1582
|
* Resets an edge to default appearance
|
|
1530
1583
|
*/
|
|
1531
1584
|
unhighlightEdge(e) {
|
|
1532
|
-
e.line.material instanceof
|
|
1585
|
+
e.line.material instanceof x.Material && e.line.material.dispose(), e.line.material = this.getDefaultMaterial().clone();
|
|
1533
1586
|
}
|
|
1534
1587
|
/**
|
|
1535
1588
|
* Updates an edge's positions
|
|
@@ -1542,7 +1595,7 @@ class wt {
|
|
|
1542
1595
|
* Disposes an edge's resources
|
|
1543
1596
|
*/
|
|
1544
1597
|
disposeEdge(e) {
|
|
1545
|
-
e.line.geometry.dispose(), e.line.material instanceof
|
|
1598
|
+
e.line.geometry.dispose(), e.line.material instanceof x.Material && e.line.material.dispose();
|
|
1546
1599
|
}
|
|
1547
1600
|
/**
|
|
1548
1601
|
* Dispose factory resources
|
|
@@ -1551,7 +1604,7 @@ class wt {
|
|
|
1551
1604
|
this.defaultMaterial && this.defaultMaterial.dispose(), this.highlightMaterial && this.highlightMaterial.dispose();
|
|
1552
1605
|
}
|
|
1553
1606
|
}
|
|
1554
|
-
class
|
|
1607
|
+
class Mt {
|
|
1555
1608
|
constructor(e, s = [50, 100, 200], t = !0) {
|
|
1556
1609
|
l(this, "camera");
|
|
1557
1610
|
l(this, "lodDistances");
|
|
@@ -1563,9 +1616,9 @@ class Et {
|
|
|
1563
1616
|
*/
|
|
1564
1617
|
getLODLevel(e) {
|
|
1565
1618
|
if (!this.enabled)
|
|
1566
|
-
return
|
|
1619
|
+
return _.HIGH;
|
|
1567
1620
|
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);
|
|
1568
|
-
return o < this.lodDistances[0] ?
|
|
1621
|
+
return o < this.lodDistances[0] ? _.HIGH : o < this.lodDistances[1] ? _.MEDIUM : _.LOW;
|
|
1569
1622
|
}
|
|
1570
1623
|
/**
|
|
1571
1624
|
* Checks if a node should be visible based on distance
|
|
@@ -1587,13 +1640,13 @@ class Et {
|
|
|
1587
1640
|
this.enabled = e;
|
|
1588
1641
|
}
|
|
1589
1642
|
}
|
|
1590
|
-
class
|
|
1643
|
+
class Et {
|
|
1591
1644
|
constructor(e, s = !0) {
|
|
1592
1645
|
l(this, "camera");
|
|
1593
1646
|
l(this, "frustum");
|
|
1594
1647
|
l(this, "projScreenMatrix");
|
|
1595
1648
|
l(this, "enabled");
|
|
1596
|
-
this.camera = e, this.frustum = new
|
|
1649
|
+
this.camera = e, this.frustum = new x.Frustum(), this.projScreenMatrix = new x.Matrix4(), this.enabled = s;
|
|
1597
1650
|
}
|
|
1598
1651
|
/**
|
|
1599
1652
|
* Updates the frustum from the camera
|
|
@@ -1609,7 +1662,7 @@ class Ct {
|
|
|
1609
1662
|
*/
|
|
1610
1663
|
isPointVisible(e) {
|
|
1611
1664
|
if (!this.enabled) return !0;
|
|
1612
|
-
const s = new
|
|
1665
|
+
const s = new x.Vector3(e.x, e.y, e.z);
|
|
1613
1666
|
return this.frustum.containsPoint(s);
|
|
1614
1667
|
}
|
|
1615
1668
|
/**
|
|
@@ -1617,8 +1670,8 @@ class Ct {
|
|
|
1617
1670
|
*/
|
|
1618
1671
|
isSphereVisible(e, s) {
|
|
1619
1672
|
if (!this.enabled) return !0;
|
|
1620
|
-
const t = new
|
|
1621
|
-
new
|
|
1673
|
+
const t = new x.Sphere(
|
|
1674
|
+
new x.Vector3(e.x, e.y, e.z),
|
|
1622
1675
|
s
|
|
1623
1676
|
);
|
|
1624
1677
|
return this.frustum.intersectsSphere(t);
|
|
@@ -1628,14 +1681,14 @@ class Ct {
|
|
|
1628
1681
|
*/
|
|
1629
1682
|
isLineVisible(e, s) {
|
|
1630
1683
|
if (!this.enabled) return !0;
|
|
1631
|
-
const t = new
|
|
1684
|
+
const t = new x.Vector3(e.x, e.y, e.z), i = new x.Vector3(s.x, s.y, s.z);
|
|
1632
1685
|
if (this.frustum.containsPoint(t) || this.frustum.containsPoint(i))
|
|
1633
1686
|
return !0;
|
|
1634
|
-
const o = new
|
|
1687
|
+
const o = new x.Vector3(
|
|
1635
1688
|
(e.x + s.x) / 2,
|
|
1636
1689
|
(e.y + s.y) / 2,
|
|
1637
1690
|
(e.z + s.z) / 2
|
|
1638
|
-
),
|
|
1691
|
+
), n = o.distanceTo(t), r = new x.Sphere(o, n);
|
|
1639
1692
|
return this.frustum.intersectsSphere(r);
|
|
1640
1693
|
}
|
|
1641
1694
|
/**
|
|
@@ -1645,7 +1698,7 @@ class Ct {
|
|
|
1645
1698
|
this.enabled = e;
|
|
1646
1699
|
}
|
|
1647
1700
|
}
|
|
1648
|
-
class
|
|
1701
|
+
class Ct {
|
|
1649
1702
|
constructor(e, s) {
|
|
1650
1703
|
l(this, "sceneManager");
|
|
1651
1704
|
l(this, "raycaster");
|
|
@@ -1659,7 +1712,7 @@ class Nt {
|
|
|
1659
1712
|
l(this, "hoveredEdgeKey", null);
|
|
1660
1713
|
l(this, "nodeObjects", []);
|
|
1661
1714
|
l(this, "edgeObjects", []);
|
|
1662
|
-
this.sceneManager = e, this.container = s, this.raycaster = new
|
|
1715
|
+
this.sceneManager = e, this.container = s, this.raycaster = new x.Raycaster(), this.raycaster.params.Line = { threshold: 1.5 }, this.mouse = new x.Vector2(), this.handleClick = this.handleClick.bind(this), this.handleMouseMove = this.handleMouseMove.bind(this), s.addEventListener("click", this.handleClick), s.addEventListener("mousemove", this.handleMouseMove);
|
|
1663
1716
|
}
|
|
1664
1717
|
/**
|
|
1665
1718
|
* Updates the list of node objects to raycast against
|
|
@@ -1748,13 +1801,17 @@ class Nt {
|
|
|
1748
1801
|
const t = this.raycaster.intersectObjects(this.edgeObjects, !1);
|
|
1749
1802
|
if (t.length > 0) {
|
|
1750
1803
|
const i = t[0].object, o = i.userData;
|
|
1751
|
-
if (o != null && o.edge && (o != null && o.sourceNode) && (o != null && o.targetNode))
|
|
1804
|
+
if (o != null && o.edge && (o != null && o.sourceNode) && (o != null && o.targetNode)) {
|
|
1805
|
+
const n = Array.isArray(o.relationships) ? o.relationships : [o.edge];
|
|
1752
1806
|
return {
|
|
1753
1807
|
edge: o.edge,
|
|
1808
|
+
relationships: n,
|
|
1809
|
+
relationshipCount: typeof o.relationshipCount == "number" ? o.relationshipCount : n.length,
|
|
1754
1810
|
sourceNode: o.sourceNode,
|
|
1755
1811
|
targetNode: o.targetNode,
|
|
1756
1812
|
edgeLine: i
|
|
1757
1813
|
};
|
|
1814
|
+
}
|
|
1758
1815
|
}
|
|
1759
1816
|
return null;
|
|
1760
1817
|
}
|
|
@@ -1767,11 +1824,11 @@ class Nt {
|
|
|
1767
1824
|
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);
|
|
1768
1825
|
const i = this.raycaster.intersectObjects(this.nodeObjects, !0);
|
|
1769
1826
|
if (i.length > 0) {
|
|
1770
|
-
let
|
|
1771
|
-
for (;
|
|
1772
|
-
if ((o =
|
|
1773
|
-
return
|
|
1774
|
-
|
|
1827
|
+
let n = i[0].object;
|
|
1828
|
+
for (; n; ) {
|
|
1829
|
+
if ((o = n.userData) != null && o.nodeId)
|
|
1830
|
+
return n.userData.nodeId;
|
|
1831
|
+
n = n.parent;
|
|
1775
1832
|
}
|
|
1776
1833
|
}
|
|
1777
1834
|
return null;
|
|
@@ -1783,7 +1840,7 @@ class Nt {
|
|
|
1783
1840
|
this.container.removeEventListener("click", this.handleClick), this.container.removeEventListener("mousemove", this.handleMouseMove);
|
|
1784
1841
|
}
|
|
1785
1842
|
}
|
|
1786
|
-
class
|
|
1843
|
+
class Nt {
|
|
1787
1844
|
constructor(e) {
|
|
1788
1845
|
l(this, "container");
|
|
1789
1846
|
l(this, "panel", null);
|
|
@@ -1806,17 +1863,15 @@ class St {
|
|
|
1806
1863
|
width: 280px;
|
|
1807
1864
|
max-height: 80vh;
|
|
1808
1865
|
overflow-y: auto;
|
|
1809
|
-
background: rgba(
|
|
1866
|
+
background: rgba(255, 255, 255, 0.08);
|
|
1810
1867
|
backdrop-filter: blur(20px);
|
|
1811
1868
|
-webkit-backdrop-filter: blur(20px);
|
|
1812
|
-
border: 1px solid rgba(255, 255, 255, 0.
|
|
1813
|
-
border-radius:
|
|
1869
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
1870
|
+
border-radius: 12px;
|
|
1814
1871
|
padding: 24px;
|
|
1815
1872
|
color: white;
|
|
1816
|
-
font-family:
|
|
1817
|
-
box-shadow:
|
|
1818
|
-
0 8px 32px rgba(0, 0, 0, 0.4),
|
|
1819
|
-
inset 0 0 0 1px rgba(255, 255, 255, 0.05);
|
|
1873
|
+
font-family: inherit;
|
|
1874
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
|
1820
1875
|
z-index: 1000;
|
|
1821
1876
|
opacity: 0;
|
|
1822
1877
|
pointer-events: none;
|
|
@@ -1852,16 +1907,9 @@ class St {
|
|
|
1852
1907
|
if (!this.panel) return;
|
|
1853
1908
|
this.currentNodeId = e.id;
|
|
1854
1909
|
let t;
|
|
1855
|
-
this.panelTemplate ? t = this.panelTemplate(e, s) : t = this.generateDefaultContent(e, s), this.panel.innerHTML = t;
|
|
1856
|
-
const i = this.panel.querySelector('[data-action="
|
|
1857
|
-
i &&
|
|
1858
|
-
if (this.currentNodeId) {
|
|
1859
|
-
const r = o ? parseInt(o.value, 10) : 1;
|
|
1860
|
-
this.onExpand(this.currentNodeId, r);
|
|
1861
|
-
}
|
|
1862
|
-
});
|
|
1863
|
-
const a = this.panel.querySelector('[data-action="close"]');
|
|
1864
|
-
a && a.addEventListener("click", () => {
|
|
1910
|
+
this.panelTemplate ? t = this.panelTemplate(e, s) : t = this.generateDefaultContent(e, s), this.panel.innerHTML = t, this.onExpand;
|
|
1911
|
+
const i = this.panel.querySelector('[data-action="close"]');
|
|
1912
|
+
i && i.addEventListener("click", () => {
|
|
1865
1913
|
this.hide();
|
|
1866
1914
|
}), this.panel.style.opacity = "1", this.panel.style.pointerEvents = "auto", this.panel.style.transform = "translateY(-50%) translateX(0)", this.visible = !0;
|
|
1867
1915
|
}
|
|
@@ -1874,8 +1922,8 @@ class St {
|
|
|
1874
1922
|
<style>
|
|
1875
1923
|
.force-graph-panel h2 {
|
|
1876
1924
|
margin: 0 0 16px 0;
|
|
1877
|
-
font-size:
|
|
1878
|
-
font-weight:
|
|
1925
|
+
font-size: 19px;
|
|
1926
|
+
font-weight: 650;
|
|
1879
1927
|
letter-spacing: -0.5px;
|
|
1880
1928
|
display: flex;
|
|
1881
1929
|
align-items: center;
|
|
@@ -1893,13 +1941,13 @@ class St {
|
|
|
1893
1941
|
height: 12px;
|
|
1894
1942
|
border-radius: 50%;
|
|
1895
1943
|
background: ${t};
|
|
1896
|
-
box-shadow: 0 0
|
|
1944
|
+
box-shadow: 0 0 12px ${t}80;
|
|
1897
1945
|
}
|
|
1898
1946
|
.force-graph-panel .info-row {
|
|
1899
1947
|
display: flex;
|
|
1900
1948
|
justify-content: space-between;
|
|
1901
1949
|
padding: 8px 0;
|
|
1902
|
-
border-bottom: 1px solid rgba(255, 255, 255, 0.
|
|
1950
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
|
1903
1951
|
font-size: 13px;
|
|
1904
1952
|
}
|
|
1905
1953
|
.force-graph-panel .info-row:last-child {
|
|
@@ -1919,51 +1967,27 @@ class St {
|
|
|
1919
1967
|
}
|
|
1920
1968
|
.force-graph-panel .neighbors-section {
|
|
1921
1969
|
margin-top: 16px;
|
|
1970
|
+
padding: 10px;
|
|
1971
|
+
background: rgba(255, 255, 255, 0.04);
|
|
1972
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
1973
|
+
border-radius: 10px;
|
|
1922
1974
|
}
|
|
1923
1975
|
.force-graph-panel .neighbors-title {
|
|
1924
1976
|
font-size: 12px;
|
|
1925
1977
|
text-transform: uppercase;
|
|
1926
1978
|
letter-spacing: 1px;
|
|
1927
|
-
color: rgba(255, 255, 255, 0.
|
|
1979
|
+
color: rgba(255, 255, 255, 0.55);
|
|
1928
1980
|
margin-bottom: 8px;
|
|
1929
1981
|
}
|
|
1930
1982
|
.force-graph-panel .neighbor-chip {
|
|
1931
1983
|
display: inline-block;
|
|
1932
1984
|
padding: 4px 10px;
|
|
1933
1985
|
margin: 2px;
|
|
1934
|
-
background: rgba(255, 255, 255, 0.
|
|
1986
|
+
background: rgba(255, 255, 255, 0.08);
|
|
1987
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
1935
1988
|
border-radius: 12px;
|
|
1936
1989
|
font-size: 12px;
|
|
1937
1990
|
}
|
|
1938
|
-
.force-graph-panel .depth-selector {
|
|
1939
|
-
margin-top: 16px;
|
|
1940
|
-
margin-bottom: 8px;
|
|
1941
|
-
}
|
|
1942
|
-
.force-graph-panel .depth-label {
|
|
1943
|
-
font-size: 12px;
|
|
1944
|
-
color: rgba(255, 255, 255, 0.6);
|
|
1945
|
-
margin-bottom: 6px;
|
|
1946
|
-
text-transform: uppercase;
|
|
1947
|
-
letter-spacing: 0.5px;
|
|
1948
|
-
}
|
|
1949
|
-
.force-graph-panel select {
|
|
1950
|
-
width: 100%;
|
|
1951
|
-
padding: 8px 12px;
|
|
1952
|
-
background: rgba(255, 255, 255, 0.1);
|
|
1953
|
-
border: 1px solid rgba(255, 255, 255, 0.15);
|
|
1954
|
-
border-radius: 6px;
|
|
1955
|
-
color: white;
|
|
1956
|
-
font-size: 13px;
|
|
1957
|
-
cursor: pointer;
|
|
1958
|
-
outline: none;
|
|
1959
|
-
transition: all 0.2s ease;
|
|
1960
|
-
}
|
|
1961
|
-
.force-graph-panel select:hover {
|
|
1962
|
-
background: rgba(255, 255, 255, 0.15);
|
|
1963
|
-
}
|
|
1964
|
-
.force-graph-panel select:focus {
|
|
1965
|
-
border-color: rgba(96, 165, 250, 0.5);
|
|
1966
|
-
}
|
|
1967
1991
|
.force-graph-panel .btn-row {
|
|
1968
1992
|
display: flex;
|
|
1969
1993
|
gap: 8px;
|
|
@@ -1972,28 +1996,24 @@ class St {
|
|
|
1972
1996
|
.force-graph-panel button {
|
|
1973
1997
|
flex: 1;
|
|
1974
1998
|
padding: 10px 16px;
|
|
1975
|
-
border:
|
|
1999
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
1976
2000
|
border-radius: 8px;
|
|
1977
2001
|
font-size: 13px;
|
|
1978
|
-
font-weight:
|
|
2002
|
+
font-weight: 600;
|
|
1979
2003
|
cursor: pointer;
|
|
1980
2004
|
transition: all 0.2s ease;
|
|
1981
2005
|
}
|
|
1982
|
-
.force-graph-panel .btn-expand {
|
|
1983
|
-
background: linear-gradient(135deg, #60a5fa, #a78bfa);
|
|
1984
|
-
color: white;
|
|
1985
|
-
}
|
|
1986
|
-
.force-graph-panel .btn-expand:hover {
|
|
1987
|
-
transform: translateY(-1px);
|
|
1988
|
-
box-shadow: 0 4px 12px rgba(96, 165, 250, 0.4);
|
|
1989
|
-
}
|
|
1990
2006
|
.force-graph-panel .btn-close {
|
|
1991
|
-
background: rgba(255, 255, 255, 0.
|
|
2007
|
+
background: rgba(255, 255, 255, 0.08);
|
|
1992
2008
|
color: rgba(255, 255, 255, 0.8);
|
|
1993
2009
|
}
|
|
1994
2010
|
.force-graph-panel .btn-close:hover {
|
|
1995
|
-
background: rgba(255, 255, 255, 0.
|
|
2011
|
+
background: rgba(255, 255, 255, 0.12);
|
|
1996
2012
|
}
|
|
2013
|
+
.force-graph-panel::-webkit-scrollbar { width: 6px; }
|
|
2014
|
+
.force-graph-panel::-webkit-scrollbar-track { background: transparent; }
|
|
2015
|
+
.force-graph-panel::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.15); border-radius: 3px; }
|
|
2016
|
+
.force-graph-panel::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.25); }
|
|
1997
2017
|
</style>
|
|
1998
2018
|
|
|
1999
2019
|
<h2>
|
|
@@ -2021,18 +2041,7 @@ class St {
|
|
|
2021
2041
|
</div>
|
|
2022
2042
|
` : ""}
|
|
2023
2043
|
|
|
2024
|
-
<div class="depth-selector">
|
|
2025
|
-
<div class="depth-label">Expansion Depth</div>
|
|
2026
|
-
<select data-depth-select>
|
|
2027
|
-
<option value="1">1 Level</option>
|
|
2028
|
-
<option value="2">2 Levels</option>
|
|
2029
|
-
<option value="3" selected>3 Levels</option>
|
|
2030
|
-
</select>
|
|
2031
|
-
</div>
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
2044
|
<div class="btn-row">
|
|
2035
|
-
<button class="btn-expand" data-action="expand">Expand</button>
|
|
2036
2045
|
<button class="btn-close" data-action="close">Close</button>
|
|
2037
2046
|
</div>
|
|
2038
2047
|
`;
|
|
@@ -2069,7 +2078,7 @@ class St {
|
|
|
2069
2078
|
this.panel && this.panel.parentNode && this.panel.parentNode.removeChild(this.panel), this.panel = null;
|
|
2070
2079
|
}
|
|
2071
2080
|
}
|
|
2072
|
-
class
|
|
2081
|
+
class St {
|
|
2073
2082
|
constructor(e) {
|
|
2074
2083
|
l(this, "container");
|
|
2075
2084
|
l(this, "panel", null);
|
|
@@ -2092,17 +2101,15 @@ class zt {
|
|
|
2092
2101
|
width: 300px;
|
|
2093
2102
|
max-height: 80vh;
|
|
2094
2103
|
overflow-y: auto;
|
|
2095
|
-
background: rgba(
|
|
2104
|
+
background: rgba(255, 255, 255, 0.08);
|
|
2096
2105
|
backdrop-filter: blur(20px);
|
|
2097
2106
|
-webkit-backdrop-filter: blur(20px);
|
|
2098
|
-
border: 1px solid rgba(255, 255, 255, 0.
|
|
2099
|
-
border-radius:
|
|
2107
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
2108
|
+
border-radius: 12px;
|
|
2100
2109
|
padding: 24px;
|
|
2101
2110
|
color: white;
|
|
2102
|
-
font-family:
|
|
2103
|
-
box-shadow:
|
|
2104
|
-
0 8px 32px rgba(0, 0, 0, 0.4),
|
|
2105
|
-
inset 0 0 0 1px rgba(255, 255, 255, 0.05);
|
|
2111
|
+
font-family: inherit;
|
|
2112
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
|
2106
2113
|
z-index: 1000;
|
|
2107
2114
|
opacity: 0;
|
|
2108
2115
|
pointer-events: none;
|
|
@@ -2130,29 +2137,34 @@ class zt {
|
|
|
2130
2137
|
/**
|
|
2131
2138
|
* Shows the panel with edge/relationship information
|
|
2132
2139
|
*/
|
|
2133
|
-
show(e, s, t) {
|
|
2140
|
+
show(e, s, t, i = [e]) {
|
|
2134
2141
|
if (!this.panel) return;
|
|
2135
2142
|
this.currentEdgeKey = `${e.source}-${e.target}`;
|
|
2136
|
-
let
|
|
2137
|
-
this.panelTemplate ?
|
|
2138
|
-
const
|
|
2139
|
-
|
|
2143
|
+
let o;
|
|
2144
|
+
this.panelTemplate ? o = this.panelTemplate(e, s, t) : o = this.generateDefaultContent(e, s, t, i), this.panel.innerHTML = o;
|
|
2145
|
+
const n = this.panel.querySelector('[data-action="close"]');
|
|
2146
|
+
n && n.addEventListener("click", () => {
|
|
2140
2147
|
this.hide(), this.onClose && this.onClose();
|
|
2141
2148
|
});
|
|
2142
|
-
const
|
|
2143
|
-
|
|
2149
|
+
const r = this.panel.querySelector('[data-action="goto-source"]');
|
|
2150
|
+
r && this.onNodeClick && r.addEventListener("click", () => {
|
|
2144
2151
|
this.onNodeClick && this.onNodeClick(e.source);
|
|
2145
2152
|
});
|
|
2146
|
-
const
|
|
2147
|
-
|
|
2153
|
+
const h = this.panel.querySelector('[data-action="goto-target"]');
|
|
2154
|
+
h && this.onNodeClick && h.addEventListener("click", () => {
|
|
2148
2155
|
this.onNodeClick && this.onNodeClick(e.target);
|
|
2149
2156
|
}), this.panel.style.opacity = "1", this.panel.style.pointerEvents = "auto", this.panel.style.transform = "translateY(-50%) translateX(0)", this.visible = !0;
|
|
2150
2157
|
}
|
|
2151
2158
|
/**
|
|
2152
2159
|
* Generates default panel content
|
|
2153
2160
|
*/
|
|
2154
|
-
generateDefaultContent(e, s, t) {
|
|
2155
|
-
const
|
|
2161
|
+
generateDefaultContent(e, s, t, i = [e]) {
|
|
2162
|
+
const o = s.color ? `#${s.color.toString(16).padStart(6, "0")}` : "#ff9966", n = t.color ? `#${t.color.toString(16).padStart(6, "0")}` : "#ff9966", r = this.getRelationshipLabel(e), h = i.length > 0 ? i : [e], c = this.summarizeRelationships(h), p = c.slice(0, 10).map((m) => `
|
|
2163
|
+
<div class="relationship-item">
|
|
2164
|
+
<span class="relationship-item-label">${this.escapeHtml(m.label)}</span>
|
|
2165
|
+
<span class="relationship-item-count">${m.count}</span>
|
|
2166
|
+
</div>
|
|
2167
|
+
`).join(""), f = c.length - Math.min(c.length, 10);
|
|
2156
2168
|
return `
|
|
2157
2169
|
<style>
|
|
2158
2170
|
.force-graph-edge-panel .panel-header {
|
|
@@ -2162,28 +2174,72 @@ class zt {
|
|
|
2162
2174
|
margin-bottom: 20px;
|
|
2163
2175
|
}
|
|
2164
2176
|
.force-graph-edge-panel .panel-title {
|
|
2165
|
-
font-size:
|
|
2177
|
+
font-size: 12px;
|
|
2166
2178
|
text-transform: uppercase;
|
|
2167
2179
|
letter-spacing: 1px;
|
|
2168
|
-
color: rgba(255, 255, 255, 0.
|
|
2180
|
+
color: rgba(255, 255, 255, 0.55);
|
|
2169
2181
|
margin: 0;
|
|
2170
2182
|
}
|
|
2171
2183
|
.force-graph-edge-panel .relationship-section {
|
|
2172
|
-
background: rgba(255, 255, 255, 0.
|
|
2184
|
+
background: rgba(255, 255, 255, 0.04);
|
|
2185
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
2173
2186
|
border-radius: 12px;
|
|
2174
2187
|
padding: 16px;
|
|
2175
2188
|
text-align: center;
|
|
2176
|
-
margin-bottom:
|
|
2189
|
+
margin-bottom: 14px;
|
|
2177
2190
|
}
|
|
2178
2191
|
.force-graph-edge-panel .relationship-label {
|
|
2179
2192
|
font-size: 18px;
|
|
2180
2193
|
font-weight: 600;
|
|
2181
|
-
color:
|
|
2194
|
+
color: rgba(255, 153, 102, 0.95);
|
|
2182
2195
|
letter-spacing: 0.5px;
|
|
2183
2196
|
}
|
|
2197
|
+
.force-graph-edge-panel .relationship-count {
|
|
2198
|
+
margin-top: 6px;
|
|
2199
|
+
font-size: 11px;
|
|
2200
|
+
text-transform: uppercase;
|
|
2201
|
+
letter-spacing: 0.8px;
|
|
2202
|
+
color: rgba(255, 255, 255, 0.6);
|
|
2203
|
+
}
|
|
2204
|
+
.force-graph-edge-panel .relationship-list {
|
|
2205
|
+
margin-bottom: 16px;
|
|
2206
|
+
max-height: 190px;
|
|
2207
|
+
overflow-y: auto;
|
|
2208
|
+
padding-right: 4px;
|
|
2209
|
+
}
|
|
2210
|
+
.force-graph-edge-panel .relationship-item {
|
|
2211
|
+
display: flex;
|
|
2212
|
+
justify-content: space-between;
|
|
2213
|
+
gap: 12px;
|
|
2214
|
+
padding: 8px 10px;
|
|
2215
|
+
background: rgba(255, 255, 255, 0.04);
|
|
2216
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
2217
|
+
border-radius: 8px;
|
|
2218
|
+
margin-bottom: 6px;
|
|
2219
|
+
}
|
|
2220
|
+
.force-graph-edge-panel .relationship-item-label {
|
|
2221
|
+
font-size: 12px;
|
|
2222
|
+
color: rgba(255, 255, 255, 0.88);
|
|
2223
|
+
overflow: hidden;
|
|
2224
|
+
text-overflow: ellipsis;
|
|
2225
|
+
white-space: nowrap;
|
|
2226
|
+
}
|
|
2227
|
+
.force-graph-edge-panel .relationship-item-count {
|
|
2228
|
+
font-size: 12px;
|
|
2229
|
+
font-weight: 700;
|
|
2230
|
+
color: rgba(255, 153, 102, 0.95);
|
|
2231
|
+
min-width: 24px;
|
|
2232
|
+
text-align: right;
|
|
2233
|
+
}
|
|
2234
|
+
.force-graph-edge-panel .relationship-more {
|
|
2235
|
+
font-size: 11px;
|
|
2236
|
+
color: rgba(255, 255, 255, 0.45);
|
|
2237
|
+
text-align: center;
|
|
2238
|
+
margin-top: 2px;
|
|
2239
|
+
}
|
|
2184
2240
|
.force-graph-edge-panel .node-card {
|
|
2185
|
-
background: rgba(255, 255, 255, 0.
|
|
2186
|
-
border: 1px solid rgba(255, 255, 255, 0.
|
|
2241
|
+
background: rgba(255, 255, 255, 0.06);
|
|
2242
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
2187
2243
|
border-radius: 12px;
|
|
2188
2244
|
padding: 14px;
|
|
2189
2245
|
margin-bottom: 12px;
|
|
@@ -2192,8 +2248,9 @@ class zt {
|
|
|
2192
2248
|
}
|
|
2193
2249
|
.force-graph-edge-panel .node-card:hover {
|
|
2194
2250
|
background: rgba(255, 255, 255, 0.1);
|
|
2195
|
-
border-color: rgba(255,
|
|
2251
|
+
border-color: rgba(255, 153, 102, 0.35);
|
|
2196
2252
|
transform: translateX(4px);
|
|
2253
|
+
box-shadow: 0 0 15px rgba(255, 153, 102, 0.15);
|
|
2197
2254
|
}
|
|
2198
2255
|
.force-graph-edge-panel .node-card-header {
|
|
2199
2256
|
display: flex;
|
|
@@ -2230,18 +2287,18 @@ class zt {
|
|
|
2230
2287
|
.force-graph-edge-panel .btn-close {
|
|
2231
2288
|
width: 100%;
|
|
2232
2289
|
padding: 12px 16px;
|
|
2233
|
-
border:
|
|
2290
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
2234
2291
|
border-radius: 8px;
|
|
2235
2292
|
font-size: 13px;
|
|
2236
|
-
font-weight:
|
|
2293
|
+
font-weight: 600;
|
|
2237
2294
|
cursor: pointer;
|
|
2238
2295
|
transition: all 0.2s ease;
|
|
2239
|
-
background: rgba(255, 255, 255, 0.
|
|
2296
|
+
background: rgba(255, 255, 255, 0.08);
|
|
2240
2297
|
color: rgba(255, 255, 255, 0.8);
|
|
2241
2298
|
margin-top: 16px;
|
|
2242
2299
|
}
|
|
2243
2300
|
.force-graph-edge-panel .btn-close:hover {
|
|
2244
|
-
background: rgba(255, 255, 255, 0.
|
|
2301
|
+
background: rgba(255, 255, 255, 0.12);
|
|
2245
2302
|
}
|
|
2246
2303
|
.force-graph-edge-panel .hint-text {
|
|
2247
2304
|
font-size: 11px;
|
|
@@ -2249,6 +2306,10 @@ class zt {
|
|
|
2249
2306
|
text-align: center;
|
|
2250
2307
|
margin-top: 8px;
|
|
2251
2308
|
}
|
|
2309
|
+
.force-graph-edge-panel .relationship-list::-webkit-scrollbar { width: 6px; }
|
|
2310
|
+
.force-graph-edge-panel .relationship-list::-webkit-scrollbar-track { background: transparent; }
|
|
2311
|
+
.force-graph-edge-panel .relationship-list::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.15); border-radius: 3px; }
|
|
2312
|
+
.force-graph-edge-panel .relationship-list::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.25); }
|
|
2252
2313
|
</style>
|
|
2253
2314
|
|
|
2254
2315
|
<div class="panel-header">
|
|
@@ -2256,13 +2317,19 @@ class zt {
|
|
|
2256
2317
|
</div>
|
|
2257
2318
|
|
|
2258
2319
|
<div class="relationship-section">
|
|
2259
|
-
<span class="relationship-label">${this.escapeHtml(
|
|
2320
|
+
<span class="relationship-label">${this.escapeHtml(r)}</span>
|
|
2321
|
+
<div class="relationship-count">${h.length} relationships</div>
|
|
2322
|
+
</div>
|
|
2323
|
+
|
|
2324
|
+
<div class="relationship-list">
|
|
2325
|
+
${p}
|
|
2326
|
+
${f > 0 ? `<div class="relationship-more">+ ${f} more</div>` : ""}
|
|
2260
2327
|
</div>
|
|
2261
2328
|
|
|
2262
2329
|
<div class="node-card" data-action="goto-source" title="Click to focus on ${this.escapeHtml(s.label)}">
|
|
2263
2330
|
<div class="node-type">Source</div>
|
|
2264
2331
|
<div class="node-card-header">
|
|
2265
|
-
<span class="color-dot" style="background: ${
|
|
2332
|
+
<span class="color-dot" style="background: ${o}; box-shadow: 0 0 8px ${o}80;"></span>
|
|
2266
2333
|
<span class="node-label">${this.escapeHtml(s.label)}</span>
|
|
2267
2334
|
</div>
|
|
2268
2335
|
</div>
|
|
@@ -2272,7 +2339,7 @@ class zt {
|
|
|
2272
2339
|
<div class="node-card" data-action="goto-target" title="Click to focus on ${this.escapeHtml(t.label)}">
|
|
2273
2340
|
<div class="node-type">Target</div>
|
|
2274
2341
|
<div class="node-card-header">
|
|
2275
|
-
<span class="color-dot" style="background: ${
|
|
2342
|
+
<span class="color-dot" style="background: ${n}; box-shadow: 0 0 8px ${n}80;"></span>
|
|
2276
2343
|
<span class="node-label">${this.escapeHtml(t.label)}</span>
|
|
2277
2344
|
</div>
|
|
2278
2345
|
</div>
|
|
@@ -2289,6 +2356,17 @@ class zt {
|
|
|
2289
2356
|
const s = document.createElement("div");
|
|
2290
2357
|
return s.textContent = e, s.innerHTML;
|
|
2291
2358
|
}
|
|
2359
|
+
getRelationshipLabel(e) {
|
|
2360
|
+
return e.relationship || e.label || "connected to";
|
|
2361
|
+
}
|
|
2362
|
+
summarizeRelationships(e) {
|
|
2363
|
+
const s = /* @__PURE__ */ new Map();
|
|
2364
|
+
for (const t of e) {
|
|
2365
|
+
const i = this.getRelationshipLabel(t);
|
|
2366
|
+
s.set(i, (s.get(i) || 0) + 1);
|
|
2367
|
+
}
|
|
2368
|
+
return Array.from(s.entries()).map(([t, i]) => ({ label: t, count: i })).sort((t, i) => i.count - t.count);
|
|
2369
|
+
}
|
|
2292
2370
|
/**
|
|
2293
2371
|
* Hides the panel
|
|
2294
2372
|
*/
|
|
@@ -2314,7 +2392,7 @@ class zt {
|
|
|
2314
2392
|
this.panel && this.panel.parentNode && this.panel.parentNode.removeChild(this.panel), this.panel = null;
|
|
2315
2393
|
}
|
|
2316
2394
|
}
|
|
2317
|
-
class
|
|
2395
|
+
class zt {
|
|
2318
2396
|
constructor() {
|
|
2319
2397
|
l(this, "tooltip", null);
|
|
2320
2398
|
l(this, "visible", !1);
|
|
@@ -2361,28 +2439,51 @@ class kt {
|
|
|
2361
2439
|
positionTooltip(e, s) {
|
|
2362
2440
|
if (!this.tooltip) return;
|
|
2363
2441
|
const t = this.tooltip.getBoundingClientRect(), i = window.innerWidth, o = window.innerHeight;
|
|
2364
|
-
let
|
|
2365
|
-
|
|
2442
|
+
let n = e + 15, r = s + 15;
|
|
2443
|
+
n + t.width > i - 10 && (n = e - t.width - 15), r + t.height > o - 10 && (r = s - t.height - 15), n < 10 && (n = 10), r < 10 && (r = 10), this.tooltip.style.left = `${n}px`, this.tooltip.style.top = `${r}px`;
|
|
2366
2444
|
}
|
|
2367
2445
|
/**
|
|
2368
2446
|
* Shows the tooltip with edge info
|
|
2369
2447
|
*/
|
|
2370
|
-
show(e, s, t, i, o) {
|
|
2448
|
+
show(e, s, t, i, o, n = [e]) {
|
|
2371
2449
|
if (!this.tooltip) return;
|
|
2372
|
-
const
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2450
|
+
const r = n.length > 0 ? n : [e], h = this.summarizeRelationships(r), c = r.length;
|
|
2451
|
+
if (c <= 1) {
|
|
2452
|
+
const p = this.getRelationshipLabel(r[0]);
|
|
2453
|
+
this.tooltip.innerHTML = `
|
|
2454
|
+
<div style="display: flex; flex-direction: column; gap: 4px;">
|
|
2455
|
+
<div style="display: flex; align-items: center; gap: 6px; flex-wrap: wrap;">
|
|
2456
|
+
<span style="font-weight: 600; color: #ff9966;">${this.escapeHtml(s.label)}</span>
|
|
2457
|
+
</div>
|
|
2458
|
+
<div style="color: rgba(255, 255, 255, 0.6); font-style: italic; font-size: 12px; padding-left: 8px;">
|
|
2459
|
+
↳ ${this.escapeHtml(p)}
|
|
2460
|
+
</div>
|
|
2461
|
+
<div style="display: flex; align-items: center; gap: 6px; flex-wrap: wrap;">
|
|
2462
|
+
<span style="font-weight: 600; color: #ff9966;">${this.escapeHtml(t.label)}</span>
|
|
2463
|
+
</div>
|
|
2380
2464
|
</div>
|
|
2381
|
-
|
|
2382
|
-
|
|
2465
|
+
`;
|
|
2466
|
+
} else {
|
|
2467
|
+
const p = h.slice(0, 4), f = h.length - p.length, m = p.map((u) => `<div style="display:flex; justify-content:space-between; gap:10px; font-size:12px; color: rgba(255,255,255,0.8);">
|
|
2468
|
+
<span style="overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">${this.escapeHtml(u.label)}</span>
|
|
2469
|
+
<span style="color: rgba(255,153,102,0.9); font-weight:600;">${u.count}</span>
|
|
2470
|
+
</div>`).join("");
|
|
2471
|
+
this.tooltip.innerHTML = `
|
|
2472
|
+
<div style="display:flex; flex-direction:column; gap:8px; min-width:220px;">
|
|
2473
|
+
<div style="font-size:13px; font-weight:600; color:#ff9966;">
|
|
2474
|
+
${this.escapeHtml(s.label)} → ${this.escapeHtml(t.label)}
|
|
2475
|
+
</div>
|
|
2476
|
+
<div style="font-size:11px; letter-spacing:0.4px; text-transform:uppercase; color: rgba(255,255,255,0.6);">
|
|
2477
|
+
${c} relationships
|
|
2478
|
+
</div>
|
|
2479
|
+
<div style="display:flex; flex-direction:column; gap:4px;">
|
|
2480
|
+
${m}
|
|
2481
|
+
</div>
|
|
2482
|
+
${f > 0 ? `<div style="font-size:11px; color: rgba(255,255,255,0.45);">+ ${f} more</div>` : ""}
|
|
2383
2483
|
</div>
|
|
2384
|
-
|
|
2385
|
-
|
|
2484
|
+
`;
|
|
2485
|
+
}
|
|
2486
|
+
this.positionTooltip(i, o), this.tooltip.style.opacity = "1", this.tooltip.style.transform = "translateY(0)", this.visible = !0;
|
|
2386
2487
|
}
|
|
2387
2488
|
/**
|
|
2388
2489
|
* Updates tooltip position (called externally on mouse move)
|
|
@@ -2409,6 +2510,17 @@ class kt {
|
|
|
2409
2510
|
const s = document.createElement("div");
|
|
2410
2511
|
return s.textContent = e, s.innerHTML;
|
|
2411
2512
|
}
|
|
2513
|
+
getRelationshipLabel(e) {
|
|
2514
|
+
return e.relationship || e.label || "connected to";
|
|
2515
|
+
}
|
|
2516
|
+
summarizeRelationships(e) {
|
|
2517
|
+
const s = /* @__PURE__ */ new Map();
|
|
2518
|
+
for (const t of e) {
|
|
2519
|
+
const i = this.getRelationshipLabel(t);
|
|
2520
|
+
s.set(i, (s.get(i) || 0) + 1);
|
|
2521
|
+
}
|
|
2522
|
+
return Array.from(s.entries()).map(([t, i]) => ({ label: t, count: i })).sort((t, i) => i.count - t.count);
|
|
2523
|
+
}
|
|
2412
2524
|
/**
|
|
2413
2525
|
* Dispose the tooltip
|
|
2414
2526
|
*/
|
|
@@ -2416,7 +2528,7 @@ class kt {
|
|
|
2416
2528
|
this.tooltip && this.tooltip.parentNode && this.tooltip.parentNode.removeChild(this.tooltip), this.tooltip = null;
|
|
2417
2529
|
}
|
|
2418
2530
|
}
|
|
2419
|
-
class
|
|
2531
|
+
class kt {
|
|
2420
2532
|
constructor(e, s) {
|
|
2421
2533
|
l(this, "container");
|
|
2422
2534
|
l(this, "searchContainer", null);
|
|
@@ -2561,24 +2673,24 @@ class Tt {
|
|
|
2561
2673
|
}
|
|
2562
2674
|
let i = "";
|
|
2563
2675
|
s.length > 0 && (i += '<div class="f3d-search-section-header">Nodes</div>', s.slice(0, 10).forEach((o) => {
|
|
2564
|
-
const
|
|
2676
|
+
const n = o.type || "Node";
|
|
2565
2677
|
i += `
|
|
2566
2678
|
<div class="f3d-search-result-item" data-node-id="${this.escapeHtml(o.id)}">
|
|
2567
2679
|
<div class="f3d-result-label">${this.escapeHtml(o.label)}</div>
|
|
2568
|
-
<div class="f3d-result-type">${this.escapeHtml(
|
|
2680
|
+
<div class="f3d-result-type">${this.escapeHtml(n)}</div>
|
|
2569
2681
|
</div>
|
|
2570
2682
|
`;
|
|
2571
|
-
}), 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:
|
|
2683
|
+
}), 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: n, targetNode: r }) => {
|
|
2572
2684
|
i += `
|
|
2573
2685
|
<div class="f3d-search-result-item" data-node-id="${this.escapeHtml(o.source)}">
|
|
2574
|
-
<div class="f3d-result-label">${this.escapeHtml(
|
|
2686
|
+
<div class="f3d-result-label">${this.escapeHtml(n.label)} → ${this.escapeHtml(r.label)}</div>
|
|
2575
2687
|
<div class="f3d-result-relationship">${this.escapeHtml(o.relationship || "connected")}</div>
|
|
2576
2688
|
</div>
|
|
2577
2689
|
`;
|
|
2578
2690
|
}), 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) => {
|
|
2579
2691
|
o.addEventListener("click", () => {
|
|
2580
|
-
const
|
|
2581
|
-
|
|
2692
|
+
const n = o.dataset.nodeId;
|
|
2693
|
+
n && (this.onResultClick(n), this.searchResults && (this.searchResults.style.display = "none"), this.searchInput && this.searchInput.blur());
|
|
2582
2694
|
});
|
|
2583
2695
|
});
|
|
2584
2696
|
}
|
|
@@ -2590,7 +2702,7 @@ class Tt {
|
|
|
2590
2702
|
this.searchContainer && this.searchContainer.parentNode && this.searchContainer.parentNode.removeChild(this.searchContainer);
|
|
2591
2703
|
}
|
|
2592
2704
|
}
|
|
2593
|
-
class
|
|
2705
|
+
class Tt {
|
|
2594
2706
|
constructor(e, s) {
|
|
2595
2707
|
l(this, "container");
|
|
2596
2708
|
l(this, "toggleContainer", null);
|
|
@@ -2682,7 +2794,7 @@ class Pt {
|
|
|
2682
2794
|
this.toggleContainer && this.toggleContainer.parentNode && this.toggleContainer.parentNode.removeChild(this.toggleContainer);
|
|
2683
2795
|
}
|
|
2684
2796
|
}
|
|
2685
|
-
class
|
|
2797
|
+
class Pt {
|
|
2686
2798
|
constructor(e) {
|
|
2687
2799
|
l(this, "container");
|
|
2688
2800
|
l(this, "legendContainer", null);
|
|
@@ -2778,7 +2890,7 @@ const Rt = {
|
|
|
2778
2890
|
damping: 0.85
|
|
2779
2891
|
// Fast energy dissipation
|
|
2780
2892
|
};
|
|
2781
|
-
class
|
|
2893
|
+
class Lt {
|
|
2782
2894
|
constructor(e, s = {}) {
|
|
2783
2895
|
l(this, "container");
|
|
2784
2896
|
l(this, "canvas");
|
|
@@ -2818,21 +2930,21 @@ class It {
|
|
|
2818
2930
|
setupInteractions() {
|
|
2819
2931
|
this.canvas.addEventListener("wheel", (e) => {
|
|
2820
2932
|
e.preventDefault();
|
|
2821
|
-
const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, o = e.deltaY > 0 ? 0.9 : 1.1,
|
|
2822
|
-
this.transform.x = t - (t - this.transform.x) * r, this.transform.y = i - (i - this.transform.y) * r, this.transform.scale =
|
|
2933
|
+
const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, o = e.deltaY > 0 ? 0.9 : 1.1, n = Math.max(0.1, Math.min(5, this.transform.scale * o)), r = n / this.transform.scale;
|
|
2934
|
+
this.transform.x = t - (t - this.transform.x) * r, this.transform.y = i - (i - this.transform.y) * r, this.transform.scale = n;
|
|
2823
2935
|
}), this.canvas.addEventListener("mousedown", (e) => {
|
|
2824
|
-
const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, o = this.screenToWorld(t, i),
|
|
2825
|
-
this.dragStartPos = { x: e.clientX, y: e.clientY },
|
|
2936
|
+
const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, o = this.screenToWorld(t, i), n = this.findNodeAt(o.x, o.y);
|
|
2937
|
+
this.dragStartPos = { x: e.clientX, y: e.clientY }, n ? (this.isDragging = !0, this.draggedNode = n, this.canvas.style.cursor = "grabbing", this.isSimulating = !0) : (this.isPanning = !0, this.canvas.style.cursor = "grabbing"), this.lastMousePos = { x: e.clientX, y: e.clientY };
|
|
2826
2938
|
}), this.canvas.addEventListener("mousemove", (e) => {
|
|
2827
2939
|
const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, i = e.clientY - s.top, o = this.screenToWorld(t, i);
|
|
2828
2940
|
if (this.isDragging && this.draggedNode)
|
|
2829
2941
|
this.draggedNode.x = o.x, this.draggedNode.y = o.y, this.draggedNode.vx = 0, this.draggedNode.vy = 0;
|
|
2830
2942
|
else if (this.isPanning) {
|
|
2831
|
-
const
|
|
2832
|
-
this.transform.x +=
|
|
2943
|
+
const n = e.clientX - this.lastMousePos.x, r = e.clientY - this.lastMousePos.y;
|
|
2944
|
+
this.transform.x += n, this.transform.y += r, this.lastMousePos = { x: e.clientX, y: e.clientY };
|
|
2833
2945
|
} else {
|
|
2834
|
-
const
|
|
2835
|
-
if (
|
|
2946
|
+
const n = this.findNodeAt(o.x, o.y);
|
|
2947
|
+
if (n !== this.hoveredNode && (this.hoveredNode = n, n ? (this.hoveredEdge && (this.hoveredEdge = null, this.options.onEdgeHover && this.options.onEdgeHover(null)), this.canvas.style.cursor = "pointer", this.options.onNodeHover && this.options.onNodeHover(n.data)) : this.options.onNodeHover && this.options.onNodeHover(null)), !n) {
|
|
2836
2948
|
const r = this.findEdgeAt(o.x, o.y);
|
|
2837
2949
|
r !== this.hoveredEdge && (this.hoveredEdge = r, this.canvas.style.cursor = r ? "pointer" : "grab", this.options.onEdgeHover && this.options.onEdgeHover(r ? r.data : null, e));
|
|
2838
2950
|
}
|
|
@@ -2842,7 +2954,7 @@ class It {
|
|
|
2842
2954
|
if (this.isDragging && this.draggedNode)
|
|
2843
2955
|
i && this.options.onNodeClick && (this.selectedNode = this.draggedNode, this.options.onNodeClick(this.draggedNode.data));
|
|
2844
2956
|
else if (i) {
|
|
2845
|
-
const o = this.canvas.getBoundingClientRect(),
|
|
2957
|
+
const o = this.canvas.getBoundingClientRect(), n = this.screenToWorld(e.clientX - o.left, e.clientY - o.top), r = this.findEdgeAt(n.x, n.y);
|
|
2846
2958
|
r && this.options.onEdgeClick && this.options.onEdgeClick(r.data);
|
|
2847
2959
|
}
|
|
2848
2960
|
this.isDragging = !1, this.isPanning = !1, this.draggedNode = null, this.canvas.style.cursor = this.hoveredNode ? "pointer" : "grab";
|
|
@@ -2866,12 +2978,12 @@ class It {
|
|
|
2866
2978
|
}
|
|
2867
2979
|
findEdgeAt(e, s) {
|
|
2868
2980
|
for (const i of this.edges) {
|
|
2869
|
-
const o = this.nodes.get(i.source),
|
|
2870
|
-
if (!o || !
|
|
2871
|
-
const r =
|
|
2872
|
-
if (
|
|
2873
|
-
const p = Math.max(0, Math.min(1, ((e - o.x) * r + (s - o.y) *
|
|
2874
|
-
if (Math.sqrt(u * u +
|
|
2981
|
+
const o = this.nodes.get(i.source), n = this.nodes.get(i.target);
|
|
2982
|
+
if (!o || !n) continue;
|
|
2983
|
+
const r = n.x - o.x, h = n.y - o.y, c = r * r + h * h;
|
|
2984
|
+
if (c === 0) continue;
|
|
2985
|
+
const p = Math.max(0, Math.min(1, ((e - o.x) * r + (s - o.y) * h) / c)), f = o.x + p * r, m = o.y + p * h, u = e - f, y = s - m;
|
|
2986
|
+
if (Math.sqrt(u * u + y * y) < 12)
|
|
2875
2987
|
return i;
|
|
2876
2988
|
}
|
|
2877
2989
|
return null;
|
|
@@ -2888,29 +3000,29 @@ class It {
|
|
|
2888
3000
|
const t = 60, i = 5;
|
|
2889
3001
|
let o = 0;
|
|
2890
3002
|
for (let r = 0; r < s; r++)
|
|
2891
|
-
for (let
|
|
2892
|
-
const
|
|
2893
|
-
let
|
|
3003
|
+
for (let h = r + 1; h < s; h++) {
|
|
3004
|
+
const c = e[r], p = e[h];
|
|
3005
|
+
let f = p.x - c.x, m = p.y - c.y, u = Math.sqrt(f * f + m * m);
|
|
2894
3006
|
if (u < t * 3) {
|
|
2895
3007
|
u < 1 && (u = 1);
|
|
2896
|
-
const
|
|
2897
|
-
|
|
3008
|
+
const y = this.options.repulsionStrength / (u * u), b = f / u * y, w = m / u * y;
|
|
3009
|
+
c.vx -= b, c.vy -= w, p.vx += b, p.vy += w;
|
|
2898
3010
|
}
|
|
2899
3011
|
}
|
|
2900
|
-
const
|
|
3012
|
+
const n = 80;
|
|
2901
3013
|
for (const r of this.edges) {
|
|
2902
|
-
const
|
|
2903
|
-
if (!
|
|
2904
|
-
let p =
|
|
3014
|
+
const h = this.nodes.get(r.source), c = this.nodes.get(r.target);
|
|
3015
|
+
if (!h || !c) continue;
|
|
3016
|
+
let p = c.x - h.x, f = c.y - h.y, m = Math.sqrt(p * p + f * f);
|
|
2905
3017
|
m < 1 && (m = 1);
|
|
2906
|
-
const
|
|
2907
|
-
|
|
3018
|
+
const y = (m - n) * this.options.attractionStrength, b = p / m * y, w = f / m * y;
|
|
3019
|
+
h.vx += b, h.vy += w, c.vx -= b, c.vy -= w;
|
|
2908
3020
|
}
|
|
2909
3021
|
for (const r of e) {
|
|
2910
3022
|
if (this.draggedNode === r) continue;
|
|
2911
3023
|
r.vx *= this.options.damping, r.vy *= this.options.damping;
|
|
2912
|
-
const
|
|
2913
|
-
|
|
3024
|
+
const h = Math.sqrt(r.vx * r.vx + r.vy * r.vy);
|
|
3025
|
+
h > i && (r.vx = r.vx / h * i, r.vy = r.vy / h * i), r.x += r.vx, r.y += r.vy, o += r.vx * r.vx + r.vy * r.vy;
|
|
2914
3026
|
}
|
|
2915
3027
|
o < 0.01 && !this.draggedNode && (this.isSimulating = !1);
|
|
2916
3028
|
}
|
|
@@ -2919,49 +3031,49 @@ class It {
|
|
|
2919
3031
|
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();
|
|
2920
3032
|
}
|
|
2921
3033
|
renderGrid(e, s) {
|
|
2922
|
-
const t = this.ctx, i = 40 * this.transform.scale, o = 1.5,
|
|
3034
|
+
const t = this.ctx, i = 40 * this.transform.scale, o = 1.5, n = this.transform.x % i, r = this.transform.y % i;
|
|
2923
3035
|
t.fillStyle = this.options.gridColor;
|
|
2924
|
-
for (let
|
|
2925
|
-
for (let
|
|
2926
|
-
t.beginPath(), t.arc(
|
|
3036
|
+
for (let h = n; h < e; h += i)
|
|
3037
|
+
for (let c = r; c < s; c += i)
|
|
3038
|
+
t.beginPath(), t.arc(h, c, o, 0, Math.PI * 2), t.fill();
|
|
2927
3039
|
}
|
|
2928
3040
|
renderEdges() {
|
|
2929
3041
|
const e = this.ctx;
|
|
2930
3042
|
for (const s of this.edges) {
|
|
2931
3043
|
const t = this.nodes.get(s.source), i = this.nodes.get(s.target);
|
|
2932
3044
|
if (!t || !i) continue;
|
|
2933
|
-
const o = s === this.hoveredEdge,
|
|
2934
|
-
o ? (
|
|
3045
|
+
const o = s === this.hoveredEdge, n = e.createLinearGradient(t.x, t.y, i.x, i.y);
|
|
3046
|
+
o ? (n.addColorStop(0, "rgba(255, 153, 102, 0.8)"), n.addColorStop(0.5, "rgba(255, 255, 255, 0.5)"), n.addColorStop(1, "rgba(102, 153, 255, 0.8)"), e.lineWidth = 3) : (n.addColorStop(0, "rgba(255, 153, 102, 0.3)"), n.addColorStop(0.5, "rgba(255, 255, 255, 0.15)"), n.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 = n, e.stroke();
|
|
2935
3047
|
}
|
|
2936
3048
|
}
|
|
2937
3049
|
renderNodes() {
|
|
2938
3050
|
const e = this.ctx;
|
|
2939
3051
|
for (const s of this.nodes.values()) {
|
|
2940
|
-
const t = s === this.hoveredNode, i = s === this.selectedNode, o = this.hoveredEdge && (s.data.id === this.hoveredEdge.source || s.data.id === this.hoveredEdge.target),
|
|
3052
|
+
const t = s === this.hoveredNode, i = s === this.selectedNode, o = this.hoveredEdge && (s.data.id === this.hoveredEdge.source || s.data.id === this.hoveredEdge.target), n = s.radius * (t ? 1.1 : 1);
|
|
2941
3053
|
if (t || i || o) {
|
|
2942
|
-
const
|
|
3054
|
+
const y = e.createRadialGradient(
|
|
2943
3055
|
s.x,
|
|
2944
3056
|
s.y,
|
|
2945
|
-
|
|
3057
|
+
n * 0.5,
|
|
2946
3058
|
s.x,
|
|
2947
3059
|
s.y,
|
|
2948
|
-
|
|
3060
|
+
n * 2
|
|
2949
3061
|
), b = t || i ? 0.4 : 0.25;
|
|
2950
|
-
|
|
3062
|
+
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, n * 2, 0, Math.PI * 2), e.fill();
|
|
2951
3063
|
}
|
|
2952
3064
|
const r = e.createRadialGradient(
|
|
2953
|
-
s.x -
|
|
2954
|
-
s.y -
|
|
3065
|
+
s.x - n * 0.3,
|
|
3066
|
+
s.y - n * 0.3,
|
|
2955
3067
|
0,
|
|
2956
3068
|
s.x,
|
|
2957
3069
|
s.y,
|
|
2958
|
-
|
|
2959
|
-
),
|
|
2960
|
-
r.addColorStop(0, `rgba(${Math.min(255,
|
|
2961
|
-
const
|
|
3070
|
+
n
|
|
3071
|
+
), h = s.color >> 16 & 255, c = s.color >> 8 & 255, p = s.color & 255;
|
|
3072
|
+
r.addColorStop(0, `rgba(${Math.min(255, h + 60)}, ${Math.min(255, c + 60)}, ${Math.min(255, p + 60)}, 0.95)`), r.addColorStop(0.7, `rgba(${h}, ${c}, ${p}, 0.9)`), r.addColorStop(1, `rgba(${Math.max(0, h - 40)}, ${Math.max(0, c - 40)}, ${Math.max(0, p - 40)}, 0.85)`), e.beginPath(), e.arc(s.x, s.y, n, 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 - n * 0.25, s.y - n * 0.25, n * 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";
|
|
3073
|
+
const f = n * 1.6;
|
|
2962
3074
|
let m = s.label, u = e.measureText(m).width;
|
|
2963
|
-
if (u >
|
|
2964
|
-
for (; u >
|
|
3075
|
+
if (u > f) {
|
|
3076
|
+
for (; u > f && m.length > 3; )
|
|
2965
3077
|
m = m.slice(0, -1), u = e.measureText(m + "...").width;
|
|
2966
3078
|
m += "...";
|
|
2967
3079
|
}
|
|
@@ -3064,11 +3176,11 @@ class It {
|
|
|
3064
3176
|
focusOnNode(e) {
|
|
3065
3177
|
const s = this.nodes.get(e);
|
|
3066
3178
|
if (!s) return;
|
|
3067
|
-
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,
|
|
3068
|
-
const p = performance.now() -
|
|
3069
|
-
this.transform.x = o + (t - o) * m, this.transform.y =
|
|
3179
|
+
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, n = this.transform.y, r = 500, h = performance.now(), c = () => {
|
|
3180
|
+
const p = performance.now() - h, f = Math.min(p / r, 1), m = 1 - Math.pow(1 - f, 3);
|
|
3181
|
+
this.transform.x = o + (t - o) * m, this.transform.y = n + (i - n) * m, f < 1 ? requestAnimationFrame(c) : this.selectedNode = s;
|
|
3070
3182
|
};
|
|
3071
|
-
|
|
3183
|
+
c();
|
|
3072
3184
|
}
|
|
3073
3185
|
/**
|
|
3074
3186
|
* Updates node positions from 3D data
|
|
@@ -3146,7 +3258,7 @@ class Ht {
|
|
|
3146
3258
|
l(this, "devControls", null);
|
|
3147
3259
|
l(this, "viewMode", "3d");
|
|
3148
3260
|
l(this, "graphData", null);
|
|
3149
|
-
this.options = { ...P, ...s }, this.container = ht(e), this.materialFactory = new
|
|
3261
|
+
this.options = { ...P, ...s }, this.container = ht(e), this.materialFactory = new bt(), this.nodeFactory = new vt(
|
|
3150
3262
|
this.materialFactory,
|
|
3151
3263
|
this.options.nodeRadius ?? P.nodeRadius,
|
|
3152
3264
|
this.options.lodSegments ?? P.lodSegments,
|
|
@@ -3155,14 +3267,14 @@ class Ht {
|
|
|
3155
3267
|
this.materialFactory,
|
|
3156
3268
|
this.options.edgeColor ?? P.edgeColor,
|
|
3157
3269
|
this.options.edgeOpacity ?? P.edgeOpacity
|
|
3158
|
-
), this.sceneManager = new
|
|
3270
|
+
), this.sceneManager = new ft(this.container, this.options), this.lodManager = new Mt(
|
|
3159
3271
|
this.sceneManager.camera,
|
|
3160
3272
|
this.options.lodDistances ?? P.lodDistances,
|
|
3161
3273
|
this.options.enableLOD ?? P.enableLOD
|
|
3162
|
-
), this.frustumCuller = new
|
|
3274
|
+
), this.frustumCuller = new Et(
|
|
3163
3275
|
this.sceneManager.camera,
|
|
3164
3276
|
this.options.enableEdgeCulling ?? P.enableEdgeCulling
|
|
3165
|
-
), this.nodeManager = new
|
|
3277
|
+
), this.nodeManager = new ee(this.sceneManager, this.nodeFactory), this.edgeManager = new mt(this.sceneManager, this.nodeManager, this.edgeFactory), this.graphEngine = new Le(
|
|
3166
3278
|
this.nodeManager.getAllNodes(),
|
|
3167
3279
|
this.edgeManager.getAllEdges(),
|
|
3168
3280
|
{
|
|
@@ -3172,16 +3284,16 @@ class Ht {
|
|
|
3172
3284
|
useBarnesHut: this.options.useBarnesHut,
|
|
3173
3285
|
barnesHutTheta: this.options.barnesHutTheta
|
|
3174
3286
|
}
|
|
3175
|
-
), this.rendererManager = new
|
|
3287
|
+
), this.rendererManager = new xt(
|
|
3176
3288
|
this.sceneManager,
|
|
3177
3289
|
() => this.onSimulate(),
|
|
3178
3290
|
() => this.onRender(),
|
|
3179
3291
|
this.options.targetFPS ?? P.targetFPS
|
|
3180
|
-
), this.raycasterManager = new
|
|
3292
|
+
), 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) => {
|
|
3181
3293
|
this.edgePanelManager.hide(), this.focusOnNode(t), setTimeout(() => {
|
|
3182
3294
|
this.showNodePanel(t);
|
|
3183
3295
|
}, 400);
|
|
3184
|
-
}), this.options.showSearch !== !1 && (this.searchManager = new
|
|
3296
|
+
}), this.options.showSearch !== !1 && (this.searchManager = new kt(this.container, {
|
|
3185
3297
|
placeholder: this.options.searchPlaceholder,
|
|
3186
3298
|
onSearch: (t) => ({
|
|
3187
3299
|
nodeResults: this.searchNodes(t),
|
|
@@ -3192,12 +3304,12 @@ class Ht {
|
|
|
3192
3304
|
this.showNodePanel(t);
|
|
3193
3305
|
}, 400);
|
|
3194
3306
|
}
|
|
3195
|
-
})), this.options.showViewToggle !== !1 && (this.viewMode = this.options.initialViewMode || "3d", this.viewToggleManager = new
|
|
3307
|
+
})), this.options.showViewToggle !== !1 && (this.viewMode = this.options.initialViewMode || "3d", this.viewToggleManager = new Tt(this.container, {
|
|
3196
3308
|
initialMode: this.viewMode,
|
|
3197
3309
|
onViewChange: (t) => {
|
|
3198
3310
|
this.switchView(t);
|
|
3199
3311
|
}
|
|
3200
|
-
})), this.options.showLegend !== !1 && (this.legendManager = new
|
|
3312
|
+
})), this.options.showLegend !== !1 && (this.legendManager = new Pt(this.container), this.updateLegendCounts()), this.setupCallbacks(), this.rendererManager.start(), this.initialized = !0, this.emit("ready");
|
|
3201
3313
|
}
|
|
3202
3314
|
/**
|
|
3203
3315
|
* Sets up internal callbacks
|
|
@@ -3220,7 +3332,14 @@ class Ht {
|
|
|
3220
3332
|
if (e) {
|
|
3221
3333
|
this.edgeManager.highlightEdge(e.edge.source, e.edge.target);
|
|
3222
3334
|
const s = this.container.getBoundingClientRect(), t = s.left + s.width / 2, i = s.top + s.height / 2;
|
|
3223
|
-
this.edgeTooltipManager.show(
|
|
3335
|
+
this.edgeTooltipManager.show(
|
|
3336
|
+
e.edge,
|
|
3337
|
+
e.sourceNode,
|
|
3338
|
+
e.targetNode,
|
|
3339
|
+
t,
|
|
3340
|
+
i,
|
|
3341
|
+
e.relationships
|
|
3342
|
+
), this.options.onEdgeHover && this.options.onEdgeHover(e.edge, e.sourceNode, e.targetNode), this.emit("edgeHover", e.edge, e.sourceNode, e.targetNode);
|
|
3224
3343
|
} else
|
|
3225
3344
|
this.edgeManager.unhighlightCurrentEdge(), this.edgeTooltipManager.hide(), this.options.onEdgeHover && this.options.onEdgeHover(null, null, null), this.emit("edgeHover", null, null, null);
|
|
3226
3345
|
}
|
|
@@ -3236,7 +3355,7 @@ class Ht {
|
|
|
3236
3355
|
* Handles edge click
|
|
3237
3356
|
*/
|
|
3238
3357
|
onEdgeClick(e) {
|
|
3239
|
-
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);
|
|
3358
|
+
this.panelManager.hide(), this.edgeTooltipManager.hide(), this.edgeManager.highlightEdge(e.edge.source, e.edge.target), this.edgePanelManager.show(e.edge, e.sourceNode, e.targetNode, e.relationships), this.focusOnEdge(e.edge.source, e.edge.target), this.emit("edgeClick", e.edge, e.sourceNode, e.targetNode);
|
|
3240
3359
|
}
|
|
3241
3360
|
/**
|
|
3242
3361
|
* Called every simulation step
|
|
@@ -3269,8 +3388,8 @@ class Ht {
|
|
|
3269
3388
|
* Sets the graph data
|
|
3270
3389
|
*/
|
|
3271
3390
|
setData(e) {
|
|
3272
|
-
var
|
|
3273
|
-
const s = (
|
|
3391
|
+
var n;
|
|
3392
|
+
const s = (n = e.data) != null && n.nodes ? e.data : e, i = (s.edges || s.links || []).map((r) => ({
|
|
3274
3393
|
...r,
|
|
3275
3394
|
relationship: r.relationship || r.label || "related_to"
|
|
3276
3395
|
})), o = {
|
|
@@ -3278,14 +3397,14 @@ class Ht {
|
|
|
3278
3397
|
edges: i
|
|
3279
3398
|
};
|
|
3280
3399
|
if (this.graphData = o, this.edgeManager.clear(), this.nodeManager.clear(), o.nodes && Array.isArray(o.nodes)) {
|
|
3281
|
-
|
|
3400
|
+
ee.setExpectedNodeCount(o.nodes.length);
|
|
3282
3401
|
for (const r of o.nodes)
|
|
3283
3402
|
this.addNode(r);
|
|
3284
3403
|
}
|
|
3285
3404
|
if (o.edges && Array.isArray(o.edges))
|
|
3286
3405
|
for (const r of o.edges)
|
|
3287
3406
|
this.addEdge(r);
|
|
3288
|
-
this.graphEngine = new
|
|
3407
|
+
this.graphEngine = new Le(
|
|
3289
3408
|
this.nodeManager.getAllNodes(),
|
|
3290
3409
|
this.edgeManager.getAllEdges(),
|
|
3291
3410
|
{
|
|
@@ -3302,7 +3421,7 @@ class Ht {
|
|
|
3302
3421
|
* @returns true if added, false if node already exists or invalid
|
|
3303
3422
|
*/
|
|
3304
3423
|
addNode(e) {
|
|
3305
|
-
if (!
|
|
3424
|
+
if (!Fe(e))
|
|
3306
3425
|
return !1;
|
|
3307
3426
|
const s = this.nodeManager.addNode(e);
|
|
3308
3427
|
return s && (this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.addNode(e), this.options.onNodeAdd && this.options.onNodeAdd(e), this.emit("nodeAdd", e), this.updateLegendCounts()), s;
|
|
@@ -3312,7 +3431,7 @@ class Ht {
|
|
|
3312
3431
|
* @returns true if removed, false if not found
|
|
3313
3432
|
*/
|
|
3314
3433
|
removeNode(e) {
|
|
3315
|
-
if (!
|
|
3434
|
+
if (!dt(e))
|
|
3316
3435
|
return !1;
|
|
3317
3436
|
this.edgeManager.removeEdgesForNode(e);
|
|
3318
3437
|
const s = this.nodeManager.removeNode(e);
|
|
@@ -3326,10 +3445,10 @@ class Ht {
|
|
|
3326
3445
|
}
|
|
3327
3446
|
/**
|
|
3328
3447
|
* Adds an edge to the graph
|
|
3329
|
-
* @returns true if added, false if
|
|
3448
|
+
* @returns true if added, false if invalid or nodes don't exist
|
|
3330
3449
|
*/
|
|
3331
3450
|
addEdge(e) {
|
|
3332
|
-
if (!
|
|
3451
|
+
if (!De(e))
|
|
3333
3452
|
return !1;
|
|
3334
3453
|
const s = this.edgeManager.addEdge(e);
|
|
3335
3454
|
return s && (this.graphEngine.setEdges(this.edgeManager.getAllEdges()), this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.addEdge(e), this.options.onEdgeAdd && this.options.onEdgeAdd(e), this.emit("edgeAdd", e), this.updateLegendCounts()), s;
|
|
@@ -3355,11 +3474,11 @@ class Ht {
|
|
|
3355
3474
|
try {
|
|
3356
3475
|
const o = await i(e, s);
|
|
3357
3476
|
if (o.nodes && Array.isArray(o.nodes))
|
|
3358
|
-
for (const
|
|
3359
|
-
this.addNode(
|
|
3477
|
+
for (const n of o.nodes)
|
|
3478
|
+
this.addNode(n);
|
|
3360
3479
|
if (o.edges && Array.isArray(o.edges))
|
|
3361
|
-
for (const
|
|
3362
|
-
this.addEdge(
|
|
3480
|
+
for (const n of o.edges)
|
|
3481
|
+
this.addEdge(n);
|
|
3363
3482
|
return this.panelManager.hide(), this.emit("expand", e, o), !0;
|
|
3364
3483
|
} catch (o) {
|
|
3365
3484
|
return console.error("[ForceGraph3D] Error expanding node:", o), !1;
|
|
@@ -3409,13 +3528,13 @@ class Ht {
|
|
|
3409
3528
|
console.warn(`[ForceGraph3D] Node "${e}" not found`);
|
|
3410
3529
|
return;
|
|
3411
3530
|
}
|
|
3412
|
-
const i = t.position, o = this.sceneManager.camera,
|
|
3531
|
+
const i = t.position, o = this.sceneManager.camera, n = this.sceneManager.controls, r = o.position.clone().sub(n.target).normalize(), h = {
|
|
3413
3532
|
x: i.x + r.x * s,
|
|
3414
3533
|
y: i.y + r.y * s,
|
|
3415
3534
|
z: i.z + r.z * s
|
|
3416
|
-
},
|
|
3417
|
-
const
|
|
3418
|
-
o.position.x =
|
|
3535
|
+
}, c = { x: o.position.x, y: o.position.y, z: o.position.z }, p = { x: n.target.x, y: n.target.y, z: n.target.z }, f = 800, m = performance.now(), u = () => {
|
|
3536
|
+
const y = performance.now() - m, b = Math.min(y / f, 1), w = 1 - Math.pow(1 - b, 3);
|
|
3537
|
+
o.position.x = c.x + (h.x - c.x) * w, o.position.y = c.y + (h.y - c.y) * w, o.position.z = c.z + (h.z - c.z) * w, n.target.x = p.x + (i.x - p.x) * w, n.target.y = p.y + (i.y - p.y) * w, n.target.z = p.z + (i.z - p.z) * w, n.update(), b < 1 && requestAnimationFrame(u);
|
|
3419
3538
|
};
|
|
3420
3539
|
u();
|
|
3421
3540
|
}
|
|
@@ -3429,19 +3548,19 @@ class Ht {
|
|
|
3429
3548
|
console.warn(`[ForceGraph3D] Could not find nodes for edge "${e}" -> "${s}"`);
|
|
3430
3549
|
return;
|
|
3431
3550
|
}
|
|
3432
|
-
const
|
|
3551
|
+
const n = this.sceneManager.camera, r = this.sceneManager.controls, h = {
|
|
3433
3552
|
x: (i.position.x + o.position.x) / 2,
|
|
3434
3553
|
y: (i.position.y + o.position.y) / 2,
|
|
3435
3554
|
z: (i.position.z + o.position.z) / 2
|
|
3436
|
-
},
|
|
3437
|
-
x:
|
|
3438
|
-
y:
|
|
3439
|
-
z:
|
|
3440
|
-
},
|
|
3441
|
-
const T = performance.now() -
|
|
3442
|
-
|
|
3555
|
+
}, c = o.position.x - i.position.x, p = o.position.y - i.position.y, f = o.position.z - i.position.z, m = Math.sqrt(c * c + p * p + f * f), u = Math.max(m * t, 40), y = n.position.clone().sub(r.target).normalize(), b = {
|
|
3556
|
+
x: h.x + y.x * u,
|
|
3557
|
+
y: h.y + y.y * u,
|
|
3558
|
+
z: h.z + y.z * u
|
|
3559
|
+
}, w = { x: n.position.x, y: n.position.y, z: n.position.z }, N = { x: r.target.x, y: r.target.y, z: r.target.z }, O = 800, R = performance.now(), G = () => {
|
|
3560
|
+
const T = performance.now() - R, D = Math.min(T / O, 1), E = 1 - Math.pow(1 - D, 3);
|
|
3561
|
+
n.position.x = w.x + (b.x - w.x) * E, n.position.y = w.y + (b.y - w.y) * E, n.position.z = w.z + (b.z - w.z) * E, r.target.x = N.x + (h.x - N.x) * E, r.target.y = N.y + (h.y - N.y) * E, r.target.z = N.z + (h.z - N.z) * E, r.update(), D < 1 && requestAnimationFrame(G);
|
|
3443
3562
|
};
|
|
3444
|
-
|
|
3563
|
+
G();
|
|
3445
3564
|
}
|
|
3446
3565
|
/**
|
|
3447
3566
|
* Shows the info panel for a specific node
|
|
@@ -3464,9 +3583,9 @@ class Ht {
|
|
|
3464
3583
|
return [];
|
|
3465
3584
|
const s = e.toLowerCase().trim(), t = this.nodeManager.getAllNodes(), i = [];
|
|
3466
3585
|
return t.forEach((o) => {
|
|
3467
|
-
var
|
|
3468
|
-
const
|
|
3469
|
-
(
|
|
3586
|
+
var c, p, f;
|
|
3587
|
+
const n = (c = o.label) == null ? void 0 : c.toLowerCase().includes(s), r = (p = o.id) == null ? void 0 : p.toLowerCase().includes(s), h = (f = o.type) == null ? void 0 : f.toLowerCase().includes(s);
|
|
3588
|
+
(n || r || h) && i.push(o);
|
|
3470
3589
|
}), i;
|
|
3471
3590
|
}
|
|
3472
3591
|
/**
|
|
@@ -3478,10 +3597,10 @@ class Ht {
|
|
|
3478
3597
|
if (!e || e.trim() === "")
|
|
3479
3598
|
return [];
|
|
3480
3599
|
const s = e.toLowerCase().trim(), t = this.edgeManager.getAllEdges(), i = [];
|
|
3481
|
-
for (const
|
|
3482
|
-
if ((o =
|
|
3483
|
-
const
|
|
3484
|
-
|
|
3600
|
+
for (const n of t)
|
|
3601
|
+
if ((o = n.relationship) == null ? void 0 : o.toLowerCase().includes(s)) {
|
|
3602
|
+
const h = this.nodeManager.getNode(n.source), c = this.nodeManager.getNode(n.target);
|
|
3603
|
+
h && c && i.push({ edge: n, sourceNode: h, targetNode: c });
|
|
3485
3604
|
}
|
|
3486
3605
|
return i;
|
|
3487
3606
|
}
|
|
@@ -3514,7 +3633,7 @@ class Ht {
|
|
|
3514
3633
|
* Switches between 2D and 3D view modes
|
|
3515
3634
|
*/
|
|
3516
3635
|
switchView(e) {
|
|
3517
|
-
this.viewMode !== e && (this.viewMode = e, this.panelManager.hide(), this.edgePanelManager.hide(), this.edgeTooltipManager.hide(), e === "2d" ? (this.sceneManager.renderer.domElement.style.display = "none", this.rendererManager.stop(), this.forceGraph2D ? (this.forceGraph2D.show(), this.forceGraph2D.syncFrom3D(this.nodeManager.getAllNodes())) : (this.forceGraph2D = new
|
|
3636
|
+
this.viewMode !== e && (this.viewMode = e, this.panelManager.hide(), this.edgePanelManager.hide(), this.edgeTooltipManager.hide(), e === "2d" ? (this.sceneManager.renderer.domElement.style.display = "none", this.rendererManager.stop(), this.forceGraph2D ? (this.forceGraph2D.show(), this.forceGraph2D.syncFrom3D(this.nodeManager.getAllNodes())) : (this.forceGraph2D = new Lt(this.container, {
|
|
3518
3637
|
backgroundColor: "#0a0a0a",
|
|
3519
3638
|
nodeRadius: 24,
|
|
3520
3639
|
onNodeClick: (s) => {
|
|
@@ -3526,19 +3645,31 @@ class Ht {
|
|
|
3526
3645
|
onEdgeHover: (s, t) => {
|
|
3527
3646
|
if (s && t) {
|
|
3528
3647
|
const i = this.nodeManager.getNode(s.source), o = this.nodeManager.getNode(s.target);
|
|
3529
|
-
i && o
|
|
3530
|
-
s
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3648
|
+
if (i && o) {
|
|
3649
|
+
const n = this.edgeManager.getAllEdges().filter((r) => r.source === s.source && r.target === s.target);
|
|
3650
|
+
this.edgeTooltipManager.show(
|
|
3651
|
+
s,
|
|
3652
|
+
i,
|
|
3653
|
+
o,
|
|
3654
|
+
t.clientX,
|
|
3655
|
+
t.clientY,
|
|
3656
|
+
n.length > 0 ? n : [s]
|
|
3657
|
+
);
|
|
3658
|
+
}
|
|
3536
3659
|
} else
|
|
3537
3660
|
this.edgeTooltipManager.hide();
|
|
3538
3661
|
},
|
|
3539
3662
|
onEdgeClick: (s) => {
|
|
3540
3663
|
const t = this.nodeManager.getNode(s.source), i = this.nodeManager.getNode(s.target);
|
|
3541
|
-
t && i
|
|
3664
|
+
if (t && i) {
|
|
3665
|
+
const o = this.edgeManager.getAllEdges().filter((n) => n.source === s.source && n.target === s.target);
|
|
3666
|
+
this.edgePanelManager.show(
|
|
3667
|
+
s,
|
|
3668
|
+
t,
|
|
3669
|
+
i,
|
|
3670
|
+
o.length > 0 ? o : [s]
|
|
3671
|
+
);
|
|
3672
|
+
}
|
|
3542
3673
|
}
|
|
3543
3674
|
}), 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));
|
|
3544
3675
|
}
|
|
@@ -3639,8 +3770,8 @@ class Ht {
|
|
|
3639
3770
|
const i = parseFloat(t.value) / 100;
|
|
3640
3771
|
this.setPhysicsParams({ damping: i }), this.devControls.querySelector("#dev-damping-val").textContent = i.toFixed(2);
|
|
3641
3772
|
}), setInterval(() => {
|
|
3642
|
-
const i = this.devControls.querySelector("#dev-node-count"), o = this.devControls.querySelector("#dev-edge-count"),
|
|
3643
|
-
i && (i.textContent = this.getNodeCount().toString()), o && (o.textContent = this.getEdgeCount().toString()),
|
|
3773
|
+
const i = this.devControls.querySelector("#dev-node-count"), o = this.devControls.querySelector("#dev-edge-count"), n = this.devControls.querySelector("#dev-fps");
|
|
3774
|
+
i && (i.textContent = this.getNodeCount().toString()), o && (o.textContent = this.getEdgeCount().toString()), n && (n.textContent = this.rendererManager.getFPS().toString());
|
|
3644
3775
|
}, 500);
|
|
3645
3776
|
}
|
|
3646
3777
|
/**
|
|
@@ -3650,7 +3781,7 @@ class Ht {
|
|
|
3650
3781
|
this.rendererManager.dispose(), this.panelManager.dispose(), this.raycasterManager.dispose(), this.edgeTooltipManager.dispose(), this.searchManager && this.searchManager.dispose(), this.viewToggleManager && this.viewToggleManager.dispose(), this.legendManager && this.legendManager.dispose(), this.forceGraph2D && this.forceGraph2D.dispose(), this.edgeManager.dispose(), this.nodeManager.dispose(), this.nodeFactory.dispose(), this.materialFactory.dispose(), this.sceneManager.dispose(), this.devControls && this.devControls.parentNode && this.devControls.parentNode.removeChild(this.devControls), this.eventCallbacks.clear(), this.initialized = !1;
|
|
3651
3782
|
}
|
|
3652
3783
|
}
|
|
3653
|
-
const
|
|
3784
|
+
const Ie = [
|
|
3654
3785
|
"Alpha",
|
|
3655
3786
|
"Beta",
|
|
3656
3787
|
"Gamma",
|
|
@@ -3681,7 +3812,7 @@ const Oe = [
|
|
|
3681
3812
|
"Link",
|
|
3682
3813
|
"Point",
|
|
3683
3814
|
"Vertex"
|
|
3684
|
-
],
|
|
3815
|
+
], J = [
|
|
3685
3816
|
"connects to",
|
|
3686
3817
|
"links with",
|
|
3687
3818
|
"relates to",
|
|
@@ -3692,7 +3823,7 @@ const Oe = [
|
|
|
3692
3823
|
"partners with",
|
|
3693
3824
|
"collaborates with",
|
|
3694
3825
|
"supports"
|
|
3695
|
-
],
|
|
3826
|
+
], Oe = [
|
|
3696
3827
|
16777215,
|
|
3697
3828
|
// White
|
|
3698
3829
|
16750950,
|
|
@@ -3704,14 +3835,14 @@ const Oe = [
|
|
|
3704
3835
|
16746564
|
|
3705
3836
|
// Darker tangerine
|
|
3706
3837
|
];
|
|
3707
|
-
function At(
|
|
3838
|
+
function At(d = 30) {
|
|
3708
3839
|
const e = [], s = [];
|
|
3709
|
-
for (let i = 0; i <
|
|
3710
|
-
const o = i <
|
|
3840
|
+
for (let i = 0; i < d; i++) {
|
|
3841
|
+
const o = i < Ie.length ? Ie[i] : `Node ${i + 1}`;
|
|
3711
3842
|
e.push({
|
|
3712
3843
|
id: `node-${i}`,
|
|
3713
3844
|
label: o,
|
|
3714
|
-
color:
|
|
3845
|
+
color: Oe[i % Oe.length],
|
|
3715
3846
|
position: {
|
|
3716
3847
|
x: (Math.random() - 0.5) * 60,
|
|
3717
3848
|
y: (Math.random() - 0.5) * 60,
|
|
@@ -3719,52 +3850,52 @@ function At(h = 30) {
|
|
|
3719
3850
|
}
|
|
3720
3851
|
});
|
|
3721
3852
|
}
|
|
3722
|
-
for (let i = 1; i <
|
|
3853
|
+
for (let i = 1; i < d; i++) {
|
|
3723
3854
|
const o = Math.floor(Math.random() * i);
|
|
3724
3855
|
s.push({
|
|
3725
3856
|
source: `node-${i}`,
|
|
3726
3857
|
target: `node-${o}`,
|
|
3727
|
-
relationship:
|
|
3858
|
+
relationship: J[Math.floor(Math.random() * J.length)]
|
|
3728
3859
|
});
|
|
3729
3860
|
}
|
|
3730
|
-
const t = Math.floor(
|
|
3861
|
+
const t = Math.floor(d * 0.5);
|
|
3731
3862
|
for (let i = 0; i < t; i++) {
|
|
3732
|
-
const o = Math.floor(Math.random() *
|
|
3733
|
-
let
|
|
3734
|
-
o ===
|
|
3735
|
-
const r = `node-${o}`,
|
|
3863
|
+
const o = Math.floor(Math.random() * d);
|
|
3864
|
+
let n = Math.floor(Math.random() * d);
|
|
3865
|
+
o === n && (n = (n + 1) % d);
|
|
3866
|
+
const r = `node-${o}`, h = `node-${n}`;
|
|
3736
3867
|
s.some(
|
|
3737
|
-
(p) => p.source === r && p.target ===
|
|
3868
|
+
(p) => p.source === r && p.target === h || p.source === h && p.target === r
|
|
3738
3869
|
) || s.push({
|
|
3739
3870
|
source: r,
|
|
3740
|
-
target:
|
|
3741
|
-
relationship:
|
|
3871
|
+
target: h,
|
|
3872
|
+
relationship: J[Math.floor(Math.random() * J.length)]
|
|
3742
3873
|
});
|
|
3743
3874
|
}
|
|
3744
3875
|
return { nodes: e, edges: s };
|
|
3745
3876
|
}
|
|
3746
|
-
function jt(
|
|
3747
|
-
const e = [], s = [], t = Math.ceil(
|
|
3877
|
+
function jt(d = 1e3) {
|
|
3878
|
+
const e = [], s = [], t = Math.ceil(d / 50), i = [];
|
|
3748
3879
|
for (let o = 0; o < t; o++)
|
|
3749
3880
|
i.push({
|
|
3750
3881
|
x: (Math.random() - 0.5) * 200,
|
|
3751
3882
|
y: (Math.random() - 0.5) * 200,
|
|
3752
3883
|
z: (Math.random() - 0.5) * 200
|
|
3753
3884
|
});
|
|
3754
|
-
for (let o = 0; o <
|
|
3755
|
-
const
|
|
3885
|
+
for (let o = 0; o < d; o++) {
|
|
3886
|
+
const n = i[o % t];
|
|
3756
3887
|
e.push({
|
|
3757
3888
|
id: `node-${o}`,
|
|
3758
3889
|
label: `N${o}`,
|
|
3759
3890
|
position: {
|
|
3760
|
-
x:
|
|
3761
|
-
y:
|
|
3762
|
-
z:
|
|
3891
|
+
x: n.x + (Math.random() - 0.5) * 40,
|
|
3892
|
+
y: n.y + (Math.random() - 0.5) * 40,
|
|
3893
|
+
z: n.z + (Math.random() - 0.5) * 40
|
|
3763
3894
|
}
|
|
3764
3895
|
});
|
|
3765
3896
|
}
|
|
3766
|
-
for (let o = 1; o <
|
|
3767
|
-
const
|
|
3897
|
+
for (let o = 1; o < d; o++) {
|
|
3898
|
+
const n = Math.floor(o / 50) * 50, r = n === 0 ? Math.floor(Math.random() * o) : n + Math.floor(Math.random() * Math.min(o - n, 50));
|
|
3768
3899
|
s.push({
|
|
3769
3900
|
source: `node-${o}`,
|
|
3770
3901
|
target: `node-${Math.min(r, o - 1)}`,
|
|
@@ -3772,9 +3903,9 @@ function jt(h = 1e3) {
|
|
|
3772
3903
|
});
|
|
3773
3904
|
}
|
|
3774
3905
|
for (let o = 1; o < t; o++) {
|
|
3775
|
-
const
|
|
3906
|
+
const n = o * 50, r = (o - 1) * 50 + Math.floor(Math.random() * 50);
|
|
3776
3907
|
s.push({
|
|
3777
|
-
source: `node-${
|
|
3908
|
+
source: `node-${n}`,
|
|
3778
3909
|
target: `node-${r}`,
|
|
3779
3910
|
relationship: "bridges to"
|
|
3780
3911
|
});
|
|
@@ -3784,11 +3915,11 @@ function jt(h = 1e3) {
|
|
|
3784
3915
|
export {
|
|
3785
3916
|
P as DEFAULT_OPTIONS,
|
|
3786
3917
|
Ht as ForceGraph3D,
|
|
3787
|
-
|
|
3788
|
-
|
|
3918
|
+
_ as LODLevel,
|
|
3919
|
+
Dt as createEdgeKey,
|
|
3789
3920
|
jt as generateLargeSampleData,
|
|
3790
3921
|
At as generateSampleData,
|
|
3791
|
-
|
|
3792
|
-
|
|
3922
|
+
De as validateEdgeData,
|
|
3923
|
+
Fe as validateNodeData
|
|
3793
3924
|
};
|
|
3794
3925
|
//# sourceMappingURL=force-3d-graph.js.map
|