@logixode/force-graph-lib 0.4.1 → 0.5.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-graph-lib.js +130 -91
- package/dist/force-graph-lib.umd.cjs +1 -1
- package/dist/index.d.ts +6 -0
- package/package.json +2 -1
package/dist/force-graph-lib.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
class
|
|
1
|
+
import c from "force-graph";
|
|
2
|
+
import "d3";
|
|
3
|
+
class C {
|
|
4
4
|
container;
|
|
5
5
|
graph;
|
|
6
6
|
data = { nodes: [], links: [] };
|
|
@@ -10,15 +10,15 @@ class m {
|
|
|
10
10
|
worker = null;
|
|
11
11
|
groupBounds = /* @__PURE__ */ new Map();
|
|
12
12
|
isFirstRender = !0;
|
|
13
|
-
constructor(t,
|
|
14
|
-
this.container = t, this.data =
|
|
13
|
+
constructor(t, o = { nodes: [], links: [] }, i = {}) {
|
|
14
|
+
this.container = t, this.data = o, this.graph = new c(this.container), o.nodes.forEach((r) => {
|
|
15
15
|
this.nodesMap.set(r.id.toString(), r);
|
|
16
16
|
});
|
|
17
17
|
const e = {
|
|
18
18
|
labelThreshold: 1.5,
|
|
19
19
|
// Show labels when they're not bigger than the node
|
|
20
20
|
showGroups: !1,
|
|
21
|
-
...
|
|
21
|
+
...i
|
|
22
22
|
}, s = e.showGroups ? {
|
|
23
23
|
groupBy: "topic",
|
|
24
24
|
groupBorderColor: "#666",
|
|
@@ -49,29 +49,29 @@ class m {
|
|
|
49
49
|
focusPosition(t = {}) {
|
|
50
50
|
if (Object.values(t).length) {
|
|
51
51
|
if (t.id) {
|
|
52
|
-
const { x:
|
|
53
|
-
|
|
52
|
+
const { x: o, y: i } = this.nodesMap.get(t.id) ?? { x: 0, y: 0 };
|
|
53
|
+
o && i && (t = { x: o, y: i });
|
|
54
54
|
}
|
|
55
55
|
t && (this.graph.centerAt(t.x, t.y, 1e3), this.graph.zoom(8, 2e3));
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
render() {
|
|
59
|
-
this.graph.width(this.options.width ?? 800).height(this.options.height ?? 400)
|
|
59
|
+
this.graph.width(this.options.width ?? 800).height(this.options.height ?? 400), this.options.cooldownTicks !== void 0 && this.graph.cooldownTicks(this.options.cooldownTicks);
|
|
60
60
|
}
|
|
61
|
-
force(t,
|
|
62
|
-
return this.graph.d3Force(t,
|
|
61
|
+
force(t, o) {
|
|
62
|
+
return this.graph.d3Force(t, o);
|
|
63
63
|
}
|
|
64
64
|
applyOptions() {
|
|
65
65
|
this.options.keepDragPosition && this.graph.onNodeDragEnd((t) => {
|
|
66
66
|
t.fx = t.x, t.fy = t.y;
|
|
67
|
-
}), this.options.pointerInteraction || this.graph.enablePointerInteraction(!1), this.graph.nodeCanvasObject((t,
|
|
68
|
-
t === this.data.nodes[0] && this.renderGroups(
|
|
69
|
-
const e = this.getNodeSize(t) * 2, s = typeof this.options.nodeBorderWidth == "function" ? this.options.nodeBorderWidth(t) : this.options.nodeBorderWidth;
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
if (
|
|
73
|
-
const
|
|
74
|
-
|
|
67
|
+
}), this.options.pointerInteraction || this.graph.enablePointerInteraction(!1), this.graph.nodeCanvasObject((t, o, i) => {
|
|
68
|
+
t === this.data.nodes[0] && this.renderGroups(o, i);
|
|
69
|
+
const e = this.getNodeSize(t) * 2, s = typeof this.options.nodeBorderWidth == "function" ? this.options.nodeBorderWidth(t) : this.options.nodeBorderWidth, r = this.resolveNodeShape(t), a = t.x || 0, h = t.y || 0;
|
|
70
|
+
this.drawNodeShape(o, a, h, e, r), o.fillStyle = this.getNodeColor(t), o.fill(), s && s > 0 && (this.drawNodeShape(o, a, h, e, r), o.strokeStyle = this.getNodeBorderColor(t), o.lineWidth = s, o.stroke());
|
|
71
|
+
const n = this.getNodeLabel(t);
|
|
72
|
+
if (n && this.shouldShowLabel(t, i)) {
|
|
73
|
+
const p = typeof this.options.nodeLabelColor == "function" ? this.options.nodeLabelColor(t) : this.options.nodeLabelColor ?? "#555", l = (this.options.labelFontSize || 14) / i;
|
|
74
|
+
o.font = `${l}px Arial`, o.fillStyle = p, o.textAlign = "center", o.textBaseline = "middle", o.fillText(n, t.x || 0, (t.y || 0) + e + l / 2 + 2);
|
|
75
75
|
}
|
|
76
76
|
}), this.applyLinkOptions();
|
|
77
77
|
}
|
|
@@ -85,13 +85,13 @@ class m {
|
|
|
85
85
|
* Check if label should be shown based on threshold logic
|
|
86
86
|
* The threshold determines when labels become too big relative to nodes
|
|
87
87
|
*/
|
|
88
|
-
shouldShowLabel(t,
|
|
89
|
-
const
|
|
90
|
-
return s <=
|
|
88
|
+
shouldShowLabel(t, o) {
|
|
89
|
+
const i = this.getNodeSize(t) * 2, s = (this.options.labelFontSize || 14) / o, r = this.options.labelThreshold || 1.5;
|
|
90
|
+
return s <= i * r;
|
|
91
91
|
}
|
|
92
92
|
updateData(t) {
|
|
93
|
-
const
|
|
94
|
-
|
|
93
|
+
const o = new Set(this.data.nodes.map((r) => r.id.toString())), i = t.nodes.filter((r) => !o.has(r.id.toString()));
|
|
94
|
+
i.forEach((r) => {
|
|
95
95
|
this.nodesMap.set(r.id.toString(), r);
|
|
96
96
|
});
|
|
97
97
|
const e = new Set(
|
|
@@ -100,20 +100,61 @@ class m {
|
|
|
100
100
|
(r) => !e.has(this.createLinkKey(r.source, r.target))
|
|
101
101
|
);
|
|
102
102
|
this.data = {
|
|
103
|
-
nodes: [...this.data.nodes, ...
|
|
103
|
+
nodes: [...this.data.nodes, ...i],
|
|
104
104
|
links: [...this.data.links, ...s]
|
|
105
105
|
}, this.refreshGraph();
|
|
106
106
|
}
|
|
107
107
|
getNodeColor(t) {
|
|
108
108
|
if (typeof this.options.nodeColor == "function") {
|
|
109
|
-
const
|
|
110
|
-
if (
|
|
109
|
+
const o = this.options.nodeColor(t);
|
|
110
|
+
if (o) return o;
|
|
111
111
|
}
|
|
112
112
|
return t?.color ?? "";
|
|
113
113
|
}
|
|
114
114
|
getNodeBorderColor(t) {
|
|
115
115
|
return typeof this.options.nodeBorderColor == "function" ? this.options.nodeBorderColor(t) : this.options.nodeBorderColor || "#333";
|
|
116
116
|
}
|
|
117
|
+
resolveNodeShape(t) {
|
|
118
|
+
return t.shape ? t.shape : typeof this.options.nodeShape == "function" ? this.options.nodeShape(t) : this.options.nodeShape ?? "circle";
|
|
119
|
+
}
|
|
120
|
+
drawNodeShape(t, o, i, e, s) {
|
|
121
|
+
switch (t.beginPath(), s) {
|
|
122
|
+
case "square": {
|
|
123
|
+
t.rect(o - e, i - e, e * 2, e * 2);
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
case "triangle": {
|
|
127
|
+
const r = e * Math.sqrt(3);
|
|
128
|
+
t.moveTo(o, i - e), t.lineTo(o + r / 2, i + e / 2), t.lineTo(o - r / 2, i + e / 2), t.closePath();
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
case "diamond": {
|
|
132
|
+
t.moveTo(o, i - e), t.lineTo(o + e, i), t.lineTo(o, i + e), t.lineTo(o - e, i), t.closePath();
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case "star": {
|
|
136
|
+
const r = e, a = e * 0.4, h = 5;
|
|
137
|
+
for (let n = 0; n < h * 2; n++) {
|
|
138
|
+
const p = n % 2 === 0 ? r : a, d = Math.PI / h * n - Math.PI / 2, l = o + p * Math.cos(d), u = i + p * Math.sin(d);
|
|
139
|
+
n === 0 ? t.moveTo(l, u) : t.lineTo(l, u);
|
|
140
|
+
}
|
|
141
|
+
t.closePath();
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
case "hexagon": {
|
|
145
|
+
for (let r = 0; r < 6; r++) {
|
|
146
|
+
const a = Math.PI / 3 * r - Math.PI / 6, h = o + e * Math.cos(a), n = i + e * Math.sin(a);
|
|
147
|
+
r === 0 ? t.moveTo(h, n) : t.lineTo(h, n);
|
|
148
|
+
}
|
|
149
|
+
t.closePath();
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case "circle":
|
|
153
|
+
default:
|
|
154
|
+
t.arc(o, i, e, 0, 2 * Math.PI);
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
117
158
|
applyLinkOptions() {
|
|
118
159
|
this.graph.linkColor((t) => typeof this.options.linkColor == "function" ? this.options.linkColor(t) : this.options.linkColor ? this.options.linkColor : t.color ?? ""), this.options.linkWidth !== void 0 && this.graph.linkWidth(
|
|
119
160
|
(t) => this.getLinkProperty(this.options.linkWidth, t) ?? 1
|
|
@@ -130,8 +171,8 @@ class m {
|
|
|
130
171
|
getLinkCurvature(t) {
|
|
131
172
|
return typeof this.options.linkCurvature == "function" ? this.options.linkCurvature(t) : typeof this.options.linkCurvature == "string" ? t[this.options.linkCurvature] || 0 : typeof this.options.linkCurvature == "number" ? this.options.linkCurvature : t.curvature || 0;
|
|
132
173
|
}
|
|
133
|
-
getLinkProperty(t,
|
|
134
|
-
return typeof t == "function" ? t(
|
|
174
|
+
getLinkProperty(t, o) {
|
|
175
|
+
return typeof t == "function" ? t(o) : t;
|
|
135
176
|
}
|
|
136
177
|
/**
|
|
137
178
|
* Calculate group boundaries based on node positions
|
|
@@ -139,24 +180,24 @@ class m {
|
|
|
139
180
|
calculateGroupBounds() {
|
|
140
181
|
if (!this.options.showGroups) return;
|
|
141
182
|
this.groupBounds.clear();
|
|
142
|
-
const t = this.options.groupPadding || 20,
|
|
143
|
-
this.data.nodes.forEach((
|
|
144
|
-
const e = this.getNodeGroupId(
|
|
145
|
-
e && (
|
|
146
|
-
}),
|
|
147
|
-
if (
|
|
148
|
-
let s = 1 / 0, r = 1 / 0, a = -1 / 0,
|
|
149
|
-
|
|
183
|
+
const t = this.options.groupPadding || 20, o = /* @__PURE__ */ new Map();
|
|
184
|
+
this.data.nodes.forEach((i) => {
|
|
185
|
+
const e = this.getNodeGroupId(i);
|
|
186
|
+
e && (o.has(e) || o.set(e, []), o.get(e).push(i));
|
|
187
|
+
}), o.forEach((i, e) => {
|
|
188
|
+
if (i.length === 0) return;
|
|
189
|
+
let s = 1 / 0, r = 1 / 0, a = -1 / 0, h = -1 / 0;
|
|
190
|
+
i.forEach((n) => {
|
|
150
191
|
if (n.x !== void 0 && n.y !== void 0) {
|
|
151
|
-
const
|
|
152
|
-
s = Math.min(s, n.x -
|
|
192
|
+
const p = this.getNodeSize(n);
|
|
193
|
+
s = Math.min(s, n.x - p), r = Math.min(r, n.y - p), a = Math.max(a, n.x + p), h = Math.max(h, n.y + p);
|
|
153
194
|
}
|
|
154
195
|
}), s !== 1 / 0 && this.groupBounds.set(e, {
|
|
155
196
|
minX: s - t,
|
|
156
197
|
minY: r - t,
|
|
157
198
|
maxX: a + t,
|
|
158
|
-
maxY:
|
|
159
|
-
nodes:
|
|
199
|
+
maxY: h + t,
|
|
200
|
+
nodes: i
|
|
160
201
|
});
|
|
161
202
|
});
|
|
162
203
|
}
|
|
@@ -174,21 +215,21 @@ class m {
|
|
|
174
215
|
/**
|
|
175
216
|
* Render group borders and labels
|
|
176
217
|
*/
|
|
177
|
-
renderGroups(t,
|
|
178
|
-
this.options.showGroups && (this.calculateGroupBounds(), this.groupBounds.forEach((
|
|
218
|
+
renderGroups(t, o) {
|
|
219
|
+
this.options.showGroups && (this.calculateGroupBounds(), this.groupBounds.forEach((i, e) => {
|
|
179
220
|
const s = this.getGroupBorderColor(e), r = this.options.groupBorderWidth || 2, a = this.options.groupBorderOpacity || 0.3;
|
|
180
|
-
t.save(), t.globalAlpha = a, t.strokeStyle = s, t.lineWidth = r /
|
|
181
|
-
const
|
|
182
|
-
if (
|
|
183
|
-
const n = this.getGroupLabelColor(e),
|
|
184
|
-
t.save(), t.font = `bold ${
|
|
185
|
-
const
|
|
221
|
+
t.save(), t.globalAlpha = a, t.strokeStyle = s, t.lineWidth = r / o, t.setLineDash([10 / o, 5 / o]), t.strokeRect(i.minX, i.minY, i.maxX - i.minX, i.maxY - i.minY), t.restore();
|
|
222
|
+
const h = this.options.groupLabelThreshold || 0.8;
|
|
223
|
+
if (o <= h) {
|
|
224
|
+
const n = this.getGroupLabelColor(e), p = (this.options.groupLabelSize || 16) / o;
|
|
225
|
+
t.save(), t.font = `bold ${p}px Arial`, t.fillStyle = n, t.textAlign = "center", t.textBaseline = "middle";
|
|
226
|
+
const d = (i.minX + i.maxX) / 2, l = i.minY - p / 2, g = t.measureText(e).width, f = p;
|
|
186
227
|
t.globalAlpha = 0.8, t.fillStyle = "rgba(255, 255, 255, 0.9)", t.fillRect(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
), t.globalAlpha = 1, t.fillStyle = n, t.fillText(e,
|
|
228
|
+
d - g / 2 - 4,
|
|
229
|
+
l - f / 2 - 2,
|
|
230
|
+
g + 8,
|
|
231
|
+
f + 4
|
|
232
|
+
), t.globalAlpha = 1, t.fillStyle = n, t.fillText(e, d, l), t.restore();
|
|
192
233
|
}
|
|
193
234
|
}));
|
|
194
235
|
}
|
|
@@ -222,41 +263,41 @@ class m {
|
|
|
222
263
|
getCooldownTime() {
|
|
223
264
|
if (this.options.cooldownTime !== void 0)
|
|
224
265
|
return this.options.cooldownTime;
|
|
225
|
-
const
|
|
226
|
-
return Math.max(4e3,
|
|
266
|
+
const o = this.data.nodes.length * (125 / 100);
|
|
267
|
+
return Math.max(4e3, o);
|
|
227
268
|
}
|
|
228
269
|
getDataSize() {
|
|
229
|
-
const { nodes: t, links:
|
|
270
|
+
const { nodes: t, links: o } = this.graph.graphData();
|
|
230
271
|
return {
|
|
231
272
|
nodes: t.length,
|
|
232
|
-
links:
|
|
273
|
+
links: o.length
|
|
233
274
|
};
|
|
234
275
|
}
|
|
235
276
|
getAllNodeIds() {
|
|
236
277
|
return Array.from(this.nodesMap.keys());
|
|
237
278
|
}
|
|
238
|
-
updateNode(t,
|
|
239
|
-
const
|
|
240
|
-
if (
|
|
241
|
-
Object.assign(
|
|
279
|
+
updateNode(t, o) {
|
|
280
|
+
const i = this.nodesMap.get(t.toString());
|
|
281
|
+
if (i) {
|
|
282
|
+
Object.assign(i, o);
|
|
242
283
|
const e = this.data.nodes.findIndex((s) => s.id.toString() === t.toString());
|
|
243
|
-
return e !== -1 && (this.data.nodes[e] =
|
|
284
|
+
return e !== -1 && (this.data.nodes[e] = i), this.refreshGraph(), !0;
|
|
244
285
|
}
|
|
245
286
|
return !1;
|
|
246
287
|
}
|
|
247
288
|
removeNode(t) {
|
|
248
|
-
const
|
|
249
|
-
return this.nodesMap.has(
|
|
250
|
-
const e = typeof
|
|
251
|
-
return e?.toString() !==
|
|
252
|
-
}), this.
|
|
289
|
+
const o = t.toString();
|
|
290
|
+
return this.nodesMap.has(o) ? (this.nodesMap.delete(o), this.data.nodes = this.data.nodes.filter((i) => i.id.toString() !== o), this.data.links = this.data.links.filter((i) => {
|
|
291
|
+
const e = typeof i.source == "object" ? i.source.id : i.source, s = typeof i.target == "object" ? i.target.id : i.target;
|
|
292
|
+
return e?.toString() !== o && s?.toString() !== o;
|
|
293
|
+
}), this.refreshGraph(), !0) : !1;
|
|
253
294
|
}
|
|
254
295
|
async addData(t) {
|
|
255
|
-
t.nodes.forEach((
|
|
256
|
-
this.nodesMap.has(
|
|
257
|
-
}), t.links.forEach((
|
|
258
|
-
const
|
|
259
|
-
this.linkMap.has(
|
|
296
|
+
t.nodes.forEach((o) => {
|
|
297
|
+
this.nodesMap.has(o.id.toString()) || this.nodesMap.set(o.id.toString(), o);
|
|
298
|
+
}), t.links.forEach((o) => {
|
|
299
|
+
const i = this.createLinkKey(o.source, o.target);
|
|
300
|
+
this.linkMap.has(i) ? console.log("link already exists", o) : this.linkMap.set(i, o);
|
|
260
301
|
}), this.data = {
|
|
261
302
|
nodes: Array.from(this.nodesMap.values()),
|
|
262
303
|
links: Array.from(this.linkMap.values())
|
|
@@ -281,9 +322,7 @@ class m {
|
|
|
281
322
|
this.initGraph();
|
|
282
323
|
}
|
|
283
324
|
reset() {
|
|
284
|
-
this.graph.pauseAnimation();
|
|
285
|
-
const t = this.graph.d3Force("simulation");
|
|
286
|
-
t && t.stop(), this.data = { nodes: [], links: [] }, this.nodesMap.clear(), this.graph = new f(this.container), this.initGraph();
|
|
325
|
+
this.graph.pauseAnimation(), this.data = { nodes: [], links: [] }, this.nodesMap.clear(), this.graph = new c(this.container), this.initGraph();
|
|
287
326
|
}
|
|
288
327
|
getData() {
|
|
289
328
|
return this.data;
|
|
@@ -294,20 +333,20 @@ class m {
|
|
|
294
333
|
getLinksData() {
|
|
295
334
|
return this.data.links;
|
|
296
335
|
}
|
|
297
|
-
createLinkKey(t,
|
|
298
|
-
const
|
|
299
|
-
return `${
|
|
336
|
+
createLinkKey(t, o) {
|
|
337
|
+
const i = t === void 0 ? "undefined" : typeof t == "object" ? t.id : t, e = o === void 0 ? "undefined" : typeof o == "object" ? o.id : o;
|
|
338
|
+
return `${i}-${e}`;
|
|
300
339
|
}
|
|
301
340
|
/**
|
|
302
341
|
* Set graph data (chainable method)
|
|
303
342
|
* @param data - Graph data to set
|
|
304
343
|
*/
|
|
305
344
|
graphData(t) {
|
|
306
|
-
return this.nodesMap.clear(), this.linkMap.clear(), t.nodes.forEach((
|
|
307
|
-
this.nodesMap.has(
|
|
308
|
-
}), t.links.forEach((
|
|
309
|
-
const
|
|
310
|
-
this.linkMap.has(
|
|
345
|
+
return this.nodesMap.clear(), this.linkMap.clear(), t.nodes.forEach((o) => {
|
|
346
|
+
this.nodesMap.has(o.id.toString()) || this.nodesMap.set(o.id.toString(), o);
|
|
347
|
+
}), t.links.forEach((o) => {
|
|
348
|
+
const i = this.createLinkKey(o.source, o.target);
|
|
349
|
+
this.linkMap.has(i) || this.linkMap.set(i, o);
|
|
311
350
|
}), this.data = {
|
|
312
351
|
nodes: Array.from(this.nodesMap.values()),
|
|
313
352
|
links: Array.from(this.linkMap.values())
|
|
@@ -326,8 +365,8 @@ class m {
|
|
|
326
365
|
groupLabelSize: 16,
|
|
327
366
|
groupLabelThreshold: 0.8,
|
|
328
367
|
groupPadding: 20
|
|
329
|
-
}).forEach(([
|
|
330
|
-
this.options[
|
|
368
|
+
}).forEach(([i, e]) => {
|
|
369
|
+
this.options[i] === void 0 && (this.options[i] = e);
|
|
331
370
|
}), this.applyOptions(), this.refreshGraph(), this;
|
|
332
371
|
}
|
|
333
372
|
/**
|
|
@@ -347,16 +386,16 @@ class m {
|
|
|
347
386
|
*/
|
|
348
387
|
getGroups() {
|
|
349
388
|
const t = /* @__PURE__ */ new Set();
|
|
350
|
-
return this.data.nodes.forEach((
|
|
351
|
-
const
|
|
352
|
-
|
|
389
|
+
return this.data.nodes.forEach((o) => {
|
|
390
|
+
const i = this.getNodeGroupId(o);
|
|
391
|
+
i && t.add(i);
|
|
353
392
|
}), Array.from(t);
|
|
354
393
|
}
|
|
355
394
|
/**
|
|
356
395
|
* Get nodes in a specific group
|
|
357
396
|
*/
|
|
358
397
|
getNodesInGroup(t) {
|
|
359
|
-
return this.data.nodes.filter((
|
|
398
|
+
return this.data.nodes.filter((o) => this.getNodeGroupId(o) === t);
|
|
360
399
|
}
|
|
361
400
|
/**
|
|
362
401
|
* Get current options
|
|
@@ -369,5 +408,5 @@ class m {
|
|
|
369
408
|
}
|
|
370
409
|
}
|
|
371
410
|
export {
|
|
372
|
-
|
|
411
|
+
C as ForceGraph
|
|
373
412
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(h,l){typeof exports=="object"&&typeof module<"u"?l(exports,require("force-graph"),require("d3")):typeof define=="function"&&define.amd?define(["exports","force-graph","d3"],l):(h=typeof globalThis<"u"?globalThis:h||self,l(h.ForceGraphLib={},h.ForceGraph,h.d3))})(this,(function(h,l,k){"use strict";function b(d){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(d){for(const i in d)if(i!=="default"){const o=Object.getOwnPropertyDescriptor(d,i);Object.defineProperty(t,i,o.get?o:{enumerable:!0,get:()=>d[i]})}}return t.default=d,Object.freeze(t)}const m=b(k);class C{container;graph;data={nodes:[],links:[]};nodesMap=new Map;linkMap=new Map;options;worker=null;groupBounds=new Map;isFirstRender=!0;constructor(t,i={nodes:[],links:[]},o={}){this.container=t,this.data=i,this.graph=new l(this.container),i.nodes.forEach(r=>{this.nodesMap.set(r.id.toString(),r)});const e={labelThreshold:1.5,showGroups:!1,...o},s=e.showGroups?{groupBy:"topic",groupBorderColor:"#666",groupBorderWidth:2,groupBorderOpacity:.3,groupLabelColor:"#333",groupLabelSize:16,groupLabelThreshold:.8,groupPadding:20}:{};this.options={...e,...s},this.initGraph()}initGraph(){this.applyOptions(),this.render(),this.graphData(this.data),this.graph.onEngineStop(()=>{if(!this.data.nodes.length){this.isFirstRender=!0;return}this.isFirstRender?(this.options.onRenderComplete?this.options.onRenderComplete():this.graph.zoomToFit(400),this.isFirstRender=!1):this.options.onGraphUpdated&&this.options.onGraphUpdated()})}renderer(){return this.graph}focusPosition(t={}){if(Object.values(t).length){if(t.id){const{x:i,y:o}=this.nodesMap.get(t.id)??{x:0,y:0};i&&o&&(t={x:i,y:o})}t&&(this.graph.centerAt(t.x,t.y,1e3),this.graph.zoom(8,2e3))}}render(){this.graph.width(this.options.width??800).height(this.options.height??400).cooldownTime(this.getCooldownTime()).d3Force("charge",m.forceManyBody().strength(this.options.nodeGap??-50)),this.options.cooldownTicks!==void 0&&this.graph.cooldownTicks(this.options.cooldownTicks)}force(t,i){return this.graph.d3Force(t,i)}applyOptions(){this.options.keepDragPosition&&this.graph.onNodeDragEnd(t=>{t.fx=t.x,t.fy=t.y}),this.options.pointerInteraction||this.graph.enablePointerInteraction(!1),this.graph.nodeCanvasObject((t,i,o)=>{t===this.data.nodes[0]&&this.renderGroups(i,o);const e=this.getNodeSize(t)*2,s=typeof this.options.nodeBorderWidth=="function"?this.options.nodeBorderWidth(t):this.options.nodeBorderWidth;i.beginPath(),i.arc(t.x||0,t.y||0,e,0,2*Math.PI),i.fillStyle=this.getNodeColor(t),i.fill(),s&&s>0&&(i.beginPath(),i.arc(t.x||0,t.y||0,e,0,2*Math.PI),i.strokeStyle=this.getNodeBorderColor(t),i.lineWidth=s,i.stroke());const r=this.getNodeLabel(t);if(r&&this.shouldShowLabel(t,o)){const p=typeof this.options.nodeLabelColor=="function"?this.options.nodeLabelColor(t):this.options.nodeLabelColor??"#555",n=(this.options.labelFontSize||14)/o;i.font=`${n}px Arial`,i.fillStyle=p,i.textAlign="center",i.textBaseline="middle",i.fillText(r,t.x||0,(t.y||0)+e+n/2+2)}}),this.applyLinkOptions()}getNodeSize(t){return typeof this.options.nodeSize=="function"?this.options.nodeSize(t)||t?.marker?.radius:this.options.nodeSize||t?.marker?.radius||1}getNodeLabel(t){return typeof this.options.nodeLabel=="function"?this.options.nodeLabel(t):t?.label||t.id}shouldShowLabel(t,i){const o=this.getNodeSize(t)*2,s=(this.options.labelFontSize||14)/i,r=this.options.labelThreshold||1.5;return s<=o*r}updateData(t){const i=new Set(this.data.nodes.map(r=>r.id.toString())),o=t.nodes.filter(r=>!i.has(r.id.toString()));o.forEach(r=>{this.nodesMap.set(r.id.toString(),r)});const e=new Set(this.data.links.map(r=>this.createLinkKey(r.source,r.target))),s=t.links.filter(r=>!e.has(this.createLinkKey(r.source,r.target)));this.data={nodes:[...this.data.nodes,...o],links:[...this.data.links,...s]},this.refreshGraph()}getNodeColor(t){if(typeof this.options.nodeColor=="function"){const i=this.options.nodeColor(t);if(i)return i}return t?.color??""}getNodeBorderColor(t){return typeof this.options.nodeBorderColor=="function"?this.options.nodeBorderColor(t):this.options.nodeBorderColor||"#333"}applyLinkOptions(){this.graph.linkColor(t=>typeof this.options.linkColor=="function"?this.options.linkColor(t):this.options.linkColor?this.options.linkColor:t.color??""),this.options.linkWidth!==void 0&&this.graph.linkWidth(t=>this.getLinkProperty(this.options.linkWidth,t)??1),this.options.linkCurvature!==void 0&&this.graph.linkCurvature(this.getLinkCurvature.bind(this)),this.options.linkDirectionalParticles&&this.graph.linkDirectionalParticles(t=>this.getLinkProperty(this.options.linkDirectionalParticles,t)??0),this.options.linkDirectionalParticleSpeed!==void 0&&this.graph.linkDirectionalParticleSpeed(t=>this.getLinkProperty(this.options.linkDirectionalParticleSpeed,t)??0),this.options.linkDirectionalParticleWidth!==void 0&&this.graph.linkDirectionalParticleWidth(t=>this.getLinkProperty(this.options.linkDirectionalParticleWidth,t)??0),this.options.linkDirectionalParticleColor!==void 0&&this.graph.linkDirectionalParticleColor(t=>this.getLinkProperty(this.options.linkDirectionalParticleColor,t)??"#aaa")}getLinkCurvature(t){return typeof this.options.linkCurvature=="function"?this.options.linkCurvature(t):typeof this.options.linkCurvature=="string"?t[this.options.linkCurvature]||0:typeof this.options.linkCurvature=="number"?this.options.linkCurvature:t.curvature||0}getLinkProperty(t,i){return typeof t=="function"?t(i):t}calculateGroupBounds(){if(!this.options.showGroups)return;this.groupBounds.clear();const t=this.options.groupPadding||20,i=new Map;this.data.nodes.forEach(o=>{const e=this.getNodeGroupId(o);e&&(i.has(e)||i.set(e,[]),i.get(e).push(o))}),i.forEach((o,e)=>{if(o.length===0)return;let s=1/0,r=1/0,p=-1/0,u=-1/0;o.forEach(n=>{if(n.x!==void 0&&n.y!==void 0){const a=this.getNodeSize(n);s=Math.min(s,n.x-a),r=Math.min(r,n.y-a),p=Math.max(p,n.x+a),u=Math.max(u,n.y+a)}}),s!==1/0&&this.groupBounds.set(e,{minX:s-t,minY:r-t,maxX:p+t,maxY:u+t,nodes:o})})}getNodeGroupId(t){if(this.options.groupBy){if(typeof this.options.groupBy=="function")return this.options.groupBy(t);if(typeof this.options.groupBy=="string")return t[this.options.groupBy]}}renderGroups(t,i){this.options.showGroups&&(this.calculateGroupBounds(),this.groupBounds.forEach((o,e)=>{const s=this.getGroupBorderColor(e),r=this.options.groupBorderWidth||2,p=this.options.groupBorderOpacity||.3;t.save(),t.globalAlpha=p,t.strokeStyle=s,t.lineWidth=r/i,t.setLineDash([10/i,5/i]),t.strokeRect(o.minX,o.minY,o.maxX-o.minX,o.maxY-o.minY),t.restore();const u=this.options.groupLabelThreshold||.8;if(i<=u){const n=this.getGroupLabelColor(e),a=(this.options.groupLabelSize||16)/i;t.save(),t.font=`bold ${a}px Arial`,t.fillStyle=n,t.textAlign="center",t.textBaseline="middle";const g=(o.minX+o.maxX)/2,f=o.minY-a/2,c=t.measureText(e).width,y=a;t.globalAlpha=.8,t.fillStyle="rgba(255, 255, 255, 0.9)",t.fillRect(g-c/2-4,f-y/2-2,c+8,y+4),t.globalAlpha=1,t.fillStyle=n,t.fillText(e,g,f),t.restore()}}))}getGroupBorderColor(t){return typeof this.options.groupBorderColor=="function"?this.options.groupBorderColor(t):this.options.groupBorderColor||"#666"}getGroupLabelColor(t){return typeof this.options.groupLabelColor=="function"?this.options.groupLabelColor(t):this.options.groupLabelColor||"#333"}getNodeById(t){return this.nodesMap.get(t.toString())}hasNode(t){return this.nodesMap.has(t.toString())}getCooldownTime(){if(this.options.cooldownTime!==void 0)return this.options.cooldownTime;const i=this.data.nodes.length*(125/100);return Math.max(4e3,i)}getDataSize(){const{nodes:t,links:i}=this.graph.graphData();return{nodes:t.length,links:i.length}}getAllNodeIds(){return Array.from(this.nodesMap.keys())}updateNode(t,i){const o=this.nodesMap.get(t.toString());if(o){Object.assign(o,i);const e=this.data.nodes.findIndex(s=>s.id.toString()===t.toString());return e!==-1&&(this.data.nodes[e]=o),this.refreshGraph(),!0}return!1}removeNode(t){const i=t.toString();return this.nodesMap.has(i)?(this.nodesMap.delete(i),this.data.nodes=this.data.nodes.filter(o=>o.id.toString()!==i),this.data.links=this.data.links.filter(o=>{const e=typeof o.source=="object"?o.source.id:o.source,s=typeof o.target=="object"?o.target.id:o.target;return e?.toString()!==i&&s?.toString()!==i}),this.graph.cooldownTime(this.getCooldownTime()),this.refreshGraph(),!0):!1}async addData(t){t.nodes.forEach(i=>{this.nodesMap.has(i.id.toString())||this.nodesMap.set(i.id.toString(),i)}),t.links.forEach(i=>{const o=this.createLinkKey(i.source,i.target);this.linkMap.has(o)?console.log("link already exists",i):this.linkMap.set(o,i)}),this.data={nodes:Array.from(this.nodesMap.values()),links:Array.from(this.linkMap.values())},this.graph.cooldownTime(this.getCooldownTime()),this.graph.graphData(this.data)}setLabelThreshold(t){this.options.labelThreshold=t,this.render()}setOptions(t){this.options={...this.options,...t},this.applyOptions()}refreshGraph(){this.graphData(this.data)}reinitialize(){this.initGraph()}reset(){this.graph.pauseAnimation();const t=this.graph.d3Force("simulation");t&&t.stop(),this.data={nodes:[],links:[]},this.nodesMap.clear(),this.graph=new l(this.container),this.initGraph()}getData(){return this.data}getNodesData(){return this.data.nodes}getLinksData(){return this.data.links}createLinkKey(t,i){const o=t===void 0?"undefined":typeof t=="object"?t.id:t,e=i===void 0?"undefined":typeof i=="object"?i.id:i;return`${o}-${e}`}graphData(t){return this.nodesMap.clear(),this.linkMap.clear(),t.nodes.forEach(i=>{this.nodesMap.has(i.id.toString())||this.nodesMap.set(i.id.toString(),i)}),t.links.forEach(i=>{const o=this.createLinkKey(i.source,i.target);this.linkMap.has(o)||this.linkMap.set(o,i)}),this.data={nodes:Array.from(this.nodesMap.values()),links:Array.from(this.linkMap.values())},this.graph.cooldownTime(this.getCooldownTime()),this.graph.graphData(this.data),this}showGroups(t){return this.options.showGroups=t,t&&Object.entries({groupBy:"topic",groupBorderColor:"#666",groupBorderWidth:2,groupBorderOpacity:.3,groupLabelColor:"#333",groupLabelSize:16,groupLabelThreshold:.8,groupPadding:20}).forEach(([o,e])=>{this.options[o]===void 0&&(this.options[o]=e)}),this.applyOptions(),this.refreshGraph(),this}setGroupBy(t){return this.options.groupBy=t,this.applyOptions(),this.refreshGraph(),this}setGroupOptions(t){return t.borderColor!==void 0&&(this.options.groupBorderColor=t.borderColor),t.borderWidth!==void 0&&(this.options.groupBorderWidth=t.borderWidth),t.borderOpacity!==void 0&&(this.options.groupBorderOpacity=t.borderOpacity),t.labelColor!==void 0&&(this.options.groupLabelColor=t.labelColor),t.labelSize!==void 0&&(this.options.groupLabelSize=t.labelSize),t.labelThreshold!==void 0&&(this.options.groupLabelThreshold=t.labelThreshold),t.padding!==void 0&&(this.options.groupPadding=t.padding),this.applyOptions(),this.refreshGraph(),this}getGroups(){const t=new Set;return this.data.nodes.forEach(i=>{const o=this.getNodeGroupId(i);o&&t.add(o)}),Array.from(t)}getNodesInGroup(t){return this.data.nodes.filter(i=>this.getNodeGroupId(i)===t)}getOptions(){return{...this.options}}destroy(){this.worker&&(this.worker.terminate(),this.worker=null),this.graph._destructor()}}h.ForceGraph=C,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})}));
|
|
1
|
+
(function(d,u){typeof exports=="object"&&typeof module<"u"?u(exports,require("force-graph"),require("d3")):typeof define=="function"&&define.amd?define(["exports","force-graph","d3"],u):(d=typeof globalThis<"u"?globalThis:d||self,u(d.ForceGraphLib={},d.ForceGraph))})(this,(function(d,u){"use strict";class k{container;graph;data={nodes:[],links:[]};nodesMap=new Map;linkMap=new Map;options;worker=null;groupBounds=new Map;isFirstRender=!0;constructor(t,o={nodes:[],links:[]},i={}){this.container=t,this.data=o,this.graph=new u(this.container),o.nodes.forEach(r=>{this.nodesMap.set(r.id.toString(),r)});const e={labelThreshold:1.5,showGroups:!1,...i},s=e.showGroups?{groupBy:"topic",groupBorderColor:"#666",groupBorderWidth:2,groupBorderOpacity:.3,groupLabelColor:"#333",groupLabelSize:16,groupLabelThreshold:.8,groupPadding:20}:{};this.options={...e,...s},this.initGraph()}initGraph(){this.applyOptions(),this.render(),this.graphData(this.data),this.graph.onEngineStop(()=>{if(!this.data.nodes.length){this.isFirstRender=!0;return}this.isFirstRender?(this.options.onRenderComplete?this.options.onRenderComplete():this.graph.zoomToFit(400),this.isFirstRender=!1):this.options.onGraphUpdated&&this.options.onGraphUpdated()})}renderer(){return this.graph}focusPosition(t={}){if(Object.values(t).length){if(t.id){const{x:o,y:i}=this.nodesMap.get(t.id)??{x:0,y:0};o&&i&&(t={x:o,y:i})}t&&(this.graph.centerAt(t.x,t.y,1e3),this.graph.zoom(8,2e3))}}render(){this.graph.width(this.options.width??800).height(this.options.height??400),this.options.cooldownTicks!==void 0&&this.graph.cooldownTicks(this.options.cooldownTicks)}force(t,o){return this.graph.d3Force(t,o)}applyOptions(){this.options.keepDragPosition&&this.graph.onNodeDragEnd(t=>{t.fx=t.x,t.fy=t.y}),this.options.pointerInteraction||this.graph.enablePointerInteraction(!1),this.graph.nodeCanvasObject((t,o,i)=>{t===this.data.nodes[0]&&this.renderGroups(o,i);const e=this.getNodeSize(t)*2,s=typeof this.options.nodeBorderWidth=="function"?this.options.nodeBorderWidth(t):this.options.nodeBorderWidth,r=this.resolveNodeShape(t),a=t.x||0,h=t.y||0;this.drawNodeShape(o,a,h,e,r),o.fillStyle=this.getNodeColor(t),o.fill(),s&&s>0&&(this.drawNodeShape(o,a,h,e,r),o.strokeStyle=this.getNodeBorderColor(t),o.lineWidth=s,o.stroke());const n=this.getNodeLabel(t);if(n&&this.shouldShowLabel(t,i)){const p=typeof this.options.nodeLabelColor=="function"?this.options.nodeLabelColor(t):this.options.nodeLabelColor??"#555",l=(this.options.labelFontSize||14)/i;o.font=`${l}px Arial`,o.fillStyle=p,o.textAlign="center",o.textBaseline="middle",o.fillText(n,t.x||0,(t.y||0)+e+l/2+2)}}),this.applyLinkOptions()}getNodeSize(t){return typeof this.options.nodeSize=="function"?this.options.nodeSize(t)||t?.marker?.radius:this.options.nodeSize||t?.marker?.radius||1}getNodeLabel(t){return typeof this.options.nodeLabel=="function"?this.options.nodeLabel(t):t?.label||t.id}shouldShowLabel(t,o){const i=this.getNodeSize(t)*2,s=(this.options.labelFontSize||14)/o,r=this.options.labelThreshold||1.5;return s<=i*r}updateData(t){const o=new Set(this.data.nodes.map(r=>r.id.toString())),i=t.nodes.filter(r=>!o.has(r.id.toString()));i.forEach(r=>{this.nodesMap.set(r.id.toString(),r)});const e=new Set(this.data.links.map(r=>this.createLinkKey(r.source,r.target))),s=t.links.filter(r=>!e.has(this.createLinkKey(r.source,r.target)));this.data={nodes:[...this.data.nodes,...i],links:[...this.data.links,...s]},this.refreshGraph()}getNodeColor(t){if(typeof this.options.nodeColor=="function"){const o=this.options.nodeColor(t);if(o)return o}return t?.color??""}getNodeBorderColor(t){return typeof this.options.nodeBorderColor=="function"?this.options.nodeBorderColor(t):this.options.nodeBorderColor||"#333"}resolveNodeShape(t){return t.shape?t.shape:typeof this.options.nodeShape=="function"?this.options.nodeShape(t):this.options.nodeShape??"circle"}drawNodeShape(t,o,i,e,s){switch(t.beginPath(),s){case"square":{t.rect(o-e,i-e,e*2,e*2);break}case"triangle":{const r=e*Math.sqrt(3);t.moveTo(o,i-e),t.lineTo(o+r/2,i+e/2),t.lineTo(o-r/2,i+e/2),t.closePath();break}case"diamond":{t.moveTo(o,i-e),t.lineTo(o+e,i),t.lineTo(o,i+e),t.lineTo(o-e,i),t.closePath();break}case"star":{const r=e,a=e*.4,h=5;for(let n=0;n<h*2;n++){const p=n%2===0?r:a,f=Math.PI/h*n-Math.PI/2,l=o+p*Math.cos(f),g=i+p*Math.sin(f);n===0?t.moveTo(l,g):t.lineTo(l,g)}t.closePath();break}case"hexagon":{for(let r=0;r<6;r++){const a=Math.PI/3*r-Math.PI/6,h=o+e*Math.cos(a),n=i+e*Math.sin(a);r===0?t.moveTo(h,n):t.lineTo(h,n)}t.closePath();break}case"circle":default:t.arc(o,i,e,0,2*Math.PI);break}}applyLinkOptions(){this.graph.linkColor(t=>typeof this.options.linkColor=="function"?this.options.linkColor(t):this.options.linkColor?this.options.linkColor:t.color??""),this.options.linkWidth!==void 0&&this.graph.linkWidth(t=>this.getLinkProperty(this.options.linkWidth,t)??1),this.options.linkCurvature!==void 0&&this.graph.linkCurvature(this.getLinkCurvature.bind(this)),this.options.linkDirectionalParticles&&this.graph.linkDirectionalParticles(t=>this.getLinkProperty(this.options.linkDirectionalParticles,t)??0),this.options.linkDirectionalParticleSpeed!==void 0&&this.graph.linkDirectionalParticleSpeed(t=>this.getLinkProperty(this.options.linkDirectionalParticleSpeed,t)??0),this.options.linkDirectionalParticleWidth!==void 0&&this.graph.linkDirectionalParticleWidth(t=>this.getLinkProperty(this.options.linkDirectionalParticleWidth,t)??0),this.options.linkDirectionalParticleColor!==void 0&&this.graph.linkDirectionalParticleColor(t=>this.getLinkProperty(this.options.linkDirectionalParticleColor,t)??"#aaa")}getLinkCurvature(t){return typeof this.options.linkCurvature=="function"?this.options.linkCurvature(t):typeof this.options.linkCurvature=="string"?t[this.options.linkCurvature]||0:typeof this.options.linkCurvature=="number"?this.options.linkCurvature:t.curvature||0}getLinkProperty(t,o){return typeof t=="function"?t(o):t}calculateGroupBounds(){if(!this.options.showGroups)return;this.groupBounds.clear();const t=this.options.groupPadding||20,o=new Map;this.data.nodes.forEach(i=>{const e=this.getNodeGroupId(i);e&&(o.has(e)||o.set(e,[]),o.get(e).push(i))}),o.forEach((i,e)=>{if(i.length===0)return;let s=1/0,r=1/0,a=-1/0,h=-1/0;i.forEach(n=>{if(n.x!==void 0&&n.y!==void 0){const p=this.getNodeSize(n);s=Math.min(s,n.x-p),r=Math.min(r,n.y-p),a=Math.max(a,n.x+p),h=Math.max(h,n.y+p)}}),s!==1/0&&this.groupBounds.set(e,{minX:s-t,minY:r-t,maxX:a+t,maxY:h+t,nodes:i})})}getNodeGroupId(t){if(this.options.groupBy){if(typeof this.options.groupBy=="function")return this.options.groupBy(t);if(typeof this.options.groupBy=="string")return t[this.options.groupBy]}}renderGroups(t,o){this.options.showGroups&&(this.calculateGroupBounds(),this.groupBounds.forEach((i,e)=>{const s=this.getGroupBorderColor(e),r=this.options.groupBorderWidth||2,a=this.options.groupBorderOpacity||.3;t.save(),t.globalAlpha=a,t.strokeStyle=s,t.lineWidth=r/o,t.setLineDash([10/o,5/o]),t.strokeRect(i.minX,i.minY,i.maxX-i.minX,i.maxY-i.minY),t.restore();const h=this.options.groupLabelThreshold||.8;if(o<=h){const n=this.getGroupLabelColor(e),p=(this.options.groupLabelSize||16)/o;t.save(),t.font=`bold ${p}px Arial`,t.fillStyle=n,t.textAlign="center",t.textBaseline="middle";const f=(i.minX+i.maxX)/2,l=i.minY-p/2,c=t.measureText(e).width,y=p;t.globalAlpha=.8,t.fillStyle="rgba(255, 255, 255, 0.9)",t.fillRect(f-c/2-4,l-y/2-2,c+8,y+4),t.globalAlpha=1,t.fillStyle=n,t.fillText(e,f,l),t.restore()}}))}getGroupBorderColor(t){return typeof this.options.groupBorderColor=="function"?this.options.groupBorderColor(t):this.options.groupBorderColor||"#666"}getGroupLabelColor(t){return typeof this.options.groupLabelColor=="function"?this.options.groupLabelColor(t):this.options.groupLabelColor||"#333"}getNodeById(t){return this.nodesMap.get(t.toString())}hasNode(t){return this.nodesMap.has(t.toString())}getCooldownTime(){if(this.options.cooldownTime!==void 0)return this.options.cooldownTime;const o=this.data.nodes.length*(125/100);return Math.max(4e3,o)}getDataSize(){const{nodes:t,links:o}=this.graph.graphData();return{nodes:t.length,links:o.length}}getAllNodeIds(){return Array.from(this.nodesMap.keys())}updateNode(t,o){const i=this.nodesMap.get(t.toString());if(i){Object.assign(i,o);const e=this.data.nodes.findIndex(s=>s.id.toString()===t.toString());return e!==-1&&(this.data.nodes[e]=i),this.refreshGraph(),!0}return!1}removeNode(t){const o=t.toString();return this.nodesMap.has(o)?(this.nodesMap.delete(o),this.data.nodes=this.data.nodes.filter(i=>i.id.toString()!==o),this.data.links=this.data.links.filter(i=>{const e=typeof i.source=="object"?i.source.id:i.source,s=typeof i.target=="object"?i.target.id:i.target;return e?.toString()!==o&&s?.toString()!==o}),this.refreshGraph(),!0):!1}async addData(t){t.nodes.forEach(o=>{this.nodesMap.has(o.id.toString())||this.nodesMap.set(o.id.toString(),o)}),t.links.forEach(o=>{const i=this.createLinkKey(o.source,o.target);this.linkMap.has(i)?console.log("link already exists",o):this.linkMap.set(i,o)}),this.data={nodes:Array.from(this.nodesMap.values()),links:Array.from(this.linkMap.values())},this.graph.cooldownTime(this.getCooldownTime()),this.graph.graphData(this.data)}setLabelThreshold(t){this.options.labelThreshold=t,this.render()}setOptions(t){this.options={...this.options,...t},this.applyOptions()}refreshGraph(){this.graphData(this.data)}reinitialize(){this.initGraph()}reset(){this.graph.pauseAnimation(),this.data={nodes:[],links:[]},this.nodesMap.clear(),this.graph=new u(this.container),this.initGraph()}getData(){return this.data}getNodesData(){return this.data.nodes}getLinksData(){return this.data.links}createLinkKey(t,o){const i=t===void 0?"undefined":typeof t=="object"?t.id:t,e=o===void 0?"undefined":typeof o=="object"?o.id:o;return`${i}-${e}`}graphData(t){return this.nodesMap.clear(),this.linkMap.clear(),t.nodes.forEach(o=>{this.nodesMap.has(o.id.toString())||this.nodesMap.set(o.id.toString(),o)}),t.links.forEach(o=>{const i=this.createLinkKey(o.source,o.target);this.linkMap.has(i)||this.linkMap.set(i,o)}),this.data={nodes:Array.from(this.nodesMap.values()),links:Array.from(this.linkMap.values())},this.graph.cooldownTime(this.getCooldownTime()),this.graph.graphData(this.data),this}showGroups(t){return this.options.showGroups=t,t&&Object.entries({groupBy:"topic",groupBorderColor:"#666",groupBorderWidth:2,groupBorderOpacity:.3,groupLabelColor:"#333",groupLabelSize:16,groupLabelThreshold:.8,groupPadding:20}).forEach(([i,e])=>{this.options[i]===void 0&&(this.options[i]=e)}),this.applyOptions(),this.refreshGraph(),this}setGroupBy(t){return this.options.groupBy=t,this.applyOptions(),this.refreshGraph(),this}setGroupOptions(t){return t.borderColor!==void 0&&(this.options.groupBorderColor=t.borderColor),t.borderWidth!==void 0&&(this.options.groupBorderWidth=t.borderWidth),t.borderOpacity!==void 0&&(this.options.groupBorderOpacity=t.borderOpacity),t.labelColor!==void 0&&(this.options.groupLabelColor=t.labelColor),t.labelSize!==void 0&&(this.options.groupLabelSize=t.labelSize),t.labelThreshold!==void 0&&(this.options.groupLabelThreshold=t.labelThreshold),t.padding!==void 0&&(this.options.groupPadding=t.padding),this.applyOptions(),this.refreshGraph(),this}getGroups(){const t=new Set;return this.data.nodes.forEach(o=>{const i=this.getNodeGroupId(o);i&&t.add(i)}),Array.from(t)}getNodesInGroup(t){return this.data.nodes.filter(o=>this.getNodeGroupId(o)===t)}getOptions(){return{...this.options}}destroy(){this.worker&&(this.worker.terminate(),this.worker=null),this.graph._destructor()}}d.ForceGraph=k,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
|
package/dist/index.d.ts
CHANGED
|
@@ -62,6 +62,8 @@ export declare class ForceGraph<TNode extends NodeData & {
|
|
|
62
62
|
updateData(data: GraphData<TNode, TLink>): void;
|
|
63
63
|
private getNodeColor;
|
|
64
64
|
private getNodeBorderColor;
|
|
65
|
+
private resolveNodeShape;
|
|
66
|
+
private drawNodeShape;
|
|
65
67
|
private applyLinkOptions;
|
|
66
68
|
private getLinkCurvature;
|
|
67
69
|
private getLinkProperty;
|
|
@@ -177,6 +179,7 @@ export declare interface GraphOptions<N extends NodeData = NodeData, L extends L
|
|
|
177
179
|
nodeColor?: string | ((node: N) => string);
|
|
178
180
|
nodeBorderColor?: string | ((node: N) => string);
|
|
179
181
|
nodeBorderWidth?: number | ((node: N) => number);
|
|
182
|
+
nodeShape?: NodeShape | ((node: N) => NodeShape);
|
|
180
183
|
nodeGap?: number;
|
|
181
184
|
linkLabel?: string | ((link: L) => string);
|
|
182
185
|
nodeIcon?: string | ((node: N) => string);
|
|
@@ -225,7 +228,10 @@ export declare interface NodeData extends NodeObject {
|
|
|
225
228
|
platform?: string;
|
|
226
229
|
type?: string;
|
|
227
230
|
topic?: string;
|
|
231
|
+
shape?: NodeShape;
|
|
228
232
|
[key: string]: any;
|
|
229
233
|
}
|
|
230
234
|
|
|
235
|
+
declare type NodeShape = 'circle' | 'square' | 'triangle' | 'diamond' | 'star' | 'hexagon';
|
|
236
|
+
|
|
231
237
|
export { }
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logixode/force-graph-lib",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.1",
|
|
5
5
|
"description": "Force-directed graph visualization library.",
|
|
6
6
|
"author": "Rohmad Kurniadi",
|
|
7
7
|
"license": "MIT",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"scripts": {
|
|
37
37
|
"dev": "bunx --bun vite",
|
|
38
38
|
"build": "bunx --bun vite build && npx tsc --project tsconfig.lib.json --noEmit",
|
|
39
|
+
"type-check": "tsc --project tsconfig.lib.json --noEmit",
|
|
39
40
|
"preview": "bunx --bun vite preview",
|
|
40
41
|
"docs:dev": "bunx --bun vitepress dev",
|
|
41
42
|
"docs:build": "vitepress build",
|