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