force-3d-graph 1.0.3 → 1.2.0
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 +1201 -708
- package/dist/force-3d-graph.js.map +1 -1
- package/dist/force-3d-graph.umd.cjs +56 -21
- package/dist/force-3d-graph.umd.cjs.map +1 -1
- package/dist/index.d.ts +22 -2
- package/package.json +1 -1
package/dist/force-3d-graph.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
var st = Object.defineProperty;
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import * as
|
|
5
|
-
import { EventDispatcher as ot, Vector3 as
|
|
6
|
-
const
|
|
2
|
+
var it = (h, e, s) => e in h ? st(h, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : h[e] = s;
|
|
3
|
+
var l = (h, e, s) => it(h, typeof e != "symbol" ? e + "" : e, s);
|
|
4
|
+
import * as m from "three";
|
|
5
|
+
import { EventDispatcher as ot, Vector3 as S, MOUSE as $, TOUCH as G, Spherical as Ne, Quaternion as Se, Vector2 as k, Ray as nt, Plane as at, MathUtils as rt } from "three";
|
|
6
|
+
const R = {
|
|
7
7
|
backgroundColor: 657930,
|
|
8
8
|
cameraPosition: { x: 0, y: 0, z: 80 },
|
|
9
9
|
cameraFov: 75,
|
|
@@ -25,101 +25,103 @@ const I = {
|
|
|
25
25
|
showPanel: !0,
|
|
26
26
|
showSearch: !0,
|
|
27
27
|
searchPlaceholder: "Search nodes or relationships...",
|
|
28
|
+
initialViewMode: "3d",
|
|
29
|
+
showViewToggle: !0,
|
|
28
30
|
targetFPS: 60,
|
|
29
31
|
maxVisibleNodes: 1e4
|
|
30
32
|
};
|
|
31
|
-
var
|
|
33
|
+
var U = /* @__PURE__ */ ((h) => (h[h.HIGH = 0] = "HIGH", h[h.MEDIUM = 1] = "MEDIUM", h[h.LOW = 2] = "LOW", h))(U || {});
|
|
32
34
|
function lt() {
|
|
33
|
-
const
|
|
34
|
-
return
|
|
35
|
+
const h = document.createElement("div");
|
|
36
|
+
return h.id = "force-graph-3d-container", h.style.cssText = `
|
|
35
37
|
width: 100%;
|
|
36
38
|
height: 100%;
|
|
37
39
|
position: absolute;
|
|
38
40
|
top: 0;
|
|
39
41
|
left: 0;
|
|
40
42
|
overflow: hidden;
|
|
41
|
-
`, document.body.appendChild(
|
|
43
|
+
`, document.body.appendChild(h), h;
|
|
42
44
|
}
|
|
43
|
-
function ct(
|
|
44
|
-
return
|
|
45
|
+
function ct(h) {
|
|
46
|
+
return h && h instanceof HTMLElement ? h : (console.warn("[ForceGraph3D] No container provided, creating one automatically"), lt());
|
|
45
47
|
}
|
|
46
|
-
function
|
|
47
|
-
const e =
|
|
48
|
+
function ze(h) {
|
|
49
|
+
const e = h.getBoundingClientRect();
|
|
48
50
|
return {
|
|
49
51
|
width: e.width || window.innerWidth,
|
|
50
52
|
height: e.height || window.innerHeight
|
|
51
53
|
};
|
|
52
54
|
}
|
|
53
|
-
function
|
|
54
|
-
if (!
|
|
55
|
+
function Oe(h) {
|
|
56
|
+
if (!h || typeof h != "object")
|
|
55
57
|
return console.warn("[ForceGraph3D] Invalid node: must be an object"), !1;
|
|
56
|
-
const e =
|
|
58
|
+
const e = h;
|
|
57
59
|
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 && !dt(e.position) ? (console.warn("[ForceGraph3D] Invalid node: position must have x, y, z numbers"), !1) : !0;
|
|
58
60
|
}
|
|
59
|
-
function Fe(
|
|
60
|
-
if (!
|
|
61
|
+
function Fe(h) {
|
|
62
|
+
if (!h || typeof h != "object")
|
|
61
63
|
return console.warn("[ForceGraph3D] Invalid edge: must be an object"), !1;
|
|
62
|
-
const e =
|
|
64
|
+
const e = h;
|
|
63
65
|
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;
|
|
64
66
|
}
|
|
65
|
-
function ht(
|
|
66
|
-
return typeof
|
|
67
|
+
function ht(h) {
|
|
68
|
+
return typeof h != "string" || h.trim() === "" ? (console.warn("[ForceGraph3D] Invalid node ID: must be a non-empty string"), !1) : !0;
|
|
67
69
|
}
|
|
68
|
-
function dt(
|
|
69
|
-
if (!
|
|
70
|
-
const e =
|
|
70
|
+
function dt(h) {
|
|
71
|
+
if (!h || typeof h != "object") return !1;
|
|
72
|
+
const e = h;
|
|
71
73
|
return typeof e.x == "number" && typeof e.y == "number" && typeof e.z == "number";
|
|
72
74
|
}
|
|
73
|
-
function
|
|
74
|
-
return
|
|
75
|
+
function D(h, e) {
|
|
76
|
+
return h === e ? `${h}-${e}` : h < e ? `${h}-${e}` : `${e}-${h}`;
|
|
75
77
|
}
|
|
76
|
-
const ke = { type: "change" }, re = { type: "start" },
|
|
78
|
+
const ke = { type: "change" }, re = { type: "start" }, Pe = { type: "end" }, Q = new nt(), Te = new at(), pt = Math.cos(70 * rt.DEG2RAD);
|
|
77
79
|
class gt extends ot {
|
|
78
80
|
constructor(e, s) {
|
|
79
|
-
super(), this.object = e, this.domElement = s, this.domElement.style.touchAction = "none", this.enabled = !0, this.target = new
|
|
80
|
-
return
|
|
81
|
+
super(), this.object = e, this.domElement = s, this.domElement.style.touchAction = "none", this.enabled = !0, this.target = new S(), this.cursor = new S(), this.minDistance = 0, this.maxDistance = 1 / 0, this.minZoom = 0, this.maxZoom = 1 / 0, this.minTargetRadius = 0, this.maxTargetRadius = 1 / 0, this.minPolarAngle = 0, this.maxPolarAngle = Math.PI, this.minAzimuthAngle = -1 / 0, this.maxAzimuthAngle = 1 / 0, this.enableDamping = !1, this.dampingFactor = 0.05, this.enableZoom = !0, this.zoomSpeed = 1, this.enableRotate = !0, this.rotateSpeed = 1, this.enablePan = !0, this.panSpeed = 1, this.screenSpacePanning = !0, this.keyPanSpeed = 7, this.zoomToCursor = !1, this.autoRotate = !1, this.autoRotateSpeed = 2, this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" }, this.mouseButtons = { LEFT: $.ROTATE, MIDDLE: $.DOLLY, RIGHT: $.PAN }, this.touches = { ONE: G.ROTATE, TWO: G.DOLLY_PAN }, this.target0 = this.target.clone(), this.position0 = this.object.position.clone(), this.zoom0 = this.object.zoom, this._domElementKeyEvents = null, this.getPolarAngle = function() {
|
|
82
|
+
return r.phi;
|
|
81
83
|
}, this.getAzimuthalAngle = function() {
|
|
82
|
-
return
|
|
84
|
+
return r.theta;
|
|
83
85
|
}, this.getDistance = function() {
|
|
84
86
|
return this.object.position.distanceTo(this.target);
|
|
85
|
-
}, this.listenToKeyEvents = function(
|
|
86
|
-
|
|
87
|
+
}, this.listenToKeyEvents = function(n) {
|
|
88
|
+
n.addEventListener("keydown", ne), this._domElementKeyEvents = n;
|
|
87
89
|
}, this.stopListenToKeyEvents = function() {
|
|
88
|
-
this._domElementKeyEvents.removeEventListener("keydown",
|
|
90
|
+
this._domElementKeyEvents.removeEventListener("keydown", ne), this._domElementKeyEvents = null;
|
|
89
91
|
}, this.saveState = function() {
|
|
90
92
|
t.target0.copy(t.target), t.position0.copy(t.object.position), t.zoom0 = t.object.zoom;
|
|
91
93
|
}, this.reset = function() {
|
|
92
|
-
t.target.copy(t.target0), t.object.position.copy(t.position0), t.object.zoom = t.zoom0, t.object.updateProjectionMatrix(), t.dispatchEvent(ke), t.update(),
|
|
94
|
+
t.target.copy(t.target0), t.object.position.copy(t.position0), t.object.zoom = t.zoom0, t.object.updateProjectionMatrix(), t.dispatchEvent(ke), t.update(), i = o.NONE;
|
|
93
95
|
}, this.update = function() {
|
|
94
|
-
const
|
|
96
|
+
const n = new S(), p = new Se().setFromUnitVectors(e.up, new S(0, 1, 0)), b = p.clone().invert(), w = new S(), C = new Se(), F = new S(), z = 2 * Math.PI;
|
|
95
97
|
return function(tt = null) {
|
|
96
98
|
const Ce = t.object.position;
|
|
97
|
-
|
|
98
|
-
let L = t.minAzimuthAngle,
|
|
99
|
-
isFinite(L) && isFinite(
|
|
99
|
+
n.copy(Ce).sub(t.target), n.applyQuaternion(p), r.setFromVector3(n), t.autoRotate && i === o.NONE && B(He(tt)), t.enableDamping ? (r.theta += c.theta * t.dampingFactor, r.phi += c.phi * t.dampingFactor) : (r.theta += c.theta, r.phi += c.phi);
|
|
100
|
+
let L = t.minAzimuthAngle, I = t.maxAzimuthAngle;
|
|
101
|
+
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(g, t.dampingFactor) : t.target.add(g), t.target.sub(t.cursor), t.target.clampLength(t.minTargetRadius, t.maxTargetRadius), t.target.add(t.cursor), t.zoomToCursor && H || t.object.isOrthographicCamera ? r.radius = ie(r.radius) : r.radius = ie(r.radius * d), n.setFromSpherical(r), n.applyQuaternion(b), Ce.copy(t.target).add(n), t.object.lookAt(t.target), t.enableDamping === !0 ? (c.theta *= 1 - t.dampingFactor, c.phi *= 1 - t.dampingFactor, g.multiplyScalar(1 - t.dampingFactor)) : (c.set(0, 0, 0), g.set(0, 0, 0));
|
|
100
102
|
let ae = !1;
|
|
101
103
|
if (t.zoomToCursor && H) {
|
|
102
|
-
let
|
|
104
|
+
let X = null;
|
|
103
105
|
if (t.object.isPerspectiveCamera) {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
const Z =
|
|
106
|
+
const V = n.length();
|
|
107
|
+
X = ie(V * d);
|
|
108
|
+
const Z = V - X;
|
|
107
109
|
t.object.position.addScaledVector(Y, Z), t.object.updateMatrixWorld();
|
|
108
110
|
} else if (t.object.isOrthographicCamera) {
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
const Z = new
|
|
112
|
-
Z.unproject(t.object), t.object.position.sub(Z).add(
|
|
111
|
+
const V = new S(P.x, P.y, 0);
|
|
112
|
+
V.unproject(t.object), t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom / d)), t.object.updateProjectionMatrix(), ae = !0;
|
|
113
|
+
const Z = new S(P.x, P.y, 0);
|
|
114
|
+
Z.unproject(t.object), t.object.position.sub(Z).add(V), t.object.updateMatrixWorld(), X = n.length();
|
|
113
115
|
} else
|
|
114
116
|
console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."), t.zoomToCursor = !1;
|
|
115
|
-
|
|
116
|
-
} else t.object.isOrthographicCamera && (t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom /
|
|
117
|
-
return
|
|
117
|
+
X !== null && (this.screenSpacePanning ? t.target.set(0, 0, -1).transformDirection(t.object.matrix).multiplyScalar(X).add(t.object.position) : (Q.origin.copy(t.object.position), Q.direction.set(0, 0, -1).transformDirection(t.object.matrix), Math.abs(t.object.up.dot(Q.direction)) < pt ? e.lookAt(t.target) : (Te.setFromNormalAndCoplanarPoint(t.object.up, t.target), Q.intersectPlane(Te, t.target))));
|
|
118
|
+
} else t.object.isOrthographicCamera && (t.object.zoom = Math.max(t.minZoom, Math.min(t.maxZoom, t.object.zoom / d)), t.object.updateProjectionMatrix(), ae = !0);
|
|
119
|
+
return d = 1, H = !1, ae || w.distanceToSquared(t.object.position) > a || 8 * (1 - C.dot(t.object.quaternion)) > a || F.distanceToSquared(t.target) > 0 ? (t.dispatchEvent(ke), w.copy(t.object.position), C.copy(t.object.quaternion), F.copy(t.target), !0) : !1;
|
|
118
120
|
};
|
|
119
121
|
}(), this.dispose = function() {
|
|
120
|
-
t.domElement.removeEventListener("contextmenu", we), t.domElement.removeEventListener("pointerdown",
|
|
122
|
+
t.domElement.removeEventListener("contextmenu", we), t.domElement.removeEventListener("pointerdown", be), t.domElement.removeEventListener("pointercancel", K), t.domElement.removeEventListener("wheel", ve), t.domElement.removeEventListener("pointermove", oe), t.domElement.removeEventListener("pointerup", K), t._domElementKeyEvents !== null && (t._domElementKeyEvents.removeEventListener("keydown", ne), t._domElementKeyEvents = null);
|
|
121
123
|
};
|
|
122
|
-
const t = this,
|
|
124
|
+
const t = this, o = {
|
|
123
125
|
NONE: -1,
|
|
124
126
|
ROTATE: 0,
|
|
125
127
|
DOLLY: 1,
|
|
@@ -129,385 +131,385 @@ class gt extends ot {
|
|
|
129
131
|
TOUCH_DOLLY_PAN: 5,
|
|
130
132
|
TOUCH_DOLLY_ROTATE: 6
|
|
131
133
|
};
|
|
132
|
-
let
|
|
133
|
-
const a = 1e-6,
|
|
134
|
-
let
|
|
135
|
-
const
|
|
134
|
+
let i = o.NONE;
|
|
135
|
+
const a = 1e-6, r = new Ne(), c = new Ne();
|
|
136
|
+
let d = 1;
|
|
137
|
+
const g = new S(), u = new k(), y = new k(), f = new k(), x = new k(), v = new k(), M = new k(), N = new k(), O = new k(), T = new k(), Y = new S(), P = new k();
|
|
136
138
|
let H = !1;
|
|
137
|
-
const
|
|
139
|
+
const E = [], _ = {};
|
|
138
140
|
let ee = !1;
|
|
139
|
-
function He(
|
|
140
|
-
return
|
|
141
|
+
function He(n) {
|
|
142
|
+
return n !== null ? 2 * Math.PI / 60 * t.autoRotateSpeed * n : 2 * Math.PI / 60 / 60 * t.autoRotateSpeed;
|
|
141
143
|
}
|
|
142
|
-
function
|
|
143
|
-
const
|
|
144
|
-
return Math.pow(0.95, t.zoomSpeed *
|
|
144
|
+
function q(n) {
|
|
145
|
+
const p = Math.abs(n * 0.01);
|
|
146
|
+
return Math.pow(0.95, t.zoomSpeed * p);
|
|
145
147
|
}
|
|
146
|
-
function
|
|
147
|
-
|
|
148
|
+
function B(n) {
|
|
149
|
+
c.theta -= n;
|
|
148
150
|
}
|
|
149
|
-
function W(
|
|
150
|
-
|
|
151
|
+
function W(n) {
|
|
152
|
+
c.phi -= n;
|
|
151
153
|
}
|
|
152
154
|
const le = function() {
|
|
153
|
-
const
|
|
154
|
-
return function(
|
|
155
|
-
|
|
155
|
+
const n = new S();
|
|
156
|
+
return function(b, w) {
|
|
157
|
+
n.setFromMatrixColumn(w, 0), n.multiplyScalar(-b), g.add(n);
|
|
156
158
|
};
|
|
157
159
|
}(), ce = function() {
|
|
158
|
-
const
|
|
159
|
-
return function(
|
|
160
|
-
t.screenSpacePanning === !0 ?
|
|
160
|
+
const n = new S();
|
|
161
|
+
return function(b, w) {
|
|
162
|
+
t.screenSpacePanning === !0 ? n.setFromMatrixColumn(w, 1) : (n.setFromMatrixColumn(w, 0), n.crossVectors(t.object.up, n)), n.multiplyScalar(b), g.add(n);
|
|
161
163
|
};
|
|
162
|
-
}(),
|
|
163
|
-
const
|
|
164
|
-
return function(
|
|
164
|
+
}(), A = function() {
|
|
165
|
+
const n = new S();
|
|
166
|
+
return function(b, w) {
|
|
165
167
|
const C = t.domElement;
|
|
166
168
|
if (t.object.isPerspectiveCamera) {
|
|
167
169
|
const F = t.object.position;
|
|
168
|
-
|
|
169
|
-
let
|
|
170
|
-
|
|
171
|
-
} else t.object.isOrthographicCamera ? (le(
|
|
170
|
+
n.copy(F).sub(t.target);
|
|
171
|
+
let z = n.length();
|
|
172
|
+
z *= Math.tan(t.object.fov / 2 * Math.PI / 180), le(2 * b * z / C.clientHeight, t.object.matrix), ce(2 * w * z / C.clientHeight, t.object.matrix);
|
|
173
|
+
} else t.object.isOrthographicCamera ? (le(b * (t.object.right - t.object.left) / t.object.zoom / C.clientWidth, t.object.matrix), ce(w * (t.object.top - t.object.bottom) / t.object.zoom / C.clientHeight, t.object.matrix)) : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."), t.enablePan = !1);
|
|
172
174
|
};
|
|
173
175
|
}();
|
|
174
|
-
function te(
|
|
175
|
-
t.object.isPerspectiveCamera || t.object.isOrthographicCamera ?
|
|
176
|
+
function te(n) {
|
|
177
|
+
t.object.isPerspectiveCamera || t.object.isOrthographicCamera ? d /= n : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), t.enableZoom = !1);
|
|
176
178
|
}
|
|
177
|
-
function he(
|
|
178
|
-
t.object.isPerspectiveCamera || t.object.isOrthographicCamera ?
|
|
179
|
+
function he(n) {
|
|
180
|
+
t.object.isPerspectiveCamera || t.object.isOrthographicCamera ? d *= n : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), t.enableZoom = !1);
|
|
179
181
|
}
|
|
180
|
-
function se(
|
|
182
|
+
function se(n, p) {
|
|
181
183
|
if (!t.zoomToCursor)
|
|
182
184
|
return;
|
|
183
185
|
H = !0;
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
+
const b = t.domElement.getBoundingClientRect(), w = n - b.left, C = p - b.top, F = b.width, z = b.height;
|
|
187
|
+
P.x = w / F * 2 - 1, P.y = -(C / z) * 2 + 1, Y.set(P.x, P.y, 1).unproject(t.object).sub(t.object.position).normalize();
|
|
186
188
|
}
|
|
187
|
-
function
|
|
188
|
-
return Math.max(t.minDistance, Math.min(t.maxDistance,
|
|
189
|
+
function ie(n) {
|
|
190
|
+
return Math.max(t.minDistance, Math.min(t.maxDistance, n));
|
|
189
191
|
}
|
|
190
|
-
function de(
|
|
191
|
-
|
|
192
|
+
function de(n) {
|
|
193
|
+
u.set(n.clientX, n.clientY);
|
|
192
194
|
}
|
|
193
|
-
function
|
|
194
|
-
se(
|
|
195
|
+
function De(n) {
|
|
196
|
+
se(n.clientX, n.clientX), N.set(n.clientX, n.clientY);
|
|
195
197
|
}
|
|
196
|
-
function pe(
|
|
197
|
-
|
|
198
|
+
function pe(n) {
|
|
199
|
+
x.set(n.clientX, n.clientY);
|
|
198
200
|
}
|
|
199
|
-
function
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
|
|
201
|
+
function Ae(n) {
|
|
202
|
+
y.set(n.clientX, n.clientY), f.subVectors(y, u).multiplyScalar(t.rotateSpeed);
|
|
203
|
+
const p = t.domElement;
|
|
204
|
+
B(2 * Math.PI * f.x / p.clientHeight), W(2 * Math.PI * f.y / p.clientHeight), u.copy(y), t.update();
|
|
203
205
|
}
|
|
204
|
-
function
|
|
205
|
-
|
|
206
|
+
function je(n) {
|
|
207
|
+
O.set(n.clientX, n.clientY), T.subVectors(O, N), T.y > 0 ? te(q(T.y)) : T.y < 0 && he(q(T.y)), N.copy(O), t.update();
|
|
206
208
|
}
|
|
207
|
-
function $e(
|
|
208
|
-
|
|
209
|
+
function $e(n) {
|
|
210
|
+
v.set(n.clientX, n.clientY), M.subVectors(v, x).multiplyScalar(t.panSpeed), A(M.x, M.y), x.copy(v), t.update();
|
|
209
211
|
}
|
|
210
|
-
function
|
|
211
|
-
se(
|
|
212
|
+
function Ge(n) {
|
|
213
|
+
se(n.clientX, n.clientY), n.deltaY < 0 ? he(q(n.deltaY)) : n.deltaY > 0 && te(q(n.deltaY)), t.update();
|
|
212
214
|
}
|
|
213
|
-
function Ye(
|
|
214
|
-
let
|
|
215
|
-
switch (
|
|
215
|
+
function Ye(n) {
|
|
216
|
+
let p = !1;
|
|
217
|
+
switch (n.code) {
|
|
216
218
|
case t.keys.UP:
|
|
217
|
-
|
|
219
|
+
n.ctrlKey || n.metaKey || n.shiftKey ? W(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(0, t.keyPanSpeed), p = !0;
|
|
218
220
|
break;
|
|
219
221
|
case t.keys.BOTTOM:
|
|
220
|
-
|
|
222
|
+
n.ctrlKey || n.metaKey || n.shiftKey ? W(-2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(0, -t.keyPanSpeed), p = !0;
|
|
221
223
|
break;
|
|
222
224
|
case t.keys.LEFT:
|
|
223
|
-
|
|
225
|
+
n.ctrlKey || n.metaKey || n.shiftKey ? B(2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(t.keyPanSpeed, 0), p = !0;
|
|
224
226
|
break;
|
|
225
227
|
case t.keys.RIGHT:
|
|
226
|
-
|
|
228
|
+
n.ctrlKey || n.metaKey || n.shiftKey ? B(-2 * Math.PI * t.rotateSpeed / t.domElement.clientHeight) : A(-t.keyPanSpeed, 0), p = !0;
|
|
227
229
|
break;
|
|
228
230
|
}
|
|
229
|
-
|
|
231
|
+
p && (n.preventDefault(), t.update());
|
|
230
232
|
}
|
|
231
|
-
function ge(
|
|
232
|
-
if (
|
|
233
|
-
|
|
233
|
+
function ge(n) {
|
|
234
|
+
if (E.length === 1)
|
|
235
|
+
u.set(n.pageX, n.pageY);
|
|
234
236
|
else {
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
+
const p = j(n), b = 0.5 * (n.pageX + p.x), w = 0.5 * (n.pageY + p.y);
|
|
238
|
+
u.set(b, w);
|
|
237
239
|
}
|
|
238
240
|
}
|
|
239
|
-
function ue(
|
|
240
|
-
if (
|
|
241
|
-
|
|
241
|
+
function ue(n) {
|
|
242
|
+
if (E.length === 1)
|
|
243
|
+
x.set(n.pageX, n.pageY);
|
|
242
244
|
else {
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
+
const p = j(n), b = 0.5 * (n.pageX + p.x), w = 0.5 * (n.pageY + p.y);
|
|
246
|
+
x.set(b, w);
|
|
245
247
|
}
|
|
246
248
|
}
|
|
247
|
-
function
|
|
248
|
-
const
|
|
249
|
-
|
|
249
|
+
function fe(n) {
|
|
250
|
+
const p = j(n), b = n.pageX - p.x, w = n.pageY - p.y, C = Math.sqrt(b * b + w * w);
|
|
251
|
+
N.set(0, C);
|
|
250
252
|
}
|
|
251
|
-
function
|
|
252
|
-
t.enableZoom &&
|
|
253
|
+
function Be(n) {
|
|
254
|
+
t.enableZoom && fe(n), t.enablePan && ue(n);
|
|
253
255
|
}
|
|
254
|
-
function
|
|
255
|
-
t.enableZoom &&
|
|
256
|
+
function Ke(n) {
|
|
257
|
+
t.enableZoom && fe(n), t.enableRotate && ge(n);
|
|
256
258
|
}
|
|
257
|
-
function
|
|
258
|
-
if (
|
|
259
|
-
|
|
259
|
+
function me(n) {
|
|
260
|
+
if (E.length == 1)
|
|
261
|
+
y.set(n.pageX, n.pageY);
|
|
260
262
|
else {
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
+
const b = j(n), w = 0.5 * (n.pageX + b.x), C = 0.5 * (n.pageY + b.y);
|
|
264
|
+
y.set(w, C);
|
|
263
265
|
}
|
|
264
|
-
f.subVectors(
|
|
265
|
-
const
|
|
266
|
-
|
|
266
|
+
f.subVectors(y, u).multiplyScalar(t.rotateSpeed);
|
|
267
|
+
const p = t.domElement;
|
|
268
|
+
B(2 * Math.PI * f.x / p.clientHeight), W(2 * Math.PI * f.y / p.clientHeight), u.copy(y);
|
|
267
269
|
}
|
|
268
|
-
function ye(
|
|
269
|
-
if (
|
|
270
|
-
|
|
270
|
+
function ye(n) {
|
|
271
|
+
if (E.length === 1)
|
|
272
|
+
v.set(n.pageX, n.pageY);
|
|
271
273
|
else {
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
+
const p = j(n), b = 0.5 * (n.pageX + p.x), w = 0.5 * (n.pageY + p.y);
|
|
275
|
+
v.set(b, w);
|
|
274
276
|
}
|
|
275
|
-
|
|
277
|
+
M.subVectors(v, x).multiplyScalar(t.panSpeed), A(M.x, M.y), x.copy(v);
|
|
276
278
|
}
|
|
277
|
-
function
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
const F = (
|
|
281
|
-
se(F,
|
|
279
|
+
function xe(n) {
|
|
280
|
+
const p = j(n), b = n.pageX - p.x, w = n.pageY - p.y, C = Math.sqrt(b * b + w * w);
|
|
281
|
+
O.set(0, C), T.set(0, Math.pow(O.y / N.y, t.zoomSpeed)), te(T.y), N.copy(O);
|
|
282
|
+
const F = (n.pageX + p.x) * 0.5, z = (n.pageY + p.y) * 0.5;
|
|
283
|
+
se(F, z);
|
|
282
284
|
}
|
|
283
|
-
function
|
|
284
|
-
t.enableZoom &&
|
|
285
|
+
function Xe(n) {
|
|
286
|
+
t.enableZoom && xe(n), t.enablePan && ye(n);
|
|
285
287
|
}
|
|
286
|
-
function
|
|
287
|
-
t.enableZoom &&
|
|
288
|
+
function Ve(n) {
|
|
289
|
+
t.enableZoom && xe(n), t.enableRotate && me(n);
|
|
288
290
|
}
|
|
289
|
-
function
|
|
290
|
-
t.enabled !== !1 && (
|
|
291
|
+
function be(n) {
|
|
292
|
+
t.enabled !== !1 && (E.length === 0 && (t.domElement.setPointerCapture(n.pointerId), t.domElement.addEventListener("pointermove", oe), t.domElement.addEventListener("pointerup", K)), Je(n), n.pointerType === "touch" ? Ze(n) : Ue(n));
|
|
291
293
|
}
|
|
292
|
-
function oe(
|
|
293
|
-
t.enabled !== !1 && (
|
|
294
|
+
function oe(n) {
|
|
295
|
+
t.enabled !== !1 && (n.pointerType === "touch" ? Qe(n) : _e(n));
|
|
294
296
|
}
|
|
295
|
-
function
|
|
296
|
-
et(
|
|
297
|
+
function K(n) {
|
|
298
|
+
et(n), E.length === 0 && (t.domElement.releasePointerCapture(n.pointerId), t.domElement.removeEventListener("pointermove", oe), t.domElement.removeEventListener("pointerup", K)), t.dispatchEvent(Pe), i = o.NONE;
|
|
297
299
|
}
|
|
298
|
-
function
|
|
299
|
-
let
|
|
300
|
-
switch (
|
|
300
|
+
function Ue(n) {
|
|
301
|
+
let p;
|
|
302
|
+
switch (n.button) {
|
|
301
303
|
case 0:
|
|
302
|
-
|
|
304
|
+
p = t.mouseButtons.LEFT;
|
|
303
305
|
break;
|
|
304
306
|
case 1:
|
|
305
|
-
|
|
307
|
+
p = t.mouseButtons.MIDDLE;
|
|
306
308
|
break;
|
|
307
309
|
case 2:
|
|
308
|
-
|
|
310
|
+
p = t.mouseButtons.RIGHT;
|
|
309
311
|
break;
|
|
310
312
|
default:
|
|
311
|
-
|
|
313
|
+
p = -1;
|
|
312
314
|
}
|
|
313
|
-
switch (
|
|
315
|
+
switch (p) {
|
|
314
316
|
case $.DOLLY:
|
|
315
317
|
if (t.enableZoom === !1) return;
|
|
316
|
-
|
|
318
|
+
De(n), i = o.DOLLY;
|
|
317
319
|
break;
|
|
318
320
|
case $.ROTATE:
|
|
319
|
-
if (
|
|
321
|
+
if (n.ctrlKey || n.metaKey || n.shiftKey) {
|
|
320
322
|
if (t.enablePan === !1) return;
|
|
321
|
-
pe(
|
|
323
|
+
pe(n), i = o.PAN;
|
|
322
324
|
} else {
|
|
323
325
|
if (t.enableRotate === !1) return;
|
|
324
|
-
de(
|
|
326
|
+
de(n), i = o.ROTATE;
|
|
325
327
|
}
|
|
326
328
|
break;
|
|
327
329
|
case $.PAN:
|
|
328
|
-
if (
|
|
330
|
+
if (n.ctrlKey || n.metaKey || n.shiftKey) {
|
|
329
331
|
if (t.enableRotate === !1) return;
|
|
330
|
-
de(
|
|
332
|
+
de(n), i = o.ROTATE;
|
|
331
333
|
} else {
|
|
332
334
|
if (t.enablePan === !1) return;
|
|
333
|
-
pe(
|
|
335
|
+
pe(n), i = o.PAN;
|
|
334
336
|
}
|
|
335
337
|
break;
|
|
336
338
|
default:
|
|
337
|
-
|
|
339
|
+
i = o.NONE;
|
|
338
340
|
}
|
|
339
|
-
|
|
341
|
+
i !== o.NONE && t.dispatchEvent(re);
|
|
340
342
|
}
|
|
341
|
-
function
|
|
342
|
-
switch (
|
|
343
|
-
case
|
|
343
|
+
function _e(n) {
|
|
344
|
+
switch (i) {
|
|
345
|
+
case o.ROTATE:
|
|
344
346
|
if (t.enableRotate === !1) return;
|
|
345
|
-
|
|
347
|
+
Ae(n);
|
|
346
348
|
break;
|
|
347
|
-
case
|
|
349
|
+
case o.DOLLY:
|
|
348
350
|
if (t.enableZoom === !1) return;
|
|
349
|
-
|
|
351
|
+
je(n);
|
|
350
352
|
break;
|
|
351
|
-
case
|
|
353
|
+
case o.PAN:
|
|
352
354
|
if (t.enablePan === !1) return;
|
|
353
|
-
$e(
|
|
355
|
+
$e(n);
|
|
354
356
|
break;
|
|
355
357
|
}
|
|
356
358
|
}
|
|
357
|
-
function ve(
|
|
358
|
-
t.enabled === !1 || t.enableZoom === !1 ||
|
|
359
|
+
function ve(n) {
|
|
360
|
+
t.enabled === !1 || t.enableZoom === !1 || i !== o.NONE || (n.preventDefault(), t.dispatchEvent(re), Ge(qe(n)), t.dispatchEvent(Pe));
|
|
359
361
|
}
|
|
360
|
-
function
|
|
361
|
-
const
|
|
362
|
-
clientX:
|
|
363
|
-
clientY:
|
|
364
|
-
deltaY:
|
|
362
|
+
function qe(n) {
|
|
363
|
+
const p = n.deltaMode, b = {
|
|
364
|
+
clientX: n.clientX,
|
|
365
|
+
clientY: n.clientY,
|
|
366
|
+
deltaY: n.deltaY
|
|
365
367
|
};
|
|
366
|
-
switch (
|
|
368
|
+
switch (p) {
|
|
367
369
|
case 1:
|
|
368
|
-
|
|
370
|
+
b.deltaY *= 16;
|
|
369
371
|
break;
|
|
370
372
|
case 2:
|
|
371
|
-
|
|
373
|
+
b.deltaY *= 100;
|
|
372
374
|
break;
|
|
373
375
|
}
|
|
374
|
-
return
|
|
376
|
+
return n.ctrlKey && !ee && (b.deltaY *= 10), b;
|
|
375
377
|
}
|
|
376
|
-
function We(
|
|
377
|
-
|
|
378
|
+
function We(n) {
|
|
379
|
+
n.key === "Control" && (ee = !0, document.addEventListener("keyup", Me, { passive: !0, capture: !0 }));
|
|
378
380
|
}
|
|
379
|
-
function Me(
|
|
380
|
-
|
|
381
|
+
function Me(n) {
|
|
382
|
+
n.key === "Control" && (ee = !1, document.removeEventListener("keyup", Me, { passive: !0, capture: !0 }));
|
|
381
383
|
}
|
|
382
|
-
function
|
|
383
|
-
t.enabled === !1 || t.enablePan === !1 || Ye(
|
|
384
|
+
function ne(n) {
|
|
385
|
+
t.enabled === !1 || t.enablePan === !1 || Ye(n);
|
|
384
386
|
}
|
|
385
|
-
function Ze(
|
|
386
|
-
switch (Ee(
|
|
387
|
+
function Ze(n) {
|
|
388
|
+
switch (Ee(n), E.length) {
|
|
387
389
|
case 1:
|
|
388
390
|
switch (t.touches.ONE) {
|
|
389
|
-
case
|
|
391
|
+
case G.ROTATE:
|
|
390
392
|
if (t.enableRotate === !1) return;
|
|
391
|
-
ge(
|
|
393
|
+
ge(n), i = o.TOUCH_ROTATE;
|
|
392
394
|
break;
|
|
393
|
-
case
|
|
395
|
+
case G.PAN:
|
|
394
396
|
if (t.enablePan === !1) return;
|
|
395
|
-
ue(
|
|
397
|
+
ue(n), i = o.TOUCH_PAN;
|
|
396
398
|
break;
|
|
397
399
|
default:
|
|
398
|
-
|
|
400
|
+
i = o.NONE;
|
|
399
401
|
}
|
|
400
402
|
break;
|
|
401
403
|
case 2:
|
|
402
404
|
switch (t.touches.TWO) {
|
|
403
|
-
case
|
|
405
|
+
case G.DOLLY_PAN:
|
|
404
406
|
if (t.enableZoom === !1 && t.enablePan === !1) return;
|
|
405
|
-
|
|
407
|
+
Be(n), i = o.TOUCH_DOLLY_PAN;
|
|
406
408
|
break;
|
|
407
|
-
case
|
|
409
|
+
case G.DOLLY_ROTATE:
|
|
408
410
|
if (t.enableZoom === !1 && t.enableRotate === !1) return;
|
|
409
|
-
|
|
411
|
+
Ke(n), i = o.TOUCH_DOLLY_ROTATE;
|
|
410
412
|
break;
|
|
411
413
|
default:
|
|
412
|
-
|
|
414
|
+
i = o.NONE;
|
|
413
415
|
}
|
|
414
416
|
break;
|
|
415
417
|
default:
|
|
416
|
-
|
|
418
|
+
i = o.NONE;
|
|
417
419
|
}
|
|
418
|
-
|
|
420
|
+
i !== o.NONE && t.dispatchEvent(re);
|
|
419
421
|
}
|
|
420
|
-
function Qe(
|
|
421
|
-
switch (Ee(
|
|
422
|
-
case
|
|
422
|
+
function Qe(n) {
|
|
423
|
+
switch (Ee(n), i) {
|
|
424
|
+
case o.TOUCH_ROTATE:
|
|
423
425
|
if (t.enableRotate === !1) return;
|
|
424
|
-
|
|
426
|
+
me(n), t.update();
|
|
425
427
|
break;
|
|
426
|
-
case
|
|
428
|
+
case o.TOUCH_PAN:
|
|
427
429
|
if (t.enablePan === !1) return;
|
|
428
|
-
ye(
|
|
430
|
+
ye(n), t.update();
|
|
429
431
|
break;
|
|
430
|
-
case
|
|
432
|
+
case o.TOUCH_DOLLY_PAN:
|
|
431
433
|
if (t.enableZoom === !1 && t.enablePan === !1) return;
|
|
432
|
-
|
|
434
|
+
Xe(n), t.update();
|
|
433
435
|
break;
|
|
434
|
-
case
|
|
436
|
+
case o.TOUCH_DOLLY_ROTATE:
|
|
435
437
|
if (t.enableZoom === !1 && t.enableRotate === !1) return;
|
|
436
|
-
|
|
438
|
+
Ve(n), t.update();
|
|
437
439
|
break;
|
|
438
440
|
default:
|
|
439
|
-
|
|
441
|
+
i = o.NONE;
|
|
440
442
|
}
|
|
441
443
|
}
|
|
442
|
-
function we(
|
|
443
|
-
t.enabled !== !1 &&
|
|
444
|
+
function we(n) {
|
|
445
|
+
t.enabled !== !1 && n.preventDefault();
|
|
444
446
|
}
|
|
445
|
-
function Je(
|
|
446
|
-
|
|
447
|
+
function Je(n) {
|
|
448
|
+
E.push(n.pointerId);
|
|
447
449
|
}
|
|
448
|
-
function et(
|
|
449
|
-
delete
|
|
450
|
-
for (let
|
|
451
|
-
if (
|
|
452
|
-
|
|
450
|
+
function et(n) {
|
|
451
|
+
delete _[n.pointerId];
|
|
452
|
+
for (let p = 0; p < E.length; p++)
|
|
453
|
+
if (E[p] == n.pointerId) {
|
|
454
|
+
E.splice(p, 1);
|
|
453
455
|
return;
|
|
454
456
|
}
|
|
455
457
|
}
|
|
456
|
-
function Ee(
|
|
457
|
-
let
|
|
458
|
-
|
|
458
|
+
function Ee(n) {
|
|
459
|
+
let p = _[n.pointerId];
|
|
460
|
+
p === void 0 && (p = new k(), _[n.pointerId] = p), p.set(n.pageX, n.pageY);
|
|
459
461
|
}
|
|
460
|
-
function
|
|
461
|
-
const
|
|
462
|
-
return
|
|
462
|
+
function j(n) {
|
|
463
|
+
const p = n.pointerId === E[0] ? E[1] : E[0];
|
|
464
|
+
return _[p];
|
|
463
465
|
}
|
|
464
|
-
t.domElement.addEventListener("contextmenu", we), t.domElement.addEventListener("pointerdown",
|
|
466
|
+
t.domElement.addEventListener("contextmenu", we), t.domElement.addEventListener("pointerdown", be), t.domElement.addEventListener("pointercancel", K), t.domElement.addEventListener("wheel", ve, { passive: !1 }), document.addEventListener("keydown", We, { passive: !0, capture: !0 }), this.update();
|
|
465
467
|
}
|
|
466
468
|
}
|
|
467
469
|
class ut {
|
|
468
470
|
constructor(e, s) {
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
this.container = e, this.scene = new
|
|
471
|
+
l(this, "scene");
|
|
472
|
+
l(this, "camera");
|
|
473
|
+
l(this, "renderer");
|
|
474
|
+
l(this, "controls");
|
|
475
|
+
l(this, "container");
|
|
476
|
+
l(this, "resizeHandler");
|
|
477
|
+
this.container = e, this.scene = new m.Scene(), this.scene.background = new m.Color(
|
|
476
478
|
s.backgroundColor ?? 657930
|
|
477
479
|
);
|
|
478
|
-
const { width: t, height:
|
|
479
|
-
this.camera = new
|
|
480
|
+
const { width: t, height: o } = ze(e), i = s.cameraFov ?? 75;
|
|
481
|
+
this.camera = new m.PerspectiveCamera(i, t / o, 0.1, 2e3);
|
|
480
482
|
const a = s.cameraPosition ?? { x: 0, y: 0, z: 80 };
|
|
481
|
-
this.camera.position.set(a.x, a.y, a.z), this.renderer = new
|
|
483
|
+
this.camera.position.set(a.x, a.y, a.z), this.renderer = new m.WebGLRenderer({
|
|
482
484
|
antialias: !0,
|
|
483
485
|
alpha: !0,
|
|
484
486
|
powerPreference: "high-performance"
|
|
485
|
-
}), this.renderer.setSize(t,
|
|
487
|
+
}), this.renderer.setSize(t, o), this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)), this.renderer.toneMapping = m.ACESFilmicToneMapping, this.renderer.toneMappingExposure = 1, this.renderer.shadowMap.enabled = !0, this.renderer.shadowMap.type = m.PCFSoftShadowMap, e.appendChild(this.renderer.domElement), this.controls = new gt(this.camera, this.renderer.domElement), this.controls.enableDamping = !0, this.controls.dampingFactor = 0.05, this.controls.rotateSpeed = 0.8, this.controls.zoomSpeed = 1.2, this.controls.minDistance = 10, this.controls.maxDistance = 500, this.setupLighting(), this.resizeHandler = this.onWindowResize.bind(this), window.addEventListener("resize", this.resizeHandler);
|
|
486
488
|
}
|
|
487
489
|
/**
|
|
488
490
|
* Sets up scene lighting for gradient glass on dark background
|
|
489
491
|
*/
|
|
490
492
|
setupLighting() {
|
|
491
|
-
const e = new
|
|
493
|
+
const e = new m.AmbientLight(16777215, 0.4);
|
|
492
494
|
this.scene.add(e);
|
|
493
|
-
const s = new
|
|
495
|
+
const s = new m.DirectionalLight(16777215, 0.9);
|
|
494
496
|
s.position.set(50, 60, 40), s.castShadow = !0, s.shadow.mapSize.width = 1024, s.shadow.mapSize.height = 1024, this.scene.add(s);
|
|
495
|
-
const t = new
|
|
497
|
+
const t = new m.DirectionalLight(16773344, 0.4);
|
|
496
498
|
t.position.set(-50, 30, -40), this.scene.add(t);
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
const
|
|
500
|
-
|
|
501
|
-
const a = new
|
|
499
|
+
const o = new m.DirectionalLight(16777215, 0.3);
|
|
500
|
+
o.position.set(0, -30, -50), this.scene.add(o);
|
|
501
|
+
const i = new m.PointLight(16750950, 0.5, 150);
|
|
502
|
+
i.position.set(40, 20, 40), this.scene.add(i);
|
|
503
|
+
const a = new m.PointLight(16764057, 0.4, 150);
|
|
502
504
|
a.position.set(-40, -20, 40), this.scene.add(a);
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
+
const r = new m.PointLight(6724095, 0.2, 100);
|
|
506
|
+
r.position.set(0, 40, -40), this.scene.add(r);
|
|
505
507
|
}
|
|
506
508
|
/**
|
|
507
509
|
* Handle window resize
|
|
508
510
|
*/
|
|
509
511
|
onWindowResize() {
|
|
510
|
-
const { width: e, height: s } =
|
|
512
|
+
const { width: e, height: s } = ze(this.container);
|
|
511
513
|
this.camera.aspect = e / s, this.camera.updateProjectionMatrix(), this.renderer.setSize(e, s);
|
|
512
514
|
}
|
|
513
515
|
/**
|
|
@@ -542,7 +544,7 @@ class ut {
|
|
|
542
544
|
* Gets the camera's forward direction
|
|
543
545
|
*/
|
|
544
546
|
getCameraDirection() {
|
|
545
|
-
const e = new
|
|
547
|
+
const e = new m.Vector3();
|
|
546
548
|
return this.camera.getWorldDirection(e), e;
|
|
547
549
|
}
|
|
548
550
|
/**
|
|
@@ -555,12 +557,12 @@ class ut {
|
|
|
555
557
|
}
|
|
556
558
|
}
|
|
557
559
|
}
|
|
558
|
-
class
|
|
560
|
+
class ft {
|
|
559
561
|
constructor(e, s) {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
562
|
+
l(this, "sceneManager");
|
|
563
|
+
l(this, "nodeFactory");
|
|
564
|
+
l(this, "nodes", /* @__PURE__ */ new Map());
|
|
565
|
+
l(this, "nodeObjects", /* @__PURE__ */ new Map());
|
|
564
566
|
this.sceneManager = e, this.nodeFactory = s;
|
|
565
567
|
}
|
|
566
568
|
/**
|
|
@@ -574,7 +576,7 @@ class mt {
|
|
|
574
576
|
* @returns true if added, false if node already exists or invalid
|
|
575
577
|
*/
|
|
576
578
|
addNode(e, s = 0) {
|
|
577
|
-
if (!
|
|
579
|
+
if (!Oe(e))
|
|
578
580
|
return !1;
|
|
579
581
|
if (this.nodes.has(e.id))
|
|
580
582
|
return console.warn(`[ForceGraph3D] Node with id "${e.id}" already exists`), !1;
|
|
@@ -582,16 +584,16 @@ class mt {
|
|
|
582
584
|
x: (Math.random() - 0.5) * 50,
|
|
583
585
|
y: (Math.random() - 0.5) * 50,
|
|
584
586
|
z: (Math.random() - 0.5) * 50
|
|
585
|
-
},
|
|
587
|
+
}, o = {
|
|
586
588
|
...e,
|
|
587
589
|
position: t,
|
|
588
590
|
velocity: { x: 0, y: 0, z: 0 },
|
|
589
591
|
mass: 1
|
|
590
|
-
},
|
|
592
|
+
}, i = this.nodeFactory.createNode(
|
|
591
593
|
{ ...e, position: t },
|
|
592
594
|
s
|
|
593
595
|
);
|
|
594
|
-
return this.sceneManager.add(
|
|
596
|
+
return this.sceneManager.add(i.group), this.nodes.set(e.id, o), this.nodeObjects.set(e.id, i), !0;
|
|
595
597
|
}
|
|
596
598
|
/**
|
|
597
599
|
* Removes a node from the graph
|
|
@@ -605,17 +607,17 @@ class mt {
|
|
|
605
607
|
* Updates a node's properties
|
|
606
608
|
*/
|
|
607
609
|
updateNode(e, s) {
|
|
608
|
-
const t = this.nodes.get(e),
|
|
609
|
-
return !t || !
|
|
610
|
-
|
|
610
|
+
const t = this.nodes.get(e), o = this.nodeObjects.get(e);
|
|
611
|
+
return !t || !o ? (console.warn(`[ForceGraph3D] Node "${e}" not found`), !1) : (s.label !== void 0 && (t.label = s.label, this.nodeFactory.updateNodeLabel(o, s.label)), s.color !== void 0 && (t.color = s.color, this.nodeFactory.updateNodeColor(o, s.color)), Object.keys(s).forEach((i) => {
|
|
612
|
+
i !== "id" && i !== "label" && i !== "color" && i !== "position" && (t[i] = s[i]);
|
|
611
613
|
}), !0);
|
|
612
614
|
}
|
|
613
615
|
/**
|
|
614
616
|
* Updates a node's position (called by physics engine)
|
|
615
617
|
*/
|
|
616
618
|
updateNodePosition(e, s) {
|
|
617
|
-
const t = this.nodes.get(e),
|
|
618
|
-
t &&
|
|
619
|
+
const t = this.nodes.get(e), o = this.nodeObjects.get(e);
|
|
620
|
+
t && o && (t.position = s, o.group.position.set(s.x, s.y, s.z));
|
|
619
621
|
}
|
|
620
622
|
/**
|
|
621
623
|
* Updates a node's LOD level
|
|
@@ -681,22 +683,22 @@ class mt {
|
|
|
681
683
|
this.clear();
|
|
682
684
|
}
|
|
683
685
|
}
|
|
684
|
-
class
|
|
686
|
+
class mt {
|
|
685
687
|
constructor(e, s, t) {
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
688
|
+
l(this, "sceneManager");
|
|
689
|
+
l(this, "nodeManager");
|
|
690
|
+
l(this, "edgeFactory");
|
|
691
|
+
l(this, "edges", []);
|
|
692
|
+
l(this, "edgeObjects", []);
|
|
693
|
+
l(this, "edgeKeySet", /* @__PURE__ */ new Set());
|
|
694
|
+
l(this, "highlightedEdgeKey", null);
|
|
693
695
|
this.sceneManager = e, this.nodeManager = s, this.edgeFactory = t;
|
|
694
696
|
}
|
|
695
697
|
/**
|
|
696
698
|
* Checks if an edge exists
|
|
697
699
|
*/
|
|
698
700
|
hasEdge(e, s) {
|
|
699
|
-
const t =
|
|
701
|
+
const t = D(e, s);
|
|
700
702
|
return this.edgeKeySet.has(t);
|
|
701
703
|
}
|
|
702
704
|
/**
|
|
@@ -710,44 +712,44 @@ class ft {
|
|
|
710
712
|
return console.warn(`[ForceGraph3D] Source node "${e.source}" does not exist`), !1;
|
|
711
713
|
if (!this.nodeManager.hasNode(e.target))
|
|
712
714
|
return console.warn(`[ForceGraph3D] Target node "${e.target}" does not exist`), !1;
|
|
713
|
-
const s =
|
|
715
|
+
const s = D(e.source, e.target);
|
|
714
716
|
if (this.edgeKeySet.has(s))
|
|
715
717
|
return console.warn(`[ForceGraph3D] Edge "${e.source}" -> "${e.target}" already exists`), !1;
|
|
716
|
-
const t = this.nodeManager.getNode(e.source),
|
|
718
|
+
const t = this.nodeManager.getNode(e.source), o = this.nodeManager.getNode(e.target), i = this.edgeFactory.createEdge(
|
|
717
719
|
e,
|
|
718
720
|
t,
|
|
719
|
-
|
|
721
|
+
o,
|
|
720
722
|
t.position,
|
|
721
|
-
|
|
723
|
+
o.position
|
|
722
724
|
);
|
|
723
|
-
return this.sceneManager.add(
|
|
725
|
+
return this.sceneManager.add(i.line), this.edges.push(e), this.edgeObjects.push(i), this.edgeKeySet.add(s), !0;
|
|
724
726
|
}
|
|
725
727
|
/**
|
|
726
728
|
* Removes an edge from the graph
|
|
727
729
|
* @returns true if removed, false if not found
|
|
728
730
|
*/
|
|
729
731
|
removeEdge(e, s) {
|
|
730
|
-
const t =
|
|
732
|
+
const t = D(e, s);
|
|
731
733
|
if (!this.edgeKeySet.has(t))
|
|
732
734
|
return !1;
|
|
733
|
-
const
|
|
734
|
-
(a) =>
|
|
735
|
+
const o = this.edges.findIndex(
|
|
736
|
+
(a) => D(a.source, a.target) === t
|
|
735
737
|
);
|
|
736
|
-
if (
|
|
738
|
+
if (o === -1)
|
|
737
739
|
return !1;
|
|
738
|
-
const
|
|
739
|
-
return this.sceneManager.remove(
|
|
740
|
+
const i = this.edgeObjects[o];
|
|
741
|
+
return this.sceneManager.remove(i.line), this.edgeFactory.disposeEdge(i), this.edges.splice(o, 1), this.edgeObjects.splice(o, 1), this.edgeKeySet.delete(t), this.highlightedEdgeKey === t && (this.highlightedEdgeKey = null), !0;
|
|
740
742
|
}
|
|
741
743
|
/**
|
|
742
744
|
* Highlights an edge
|
|
743
745
|
*/
|
|
744
746
|
highlightEdge(e, s) {
|
|
745
|
-
const t =
|
|
747
|
+
const t = D(e, s);
|
|
746
748
|
this.highlightedEdgeKey && this.highlightedEdgeKey !== t && this.unhighlightCurrentEdge();
|
|
747
|
-
const
|
|
748
|
-
(
|
|
749
|
+
const o = this.edges.findIndex(
|
|
750
|
+
(i) => D(i.source, i.target) === t
|
|
749
751
|
);
|
|
750
|
-
|
|
752
|
+
o !== -1 && (this.edgeFactory.highlightEdge(this.edgeObjects[o]), this.highlightedEdgeKey = t);
|
|
751
753
|
}
|
|
752
754
|
/**
|
|
753
755
|
* Unhighlights the currently highlighted edge
|
|
@@ -755,7 +757,7 @@ class ft {
|
|
|
755
757
|
unhighlightCurrentEdge() {
|
|
756
758
|
if (!this.highlightedEdgeKey) return;
|
|
757
759
|
const e = this.edges.findIndex(
|
|
758
|
-
(s) =>
|
|
760
|
+
(s) => D(s.source, s.target) === this.highlightedEdgeKey
|
|
759
761
|
);
|
|
760
762
|
e !== -1 && this.edgeFactory.unhighlightEdge(this.edgeObjects[e]), this.highlightedEdgeKey = null;
|
|
761
763
|
}
|
|
@@ -790,11 +792,11 @@ class ft {
|
|
|
790
792
|
*/
|
|
791
793
|
updateEdgePositions() {
|
|
792
794
|
this.edgeObjects.forEach((e, s) => {
|
|
793
|
-
const t = this.edges[s],
|
|
794
|
-
|
|
795
|
+
const t = this.edges[s], o = this.nodeManager.getNode(t.source), i = this.nodeManager.getNode(t.target);
|
|
796
|
+
o && i && this.edgeFactory.updateEdgePositions(
|
|
795
797
|
e,
|
|
796
|
-
|
|
797
|
-
|
|
798
|
+
o.position,
|
|
799
|
+
i.position
|
|
798
800
|
);
|
|
799
801
|
});
|
|
800
802
|
}
|
|
@@ -833,19 +835,19 @@ class ft {
|
|
|
833
835
|
}
|
|
834
836
|
class Le {
|
|
835
837
|
constructor(e, s, t = {}) {
|
|
836
|
-
|
|
837
|
-
|
|
838
|
+
l(this, "nodes");
|
|
839
|
+
l(this, "edges");
|
|
838
840
|
// Physics parameters
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
841
|
+
l(this, "repulsionStrength");
|
|
842
|
+
l(this, "attractionStrength");
|
|
843
|
+
l(this, "damping");
|
|
844
|
+
l(this, "useBarnesHut");
|
|
845
|
+
l(this, "barnesHutTheta");
|
|
844
846
|
// Simulation state
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
847
|
+
l(this, "alpha", 1);
|
|
848
|
+
l(this, "alphaDecay", 0.0228);
|
|
849
|
+
l(this, "alphaMin", 1e-3);
|
|
850
|
+
l(this, "alphaTarget", 0);
|
|
849
851
|
this.nodes = e, this.edges = s, this.repulsionStrength = t.repulsionStrength ?? 100, this.attractionStrength = t.attractionStrength ?? 0.01, this.damping = t.damping ?? 0.9, this.useBarnesHut = t.useBarnesHut ?? !1, this.barnesHutTheta = t.barnesHutTheta ?? 0.5;
|
|
850
852
|
}
|
|
851
853
|
/**
|
|
@@ -862,13 +864,13 @@ class Le {
|
|
|
862
864
|
calculateRepulsionBruteForce() {
|
|
863
865
|
const e = Array.from(this.nodes.values()), s = e.length;
|
|
864
866
|
for (let t = 0; t < s; t++) {
|
|
865
|
-
const
|
|
866
|
-
for (let
|
|
867
|
-
const a = e[
|
|
868
|
-
let
|
|
869
|
-
|
|
870
|
-
const
|
|
871
|
-
|
|
867
|
+
const o = e[t];
|
|
868
|
+
for (let i = t + 1; i < s; i++) {
|
|
869
|
+
const a = e[i], r = a.position.x - o.position.x, c = a.position.y - o.position.y, d = a.position.z - o.position.z;
|
|
870
|
+
let g = r * r + c * c + d * d;
|
|
871
|
+
g < 0.01 && (g = 0.01);
|
|
872
|
+
const u = Math.sqrt(g), y = this.repulsionStrength * this.alpha / g, f = r / u * y, x = c / u * y, v = d / u * y;
|
|
873
|
+
o.velocity.x -= f / o.mass, o.velocity.y -= x / o.mass, o.velocity.z -= v / o.mass, a.velocity.x += f / a.mass, a.velocity.y += x / a.mass, a.velocity.z += v / a.mass;
|
|
872
874
|
}
|
|
873
875
|
}
|
|
874
876
|
}
|
|
@@ -889,23 +891,23 @@ class Le {
|
|
|
889
891
|
return;
|
|
890
892
|
}
|
|
891
893
|
if (s.mass === 0) return;
|
|
892
|
-
const t = s.centerOfMass.x - e.position.x,
|
|
894
|
+
const t = s.centerOfMass.x - e.position.x, o = s.centerOfMass.y - e.position.y, i = s.centerOfMass.z - e.position.z, a = Math.sqrt(t * t + o * o + i * i);
|
|
893
895
|
if (s.size / a < this.barnesHutTheta) {
|
|
894
|
-
const
|
|
895
|
-
e.velocity.x -= t / a *
|
|
896
|
+
const r = Math.max(a * a, 0.01), c = this.repulsionStrength * this.alpha * s.mass / r;
|
|
897
|
+
e.velocity.x -= t / a * c / e.mass, e.velocity.y -= o / a * c / e.mass, e.velocity.z -= i / a * c / e.mass;
|
|
896
898
|
} else
|
|
897
|
-
for (const
|
|
898
|
-
|
|
899
|
+
for (const r of s.children)
|
|
900
|
+
r && this.calculateForceFromOctree(e, r);
|
|
899
901
|
}
|
|
900
902
|
/**
|
|
901
903
|
* Apply repulsion between two nodes
|
|
902
904
|
*/
|
|
903
905
|
applyRepulsionBetween(e, s) {
|
|
904
|
-
const t = s.position.x - e.position.x,
|
|
905
|
-
let a = t * t +
|
|
906
|
+
const t = s.position.x - e.position.x, o = s.position.y - e.position.y, i = s.position.z - e.position.z;
|
|
907
|
+
let a = t * t + o * o + i * i;
|
|
906
908
|
a < 0.01 && (a = 0.01);
|
|
907
|
-
const
|
|
908
|
-
e.velocity.x -= t /
|
|
909
|
+
const r = Math.sqrt(a), c = this.repulsionStrength * this.alpha / a;
|
|
910
|
+
e.velocity.x -= t / r * c / e.mass, e.velocity.y -= o / r * c / e.mass, e.velocity.z -= i / r * c / e.mass;
|
|
909
911
|
}
|
|
910
912
|
/**
|
|
911
913
|
* Calculate attraction forces along edges
|
|
@@ -914,10 +916,10 @@ class Le {
|
|
|
914
916
|
for (const e of this.edges) {
|
|
915
917
|
const s = this.nodes.get(e.source), t = this.nodes.get(e.target);
|
|
916
918
|
if (!s || !t) continue;
|
|
917
|
-
const
|
|
918
|
-
if (
|
|
919
|
-
const
|
|
920
|
-
s.velocity.x +=
|
|
919
|
+
const o = t.position.x - s.position.x, i = t.position.y - s.position.y, a = t.position.z - s.position.z, r = Math.sqrt(o * o + i * i + a * a);
|
|
920
|
+
if (r < 0.01) continue;
|
|
921
|
+
const d = (r - 15) * this.attractionStrength * this.alpha, g = o / r * d, u = i / r * d, y = a / r * d;
|
|
922
|
+
s.velocity.x += g / s.mass, s.velocity.y += u / s.mass, s.velocity.z += y / s.mass, t.velocity.x -= g / t.mass, t.velocity.y -= u / t.mass, t.velocity.z -= y / t.mass;
|
|
921
923
|
}
|
|
922
924
|
}
|
|
923
925
|
/**
|
|
@@ -954,7 +956,7 @@ class Le {
|
|
|
954
956
|
}
|
|
955
957
|
class yt {
|
|
956
958
|
constructor(e) {
|
|
957
|
-
|
|
959
|
+
l(this, "root");
|
|
958
960
|
const s = this.calculateBounds(e);
|
|
959
961
|
this.root = this.buildTree(e, s);
|
|
960
962
|
}
|
|
@@ -965,13 +967,13 @@ class yt {
|
|
|
965
967
|
max: { x: 100, y: 100, z: 100 }
|
|
966
968
|
};
|
|
967
969
|
const s = { x: 1 / 0, y: 1 / 0, z: 1 / 0 }, t = { x: -1 / 0, y: -1 / 0, z: -1 / 0 };
|
|
968
|
-
for (const
|
|
969
|
-
s.x = Math.min(s.x,
|
|
970
|
-
const
|
|
971
|
-
return s.x -=
|
|
970
|
+
for (const i of e)
|
|
971
|
+
s.x = Math.min(s.x, i.position.x), s.y = Math.min(s.y, i.position.y), s.z = Math.min(s.z, i.position.z), t.x = Math.max(t.x, i.position.x), t.y = Math.max(t.y, i.position.y), t.z = Math.max(t.z, i.position.z);
|
|
972
|
+
const o = 10;
|
|
973
|
+
return s.x -= o, s.y -= o, s.z -= o, t.x += o, t.y += o, t.z += o, { min: s, max: t };
|
|
972
974
|
}
|
|
973
975
|
buildTree(e, s, t = 0) {
|
|
974
|
-
const
|
|
976
|
+
const o = Math.max(
|
|
975
977
|
s.max.x - s.min.x,
|
|
976
978
|
s.max.y - s.min.y,
|
|
977
979
|
s.max.z - s.min.z
|
|
@@ -979,7 +981,7 @@ class yt {
|
|
|
979
981
|
if (e.length === 0)
|
|
980
982
|
return {
|
|
981
983
|
bounds: s,
|
|
982
|
-
size:
|
|
984
|
+
size: o,
|
|
983
985
|
centerOfMass: { x: 0, y: 0, z: 0 },
|
|
984
986
|
mass: 0,
|
|
985
987
|
isLeaf: !0,
|
|
@@ -988,70 +990,70 @@ class yt {
|
|
|
988
990
|
};
|
|
989
991
|
if (e.length === 1 || t > 20) {
|
|
990
992
|
let f = 0;
|
|
991
|
-
const
|
|
992
|
-
for (const
|
|
993
|
-
f +=
|
|
994
|
-
return f > 0 && (
|
|
993
|
+
const x = { x: 0, y: 0, z: 0 };
|
|
994
|
+
for (const v of e)
|
|
995
|
+
f += v.mass, x.x += v.position.x * v.mass, x.y += v.position.y * v.mass, x.z += v.position.z * v.mass;
|
|
996
|
+
return f > 0 && (x.x /= f, x.y /= f, x.z /= f), {
|
|
995
997
|
bounds: s,
|
|
996
|
-
size:
|
|
997
|
-
centerOfMass:
|
|
998
|
+
size: o,
|
|
999
|
+
centerOfMass: x,
|
|
998
1000
|
mass: f,
|
|
999
1001
|
isLeaf: !0,
|
|
1000
1002
|
node: e[0],
|
|
1001
1003
|
children: []
|
|
1002
1004
|
};
|
|
1003
1005
|
}
|
|
1004
|
-
const
|
|
1006
|
+
const i = (s.min.x + s.max.x) / 2, a = (s.min.y + s.max.y) / 2, r = (s.min.z + s.max.z) / 2, c = [[], [], [], [], [], [], [], []];
|
|
1005
1007
|
for (const f of e) {
|
|
1006
|
-
const
|
|
1007
|
-
|
|
1008
|
-
}
|
|
1009
|
-
const
|
|
1010
|
-
{ min: { x: s.min.x, y: s.min.y, z: s.min.z }, max: { x:
|
|
1011
|
-
{ min: { x:
|
|
1012
|
-
{ min: { x: s.min.x, y: a, z: s.min.z }, max: { x:
|
|
1013
|
-
{ min: { x:
|
|
1014
|
-
{ min: { x: s.min.x, y: s.min.y, z:
|
|
1015
|
-
{ min: { x:
|
|
1016
|
-
{ min: { x: s.min.x, y: a, z:
|
|
1017
|
-
{ min: { x:
|
|
1018
|
-
],
|
|
1019
|
-
let
|
|
1020
|
-
const
|
|
1008
|
+
const x = (f.position.x >= i ? 1 : 0) + (f.position.y >= a ? 2 : 0) + (f.position.z >= r ? 4 : 0);
|
|
1009
|
+
c[x].push(f);
|
|
1010
|
+
}
|
|
1011
|
+
const d = [
|
|
1012
|
+
{ min: { x: s.min.x, y: s.min.y, z: s.min.z }, max: { x: i, y: a, z: r } },
|
|
1013
|
+
{ min: { x: i, y: s.min.y, z: s.min.z }, max: { x: s.max.x, y: a, z: r } },
|
|
1014
|
+
{ min: { x: s.min.x, y: a, z: s.min.z }, max: { x: i, y: s.max.y, z: r } },
|
|
1015
|
+
{ min: { x: i, y: a, z: s.min.z }, max: { x: s.max.x, y: s.max.y, z: r } },
|
|
1016
|
+
{ min: { x: s.min.x, y: s.min.y, z: r }, max: { x: i, y: a, z: s.max.z } },
|
|
1017
|
+
{ min: { x: i, y: s.min.y, z: r }, max: { x: s.max.x, y: a, z: s.max.z } },
|
|
1018
|
+
{ min: { x: s.min.x, y: a, z: r }, max: { x: i, y: s.max.y, z: s.max.z } },
|
|
1019
|
+
{ min: { x: i, y: a, z: r }, max: { x: s.max.x, y: s.max.y, z: s.max.z } }
|
|
1020
|
+
], g = [];
|
|
1021
|
+
let u = 0;
|
|
1022
|
+
const y = { x: 0, y: 0, z: 0 };
|
|
1021
1023
|
for (let f = 0; f < 8; f++)
|
|
1022
|
-
if (
|
|
1023
|
-
const
|
|
1024
|
-
|
|
1024
|
+
if (c[f].length > 0) {
|
|
1025
|
+
const x = this.buildTree(c[f], d[f], t + 1);
|
|
1026
|
+
g.push(x), u += x.mass, y.x += x.centerOfMass.x * x.mass, y.y += x.centerOfMass.y * x.mass, y.z += x.centerOfMass.z * x.mass;
|
|
1025
1027
|
} else
|
|
1026
|
-
|
|
1027
|
-
return
|
|
1028
|
+
g.push(null);
|
|
1029
|
+
return u > 0 && (y.x /= u, y.y /= u, y.z /= u), {
|
|
1028
1030
|
bounds: s,
|
|
1029
|
-
size:
|
|
1030
|
-
centerOfMass:
|
|
1031
|
-
mass:
|
|
1031
|
+
size: o,
|
|
1032
|
+
centerOfMass: y,
|
|
1033
|
+
mass: u,
|
|
1032
1034
|
isLeaf: !1,
|
|
1033
1035
|
node: null,
|
|
1034
|
-
children:
|
|
1036
|
+
children: g
|
|
1035
1037
|
};
|
|
1036
1038
|
}
|
|
1037
1039
|
}
|
|
1038
|
-
class
|
|
1039
|
-
constructor(e, s, t,
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1040
|
+
class xt {
|
|
1041
|
+
constructor(e, s, t, o = 60) {
|
|
1042
|
+
l(this, "sceneManager");
|
|
1043
|
+
l(this, "animationId", null);
|
|
1044
|
+
l(this, "isRunning", !1);
|
|
1045
|
+
l(this, "frameInterval");
|
|
1046
|
+
l(this, "lastFrameTime", 0);
|
|
1047
|
+
l(this, "onSimulate");
|
|
1048
|
+
l(this, "onRender");
|
|
1047
1049
|
// Performance monitoring
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1050
|
+
l(this, "frameCount", 0);
|
|
1051
|
+
l(this, "fpsStartTime", 0);
|
|
1052
|
+
l(this, "currentFPS", 60);
|
|
1051
1053
|
/**
|
|
1052
1054
|
* Main animation loop
|
|
1053
1055
|
*/
|
|
1054
|
-
|
|
1056
|
+
l(this, "animate", () => {
|
|
1055
1057
|
if (!this.isRunning) return;
|
|
1056
1058
|
this.animationId = requestAnimationFrame(this.animate);
|
|
1057
1059
|
const e = performance.now(), s = e - this.lastFrameTime;
|
|
@@ -1061,7 +1063,7 @@ class bt {
|
|
|
1061
1063
|
const t = e - this.fpsStartTime;
|
|
1062
1064
|
t >= 1e3 && (this.currentFPS = this.frameCount / (t / 1e3), this.frameCount = 0, this.fpsStartTime = e), this.onSimulate(), this.onRender(), this.sceneManager.render();
|
|
1063
1065
|
});
|
|
1064
|
-
this.sceneManager = e, this.onSimulate = s, this.onRender = t, this.frameInterval = 1e3 /
|
|
1066
|
+
this.sceneManager = e, this.onSimulate = s, this.onRender = t, this.frameInterval = 1e3 / o;
|
|
1065
1067
|
}
|
|
1066
1068
|
/**
|
|
1067
1069
|
* Starts the animation loop
|
|
@@ -1100,12 +1102,12 @@ class bt {
|
|
|
1100
1102
|
this.stop();
|
|
1101
1103
|
}
|
|
1102
1104
|
}
|
|
1103
|
-
class
|
|
1105
|
+
class bt {
|
|
1104
1106
|
constructor() {
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
+
l(this, "envMap", null);
|
|
1108
|
+
l(this, "materialCache", /* @__PURE__ */ new Map());
|
|
1107
1109
|
// Color palette - white and tangerine
|
|
1108
|
-
|
|
1110
|
+
l(this, "COLORS", [
|
|
1109
1111
|
16777215,
|
|
1110
1112
|
// White
|
|
1111
1113
|
16750950,
|
|
@@ -1138,10 +1140,10 @@ class xt {
|
|
|
1138
1140
|
{ colors: ["#2d1a1a", "#1a0a0a", "#0f0505"] }
|
|
1139
1141
|
// -z
|
|
1140
1142
|
];
|
|
1141
|
-
for (const
|
|
1142
|
-
const
|
|
1143
|
-
|
|
1144
|
-
const a =
|
|
1143
|
+
for (const o of t) {
|
|
1144
|
+
const i = document.createElement("canvas");
|
|
1145
|
+
i.width = 256, i.height = 256;
|
|
1146
|
+
const a = i.getContext("2d"), r = a.createRadialGradient(
|
|
1145
1147
|
256 / 2,
|
|
1146
1148
|
256 / 2,
|
|
1147
1149
|
0,
|
|
@@ -1149,17 +1151,17 @@ class xt {
|
|
|
1149
1151
|
256 / 2,
|
|
1150
1152
|
256 * 0.8
|
|
1151
1153
|
);
|
|
1152
|
-
|
|
1153
|
-
const
|
|
1154
|
-
for (let
|
|
1155
|
-
const
|
|
1156
|
-
|
|
1154
|
+
r.addColorStop(0, o.colors[0]), r.addColorStop(0.5, o.colors[1]), r.addColorStop(1, o.colors[2]), a.fillStyle = r, a.fillRect(0, 0, 256, 256);
|
|
1155
|
+
const c = a.getImageData(0, 0, 256, 256);
|
|
1156
|
+
for (let d = 0; d < c.data.length; d += 4) {
|
|
1157
|
+
const g = (Math.random() - 0.5) * 5;
|
|
1158
|
+
c.data[d] = Math.min(255, Math.max(0, c.data[d] + g)), c.data[d + 1] = Math.min(255, Math.max(0, c.data[d + 1] + g)), c.data[d + 2] = Math.min(255, Math.max(0, c.data[d + 2] + g));
|
|
1157
1159
|
}
|
|
1158
|
-
a.putImageData(
|
|
1160
|
+
a.putImageData(c, 0, 0), s.push(i);
|
|
1159
1161
|
}
|
|
1160
|
-
this.envMap = new
|
|
1161
|
-
const
|
|
1162
|
-
return
|
|
1162
|
+
this.envMap = new m.CubeTexture(s.map((o) => {
|
|
1163
|
+
const i = new Image();
|
|
1164
|
+
return i.src = o.toDataURL(), i;
|
|
1163
1165
|
})), this.envMap.needsUpdate = !0;
|
|
1164
1166
|
}
|
|
1165
1167
|
/**
|
|
@@ -1176,11 +1178,11 @@ class xt {
|
|
|
1176
1178
|
const t = "glass-single";
|
|
1177
1179
|
if (this.materialCache.has(t))
|
|
1178
1180
|
return this.materialCache.get(t).clone();
|
|
1179
|
-
const
|
|
1181
|
+
const o = new m.Color(16750950), i = new m.ShaderMaterial({
|
|
1180
1182
|
uniforms: {
|
|
1181
|
-
uColor: { value:
|
|
1183
|
+
uColor: { value: o },
|
|
1182
1184
|
uEnvMap: { value: this.envMap },
|
|
1183
|
-
uGlowColor: { value: new
|
|
1185
|
+
uGlowColor: { value: new m.Color(16777215) },
|
|
1184
1186
|
uGlowIntensity: { value: 0.8 },
|
|
1185
1187
|
uReflectivity: { value: 0.4 },
|
|
1186
1188
|
uFresnelPower: { value: 2.5 }
|
|
@@ -1246,17 +1248,17 @@ class xt {
|
|
|
1246
1248
|
}
|
|
1247
1249
|
`,
|
|
1248
1250
|
transparent: !0,
|
|
1249
|
-
side:
|
|
1251
|
+
side: m.FrontSide,
|
|
1250
1252
|
depthWrite: !0,
|
|
1251
|
-
blending:
|
|
1253
|
+
blending: m.NormalBlending
|
|
1252
1254
|
});
|
|
1253
|
-
return this.materialCache.set(t,
|
|
1255
|
+
return this.materialCache.set(t, i), i.clone();
|
|
1254
1256
|
}
|
|
1255
1257
|
/**
|
|
1256
1258
|
* Creates material for edges (light color for dark background)
|
|
1257
1259
|
*/
|
|
1258
1260
|
createEdgeMaterial(e = 6710886, s = 0.4) {
|
|
1259
|
-
return new
|
|
1261
|
+
return new m.LineBasicMaterial({
|
|
1260
1262
|
color: e,
|
|
1261
1263
|
transparent: !0,
|
|
1262
1264
|
opacity: s,
|
|
@@ -1267,7 +1269,7 @@ class xt {
|
|
|
1267
1269
|
* Creates highlighted edge material
|
|
1268
1270
|
*/
|
|
1269
1271
|
createHighlightedEdgeMaterial() {
|
|
1270
|
-
return new
|
|
1272
|
+
return new m.LineBasicMaterial({
|
|
1271
1273
|
color: 16750950,
|
|
1272
1274
|
// Tangerine highlight
|
|
1273
1275
|
transparent: !1,
|
|
@@ -1279,13 +1281,13 @@ class xt {
|
|
|
1279
1281
|
* Creates a sprite material for labels (light text for dark background)
|
|
1280
1282
|
*/
|
|
1281
1283
|
createLabelMaterial(e, s = 24) {
|
|
1282
|
-
const t = document.createElement("canvas"),
|
|
1283
|
-
|
|
1284
|
-
const a =
|
|
1285
|
-
t.width = Math.max(128, a + 24), t.height = s + 20,
|
|
1286
|
-
const
|
|
1287
|
-
return
|
|
1288
|
-
map:
|
|
1284
|
+
const t = document.createElement("canvas"), o = t.getContext("2d");
|
|
1285
|
+
o.font = `600 ${s}px Inter, -apple-system, sans-serif`;
|
|
1286
|
+
const a = o.measureText(e).width;
|
|
1287
|
+
t.width = Math.max(128, a + 24), t.height = s + 20, o.clearRect(0, 0, t.width, t.height), o.font = `600 ${s}px Inter, -apple-system, sans-serif`, o.textAlign = "center", o.textBaseline = "middle", o.shadowColor = "rgba(0, 0, 0, 0.8)", o.shadowBlur = 4, o.shadowOffsetX = 1, o.shadowOffsetY = 1, o.fillStyle = "rgba(255, 255, 255, 0.95)", o.fillText(e, t.width / 2, t.height / 2);
|
|
1288
|
+
const r = new m.CanvasTexture(t);
|
|
1289
|
+
return r.needsUpdate = !0, new m.SpriteMaterial({
|
|
1290
|
+
map: r,
|
|
1289
1291
|
transparent: !0,
|
|
1290
1292
|
depthTest: !1,
|
|
1291
1293
|
depthWrite: !1
|
|
@@ -1306,10 +1308,10 @@ class xt {
|
|
|
1306
1308
|
}
|
|
1307
1309
|
class vt {
|
|
1308
1310
|
constructor(e, s = 2, t = [32, 16, 8]) {
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1311
|
+
l(this, "materialFactory");
|
|
1312
|
+
l(this, "geometryCache", /* @__PURE__ */ new Map());
|
|
1313
|
+
l(this, "nodeRadius");
|
|
1314
|
+
l(this, "lodSegments");
|
|
1313
1315
|
this.materialFactory = e, this.nodeRadius = s, this.lodSegments = t, this.initGeometryCache();
|
|
1314
1316
|
}
|
|
1315
1317
|
/**
|
|
@@ -1320,7 +1322,7 @@ class vt {
|
|
|
1320
1322
|
const t = `lod-${s}`;
|
|
1321
1323
|
this.geometryCache.set(
|
|
1322
1324
|
t,
|
|
1323
|
-
new
|
|
1325
|
+
new m.SphereGeometry(this.nodeRadius, e, e)
|
|
1324
1326
|
);
|
|
1325
1327
|
});
|
|
1326
1328
|
}
|
|
@@ -1335,21 +1337,21 @@ class vt {
|
|
|
1335
1337
|
* Creates a node visual (glass ball + label)
|
|
1336
1338
|
*/
|
|
1337
1339
|
createNode(e, s = 0) {
|
|
1338
|
-
const t = new
|
|
1340
|
+
const t = new m.Group();
|
|
1339
1341
|
t.name = `node-${e.id}`, t.userData = { nodeId: e.id, nodeData: e };
|
|
1340
|
-
const
|
|
1342
|
+
const o = this.getGeometry(s), i = this.materialFactory.createGlassMaterial(
|
|
1341
1343
|
e.color ?? 4886754
|
|
1342
|
-
), a = new
|
|
1344
|
+
), a = new m.Mesh(o, i);
|
|
1343
1345
|
a.castShadow = !0, a.receiveShadow = !0, t.add(a);
|
|
1344
|
-
const
|
|
1345
|
-
return
|
|
1346
|
+
const r = this.materialFactory.createLabelMaterial(e.label), c = new m.Sprite(r);
|
|
1347
|
+
return c.position.y = this.nodeRadius + 1.5, c.scale.set(4, 1, 1), t.add(c), e.position && t.position.set(
|
|
1346
1348
|
e.position.x,
|
|
1347
1349
|
e.position.y,
|
|
1348
1350
|
e.position.z
|
|
1349
1351
|
), {
|
|
1350
1352
|
group: t,
|
|
1351
1353
|
sphere: a,
|
|
1352
|
-
label:
|
|
1354
|
+
label: c,
|
|
1353
1355
|
lodLevel: s
|
|
1354
1356
|
};
|
|
1355
1357
|
}
|
|
@@ -1365,19 +1367,19 @@ class vt {
|
|
|
1365
1367
|
* Updates the color of a node
|
|
1366
1368
|
*/
|
|
1367
1369
|
updateNodeColor(e, s) {
|
|
1368
|
-
e.sphere.material instanceof
|
|
1370
|
+
e.sphere.material instanceof m.Material && e.sphere.material.dispose(), e.sphere.material = this.materialFactory.createGlassMaterial(s);
|
|
1369
1371
|
}
|
|
1370
1372
|
/**
|
|
1371
1373
|
* Updates the label of a node
|
|
1372
1374
|
*/
|
|
1373
1375
|
updateNodeLabel(e, s) {
|
|
1374
|
-
e.label.material instanceof
|
|
1376
|
+
e.label.material instanceof m.SpriteMaterial && (e.label.material.map && e.label.material.map.dispose(), e.label.material.dispose()), e.label.material = this.materialFactory.createLabelMaterial(s);
|
|
1375
1377
|
}
|
|
1376
1378
|
/**
|
|
1377
1379
|
* Disposes a node's resources
|
|
1378
1380
|
*/
|
|
1379
1381
|
disposeNode(e) {
|
|
1380
|
-
e.sphere.material instanceof
|
|
1382
|
+
e.sphere.material instanceof m.Material && e.sphere.material.dispose(), e.label.material instanceof m.SpriteMaterial && (e.label.material.map && e.label.material.map.dispose(), e.label.material.dispose());
|
|
1381
1383
|
}
|
|
1382
1384
|
/**
|
|
1383
1385
|
* Dispose factory resources
|
|
@@ -1388,11 +1390,11 @@ class vt {
|
|
|
1388
1390
|
}
|
|
1389
1391
|
class Mt {
|
|
1390
1392
|
constructor(e, s = 10066329, t = 0.5) {
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1393
|
+
l(this, "materialFactory");
|
|
1394
|
+
l(this, "edgeColor");
|
|
1395
|
+
l(this, "edgeOpacity");
|
|
1396
|
+
l(this, "defaultMaterial", null);
|
|
1397
|
+
l(this, "highlightMaterial", null);
|
|
1396
1398
|
this.materialFactory = e, this.edgeColor = s, this.edgeOpacity = t;
|
|
1397
1399
|
}
|
|
1398
1400
|
/**
|
|
@@ -1413,25 +1415,25 @@ class Mt {
|
|
|
1413
1415
|
/**
|
|
1414
1416
|
* Creates an edge line between two positions
|
|
1415
1417
|
*/
|
|
1416
|
-
createEdge(e, s, t,
|
|
1417
|
-
const a = new
|
|
1418
|
-
n.x,
|
|
1419
|
-
n.y,
|
|
1420
|
-
n.z,
|
|
1418
|
+
createEdge(e, s, t, o, i) {
|
|
1419
|
+
const a = new m.BufferGeometry(), r = new Float32Array([
|
|
1421
1420
|
o.x,
|
|
1422
1421
|
o.y,
|
|
1423
|
-
o.z
|
|
1422
|
+
o.z,
|
|
1423
|
+
i.x,
|
|
1424
|
+
i.y,
|
|
1425
|
+
i.z
|
|
1424
1426
|
]);
|
|
1425
|
-
a.setAttribute("position", new
|
|
1426
|
-
const
|
|
1427
|
-
return
|
|
1427
|
+
a.setAttribute("position", new m.BufferAttribute(r, 3));
|
|
1428
|
+
const c = this.getDefaultMaterial().clone(), d = new m.Line(a, c);
|
|
1429
|
+
return d.name = `edge-${e.source}-${e.target}`, d.userData = {
|
|
1428
1430
|
source: e.source,
|
|
1429
1431
|
target: e.target,
|
|
1430
1432
|
edge: e,
|
|
1431
1433
|
sourceNode: s,
|
|
1432
1434
|
targetNode: t
|
|
1433
|
-
},
|
|
1434
|
-
line:
|
|
1435
|
+
}, d.frustumCulled = !0, {
|
|
1436
|
+
line: d,
|
|
1435
1437
|
source: e.source,
|
|
1436
1438
|
target: e.target
|
|
1437
1439
|
};
|
|
@@ -1440,26 +1442,26 @@ class Mt {
|
|
|
1440
1442
|
* Highlights an edge
|
|
1441
1443
|
*/
|
|
1442
1444
|
highlightEdge(e) {
|
|
1443
|
-
e.line.material instanceof
|
|
1445
|
+
e.line.material instanceof m.Material && e.line.material.dispose(), e.line.material = this.getHighlightMaterial().clone();
|
|
1444
1446
|
}
|
|
1445
1447
|
/**
|
|
1446
1448
|
* Resets an edge to default appearance
|
|
1447
1449
|
*/
|
|
1448
1450
|
unhighlightEdge(e) {
|
|
1449
|
-
e.line.material instanceof
|
|
1451
|
+
e.line.material instanceof m.Material && e.line.material.dispose(), e.line.material = this.getDefaultMaterial().clone();
|
|
1450
1452
|
}
|
|
1451
1453
|
/**
|
|
1452
1454
|
* Updates an edge's positions
|
|
1453
1455
|
*/
|
|
1454
1456
|
updateEdgePositions(e, s, t) {
|
|
1455
|
-
const
|
|
1456
|
-
|
|
1457
|
+
const o = e.line.geometry.attributes.position, i = o.array;
|
|
1458
|
+
i[0] = s.x, i[1] = s.y, i[2] = s.z, i[3] = t.x, i[4] = t.y, i[5] = t.z, o.needsUpdate = !0, e.line.geometry.computeBoundingSphere();
|
|
1457
1459
|
}
|
|
1458
1460
|
/**
|
|
1459
1461
|
* Disposes an edge's resources
|
|
1460
1462
|
*/
|
|
1461
1463
|
disposeEdge(e) {
|
|
1462
|
-
e.line.geometry.dispose(), e.line.material instanceof
|
|
1464
|
+
e.line.geometry.dispose(), e.line.material instanceof m.Material && e.line.material.dispose();
|
|
1463
1465
|
}
|
|
1464
1466
|
/**
|
|
1465
1467
|
* Dispose factory resources
|
|
@@ -1470,9 +1472,9 @@ class Mt {
|
|
|
1470
1472
|
}
|
|
1471
1473
|
class wt {
|
|
1472
1474
|
constructor(e, s = [50, 100, 200], t = !0) {
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1475
|
+
l(this, "camera");
|
|
1476
|
+
l(this, "lodDistances");
|
|
1477
|
+
l(this, "enabled");
|
|
1476
1478
|
this.camera = e, this.lodDistances = s, this.enabled = t;
|
|
1477
1479
|
}
|
|
1478
1480
|
/**
|
|
@@ -1480,16 +1482,16 @@ class wt {
|
|
|
1480
1482
|
*/
|
|
1481
1483
|
getLODLevel(e) {
|
|
1482
1484
|
if (!this.enabled)
|
|
1483
|
-
return
|
|
1484
|
-
const s = e.x - this.camera.position.x, t = e.y - this.camera.position.y,
|
|
1485
|
-
return
|
|
1485
|
+
return U.HIGH;
|
|
1486
|
+
const s = e.x - this.camera.position.x, t = e.y - this.camera.position.y, o = e.z - this.camera.position.z, i = Math.sqrt(s * s + t * t + o * o);
|
|
1487
|
+
return i < this.lodDistances[0] ? U.HIGH : i < this.lodDistances[1] ? U.MEDIUM : U.LOW;
|
|
1486
1488
|
}
|
|
1487
1489
|
/**
|
|
1488
1490
|
* Checks if a node should be visible based on distance
|
|
1489
1491
|
*/
|
|
1490
1492
|
shouldRenderNode(e, s = 500) {
|
|
1491
|
-
const t = e.x - this.camera.position.x,
|
|
1492
|
-
return Math.sqrt(t * t +
|
|
1493
|
+
const t = e.x - this.camera.position.x, o = e.y - this.camera.position.y, i = e.z - this.camera.position.z;
|
|
1494
|
+
return Math.sqrt(t * t + o * o + i * i) < s;
|
|
1493
1495
|
}
|
|
1494
1496
|
/**
|
|
1495
1497
|
* Sets the LOD distances
|
|
@@ -1506,11 +1508,11 @@ class wt {
|
|
|
1506
1508
|
}
|
|
1507
1509
|
class Et {
|
|
1508
1510
|
constructor(e, s = !0) {
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
this.camera = e, this.frustum = new
|
|
1511
|
+
l(this, "camera");
|
|
1512
|
+
l(this, "frustum");
|
|
1513
|
+
l(this, "projScreenMatrix");
|
|
1514
|
+
l(this, "enabled");
|
|
1515
|
+
this.camera = e, this.frustum = new m.Frustum(), this.projScreenMatrix = new m.Matrix4(), this.enabled = s;
|
|
1514
1516
|
}
|
|
1515
1517
|
/**
|
|
1516
1518
|
* Updates the frustum from the camera
|
|
@@ -1526,7 +1528,7 @@ class Et {
|
|
|
1526
1528
|
*/
|
|
1527
1529
|
isPointVisible(e) {
|
|
1528
1530
|
if (!this.enabled) return !0;
|
|
1529
|
-
const s = new
|
|
1531
|
+
const s = new m.Vector3(e.x, e.y, e.z);
|
|
1530
1532
|
return this.frustum.containsPoint(s);
|
|
1531
1533
|
}
|
|
1532
1534
|
/**
|
|
@@ -1534,8 +1536,8 @@ class Et {
|
|
|
1534
1536
|
*/
|
|
1535
1537
|
isSphereVisible(e, s) {
|
|
1536
1538
|
if (!this.enabled) return !0;
|
|
1537
|
-
const t = new
|
|
1538
|
-
new
|
|
1539
|
+
const t = new m.Sphere(
|
|
1540
|
+
new m.Vector3(e.x, e.y, e.z),
|
|
1539
1541
|
s
|
|
1540
1542
|
);
|
|
1541
1543
|
return this.frustum.intersectsSphere(t);
|
|
@@ -1545,15 +1547,15 @@ class Et {
|
|
|
1545
1547
|
*/
|
|
1546
1548
|
isLineVisible(e, s) {
|
|
1547
1549
|
if (!this.enabled) return !0;
|
|
1548
|
-
const t = new
|
|
1549
|
-
if (this.frustum.containsPoint(t) || this.frustum.containsPoint(
|
|
1550
|
+
const t = new m.Vector3(e.x, e.y, e.z), o = new m.Vector3(s.x, s.y, s.z);
|
|
1551
|
+
if (this.frustum.containsPoint(t) || this.frustum.containsPoint(o))
|
|
1550
1552
|
return !0;
|
|
1551
|
-
const
|
|
1553
|
+
const i = new m.Vector3(
|
|
1552
1554
|
(e.x + s.x) / 2,
|
|
1553
1555
|
(e.y + s.y) / 2,
|
|
1554
1556
|
(e.z + s.z) / 2
|
|
1555
|
-
), a =
|
|
1556
|
-
return this.frustum.intersectsSphere(
|
|
1557
|
+
), a = i.distanceTo(t), r = new m.Sphere(i, a);
|
|
1558
|
+
return this.frustum.intersectsSphere(r);
|
|
1557
1559
|
}
|
|
1558
1560
|
/**
|
|
1559
1561
|
* Enables/disables frustum culling
|
|
@@ -1564,19 +1566,19 @@ class Et {
|
|
|
1564
1566
|
}
|
|
1565
1567
|
class Ct {
|
|
1566
1568
|
constructor(e, s) {
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
this.sceneManager = e, this.container = s, this.raycaster = new
|
|
1569
|
+
l(this, "sceneManager");
|
|
1570
|
+
l(this, "raycaster");
|
|
1571
|
+
l(this, "mouse");
|
|
1572
|
+
l(this, "container");
|
|
1573
|
+
l(this, "onNodeClick", null);
|
|
1574
|
+
l(this, "onNodeHover", null);
|
|
1575
|
+
l(this, "onEdgeHover", null);
|
|
1576
|
+
l(this, "onEdgeClick", null);
|
|
1577
|
+
l(this, "hoveredNodeId", null);
|
|
1578
|
+
l(this, "hoveredEdgeKey", null);
|
|
1579
|
+
l(this, "nodeObjects", []);
|
|
1580
|
+
l(this, "edgeObjects", []);
|
|
1581
|
+
this.sceneManager = e, this.container = s, this.raycaster = new m.Raycaster(), this.raycaster.params.Line = { threshold: 0.5 }, this.mouse = new m.Vector2(), this.handleClick = this.handleClick.bind(this), this.handleMouseMove = this.handleMouseMove.bind(this), s.addEventListener("click", this.handleClick), s.addEventListener("mousemove", this.handleMouseMove);
|
|
1580
1582
|
}
|
|
1581
1583
|
/**
|
|
1582
1584
|
* Updates the list of node objects to raycast against
|
|
@@ -1635,23 +1637,23 @@ class Ct {
|
|
|
1635
1637
|
this.hoveredEdgeKey !== null && this.onEdgeHover && (this.hoveredEdgeKey = null, this.onEdgeHover(null)), this.container.style.cursor = "pointer";
|
|
1636
1638
|
return;
|
|
1637
1639
|
}
|
|
1638
|
-
const
|
|
1639
|
-
|
|
1640
|
+
const o = this.getIntersectedEdge(e), i = o ? `${o.edge.source}-${o.edge.target}` : null;
|
|
1641
|
+
i !== this.hoveredEdgeKey && (this.hoveredEdgeKey = i, this.onEdgeHover && this.onEdgeHover(o)), this.container.style.cursor = o ? "pointer" : "default";
|
|
1640
1642
|
}
|
|
1641
1643
|
/**
|
|
1642
1644
|
* Gets the intersected node from a mouse event
|
|
1643
1645
|
*/
|
|
1644
1646
|
getIntersectedNode(e) {
|
|
1645
|
-
var
|
|
1647
|
+
var o;
|
|
1646
1648
|
const s = this.container.getBoundingClientRect();
|
|
1647
1649
|
this.mouse.x = (e.clientX - s.left) / s.width * 2 - 1, this.mouse.y = -((e.clientY - s.top) / s.height) * 2 + 1, this.raycaster.setFromCamera(this.mouse, this.sceneManager.camera);
|
|
1648
1650
|
const t = this.raycaster.intersectObjects(this.nodeObjects, !0);
|
|
1649
1651
|
if (t.length > 0) {
|
|
1650
|
-
let
|
|
1651
|
-
for (;
|
|
1652
|
-
if ((
|
|
1653
|
-
return
|
|
1654
|
-
|
|
1652
|
+
let i = t[0].object;
|
|
1653
|
+
for (; i; ) {
|
|
1654
|
+
if ((o = i.userData) != null && o.nodeData)
|
|
1655
|
+
return i.userData.nodeData;
|
|
1656
|
+
i = i.parent;
|
|
1655
1657
|
}
|
|
1656
1658
|
}
|
|
1657
1659
|
return null;
|
|
@@ -1664,13 +1666,13 @@ class Ct {
|
|
|
1664
1666
|
this.mouse.x = (e.clientX - s.left) / s.width * 2 - 1, this.mouse.y = -((e.clientY - s.top) / s.height) * 2 + 1, this.raycaster.setFromCamera(this.mouse, this.sceneManager.camera);
|
|
1665
1667
|
const t = this.raycaster.intersectObjects(this.edgeObjects, !1);
|
|
1666
1668
|
if (t.length > 0) {
|
|
1667
|
-
const
|
|
1668
|
-
if (
|
|
1669
|
+
const o = t[0].object, i = o.userData;
|
|
1670
|
+
if (i != null && i.edge && (i != null && i.sourceNode) && (i != null && i.targetNode))
|
|
1669
1671
|
return {
|
|
1670
|
-
edge:
|
|
1671
|
-
sourceNode:
|
|
1672
|
-
targetNode:
|
|
1673
|
-
edgeLine:
|
|
1672
|
+
edge: i.edge,
|
|
1673
|
+
sourceNode: i.sourceNode,
|
|
1674
|
+
targetNode: i.targetNode,
|
|
1675
|
+
edgeLine: o
|
|
1674
1676
|
};
|
|
1675
1677
|
}
|
|
1676
1678
|
return null;
|
|
@@ -1679,14 +1681,14 @@ class Ct {
|
|
|
1679
1681
|
* Performs a raycast and returns the intersected node ID
|
|
1680
1682
|
*/
|
|
1681
1683
|
getIntersectedNodeId(e, s) {
|
|
1682
|
-
var
|
|
1684
|
+
var i;
|
|
1683
1685
|
const t = this.container.getBoundingClientRect();
|
|
1684
1686
|
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);
|
|
1685
|
-
const
|
|
1686
|
-
if (
|
|
1687
|
-
let a =
|
|
1687
|
+
const o = this.raycaster.intersectObjects(this.nodeObjects, !0);
|
|
1688
|
+
if (o.length > 0) {
|
|
1689
|
+
let a = o[0].object;
|
|
1688
1690
|
for (; a; ) {
|
|
1689
|
-
if ((
|
|
1691
|
+
if ((i = a.userData) != null && i.nodeId)
|
|
1690
1692
|
return a.userData.nodeId;
|
|
1691
1693
|
a = a.parent;
|
|
1692
1694
|
}
|
|
@@ -1700,15 +1702,15 @@ class Ct {
|
|
|
1700
1702
|
this.container.removeEventListener("click", this.handleClick), this.container.removeEventListener("mousemove", this.handleMouseMove);
|
|
1701
1703
|
}
|
|
1702
1704
|
}
|
|
1703
|
-
class
|
|
1705
|
+
class Nt {
|
|
1704
1706
|
constructor(e) {
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1707
|
+
l(this, "container");
|
|
1708
|
+
l(this, "panel", null);
|
|
1709
|
+
l(this, "currentNodeId", null);
|
|
1710
|
+
l(this, "visible", !1);
|
|
1711
|
+
l(this, "panelTemplate", null);
|
|
1712
|
+
l(this, "panelStyles", {});
|
|
1713
|
+
l(this, "onExpand", null);
|
|
1712
1714
|
this.container = e, this.createPanel();
|
|
1713
1715
|
}
|
|
1714
1716
|
/**
|
|
@@ -1770,11 +1772,11 @@ class zt {
|
|
|
1770
1772
|
this.currentNodeId = e.id;
|
|
1771
1773
|
let t;
|
|
1772
1774
|
this.panelTemplate ? t = this.panelTemplate(e, s) : t = this.generateDefaultContent(e, s), this.panel.innerHTML = t;
|
|
1773
|
-
const
|
|
1774
|
-
|
|
1775
|
+
const o = this.panel.querySelector('[data-action="expand"]'), i = this.panel.querySelector("[data-depth-select]");
|
|
1776
|
+
o && this.onExpand && o.addEventListener("click", () => {
|
|
1775
1777
|
if (this.currentNodeId) {
|
|
1776
|
-
const
|
|
1777
|
-
this.onExpand(this.currentNodeId,
|
|
1778
|
+
const r = i ? parseInt(i.value, 10) : 1;
|
|
1779
|
+
this.onExpand(this.currentNodeId, r);
|
|
1778
1780
|
}
|
|
1779
1781
|
});
|
|
1780
1782
|
const a = this.panel.querySelector('[data-action="close"]');
|
|
@@ -1932,7 +1934,7 @@ class zt {
|
|
|
1932
1934
|
<div class="neighbors-section">
|
|
1933
1935
|
<div class="neighbors-title">Connected To</div>
|
|
1934
1936
|
${s.slice(0, 5).map(
|
|
1935
|
-
(
|
|
1937
|
+
(o) => `<span class="neighbor-chip">${this.escapeHtml(o.label)}</span>`
|
|
1936
1938
|
).join("")}
|
|
1937
1939
|
${s.length > 5 ? `<span class="neighbor-chip">+${s.length - 5} more</span>` : ""}
|
|
1938
1940
|
</div>
|
|
@@ -1986,15 +1988,15 @@ class zt {
|
|
|
1986
1988
|
this.panel && this.panel.parentNode && this.panel.parentNode.removeChild(this.panel), this.panel = null;
|
|
1987
1989
|
}
|
|
1988
1990
|
}
|
|
1989
|
-
class
|
|
1991
|
+
class St {
|
|
1990
1992
|
constructor(e) {
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1993
|
+
l(this, "container");
|
|
1994
|
+
l(this, "panel", null);
|
|
1995
|
+
l(this, "currentEdgeKey", null);
|
|
1996
|
+
l(this, "visible", !1);
|
|
1997
|
+
l(this, "panelTemplate", null);
|
|
1998
|
+
l(this, "onClose", null);
|
|
1999
|
+
l(this, "onNodeClick", null);
|
|
1998
2000
|
this.container = e, this.createPanel();
|
|
1999
2001
|
}
|
|
2000
2002
|
/**
|
|
@@ -2050,18 +2052,18 @@ class Nt {
|
|
|
2050
2052
|
show(e, s, t) {
|
|
2051
2053
|
if (!this.panel) return;
|
|
2052
2054
|
this.currentEdgeKey = `${e.source}-${e.target}`;
|
|
2053
|
-
let
|
|
2054
|
-
this.panelTemplate ?
|
|
2055
|
-
const
|
|
2056
|
-
|
|
2055
|
+
let o;
|
|
2056
|
+
this.panelTemplate ? o = this.panelTemplate(e, s, t) : o = this.generateDefaultContent(e, s, t), this.panel.innerHTML = o;
|
|
2057
|
+
const i = this.panel.querySelector('[data-action="close"]');
|
|
2058
|
+
i && i.addEventListener("click", () => {
|
|
2057
2059
|
this.hide(), this.onClose && this.onClose();
|
|
2058
2060
|
});
|
|
2059
2061
|
const a = this.panel.querySelector('[data-action="goto-source"]');
|
|
2060
2062
|
a && this.onNodeClick && a.addEventListener("click", () => {
|
|
2061
2063
|
this.onNodeClick && this.onNodeClick(e.source);
|
|
2062
2064
|
});
|
|
2063
|
-
const
|
|
2064
|
-
|
|
2065
|
+
const r = this.panel.querySelector('[data-action="goto-target"]');
|
|
2066
|
+
r && this.onNodeClick && r.addEventListener("click", () => {
|
|
2065
2067
|
this.onNodeClick && this.onNodeClick(e.target);
|
|
2066
2068
|
}), this.panel.style.opacity = "1", this.panel.style.pointerEvents = "auto", this.panel.style.transform = "translateY(-50%) translateX(0)", this.visible = !0;
|
|
2067
2069
|
}
|
|
@@ -2069,7 +2071,7 @@ class Nt {
|
|
|
2069
2071
|
* Generates default panel content
|
|
2070
2072
|
*/
|
|
2071
2073
|
generateDefaultContent(e, s, t) {
|
|
2072
|
-
const
|
|
2074
|
+
const o = s.color ? `#${s.color.toString(16).padStart(6, "0")}` : "#ff9966", i = t.color ? `#${t.color.toString(16).padStart(6, "0")}` : "#ff9966", a = e.relationship || "connected to";
|
|
2073
2075
|
return `
|
|
2074
2076
|
<style>
|
|
2075
2077
|
.force-graph-edge-panel .panel-header {
|
|
@@ -2179,7 +2181,7 @@ class Nt {
|
|
|
2179
2181
|
<div class="node-card" data-action="goto-source" title="Click to focus on ${this.escapeHtml(s.label)}">
|
|
2180
2182
|
<div class="node-type">Source</div>
|
|
2181
2183
|
<div class="node-card-header">
|
|
2182
|
-
<span class="color-dot" style="background: ${
|
|
2184
|
+
<span class="color-dot" style="background: ${o}; box-shadow: 0 0 8px ${o}80;"></span>
|
|
2183
2185
|
<span class="node-label">${this.escapeHtml(s.label)}</span>
|
|
2184
2186
|
</div>
|
|
2185
2187
|
</div>
|
|
@@ -2189,7 +2191,7 @@ class Nt {
|
|
|
2189
2191
|
<div class="node-card" data-action="goto-target" title="Click to focus on ${this.escapeHtml(t.label)}">
|
|
2190
2192
|
<div class="node-type">Target</div>
|
|
2191
2193
|
<div class="node-card-header">
|
|
2192
|
-
<span class="color-dot" style="background: ${
|
|
2194
|
+
<span class="color-dot" style="background: ${i}; box-shadow: 0 0 8px ${i}80;"></span>
|
|
2193
2195
|
<span class="node-label">${this.escapeHtml(t.label)}</span>
|
|
2194
2196
|
</div>
|
|
2195
2197
|
</div>
|
|
@@ -2231,10 +2233,10 @@ class Nt {
|
|
|
2231
2233
|
this.panel && this.panel.parentNode && this.panel.parentNode.removeChild(this.panel), this.panel = null;
|
|
2232
2234
|
}
|
|
2233
2235
|
}
|
|
2234
|
-
class
|
|
2236
|
+
class zt {
|
|
2235
2237
|
constructor() {
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
+
l(this, "tooltip", null);
|
|
2239
|
+
l(this, "visible", !1);
|
|
2238
2240
|
this.createTooltip(), this.setupMouseTracking();
|
|
2239
2241
|
}
|
|
2240
2242
|
/**
|
|
@@ -2277,14 +2279,14 @@ class St {
|
|
|
2277
2279
|
*/
|
|
2278
2280
|
positionTooltip(e, s) {
|
|
2279
2281
|
if (!this.tooltip) return;
|
|
2280
|
-
const t = this.tooltip.getBoundingClientRect(),
|
|
2281
|
-
let a = e + 15,
|
|
2282
|
-
a + t.width >
|
|
2282
|
+
const t = this.tooltip.getBoundingClientRect(), o = window.innerWidth, i = window.innerHeight;
|
|
2283
|
+
let a = e + 15, r = s + 15;
|
|
2284
|
+
a + t.width > o - 10 && (a = e - t.width - 15), r + t.height > i - 10 && (r = s - t.height - 15), a < 10 && (a = 10), r < 10 && (r = 10), this.tooltip.style.left = `${a}px`, this.tooltip.style.top = `${r}px`;
|
|
2283
2285
|
}
|
|
2284
2286
|
/**
|
|
2285
2287
|
* Shows the tooltip with edge info
|
|
2286
2288
|
*/
|
|
2287
|
-
show(e, s, t,
|
|
2289
|
+
show(e, s, t, o, i) {
|
|
2288
2290
|
if (!this.tooltip) return;
|
|
2289
2291
|
const a = e.relationship || "connected to";
|
|
2290
2292
|
this.tooltip.innerHTML = `
|
|
@@ -2299,7 +2301,7 @@ class St {
|
|
|
2299
2301
|
<span style="font-weight: 600; color: #ff9966;">${this.escapeHtml(t.label)}</span>
|
|
2300
2302
|
</div>
|
|
2301
2303
|
</div>
|
|
2302
|
-
`, this.positionTooltip(
|
|
2304
|
+
`, this.positionTooltip(o, i), this.tooltip.style.opacity = "1", this.tooltip.style.transform = "translateY(0)", this.visible = !0;
|
|
2303
2305
|
}
|
|
2304
2306
|
/**
|
|
2305
2307
|
* Updates tooltip position (called externally on mouse move)
|
|
@@ -2335,14 +2337,14 @@ class St {
|
|
|
2335
2337
|
}
|
|
2336
2338
|
class kt {
|
|
2337
2339
|
constructor(e, s) {
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2340
|
+
l(this, "container");
|
|
2341
|
+
l(this, "searchContainer", null);
|
|
2342
|
+
l(this, "searchInput", null);
|
|
2343
|
+
l(this, "searchResults", null);
|
|
2344
|
+
l(this, "searchTimeout", null);
|
|
2345
|
+
l(this, "placeholder");
|
|
2346
|
+
l(this, "onSearch");
|
|
2347
|
+
l(this, "onResultClick");
|
|
2346
2348
|
this.container = e, this.placeholder = s.placeholder || "Search nodes or relationships...", this.onSearch = s.onSearch, this.onResultClick = s.onResultClick, this.init();
|
|
2347
2349
|
}
|
|
2348
2350
|
init() {
|
|
@@ -2352,7 +2354,8 @@ class kt {
|
|
|
2352
2354
|
this.searchContainer = document.createElement("div"), this.searchContainer.className = "f3d-search-container", Object.assign(this.searchContainer.style, {
|
|
2353
2355
|
position: "absolute",
|
|
2354
2356
|
top: "20px",
|
|
2355
|
-
left: "
|
|
2357
|
+
left: "175px",
|
|
2358
|
+
// Adjusted to make room for view toggle
|
|
2356
2359
|
zIndex: "100",
|
|
2357
2360
|
width: "320px"
|
|
2358
2361
|
});
|
|
@@ -2475,25 +2478,25 @@ class kt {
|
|
|
2475
2478
|
this.searchResults.innerHTML = '<div class="f3d-no-results">No results found</div>', this.searchResults.style.display = "block";
|
|
2476
2479
|
return;
|
|
2477
2480
|
}
|
|
2478
|
-
let
|
|
2479
|
-
s.length > 0 && (
|
|
2480
|
-
const a =
|
|
2481
|
-
|
|
2482
|
-
<div class="f3d-search-result-item" data-node-id="${this.escapeHtml(
|
|
2483
|
-
<div class="f3d-result-label">${this.escapeHtml(
|
|
2481
|
+
let o = "";
|
|
2482
|
+
s.length > 0 && (o += '<div class="f3d-search-section-header">Nodes</div>', s.slice(0, 10).forEach((i) => {
|
|
2483
|
+
const a = i.type || "Node";
|
|
2484
|
+
o += `
|
|
2485
|
+
<div class="f3d-search-result-item" data-node-id="${this.escapeHtml(i.id)}">
|
|
2486
|
+
<div class="f3d-result-label">${this.escapeHtml(i.label)}</div>
|
|
2484
2487
|
<div class="f3d-result-type">${this.escapeHtml(a)}</div>
|
|
2485
2488
|
</div>
|
|
2486
2489
|
`;
|
|
2487
|
-
}), s.length > 10 && (
|
|
2488
|
-
|
|
2489
|
-
<div class="f3d-search-result-item" data-node-id="${this.escapeHtml(
|
|
2490
|
-
<div class="f3d-result-label">${this.escapeHtml(a.label)} → ${this.escapeHtml(
|
|
2491
|
-
<div class="f3d-result-relationship">${this.escapeHtml(
|
|
2490
|
+
}), s.length > 10 && (o += `<div class="f3d-no-results">+ ${s.length - 10} more nodes</div>`)), t.length > 0 && (o += '<div class="f3d-search-section-header">Relationships</div>', t.slice(0, 5).forEach(({ edge: i, sourceNode: a, targetNode: r }) => {
|
|
2491
|
+
o += `
|
|
2492
|
+
<div class="f3d-search-result-item" data-node-id="${this.escapeHtml(i.source)}">
|
|
2493
|
+
<div class="f3d-result-label">${this.escapeHtml(a.label)} → ${this.escapeHtml(r.label)}</div>
|
|
2494
|
+
<div class="f3d-result-relationship">${this.escapeHtml(i.relationship || "connected")}</div>
|
|
2492
2495
|
</div>
|
|
2493
2496
|
`;
|
|
2494
|
-
}), t.length > 5 && (
|
|
2495
|
-
|
|
2496
|
-
const a =
|
|
2497
|
+
}), t.length > 5 && (o += `<div class="f3d-no-results">+ ${t.length - 5} more relationships</div>`)), this.searchResults.innerHTML = o, this.searchResults.style.display = "block", this.searchResults.querySelectorAll(".f3d-search-result-item").forEach((i) => {
|
|
2498
|
+
i.addEventListener("click", () => {
|
|
2499
|
+
const a = i.dataset.nodeId;
|
|
2497
2500
|
a && (this.onResultClick(a), this.searchResults && (this.searchResults.style.display = "none"), this.searchInput && this.searchInput.blur());
|
|
2498
2501
|
});
|
|
2499
2502
|
});
|
|
@@ -2506,51 +2509,494 @@ class kt {
|
|
|
2506
2509
|
this.searchContainer && this.searchContainer.parentNode && this.searchContainer.parentNode.removeChild(this.searchContainer);
|
|
2507
2510
|
}
|
|
2508
2511
|
}
|
|
2509
|
-
class
|
|
2512
|
+
class Pt {
|
|
2513
|
+
constructor(e, s) {
|
|
2514
|
+
l(this, "container");
|
|
2515
|
+
l(this, "toggleContainer", null);
|
|
2516
|
+
l(this, "currentMode", "3d");
|
|
2517
|
+
l(this, "onViewChange");
|
|
2518
|
+
this.container = e, this.currentMode = s.initialMode || "3d", this.onViewChange = s.onViewChange, this.init();
|
|
2519
|
+
}
|
|
2520
|
+
init() {
|
|
2521
|
+
this.createToggleUI();
|
|
2522
|
+
}
|
|
2523
|
+
createToggleUI() {
|
|
2524
|
+
this.toggleContainer = document.createElement("div"), this.toggleContainer.className = "f3d-view-toggle", Object.assign(this.toggleContainer.style, {
|
|
2525
|
+
position: "absolute",
|
|
2526
|
+
top: "20px",
|
|
2527
|
+
left: "20px",
|
|
2528
|
+
zIndex: "100",
|
|
2529
|
+
display: "flex",
|
|
2530
|
+
gap: "0",
|
|
2531
|
+
background: "rgba(255, 255, 255, 0.08)",
|
|
2532
|
+
backdropFilter: "blur(20px)",
|
|
2533
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
2534
|
+
border: "1px solid rgba(255, 255, 255, 0.12)",
|
|
2535
|
+
borderRadius: "12px",
|
|
2536
|
+
padding: "5px",
|
|
2537
|
+
boxShadow: "0 4px 20px rgba(0, 0, 0, 0.3)"
|
|
2538
|
+
});
|
|
2539
|
+
const e = this.createButton("2D", "2d"), s = this.createButton("3D", "3d");
|
|
2540
|
+
this.toggleContainer.appendChild(e), this.toggleContainer.appendChild(s), this.container.appendChild(this.toggleContainer), this.updateButtonStates();
|
|
2541
|
+
const t = document.createElement("style");
|
|
2542
|
+
t.textContent = `
|
|
2543
|
+
.f3d-view-btn {
|
|
2544
|
+
padding: 8px 16px;
|
|
2545
|
+
background: transparent;
|
|
2546
|
+
border: none;
|
|
2547
|
+
color: rgba(255, 255, 255, 0.5);
|
|
2548
|
+
font-size: 12px;
|
|
2549
|
+
font-weight: 600;
|
|
2550
|
+
font-family: inherit;
|
|
2551
|
+
letter-spacing: 0.5px;
|
|
2552
|
+
cursor: pointer;
|
|
2553
|
+
transition: all 0.2s ease;
|
|
2554
|
+
border-radius: 8px;
|
|
2555
|
+
min-width: 44px;
|
|
2556
|
+
}
|
|
2557
|
+
.f3d-view-btn:hover {
|
|
2558
|
+
color: rgba(255, 255, 255, 0.8);
|
|
2559
|
+
}
|
|
2560
|
+
.f3d-view-btn.active {
|
|
2561
|
+
background: linear-gradient(135deg, rgba(255, 153, 102, 0.3), rgba(255, 102, 153, 0.2));
|
|
2562
|
+
color: white;
|
|
2563
|
+
box-shadow: 0 0 15px rgba(255, 153, 102, 0.2);
|
|
2564
|
+
}
|
|
2565
|
+
.f3d-view-btn:focus {
|
|
2566
|
+
outline: none;
|
|
2567
|
+
}
|
|
2568
|
+
`, document.head.appendChild(t);
|
|
2569
|
+
}
|
|
2570
|
+
createButton(e, s) {
|
|
2571
|
+
const t = document.createElement("button");
|
|
2572
|
+
return t.className = "f3d-view-btn", t.dataset.mode = s, t.innerHTML = this.getIcon(s) + `<span style="margin-left: 4px;">${e}</span>`, t.style.display = "flex", t.style.alignItems = "center", t.style.justifyContent = "center", t.addEventListener("click", () => {
|
|
2573
|
+
this.currentMode !== s && (this.currentMode = s, this.updateButtonStates(), this.onViewChange(s));
|
|
2574
|
+
}), t;
|
|
2575
|
+
}
|
|
2576
|
+
getIcon(e) {
|
|
2577
|
+
return e === "2d" ? `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2578
|
+
<rect x="3" y="3" width="7" height="7"></rect>
|
|
2579
|
+
<rect x="14" y="3" width="7" height="7"></rect>
|
|
2580
|
+
<rect x="14" y="14" width="7" height="7"></rect>
|
|
2581
|
+
<rect x="3" y="14" width="7" height="7"></rect>
|
|
2582
|
+
</svg>` : `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2583
|
+
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path>
|
|
2584
|
+
<polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline>
|
|
2585
|
+
<line x1="12" y1="22.08" x2="12" y2="12"></line>
|
|
2586
|
+
</svg>`;
|
|
2587
|
+
}
|
|
2588
|
+
updateButtonStates() {
|
|
2589
|
+
if (!this.toggleContainer) return;
|
|
2590
|
+
this.toggleContainer.querySelectorAll(".f3d-view-btn").forEach((s) => {
|
|
2591
|
+
s.dataset.mode === this.currentMode ? s.classList.add("active") : s.classList.remove("active");
|
|
2592
|
+
});
|
|
2593
|
+
}
|
|
2594
|
+
setMode(e) {
|
|
2595
|
+
this.currentMode !== e && (this.currentMode = e, this.updateButtonStates());
|
|
2596
|
+
}
|
|
2597
|
+
getMode() {
|
|
2598
|
+
return this.currentMode;
|
|
2599
|
+
}
|
|
2600
|
+
dispose() {
|
|
2601
|
+
this.toggleContainer && this.toggleContainer.parentNode && this.toggleContainer.parentNode.removeChild(this.toggleContainer);
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
const Tt = {
|
|
2605
|
+
backgroundColor: "#0a0a0a",
|
|
2606
|
+
gridColor: "rgba(255, 255, 255, 0.03)",
|
|
2607
|
+
nodeRadius: 24,
|
|
2608
|
+
edgeColor: "rgba(255, 255, 255, 0.15)",
|
|
2609
|
+
edgeOpacity: 0.4,
|
|
2610
|
+
repulsionStrength: 500,
|
|
2611
|
+
// Full repulsion
|
|
2612
|
+
attractionStrength: 1e-3,
|
|
2613
|
+
// Very low attraction
|
|
2614
|
+
damping: 0.85
|
|
2615
|
+
// Fast energy dissipation
|
|
2616
|
+
};
|
|
2617
|
+
class Lt {
|
|
2618
|
+
constructor(e, s = {}) {
|
|
2619
|
+
l(this, "container");
|
|
2620
|
+
l(this, "canvas");
|
|
2621
|
+
l(this, "ctx");
|
|
2622
|
+
l(this, "options");
|
|
2623
|
+
// Data
|
|
2624
|
+
l(this, "nodes", /* @__PURE__ */ new Map());
|
|
2625
|
+
l(this, "edges", []);
|
|
2626
|
+
l(this, "nodeIdToIndex", /* @__PURE__ */ new Map());
|
|
2627
|
+
// Transform state
|
|
2628
|
+
l(this, "transform", { x: 0, y: 0, scale: 1 });
|
|
2629
|
+
// Interaction state
|
|
2630
|
+
l(this, "isDragging", !1);
|
|
2631
|
+
l(this, "isPanning", !1);
|
|
2632
|
+
l(this, "draggedNode", null);
|
|
2633
|
+
l(this, "hoveredNode", null);
|
|
2634
|
+
l(this, "hoveredEdge", null);
|
|
2635
|
+
l(this, "lastMousePos", { x: 0, y: 0 });
|
|
2636
|
+
l(this, "dragStartPos", { x: 0, y: 0 });
|
|
2637
|
+
// Track initial click position
|
|
2638
|
+
l(this, "selectedNode", null);
|
|
2639
|
+
// Animation
|
|
2640
|
+
l(this, "animationId", null);
|
|
2641
|
+
l(this, "isSimulating", !0);
|
|
2642
|
+
// Resize handler
|
|
2643
|
+
l(this, "resizeHandler");
|
|
2644
|
+
this.container = e, this.options = { ...Tt, ...s }, this.canvas = document.createElement("canvas"), this.canvas.style.position = "absolute", this.canvas.style.top = "0", this.canvas.style.left = "0", this.canvas.style.width = "100%", this.canvas.style.height = "100%", this.canvas.style.cursor = "grab", e.appendChild(this.canvas);
|
|
2645
|
+
const t = this.canvas.getContext("2d");
|
|
2646
|
+
if (!t)
|
|
2647
|
+
throw new Error("Failed to get 2D context");
|
|
2648
|
+
this.ctx = t, this.resizeHandler = this.handleResize.bind(this), window.addEventListener("resize", this.resizeHandler), this.handleResize(), this.transform.x = this.canvas.width / 2, this.transform.y = this.canvas.height / 2, this.setupInteractions(), this.startAnimation();
|
|
2649
|
+
}
|
|
2650
|
+
handleResize() {
|
|
2651
|
+
const e = this.container.getBoundingClientRect(), s = window.devicePixelRatio || 1;
|
|
2652
|
+
this.canvas.width = e.width * s, this.canvas.height = e.height * s, this.ctx.scale(s, s);
|
|
2653
|
+
}
|
|
2654
|
+
setupInteractions() {
|
|
2655
|
+
this.canvas.addEventListener("wheel", (e) => {
|
|
2656
|
+
e.preventDefault();
|
|
2657
|
+
const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, o = e.clientY - s.top, i = e.deltaY > 0 ? 0.9 : 1.1, a = Math.max(0.1, Math.min(5, this.transform.scale * i)), r = a / this.transform.scale;
|
|
2658
|
+
this.transform.x = t - (t - this.transform.x) * r, this.transform.y = o - (o - this.transform.y) * r, this.transform.scale = a;
|
|
2659
|
+
}), this.canvas.addEventListener("mousedown", (e) => {
|
|
2660
|
+
const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, o = e.clientY - s.top, i = this.screenToWorld(t, o), a = this.findNodeAt(i.x, i.y);
|
|
2661
|
+
this.dragStartPos = { x: e.clientX, y: e.clientY }, a ? (this.isDragging = !0, this.draggedNode = a, this.canvas.style.cursor = "grabbing", this.isSimulating = !0) : (this.isPanning = !0, this.canvas.style.cursor = "grabbing"), this.lastMousePos = { x: e.clientX, y: e.clientY };
|
|
2662
|
+
}), this.canvas.addEventListener("mousemove", (e) => {
|
|
2663
|
+
const s = this.canvas.getBoundingClientRect(), t = e.clientX - s.left, o = e.clientY - s.top, i = this.screenToWorld(t, o);
|
|
2664
|
+
if (this.isDragging && this.draggedNode)
|
|
2665
|
+
this.draggedNode.x = i.x, this.draggedNode.y = i.y, this.draggedNode.vx = 0, this.draggedNode.vy = 0;
|
|
2666
|
+
else if (this.isPanning) {
|
|
2667
|
+
const a = e.clientX - this.lastMousePos.x, r = e.clientY - this.lastMousePos.y;
|
|
2668
|
+
this.transform.x += a, this.transform.y += r, this.lastMousePos = { x: e.clientX, y: e.clientY };
|
|
2669
|
+
} else {
|
|
2670
|
+
const a = this.findNodeAt(i.x, i.y);
|
|
2671
|
+
if (a !== this.hoveredNode && (this.hoveredNode = a, a ? (this.hoveredEdge && (this.hoveredEdge = null, this.options.onEdgeHover && this.options.onEdgeHover(null)), this.canvas.style.cursor = "pointer", this.options.onNodeHover && this.options.onNodeHover(a.data)) : this.options.onNodeHover && this.options.onNodeHover(null)), !a) {
|
|
2672
|
+
const r = this.findEdgeAt(i.x, i.y);
|
|
2673
|
+
r !== this.hoveredEdge && (this.hoveredEdge = r, this.canvas.style.cursor = r ? "pointer" : "grab", this.options.onEdgeHover && this.options.onEdgeHover(r ? r.data : null, e));
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
}), this.canvas.addEventListener("mouseup", (e) => {
|
|
2677
|
+
const s = Math.abs(e.clientX - this.dragStartPos.x), t = Math.abs(e.clientY - this.dragStartPos.y), o = s < 5 && t < 5;
|
|
2678
|
+
if (this.isDragging && this.draggedNode)
|
|
2679
|
+
o && this.options.onNodeClick && (this.selectedNode = this.draggedNode, this.options.onNodeClick(this.draggedNode.data));
|
|
2680
|
+
else if (o && !this.isPanning) {
|
|
2681
|
+
const i = this.canvas.getBoundingClientRect(), a = this.screenToWorld(e.clientX - i.left, e.clientY - i.top), r = this.findEdgeAt(a.x, a.y);
|
|
2682
|
+
r && this.options.onEdgeClick && this.options.onEdgeClick(r.data);
|
|
2683
|
+
}
|
|
2684
|
+
this.isDragging = !1, this.isPanning = !1, this.draggedNode = null, this.canvas.style.cursor = this.hoveredNode ? "pointer" : "grab";
|
|
2685
|
+
}), this.canvas.addEventListener("mouseleave", () => {
|
|
2686
|
+
this.isDragging = !1, this.isPanning = !1, this.draggedNode = null, this.hoveredNode = null, this.canvas.style.cursor = "grab";
|
|
2687
|
+
});
|
|
2688
|
+
}
|
|
2689
|
+
screenToWorld(e, s) {
|
|
2690
|
+
return {
|
|
2691
|
+
x: (e - this.transform.x) / this.transform.scale,
|
|
2692
|
+
y: (s - this.transform.y) / this.transform.scale
|
|
2693
|
+
};
|
|
2694
|
+
}
|
|
2695
|
+
findNodeAt(e, s) {
|
|
2696
|
+
for (const t of this.nodes.values()) {
|
|
2697
|
+
const o = t.x - e, i = t.y - s;
|
|
2698
|
+
if (Math.sqrt(o * o + i * i) < t.radius)
|
|
2699
|
+
return t;
|
|
2700
|
+
}
|
|
2701
|
+
return null;
|
|
2702
|
+
}
|
|
2703
|
+
findEdgeAt(e, s) {
|
|
2704
|
+
for (const o of this.edges) {
|
|
2705
|
+
const i = this.nodes.get(o.source), a = this.nodes.get(o.target);
|
|
2706
|
+
if (!i || !a) continue;
|
|
2707
|
+
const r = a.x - i.x, c = a.y - i.y, d = r * r + c * c;
|
|
2708
|
+
if (d === 0) continue;
|
|
2709
|
+
const g = Math.max(0, Math.min(1, ((e - i.x) * r + (s - i.y) * c) / d)), u = i.x + g * r, y = i.y + g * c, f = e - u, x = s - y;
|
|
2710
|
+
if (Math.sqrt(f * f + x * x) < 8)
|
|
2711
|
+
return o;
|
|
2712
|
+
}
|
|
2713
|
+
return null;
|
|
2714
|
+
}
|
|
2715
|
+
startAnimation() {
|
|
2716
|
+
const e = () => {
|
|
2717
|
+
this.isSimulating && this.simulate(), this.render(), this.animationId = requestAnimationFrame(e);
|
|
2718
|
+
};
|
|
2719
|
+
e();
|
|
2720
|
+
}
|
|
2721
|
+
simulate() {
|
|
2722
|
+
const e = Array.from(this.nodes.values()), s = e.length;
|
|
2723
|
+
if (s === 0) return;
|
|
2724
|
+
const t = 60, o = 5;
|
|
2725
|
+
let i = 0;
|
|
2726
|
+
for (let r = 0; r < s; r++)
|
|
2727
|
+
for (let c = r + 1; c < s; c++) {
|
|
2728
|
+
const d = e[r], g = e[c];
|
|
2729
|
+
let u = g.x - d.x, y = g.y - d.y, f = Math.sqrt(u * u + y * y);
|
|
2730
|
+
if (f < t * 3) {
|
|
2731
|
+
f < 1 && (f = 1);
|
|
2732
|
+
const x = this.options.repulsionStrength / (f * f), v = u / f * x, M = y / f * x;
|
|
2733
|
+
d.vx -= v, d.vy -= M, g.vx += v, g.vy += M;
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2736
|
+
const a = 80;
|
|
2737
|
+
for (const r of this.edges) {
|
|
2738
|
+
const c = this.nodes.get(r.source), d = this.nodes.get(r.target);
|
|
2739
|
+
if (!c || !d) continue;
|
|
2740
|
+
let g = d.x - c.x, u = d.y - c.y, y = Math.sqrt(g * g + u * u);
|
|
2741
|
+
y < 1 && (y = 1);
|
|
2742
|
+
const x = (y - a) * this.options.attractionStrength, v = g / y * x, M = u / y * x;
|
|
2743
|
+
c.vx += v, c.vy += M, d.vx -= v, d.vy -= M;
|
|
2744
|
+
}
|
|
2745
|
+
for (const r of e) {
|
|
2746
|
+
if (this.draggedNode === r) continue;
|
|
2747
|
+
r.vx *= this.options.damping, r.vy *= this.options.damping;
|
|
2748
|
+
const c = Math.sqrt(r.vx * r.vx + r.vy * r.vy);
|
|
2749
|
+
c > o && (r.vx = r.vx / c * o, r.vy = r.vy / c * o), r.x += r.vx, r.y += r.vy, i += r.vx * r.vx + r.vy * r.vy;
|
|
2750
|
+
}
|
|
2751
|
+
i < 0.01 && !this.draggedNode && (this.isSimulating = !1);
|
|
2752
|
+
}
|
|
2753
|
+
render() {
|
|
2754
|
+
const e = this.ctx, s = this.canvas.width / (window.devicePixelRatio || 1), t = this.canvas.height / (window.devicePixelRatio || 1);
|
|
2755
|
+
e.fillStyle = this.options.backgroundColor, e.fillRect(0, 0, s, t), this.renderGrid(s, t), e.save(), e.translate(this.transform.x, this.transform.y), e.scale(this.transform.scale, this.transform.scale), this.renderEdges(), this.renderNodes(), e.restore();
|
|
2756
|
+
}
|
|
2757
|
+
renderGrid(e, s) {
|
|
2758
|
+
const t = this.ctx, o = 40 * this.transform.scale, i = 1.5, a = this.transform.x % o, r = this.transform.y % o;
|
|
2759
|
+
t.fillStyle = this.options.gridColor;
|
|
2760
|
+
for (let c = a; c < e; c += o)
|
|
2761
|
+
for (let d = r; d < s; d += o)
|
|
2762
|
+
t.beginPath(), t.arc(c, d, i, 0, Math.PI * 2), t.fill();
|
|
2763
|
+
}
|
|
2764
|
+
renderEdges() {
|
|
2765
|
+
const e = this.ctx;
|
|
2766
|
+
for (const s of this.edges) {
|
|
2767
|
+
const t = this.nodes.get(s.source), o = this.nodes.get(s.target);
|
|
2768
|
+
if (!t || !o) continue;
|
|
2769
|
+
const i = e.createLinearGradient(t.x, t.y, o.x, o.y);
|
|
2770
|
+
i.addColorStop(0, "rgba(255, 153, 102, 0.3)"), i.addColorStop(0.5, "rgba(255, 255, 255, 0.15)"), i.addColorStop(1, "rgba(102, 153, 255, 0.3)"), e.beginPath(), e.moveTo(t.x, t.y), e.lineTo(o.x, o.y), e.strokeStyle = i, e.lineWidth = 1.5, e.stroke();
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2773
|
+
renderNodes() {
|
|
2774
|
+
const e = this.ctx;
|
|
2775
|
+
for (const s of this.nodes.values()) {
|
|
2776
|
+
const t = s === this.hoveredNode, o = s === this.selectedNode, i = s.radius * (t ? 1.1 : 1);
|
|
2777
|
+
if (t || o) {
|
|
2778
|
+
const f = e.createRadialGradient(
|
|
2779
|
+
s.x,
|
|
2780
|
+
s.y,
|
|
2781
|
+
i * 0.5,
|
|
2782
|
+
s.x,
|
|
2783
|
+
s.y,
|
|
2784
|
+
i * 2
|
|
2785
|
+
);
|
|
2786
|
+
f.addColorStop(0, "rgba(255, 153, 102, 0.4)"), f.addColorStop(1, "rgba(255, 153, 102, 0)"), e.fillStyle = f, e.beginPath(), e.arc(s.x, s.y, i * 2, 0, Math.PI * 2), e.fill();
|
|
2787
|
+
}
|
|
2788
|
+
const a = e.createRadialGradient(
|
|
2789
|
+
s.x - i * 0.3,
|
|
2790
|
+
s.y - i * 0.3,
|
|
2791
|
+
0,
|
|
2792
|
+
s.x,
|
|
2793
|
+
s.y,
|
|
2794
|
+
i
|
|
2795
|
+
), r = s.color >> 16 & 255, c = s.color >> 8 & 255, d = s.color & 255;
|
|
2796
|
+
a.addColorStop(0, `rgba(${Math.min(255, r + 60)}, ${Math.min(255, c + 60)}, ${Math.min(255, d + 60)}, 0.95)`), a.addColorStop(0.7, `rgba(${r}, ${c}, ${d}, 0.9)`), a.addColorStop(1, `rgba(${Math.max(0, r - 40)}, ${Math.max(0, c - 40)}, ${Math.max(0, d - 40)}, 0.85)`), e.beginPath(), e.arc(s.x, s.y, i, 0, Math.PI * 2), e.fillStyle = a, e.fill(), e.strokeStyle = "rgba(255, 255, 255, 0.2)", e.lineWidth = 1, e.stroke(), e.beginPath(), e.arc(s.x - i * 0.25, s.y - i * 0.25, i * 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";
|
|
2797
|
+
const g = i * 1.6;
|
|
2798
|
+
let u = s.label, y = e.measureText(u).width;
|
|
2799
|
+
if (y > g) {
|
|
2800
|
+
for (; y > g && u.length > 3; )
|
|
2801
|
+
u = u.slice(0, -1), y = e.measureText(u + "...").width;
|
|
2802
|
+
u += "...";
|
|
2803
|
+
}
|
|
2804
|
+
e.shadowColor = "rgba(0, 0, 0, 0.5)", e.shadowBlur = 3, e.fillText(u, s.x, s.y), e.shadowBlur = 0;
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
/**
|
|
2808
|
+
* Sets the graph data
|
|
2809
|
+
*/
|
|
2810
|
+
setData(e) {
|
|
2811
|
+
this.nodes.clear(), this.edges = [], this.nodeIdToIndex.clear(), e.nodes.forEach((s, t) => {
|
|
2812
|
+
const o = s.position || {
|
|
2813
|
+
x: (Math.random() - 0.5) * 300,
|
|
2814
|
+
y: (Math.random() - 0.5) * 300
|
|
2815
|
+
}, i = {
|
|
2816
|
+
id: s.id,
|
|
2817
|
+
label: s.label,
|
|
2818
|
+
x: o.x,
|
|
2819
|
+
y: o.y,
|
|
2820
|
+
vx: 0,
|
|
2821
|
+
vy: 0,
|
|
2822
|
+
color: s.color || 16750950,
|
|
2823
|
+
// Match 3D tangerine color
|
|
2824
|
+
radius: this.options.nodeRadius,
|
|
2825
|
+
data: s
|
|
2826
|
+
};
|
|
2827
|
+
this.nodes.set(s.id, i), this.nodeIdToIndex.set(s.id, t);
|
|
2828
|
+
}), this.edges = e.edges.map((s) => ({
|
|
2829
|
+
source: s.source,
|
|
2830
|
+
target: s.target,
|
|
2831
|
+
relationship: s.relationship,
|
|
2832
|
+
data: s
|
|
2833
|
+
}));
|
|
2834
|
+
}
|
|
2835
|
+
/**
|
|
2836
|
+
* Adds a node
|
|
2837
|
+
*/
|
|
2838
|
+
addNode(e) {
|
|
2839
|
+
const s = e.position || {
|
|
2840
|
+
x: (Math.random() - 0.5) * 300,
|
|
2841
|
+
y: (Math.random() - 0.5) * 300
|
|
2842
|
+
}, t = {
|
|
2843
|
+
id: e.id,
|
|
2844
|
+
label: e.label,
|
|
2845
|
+
x: s.x,
|
|
2846
|
+
y: s.y,
|
|
2847
|
+
vx: 0,
|
|
2848
|
+
vy: 0,
|
|
2849
|
+
color: e.color || 16750950,
|
|
2850
|
+
// Match 3D tangerine color
|
|
2851
|
+
radius: this.options.nodeRadius,
|
|
2852
|
+
data: e
|
|
2853
|
+
};
|
|
2854
|
+
this.nodes.set(e.id, t);
|
|
2855
|
+
}
|
|
2856
|
+
/**
|
|
2857
|
+
* Adds an edge
|
|
2858
|
+
*/
|
|
2859
|
+
addEdge(e) {
|
|
2860
|
+
this.edges.push({
|
|
2861
|
+
source: e.source,
|
|
2862
|
+
target: e.target,
|
|
2863
|
+
relationship: e.relationship,
|
|
2864
|
+
data: e
|
|
2865
|
+
});
|
|
2866
|
+
}
|
|
2867
|
+
/**
|
|
2868
|
+
* Removes a node
|
|
2869
|
+
*/
|
|
2870
|
+
removeNode(e) {
|
|
2871
|
+
this.nodes.delete(e), this.edges = this.edges.filter((s) => s.source !== e && s.target !== e);
|
|
2872
|
+
}
|
|
2873
|
+
/**
|
|
2874
|
+
* Gets a node by ID
|
|
2875
|
+
*/
|
|
2876
|
+
getNode(e) {
|
|
2877
|
+
return this.nodes.get(e);
|
|
2878
|
+
}
|
|
2879
|
+
/**
|
|
2880
|
+
* Gets all nodes
|
|
2881
|
+
*/
|
|
2882
|
+
getAllNodes() {
|
|
2883
|
+
return Array.from(this.nodes.values()).map((e) => e.data);
|
|
2884
|
+
}
|
|
2885
|
+
/**
|
|
2886
|
+
* Gets node count
|
|
2887
|
+
*/
|
|
2888
|
+
getNodeCount() {
|
|
2889
|
+
return this.nodes.size;
|
|
2890
|
+
}
|
|
2891
|
+
/**
|
|
2892
|
+
* Gets edge count
|
|
2893
|
+
*/
|
|
2894
|
+
getEdgeCount() {
|
|
2895
|
+
return this.edges.length;
|
|
2896
|
+
}
|
|
2897
|
+
/**
|
|
2898
|
+
* Focuses on a node
|
|
2899
|
+
*/
|
|
2900
|
+
focusOnNode(e) {
|
|
2901
|
+
const s = this.nodes.get(e);
|
|
2902
|
+
if (!s) return;
|
|
2903
|
+
const t = this.canvas.width / 2 / (window.devicePixelRatio || 1) - s.x * this.transform.scale, o = this.canvas.height / 2 / (window.devicePixelRatio || 1) - s.y * this.transform.scale, i = this.transform.x, a = this.transform.y, r = 500, c = performance.now(), d = () => {
|
|
2904
|
+
const g = performance.now() - c, u = Math.min(g / r, 1), y = 1 - Math.pow(1 - u, 3);
|
|
2905
|
+
this.transform.x = i + (t - i) * y, this.transform.y = a + (o - a) * y, u < 1 ? requestAnimationFrame(d) : this.selectedNode = s;
|
|
2906
|
+
};
|
|
2907
|
+
d();
|
|
2908
|
+
}
|
|
2909
|
+
/**
|
|
2910
|
+
* Updates node positions from 3D data
|
|
2911
|
+
*/
|
|
2912
|
+
syncFrom3D(e) {
|
|
2913
|
+
e.forEach((s, t) => {
|
|
2914
|
+
const o = this.nodes.get(t);
|
|
2915
|
+
o && (o.x = s.position.x * 3, o.y = s.position.y * 3, o.vx = 0, o.vy = 0);
|
|
2916
|
+
}), this.isSimulating = !1;
|
|
2917
|
+
}
|
|
2918
|
+
/**
|
|
2919
|
+
* Gets 2D positions for syncing to 3D
|
|
2920
|
+
*/
|
|
2921
|
+
getPositions() {
|
|
2922
|
+
const e = /* @__PURE__ */ new Map();
|
|
2923
|
+
return this.nodes.forEach((s, t) => {
|
|
2924
|
+
e.set(t, { x: s.x, y: s.y });
|
|
2925
|
+
}), e;
|
|
2926
|
+
}
|
|
2927
|
+
/**
|
|
2928
|
+
* Show/hide the canvas
|
|
2929
|
+
*/
|
|
2930
|
+
show() {
|
|
2931
|
+
this.canvas.style.display = "block";
|
|
2932
|
+
}
|
|
2933
|
+
hide() {
|
|
2934
|
+
this.canvas.style.display = "none";
|
|
2935
|
+
}
|
|
2936
|
+
/**
|
|
2937
|
+
* Updates physics parameters in real-time
|
|
2938
|
+
*/
|
|
2939
|
+
setPhysicsParams(e) {
|
|
2940
|
+
e.repulsionStrength !== void 0 && (this.options.repulsionStrength = e.repulsionStrength), e.attractionStrength !== void 0 && (this.options.attractionStrength = e.attractionStrength), e.damping !== void 0 && (this.options.damping = e.damping), this.isSimulating = !0;
|
|
2941
|
+
}
|
|
2942
|
+
/**
|
|
2943
|
+
* Dispose resources
|
|
2944
|
+
*/
|
|
2945
|
+
dispose() {
|
|
2946
|
+
this.animationId && cancelAnimationFrame(this.animationId), window.removeEventListener("resize", this.resizeHandler), this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2949
|
+
class Ft {
|
|
2950
|
+
// Store graph data for view switching
|
|
2510
2951
|
constructor(e, s = {}) {
|
|
2511
2952
|
// Options
|
|
2512
|
-
|
|
2513
|
-
|
|
2953
|
+
l(this, "options");
|
|
2954
|
+
l(this, "container");
|
|
2514
2955
|
// Core components
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2956
|
+
l(this, "sceneManager");
|
|
2957
|
+
l(this, "nodeManager");
|
|
2958
|
+
l(this, "edgeManager");
|
|
2959
|
+
l(this, "graphEngine");
|
|
2960
|
+
l(this, "rendererManager");
|
|
2520
2961
|
// Factories
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2962
|
+
l(this, "materialFactory");
|
|
2963
|
+
l(this, "nodeFactory");
|
|
2964
|
+
l(this, "edgeFactory");
|
|
2524
2965
|
// Performance
|
|
2525
|
-
|
|
2526
|
-
|
|
2966
|
+
l(this, "lodManager");
|
|
2967
|
+
l(this, "frustumCuller");
|
|
2527
2968
|
// Interaction
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2969
|
+
l(this, "raycasterManager");
|
|
2970
|
+
l(this, "panelManager");
|
|
2971
|
+
l(this, "edgePanelManager");
|
|
2972
|
+
l(this, "edgeTooltipManager");
|
|
2973
|
+
l(this, "searchManager", null);
|
|
2974
|
+
l(this, "viewToggleManager", null);
|
|
2975
|
+
// 2D Renderer
|
|
2976
|
+
l(this, "forceGraph2D", null);
|
|
2533
2977
|
// Event system
|
|
2534
|
-
|
|
2978
|
+
l(this, "eventCallbacks", /* @__PURE__ */ new Map());
|
|
2535
2979
|
// State
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
this
|
|
2980
|
+
l(this, "initialized", !1);
|
|
2981
|
+
l(this, "devControls", null);
|
|
2982
|
+
l(this, "viewMode", "3d");
|
|
2983
|
+
l(this, "graphData", null);
|
|
2984
|
+
this.options = { ...R, ...s }, this.container = ct(e), this.materialFactory = new bt(), this.nodeFactory = new vt(
|
|
2539
2985
|
this.materialFactory,
|
|
2540
|
-
this.options.nodeRadius ??
|
|
2541
|
-
this.options.lodSegments ??
|
|
2986
|
+
this.options.nodeRadius ?? R.nodeRadius,
|
|
2987
|
+
this.options.lodSegments ?? R.lodSegments
|
|
2542
2988
|
), this.edgeFactory = new Mt(
|
|
2543
2989
|
this.materialFactory,
|
|
2544
|
-
this.options.edgeColor ??
|
|
2545
|
-
this.options.edgeOpacity ??
|
|
2990
|
+
this.options.edgeColor ?? R.edgeColor,
|
|
2991
|
+
this.options.edgeOpacity ?? R.edgeOpacity
|
|
2546
2992
|
), this.sceneManager = new ut(this.container, this.options), this.lodManager = new wt(
|
|
2547
2993
|
this.sceneManager.camera,
|
|
2548
|
-
this.options.lodDistances ??
|
|
2549
|
-
this.options.enableLOD ??
|
|
2994
|
+
this.options.lodDistances ?? R.lodDistances,
|
|
2995
|
+
this.options.enableLOD ?? R.enableLOD
|
|
2550
2996
|
), this.frustumCuller = new Et(
|
|
2551
2997
|
this.sceneManager.camera,
|
|
2552
|
-
this.options.enableEdgeCulling ??
|
|
2553
|
-
), this.nodeManager = new
|
|
2998
|
+
this.options.enableEdgeCulling ?? R.enableEdgeCulling
|
|
2999
|
+
), this.nodeManager = new ft(this.sceneManager, this.nodeFactory), this.edgeManager = new mt(this.sceneManager, this.nodeManager, this.edgeFactory), this.graphEngine = new Le(
|
|
2554
3000
|
this.nodeManager.getAllNodes(),
|
|
2555
3001
|
this.edgeManager.getAllEdges(),
|
|
2556
3002
|
{
|
|
@@ -2560,12 +3006,12 @@ class Ot {
|
|
|
2560
3006
|
useBarnesHut: this.options.useBarnesHut,
|
|
2561
3007
|
barnesHutTheta: this.options.barnesHutTheta
|
|
2562
3008
|
}
|
|
2563
|
-
), this.rendererManager = new
|
|
3009
|
+
), this.rendererManager = new xt(
|
|
2564
3010
|
this.sceneManager,
|
|
2565
3011
|
() => this.onSimulate(),
|
|
2566
3012
|
() => this.onRender(),
|
|
2567
|
-
this.options.targetFPS ??
|
|
2568
|
-
), this.raycasterManager = new Ct(this.sceneManager, this.container), this.panelManager = new
|
|
3013
|
+
this.options.targetFPS ?? R.targetFPS
|
|
3014
|
+
), 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) => {
|
|
2569
3015
|
this.edgePanelManager.hide(), this.focusOnNode(t), setTimeout(() => {
|
|
2570
3016
|
this.showNodePanel(t);
|
|
2571
3017
|
}, 400);
|
|
@@ -2580,6 +3026,11 @@ class Ot {
|
|
|
2580
3026
|
this.showNodePanel(t);
|
|
2581
3027
|
}, 400);
|
|
2582
3028
|
}
|
|
3029
|
+
})), this.options.showViewToggle !== !1 && (this.viewMode = this.options.initialViewMode || "3d", this.viewToggleManager = new Pt(this.container, {
|
|
3030
|
+
initialMode: this.viewMode,
|
|
3031
|
+
onViewChange: (t) => {
|
|
3032
|
+
this.switchView(t);
|
|
3033
|
+
}
|
|
2583
3034
|
})), this.setupCallbacks(), this.rendererManager.start(), this.initialized = !0, this.emit("ready");
|
|
2584
3035
|
}
|
|
2585
3036
|
/**
|
|
@@ -2602,8 +3053,8 @@ class Ot {
|
|
|
2602
3053
|
onEdgeHover(e) {
|
|
2603
3054
|
if (e) {
|
|
2604
3055
|
this.edgeManager.highlightEdge(e.edge.source, e.edge.target);
|
|
2605
|
-
const s = this.container.getBoundingClientRect(), t = s.left + s.width / 2,
|
|
2606
|
-
this.edgeTooltipManager.show(e.edge, e.sourceNode, e.targetNode, t,
|
|
3056
|
+
const s = this.container.getBoundingClientRect(), t = s.left + s.width / 2, o = s.top + s.height / 2;
|
|
3057
|
+
this.edgeTooltipManager.show(e.edge, e.sourceNode, e.targetNode, t, o), this.options.onEdgeHover && this.options.onEdgeHover(e.edge, e.sourceNode, e.targetNode), this.emit("edgeHover", e.edge, e.sourceNode, e.targetNode);
|
|
2607
3058
|
} else
|
|
2608
3059
|
this.edgeManager.unhighlightCurrentEdge(), this.edgeTooltipManager.hide(), this.options.onEdgeHover && this.options.onEdgeHover(null, null, null), this.emit("edgeHover", null, null, null);
|
|
2609
3060
|
}
|
|
@@ -2612,7 +3063,7 @@ class Ot {
|
|
|
2612
3063
|
*/
|
|
2613
3064
|
onNodeClick(e) {
|
|
2614
3065
|
this.edgePanelManager.hide();
|
|
2615
|
-
const t = this.edgeManager.getNeighborIds(e.id).map((
|
|
3066
|
+
const t = this.edgeManager.getNeighborIds(e.id).map((o) => this.nodeManager.getNode(o)).filter((o) => o !== void 0);
|
|
2616
3067
|
this.options.showPanel !== !1 && this.panelManager.show(e, t), this.options.onNodeClick && this.options.onNodeClick(e), this.emit("nodeClick", e);
|
|
2617
3068
|
}
|
|
2618
3069
|
/**
|
|
@@ -2646,7 +3097,7 @@ class Ot {
|
|
|
2646
3097
|
* Sets the graph data
|
|
2647
3098
|
*/
|
|
2648
3099
|
setData(e) {
|
|
2649
|
-
if (this.edgeManager.clear(), this.nodeManager.clear(), e.nodes && Array.isArray(e.nodes))
|
|
3100
|
+
if (this.graphData = e, this.edgeManager.clear(), this.nodeManager.clear(), e.nodes && Array.isArray(e.nodes))
|
|
2650
3101
|
for (const s of e.nodes)
|
|
2651
3102
|
this.addNode(s);
|
|
2652
3103
|
if (e.edges && Array.isArray(e.edges))
|
|
@@ -2662,17 +3113,17 @@ class Ot {
|
|
|
2662
3113
|
useBarnesHut: this.options.useBarnesHut,
|
|
2663
3114
|
barnesHutTheta: this.options.barnesHutTheta
|
|
2664
3115
|
}
|
|
2665
|
-
), this.graphEngine.restart();
|
|
3116
|
+
), this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.setData(e);
|
|
2666
3117
|
}
|
|
2667
3118
|
/**
|
|
2668
3119
|
* Adds a node to the graph
|
|
2669
3120
|
* @returns true if added, false if node already exists or invalid
|
|
2670
3121
|
*/
|
|
2671
3122
|
addNode(e) {
|
|
2672
|
-
if (!
|
|
3123
|
+
if (!Oe(e))
|
|
2673
3124
|
return !1;
|
|
2674
3125
|
const s = this.nodeManager.addNode(e);
|
|
2675
|
-
return s && (this.graphEngine.restart(), this.options.onNodeAdd && this.options.onNodeAdd(e), this.emit("nodeAdd", e)), s;
|
|
3126
|
+
return s && (this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.addNode(e), this.options.onNodeAdd && this.options.onNodeAdd(e), this.emit("nodeAdd", e)), s;
|
|
2676
3127
|
}
|
|
2677
3128
|
/**
|
|
2678
3129
|
* Removes a node from the graph
|
|
@@ -2699,7 +3150,7 @@ class Ot {
|
|
|
2699
3150
|
if (!Fe(e))
|
|
2700
3151
|
return !1;
|
|
2701
3152
|
const s = this.edgeManager.addEdge(e);
|
|
2702
|
-
return s && (this.graphEngine.setEdges(this.edgeManager.getAllEdges()), this.graphEngine.restart(), this.options.onEdgeAdd && this.options.onEdgeAdd(e), this.emit("edgeAdd", e)), s;
|
|
3153
|
+
return s && (this.graphEngine.setEdges(this.edgeManager.getAllEdges()), this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.addEdge(e), this.options.onEdgeAdd && this.options.onEdgeAdd(e), this.emit("edgeAdd", e)), s;
|
|
2703
3154
|
}
|
|
2704
3155
|
/**
|
|
2705
3156
|
* Removes an edge from the graph
|
|
@@ -2716,20 +3167,20 @@ class Ot {
|
|
|
2716
3167
|
* @param fetchFn - Optional fetch function to override the default
|
|
2717
3168
|
*/
|
|
2718
3169
|
async expandNode(e, s = 1, t) {
|
|
2719
|
-
const
|
|
2720
|
-
if (!
|
|
3170
|
+
const o = t ?? this.options.onExpand;
|
|
3171
|
+
if (!o)
|
|
2721
3172
|
return console.warn("[ForceGraph3D] No expand callback provided"), !1;
|
|
2722
3173
|
try {
|
|
2723
|
-
const
|
|
2724
|
-
if (
|
|
2725
|
-
for (const a of
|
|
3174
|
+
const i = await o(e, s);
|
|
3175
|
+
if (i.nodes && Array.isArray(i.nodes))
|
|
3176
|
+
for (const a of i.nodes)
|
|
2726
3177
|
this.addNode(a);
|
|
2727
|
-
if (
|
|
2728
|
-
for (const a of
|
|
3178
|
+
if (i.edges && Array.isArray(i.edges))
|
|
3179
|
+
for (const a of i.edges)
|
|
2729
3180
|
this.addEdge(a);
|
|
2730
|
-
return this.panelManager.hide(), this.emit("expand", e,
|
|
2731
|
-
} catch (
|
|
2732
|
-
return console.error("[ForceGraph3D] Error expanding node:",
|
|
3181
|
+
return this.panelManager.hide(), this.emit("expand", e, i), !0;
|
|
3182
|
+
} catch (i) {
|
|
3183
|
+
return console.error("[ForceGraph3D] Error expanding node:", i), !1;
|
|
2733
3184
|
}
|
|
2734
3185
|
}
|
|
2735
3186
|
/**
|
|
@@ -2767,18 +3218,22 @@ class Ot {
|
|
|
2767
3218
|
* Focuses the camera on a specific node with smooth animation
|
|
2768
3219
|
*/
|
|
2769
3220
|
focusOnNode(e, s = 30) {
|
|
3221
|
+
if (this.viewMode === "2d" && this.forceGraph2D) {
|
|
3222
|
+
this.forceGraph2D.focusOnNode(e);
|
|
3223
|
+
return;
|
|
3224
|
+
}
|
|
2770
3225
|
const t = this.nodeManager.getNode(e);
|
|
2771
3226
|
if (!t) {
|
|
2772
3227
|
console.warn(`[ForceGraph3D] Node "${e}" not found`);
|
|
2773
3228
|
return;
|
|
2774
3229
|
}
|
|
2775
|
-
const
|
|
2776
|
-
x:
|
|
2777
|
-
y:
|
|
2778
|
-
z:
|
|
2779
|
-
},
|
|
2780
|
-
const
|
|
2781
|
-
|
|
3230
|
+
const o = t.position, i = this.sceneManager.camera, a = this.sceneManager.controls, r = i.position.clone().sub(a.target).normalize(), c = {
|
|
3231
|
+
x: o.x + r.x * s,
|
|
3232
|
+
y: o.y + r.y * s,
|
|
3233
|
+
z: o.z + r.z * s
|
|
3234
|
+
}, d = { x: i.position.x, y: i.position.y, z: i.position.z }, g = { x: a.target.x, y: a.target.y, z: a.target.z }, u = 800, y = performance.now(), f = () => {
|
|
3235
|
+
const x = performance.now() - y, v = Math.min(x / u, 1), M = 1 - Math.pow(1 - v, 3);
|
|
3236
|
+
i.position.x = d.x + (c.x - d.x) * M, i.position.y = d.y + (c.y - d.y) * M, i.position.z = d.z + (c.z - d.z) * M, a.target.x = g.x + (o.x - g.x) * M, a.target.y = g.y + (o.y - g.y) * M, a.target.z = g.z + (o.z - g.z) * M, a.update(), v < 1 && requestAnimationFrame(f);
|
|
2782
3237
|
};
|
|
2783
3238
|
f();
|
|
2784
3239
|
}
|
|
@@ -2787,22 +3242,22 @@ class Ot {
|
|
|
2787
3242
|
* Camera targets the midpoint and zooms out enough to see both nodes
|
|
2788
3243
|
*/
|
|
2789
3244
|
focusOnEdge(e, s, t = 1.5) {
|
|
2790
|
-
const
|
|
2791
|
-
if (!
|
|
3245
|
+
const o = this.nodeManager.getNode(e), i = this.nodeManager.getNode(s);
|
|
3246
|
+
if (!o || !i) {
|
|
2792
3247
|
console.warn(`[ForceGraph3D] Could not find nodes for edge "${e}" -> "${s}"`);
|
|
2793
3248
|
return;
|
|
2794
3249
|
}
|
|
2795
|
-
const a = this.sceneManager.camera,
|
|
2796
|
-
x: (
|
|
2797
|
-
y: (
|
|
2798
|
-
z: (
|
|
2799
|
-
},
|
|
2800
|
-
x:
|
|
2801
|
-
y:
|
|
2802
|
-
z:
|
|
2803
|
-
},
|
|
2804
|
-
const
|
|
2805
|
-
a.position.x =
|
|
3250
|
+
const a = this.sceneManager.camera, r = this.sceneManager.controls, c = {
|
|
3251
|
+
x: (o.position.x + i.position.x) / 2,
|
|
3252
|
+
y: (o.position.y + i.position.y) / 2,
|
|
3253
|
+
z: (o.position.z + i.position.z) / 2
|
|
3254
|
+
}, d = i.position.x - o.position.x, g = i.position.y - o.position.y, u = i.position.z - o.position.z, y = Math.sqrt(d * d + g * g + u * u), f = Math.max(y * t, 40), x = a.position.clone().sub(r.target).normalize(), v = {
|
|
3255
|
+
x: c.x + x.x * f,
|
|
3256
|
+
y: c.y + x.y * f,
|
|
3257
|
+
z: c.z + x.z * f
|
|
3258
|
+
}, M = { x: a.position.x, y: a.position.y, z: a.position.z }, N = { x: r.target.x, y: r.target.y, z: r.target.z }, O = 800, T = performance.now(), Y = () => {
|
|
3259
|
+
const P = performance.now() - T, H = Math.min(P / O, 1), E = 1 - Math.pow(1 - H, 3);
|
|
3260
|
+
a.position.x = M.x + (v.x - M.x) * E, a.position.y = M.y + (v.y - M.y) * E, a.position.z = M.z + (v.z - M.z) * E, r.target.x = N.x + (c.x - N.x) * E, r.target.y = N.y + (c.y - N.y) * E, r.target.z = N.z + (c.z - N.z) * E, r.update(), H < 1 && requestAnimationFrame(Y);
|
|
2806
3261
|
};
|
|
2807
3262
|
Y();
|
|
2808
3263
|
}
|
|
@@ -2825,28 +3280,28 @@ class Ot {
|
|
|
2825
3280
|
searchNodes(e) {
|
|
2826
3281
|
if (!e || e.trim() === "")
|
|
2827
3282
|
return [];
|
|
2828
|
-
const s = e.toLowerCase().trim(), t = this.nodeManager.getAllNodes(),
|
|
2829
|
-
return t.forEach((
|
|
2830
|
-
var g, u
|
|
2831
|
-
const a = (
|
|
2832
|
-
(a ||
|
|
2833
|
-
}),
|
|
3283
|
+
const s = e.toLowerCase().trim(), t = this.nodeManager.getAllNodes(), o = [];
|
|
3284
|
+
return t.forEach((i) => {
|
|
3285
|
+
var d, g, u;
|
|
3286
|
+
const a = (d = i.label) == null ? void 0 : d.toLowerCase().includes(s), r = (g = i.id) == null ? void 0 : g.toLowerCase().includes(s), c = (u = i.type) == null ? void 0 : u.toLowerCase().includes(s);
|
|
3287
|
+
(a || r || c) && o.push(i);
|
|
3288
|
+
}), o;
|
|
2834
3289
|
}
|
|
2835
3290
|
/**
|
|
2836
3291
|
* Searches edges by relationship (case-insensitive)
|
|
2837
3292
|
* @returns Array of matching edges with source/target node info
|
|
2838
3293
|
*/
|
|
2839
3294
|
searchEdges(e) {
|
|
2840
|
-
var
|
|
3295
|
+
var i;
|
|
2841
3296
|
if (!e || e.trim() === "")
|
|
2842
3297
|
return [];
|
|
2843
|
-
const s = e.toLowerCase().trim(), t = this.edgeManager.getAllEdges(),
|
|
3298
|
+
const s = e.toLowerCase().trim(), t = this.edgeManager.getAllEdges(), o = [];
|
|
2844
3299
|
for (const a of t)
|
|
2845
|
-
if ((
|
|
2846
|
-
const
|
|
2847
|
-
|
|
3300
|
+
if ((i = a.relationship) == null ? void 0 : i.toLowerCase().includes(s)) {
|
|
3301
|
+
const c = this.nodeManager.getNode(a.source), d = this.nodeManager.getNode(a.target);
|
|
3302
|
+
c && d && o.push({ edge: a, sourceNode: c, targetNode: d });
|
|
2848
3303
|
}
|
|
2849
|
-
return
|
|
3304
|
+
return o;
|
|
2850
3305
|
}
|
|
2851
3306
|
/**
|
|
2852
3307
|
* Gets all nodes as an array
|
|
@@ -2867,6 +3322,44 @@ class Ot {
|
|
|
2867
3322
|
isInitialized() {
|
|
2868
3323
|
return this.initialized;
|
|
2869
3324
|
}
|
|
3325
|
+
/**
|
|
3326
|
+
* Gets the current view mode
|
|
3327
|
+
*/
|
|
3328
|
+
getViewMode() {
|
|
3329
|
+
return this.viewMode;
|
|
3330
|
+
}
|
|
3331
|
+
/**
|
|
3332
|
+
* Switches between 2D and 3D view modes
|
|
3333
|
+
*/
|
|
3334
|
+
switchView(e) {
|
|
3335
|
+
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, {
|
|
3336
|
+
backgroundColor: "#0a0a0a",
|
|
3337
|
+
nodeRadius: 24,
|
|
3338
|
+
onNodeClick: (s) => {
|
|
3339
|
+
this.onNodeClick(s);
|
|
3340
|
+
},
|
|
3341
|
+
onNodeHover: (s) => {
|
|
3342
|
+
this.options.onNodeHover && this.options.onNodeHover(s);
|
|
3343
|
+
},
|
|
3344
|
+
onEdgeHover: (s, t) => {
|
|
3345
|
+
if (s && t) {
|
|
3346
|
+
const o = this.nodeManager.getNode(s.source), i = this.nodeManager.getNode(s.target);
|
|
3347
|
+
o && i && this.edgeTooltipManager.show(
|
|
3348
|
+
s,
|
|
3349
|
+
o,
|
|
3350
|
+
i,
|
|
3351
|
+
t.clientX,
|
|
3352
|
+
t.clientY
|
|
3353
|
+
);
|
|
3354
|
+
} else
|
|
3355
|
+
this.edgeTooltipManager.hide();
|
|
3356
|
+
},
|
|
3357
|
+
onEdgeClick: (s) => {
|
|
3358
|
+
const t = this.nodeManager.getNode(s.source), o = this.nodeManager.getNode(s.target);
|
|
3359
|
+
t && o && this.edgePanelManager.show(s, t, o);
|
|
3360
|
+
}
|
|
3361
|
+
}), this.graphData && (this.forceGraph2D.setData(this.graphData), this.forceGraph2D.syncFrom3D(this.nodeManager.getAllNodes())))) : (this.forceGraph2D && this.forceGraph2D.hide(), this.sceneManager.renderer.domElement.style.display = "block", this.rendererManager.start()), this.emit("viewChange", e));
|
|
3362
|
+
}
|
|
2870
3363
|
/**
|
|
2871
3364
|
* Registers an event listener
|
|
2872
3365
|
*/
|
|
@@ -2878,13 +3371,13 @@ class Ot {
|
|
|
2878
3371
|
*/
|
|
2879
3372
|
emit(e, ...s) {
|
|
2880
3373
|
const t = this.eventCallbacks.get(e);
|
|
2881
|
-
t && t.forEach((
|
|
3374
|
+
t && t.forEach((o) => o(...s));
|
|
2882
3375
|
}
|
|
2883
3376
|
/**
|
|
2884
|
-
* Sets physics parameters
|
|
3377
|
+
* Sets physics parameters for both 3D and 2D views
|
|
2885
3378
|
*/
|
|
2886
3379
|
setPhysicsParams(e) {
|
|
2887
|
-
this.graphEngine.setPhysicsParams(e), this.graphEngine.restart();
|
|
3380
|
+
this.graphEngine.setPhysicsParams(e), this.graphEngine.restart(), this.forceGraph2D && this.forceGraph2D.setPhysicsParams(e);
|
|
2888
3381
|
}
|
|
2889
3382
|
/**
|
|
2890
3383
|
* Creates dev mode controls (only in development)
|
|
@@ -2955,27 +3448,27 @@ class Ot {
|
|
|
2955
3448
|
`, this.container.appendChild(this.devControls);
|
|
2956
3449
|
const e = this.devControls.querySelector("#dev-repulsion"), s = this.devControls.querySelector("#dev-attraction"), t = this.devControls.querySelector("#dev-damping");
|
|
2957
3450
|
e == null || e.addEventListener("input", () => {
|
|
2958
|
-
const
|
|
2959
|
-
this.setPhysicsParams({ repulsionStrength:
|
|
3451
|
+
const o = parseFloat(e.value);
|
|
3452
|
+
this.setPhysicsParams({ repulsionStrength: o }), this.devControls.querySelector("#dev-repulsion-val").textContent = o.toString();
|
|
2960
3453
|
}), s == null || s.addEventListener("input", () => {
|
|
2961
|
-
const
|
|
2962
|
-
this.setPhysicsParams({ attractionStrength:
|
|
3454
|
+
const o = parseFloat(s.value) / 1e3;
|
|
3455
|
+
this.setPhysicsParams({ attractionStrength: o }), this.devControls.querySelector("#dev-attraction-val").textContent = o.toFixed(3);
|
|
2963
3456
|
}), t == null || t.addEventListener("input", () => {
|
|
2964
|
-
const
|
|
2965
|
-
this.setPhysicsParams({ damping:
|
|
3457
|
+
const o = parseFloat(t.value) / 100;
|
|
3458
|
+
this.setPhysicsParams({ damping: o }), this.devControls.querySelector("#dev-damping-val").textContent = o.toFixed(2);
|
|
2966
3459
|
}), setInterval(() => {
|
|
2967
|
-
const
|
|
2968
|
-
|
|
3460
|
+
const o = this.devControls.querySelector("#dev-node-count"), i = this.devControls.querySelector("#dev-edge-count"), a = this.devControls.querySelector("#dev-fps");
|
|
3461
|
+
o && (o.textContent = this.getNodeCount().toString()), i && (i.textContent = this.getEdgeCount().toString()), a && (a.textContent = this.rendererManager.getFPS().toString());
|
|
2969
3462
|
}, 500);
|
|
2970
3463
|
}
|
|
2971
3464
|
/**
|
|
2972
3465
|
* Destroys the graph and releases all resources
|
|
2973
3466
|
*/
|
|
2974
3467
|
destroy() {
|
|
2975
|
-
this.rendererManager.dispose(), this.panelManager.dispose(), this.raycasterManager.dispose(), this.edgeTooltipManager.dispose(), this.searchManager && this.searchManager.dispose(), this.edgeManager.dispose(), this.nodeManager.dispose(), this.nodeFactory.dispose(), this.materialFactory.dispose(), this.sceneManager.dispose(), this.devControls && this.devControls.parentNode && this.devControls.parentNode.removeChild(this.devControls), this.eventCallbacks.clear(), this.initialized = !1;
|
|
3468
|
+
this.rendererManager.dispose(), this.panelManager.dispose(), this.raycasterManager.dispose(), this.edgeTooltipManager.dispose(), this.searchManager && this.searchManager.dispose(), this.viewToggleManager && this.viewToggleManager.dispose(), this.forceGraph2D && this.forceGraph2D.dispose(), this.edgeManager.dispose(), this.nodeManager.dispose(), this.nodeFactory.dispose(), this.materialFactory.dispose(), this.sceneManager.dispose(), this.devControls && this.devControls.parentNode && this.devControls.parentNode.removeChild(this.devControls), this.eventCallbacks.clear(), this.initialized = !1;
|
|
2976
3469
|
}
|
|
2977
3470
|
}
|
|
2978
|
-
const
|
|
3471
|
+
const Ie = [
|
|
2979
3472
|
"Alpha",
|
|
2980
3473
|
"Beta",
|
|
2981
3474
|
"Gamma",
|
|
@@ -3017,7 +3510,7 @@ const Oe = [
|
|
|
3017
3510
|
"partners with",
|
|
3018
3511
|
"collaborates with",
|
|
3019
3512
|
"supports"
|
|
3020
|
-
],
|
|
3513
|
+
], Re = [
|
|
3021
3514
|
16777215,
|
|
3022
3515
|
// White
|
|
3023
3516
|
16750950,
|
|
@@ -3029,14 +3522,14 @@ const Oe = [
|
|
|
3029
3522
|
16746564
|
|
3030
3523
|
// Darker tangerine
|
|
3031
3524
|
];
|
|
3032
|
-
function
|
|
3525
|
+
function Ht(h = 30) {
|
|
3033
3526
|
const e = [], s = [];
|
|
3034
|
-
for (let
|
|
3035
|
-
const
|
|
3527
|
+
for (let o = 0; o < h; o++) {
|
|
3528
|
+
const i = o < Ie.length ? Ie[o] : `Node ${o + 1}`;
|
|
3036
3529
|
e.push({
|
|
3037
|
-
id: `node-${
|
|
3038
|
-
label:
|
|
3039
|
-
color:
|
|
3530
|
+
id: `node-${o}`,
|
|
3531
|
+
label: i,
|
|
3532
|
+
color: Re[o % Re.length],
|
|
3040
3533
|
position: {
|
|
3041
3534
|
x: (Math.random() - 0.5) * 60,
|
|
3042
3535
|
y: (Math.random() - 0.5) * 60,
|
|
@@ -3044,43 +3537,43 @@ function It(c = 30) {
|
|
|
3044
3537
|
}
|
|
3045
3538
|
});
|
|
3046
3539
|
}
|
|
3047
|
-
for (let
|
|
3048
|
-
const
|
|
3540
|
+
for (let o = 1; o < h; o++) {
|
|
3541
|
+
const i = Math.floor(Math.random() * o);
|
|
3049
3542
|
s.push({
|
|
3050
|
-
source: `node-${
|
|
3051
|
-
target: `node-${
|
|
3543
|
+
source: `node-${o}`,
|
|
3544
|
+
target: `node-${i}`,
|
|
3052
3545
|
relationship: J[Math.floor(Math.random() * J.length)]
|
|
3053
3546
|
});
|
|
3054
3547
|
}
|
|
3055
|
-
const t = Math.floor(
|
|
3056
|
-
for (let
|
|
3057
|
-
const
|
|
3058
|
-
let a = Math.floor(Math.random() *
|
|
3059
|
-
|
|
3060
|
-
const
|
|
3548
|
+
const t = Math.floor(h * 0.5);
|
|
3549
|
+
for (let o = 0; o < t; o++) {
|
|
3550
|
+
const i = Math.floor(Math.random() * h);
|
|
3551
|
+
let a = Math.floor(Math.random() * h);
|
|
3552
|
+
i === a && (a = (a + 1) % h);
|
|
3553
|
+
const r = `node-${i}`, c = `node-${a}`;
|
|
3061
3554
|
s.some(
|
|
3062
|
-
(
|
|
3555
|
+
(g) => g.source === r && g.target === c || g.source === c && g.target === r
|
|
3063
3556
|
) || s.push({
|
|
3064
|
-
source:
|
|
3065
|
-
target:
|
|
3557
|
+
source: r,
|
|
3558
|
+
target: c,
|
|
3066
3559
|
relationship: J[Math.floor(Math.random() * J.length)]
|
|
3067
3560
|
});
|
|
3068
3561
|
}
|
|
3069
3562
|
return { nodes: e, edges: s };
|
|
3070
3563
|
}
|
|
3071
|
-
function
|
|
3072
|
-
const e = [], s = [], t = Math.ceil(
|
|
3073
|
-
for (let
|
|
3074
|
-
|
|
3564
|
+
function Dt(h = 1e3) {
|
|
3565
|
+
const e = [], s = [], t = Math.ceil(h / 50), o = [];
|
|
3566
|
+
for (let i = 0; i < t; i++)
|
|
3567
|
+
o.push({
|
|
3075
3568
|
x: (Math.random() - 0.5) * 200,
|
|
3076
3569
|
y: (Math.random() - 0.5) * 200,
|
|
3077
3570
|
z: (Math.random() - 0.5) * 200
|
|
3078
3571
|
});
|
|
3079
|
-
for (let
|
|
3080
|
-
const a =
|
|
3572
|
+
for (let i = 0; i < h; i++) {
|
|
3573
|
+
const a = o[i % t];
|
|
3081
3574
|
e.push({
|
|
3082
|
-
id: `node-${
|
|
3083
|
-
label: `N${
|
|
3575
|
+
id: `node-${i}`,
|
|
3576
|
+
label: `N${i}`,
|
|
3084
3577
|
position: {
|
|
3085
3578
|
x: a.x + (Math.random() - 0.5) * 40,
|
|
3086
3579
|
y: a.y + (Math.random() - 0.5) * 40,
|
|
@@ -3088,32 +3581,32 @@ function Rt(c = 1e3) {
|
|
|
3088
3581
|
}
|
|
3089
3582
|
});
|
|
3090
3583
|
}
|
|
3091
|
-
for (let
|
|
3092
|
-
const a = Math.floor(
|
|
3584
|
+
for (let i = 1; i < h; i++) {
|
|
3585
|
+
const a = Math.floor(i / 50) * 50, r = a === 0 ? Math.floor(Math.random() * i) : a + Math.floor(Math.random() * Math.min(i - a, 50));
|
|
3093
3586
|
s.push({
|
|
3094
|
-
source: `node-${
|
|
3095
|
-
target: `node-${Math.min(
|
|
3587
|
+
source: `node-${i}`,
|
|
3588
|
+
target: `node-${Math.min(r, i - 1)}`,
|
|
3096
3589
|
relationship: "links to"
|
|
3097
3590
|
});
|
|
3098
3591
|
}
|
|
3099
|
-
for (let
|
|
3100
|
-
const a =
|
|
3592
|
+
for (let i = 1; i < t; i++) {
|
|
3593
|
+
const a = i * 50, r = (i - 1) * 50 + Math.floor(Math.random() * 50);
|
|
3101
3594
|
s.push({
|
|
3102
3595
|
source: `node-${a}`,
|
|
3103
|
-
target: `node-${
|
|
3596
|
+
target: `node-${r}`,
|
|
3104
3597
|
relationship: "bridges to"
|
|
3105
3598
|
});
|
|
3106
3599
|
}
|
|
3107
3600
|
return { nodes: e, edges: s };
|
|
3108
3601
|
}
|
|
3109
3602
|
export {
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3603
|
+
R as DEFAULT_OPTIONS,
|
|
3604
|
+
Ft as ForceGraph3D,
|
|
3605
|
+
U as LODLevel,
|
|
3606
|
+
D as createEdgeKey,
|
|
3607
|
+
Dt as generateLargeSampleData,
|
|
3608
|
+
Ht as generateSampleData,
|
|
3116
3609
|
Fe as validateEdgeData,
|
|
3117
|
-
|
|
3610
|
+
Oe as validateNodeData
|
|
3118
3611
|
};
|
|
3119
3612
|
//# sourceMappingURL=force-3d-graph.js.map
|