@krainovsd/graph 0.13.0-beta3 → 0.14.0-beta.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/lib/cjs/index.cjs +729 -426
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/esm/constants/force-controls.js +4 -2
- package/lib/esm/constants/force-controls.js.map +1 -1
- package/lib/esm/constants/highlight-controls.js +9 -16
- package/lib/esm/constants/highlight-controls.js.map +1 -1
- package/lib/esm/constants/link-controls.js +17 -30
- package/lib/esm/constants/link-controls.js.map +1 -1
- package/lib/esm/constants/node-controls.js +4 -2
- package/lib/esm/constants/node-controls.js.map +1 -1
- package/lib/esm/index.js +8 -7
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/module/GraphCanvas/GraphCanvas.js +222 -34
- package/lib/esm/module/GraphCanvas/GraphCanvas.js.map +1 -1
- package/lib/esm/module/GraphCanvas/constants/force-settings.js +11 -1
- package/lib/esm/module/GraphCanvas/constants/force-settings.js.map +1 -1
- package/lib/esm/module/GraphCanvas/constants/graph-settings.js +17 -5
- package/lib/esm/module/GraphCanvas/constants/graph-settings.js.map +1 -1
- package/lib/esm/module/GraphCanvas/constants/highlight-settings.js +5 -3
- package/lib/esm/module/GraphCanvas/constants/highlight-settings.js.map +1 -1
- package/lib/esm/module/GraphCanvas/constants/index.js +5 -2
- package/lib/esm/module/GraphCanvas/constants/index.js.map +1 -1
- package/lib/esm/module/GraphCanvas/constants/link-settings.js +19 -10
- package/lib/esm/module/GraphCanvas/constants/link-settings.js.map +1 -1
- package/lib/esm/module/GraphCanvas/constants/node-settings.js +13 -3
- package/lib/esm/module/GraphCanvas/constants/node-settings.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/settings/force-settings-getter.js +4 -2
- package/lib/esm/module/GraphCanvas/lib/settings/force-settings-getter.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/settings/graph-settings-getter.js +4 -0
- package/lib/esm/module/GraphCanvas/lib/settings/graph-settings-getter.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/settings/highlight-settings-getter.js +4 -2
- package/lib/esm/module/GraphCanvas/lib/settings/highlight-settings-getter.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/settings/link-settings-getter.js +8 -5
- package/lib/esm/module/GraphCanvas/lib/settings/link-settings-getter.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/settings/node-settings-getter.js +14 -2
- package/lib/esm/module/GraphCanvas/lib/settings/node-settings-getter.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/utils/calculate-curve-link-position-by-node.js +5 -2
- package/lib/esm/module/GraphCanvas/lib/utils/calculate-curve-link-position-by-node.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/utils/calculate-link-position-by-node.js +5 -2
- package/lib/esm/module/GraphCanvas/lib/utils/calculate-link-position-by-node.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/utils/compute-graph-bounds.js +26 -0
- package/lib/esm/module/GraphCanvas/lib/utils/compute-graph-bounds.js.map +1 -0
- package/lib/esm/module/GraphCanvas/lib/utils/get-particle-position.js +40 -30
- package/lib/esm/module/GraphCanvas/lib/utils/get-particle-position.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/utils/is-empty-object.js +11 -0
- package/lib/esm/module/GraphCanvas/lib/utils/is-empty-object.js.map +1 -0
- package/lib/esm/module/GraphCanvas/lib/utils/is-node-visible.js +5 -2
- package/lib/esm/module/GraphCanvas/lib/utils/is-node-visible.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/draw-links.js +47 -62
- package/lib/esm/module/GraphCanvas/slices/draw-links.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/draw-nodes.js +9 -4
- package/lib/esm/module/GraphCanvas/slices/draw-nodes.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/init-dnd.js +21 -4
- package/lib/esm/module/GraphCanvas/slices/init-dnd.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/init-draw.js +1 -52
- package/lib/esm/module/GraphCanvas/slices/init-draw.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/init-pointer.js +6 -34
- package/lib/esm/module/GraphCanvas/slices/init-pointer.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/init-simulation.js +12 -2
- package/lib/esm/module/GraphCanvas/slices/init-simulation.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/init-zoom.js +85 -16
- package/lib/esm/module/GraphCanvas/slices/init-zoom.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/update-link-cache.js +33 -3
- package/lib/esm/module/GraphCanvas/slices/update-link-cache.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/update-node-cache.js +61 -16
- package/lib/esm/module/GraphCanvas/slices/update-node-cache.js.map +1 -1
- package/lib/index.d.ts +68 -29
- package/package.json +3 -2
package/lib/cjs/index.cjs
CHANGED
|
@@ -4,11 +4,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
4
4
|
|
|
5
5
|
const jsHelpers = require('@krainovsd/js-helpers');
|
|
6
6
|
const d3Force = require('d3-force');
|
|
7
|
+
const d3Selection = require('d3-selection');
|
|
7
8
|
const d3Zoom = require('d3-zoom');
|
|
8
9
|
const d3Array = require('d3-array');
|
|
9
|
-
const d3Selection = require('d3-selection');
|
|
10
10
|
const d3Drag = require('d3-drag');
|
|
11
|
-
const lodash = require('lodash');
|
|
12
11
|
|
|
13
12
|
const COMMON_SETTINGS = {
|
|
14
13
|
nodeRadius: 5,
|
|
@@ -23,6 +22,10 @@ const FORCE_SETTINGS = {
|
|
|
23
22
|
xForce: true,
|
|
24
23
|
yForce: true,
|
|
25
24
|
collideForce: true,
|
|
25
|
+
precompute: true,
|
|
26
|
+
precomputeMaxTicks: 300,
|
|
27
|
+
precomputeMaxTimeMs: 200,
|
|
28
|
+
precomputeDisableForcesAfter: false,
|
|
26
29
|
centerPosition: {},
|
|
27
30
|
centerStrength: 1,
|
|
28
31
|
collideStrength: 0.1,
|
|
@@ -40,6 +43,12 @@ const FORCE_SETTINGS = {
|
|
|
40
43
|
linkStrength: 1,
|
|
41
44
|
collideRadius: null,
|
|
42
45
|
};
|
|
46
|
+
const PERFORMANCE_FORCE_SETTINGS = {
|
|
47
|
+
...FORCE_SETTINGS,
|
|
48
|
+
collideIterations: 1,
|
|
49
|
+
precomputeMaxTimeMs: 350,
|
|
50
|
+
precomputeDisableForcesAfter: true,
|
|
51
|
+
};
|
|
43
52
|
|
|
44
53
|
function forceSettingsGetter(settings, prevSettings) {
|
|
45
54
|
return {
|
|
@@ -59,17 +68,18 @@ function linkSettingsGetter(settings, prevSettings) {
|
|
|
59
68
|
return { ...(prevSettings ?? LINK_SETTINGS), ...settings };
|
|
60
69
|
}
|
|
61
70
|
function linkOptionsGetter() {
|
|
71
|
+
const aboveScale = this.areaTransform && this.areaTransform.k > this.linkSettings.linkScaleSwitch;
|
|
62
72
|
return {
|
|
63
73
|
...LINK_OPTIONS,
|
|
64
74
|
drawExtraLink: null,
|
|
65
75
|
drawLink: null,
|
|
66
|
-
color:
|
|
76
|
+
color: aboveScale
|
|
67
77
|
? this.linkSettings.linkColorAfterScaleSwitch
|
|
68
78
|
: this.linkSettings.linkColorBeforeScaleSwitch,
|
|
69
|
-
arrowColor:
|
|
79
|
+
arrowColor: aboveScale
|
|
70
80
|
? this.linkSettings.linkColorAfterScaleSwitch
|
|
71
81
|
: this.linkSettings.linkColorBeforeScaleSwitch,
|
|
72
|
-
width:
|
|
82
|
+
width: aboveScale
|
|
73
83
|
? this.linkSettings.linkWidthAfterScaleSwitch
|
|
74
84
|
: this.linkSettings.linkWidthBeforeScaleSwitch,
|
|
75
85
|
};
|
|
@@ -185,11 +195,20 @@ function resetDrawTime() {
|
|
|
185
195
|
}
|
|
186
196
|
|
|
187
197
|
function nodeSettingsGetter(settings, prevNodeSettings) {
|
|
188
|
-
|
|
198
|
+
const result = {
|
|
189
199
|
...(prevNodeSettings ?? NODE_SETTINGS),
|
|
190
200
|
idGetter: nodeIdGetter,
|
|
191
201
|
...settings,
|
|
192
202
|
};
|
|
203
|
+
if (result.smartCache && (!result.textScaleSteps || result.textScaleSteps.length === 0)) {
|
|
204
|
+
const step = (result.textScaleMax - result.textScaleMin) / 9;
|
|
205
|
+
const steps = [];
|
|
206
|
+
for (let i = 0; i < 10; i++) {
|
|
207
|
+
steps.push(result.textScaleMin + i * step);
|
|
208
|
+
}
|
|
209
|
+
result.textScaleSteps = steps;
|
|
210
|
+
}
|
|
211
|
+
return result;
|
|
193
212
|
}
|
|
194
213
|
const color = colorGetter();
|
|
195
214
|
function nodeOptionsGetter(node) {
|
|
@@ -271,6 +290,30 @@ function highlightSettingsGetter(settings, prevSettings) {
|
|
|
271
290
|
};
|
|
272
291
|
}
|
|
273
292
|
|
|
293
|
+
function computeGraphBounds(nodes) {
|
|
294
|
+
if (!nodes.length)
|
|
295
|
+
return null;
|
|
296
|
+
let minX = Infinity;
|
|
297
|
+
let minY = Infinity;
|
|
298
|
+
let maxX = -Infinity;
|
|
299
|
+
let maxY = -Infinity;
|
|
300
|
+
for (const node of nodes) {
|
|
301
|
+
if (node.x === null || node.x === undefined || node.y === null || node.y === undefined)
|
|
302
|
+
continue;
|
|
303
|
+
if (node.visible === false)
|
|
304
|
+
continue;
|
|
305
|
+
let radius = node._radius;
|
|
306
|
+
radius ??= Math.max(node._width ?? 0, node._height ?? 0) / 2;
|
|
307
|
+
minX = Math.min(minX, node.x - radius);
|
|
308
|
+
minY = Math.min(minY, node.y - radius);
|
|
309
|
+
maxX = Math.max(maxX, node.x + radius);
|
|
310
|
+
maxY = Math.max(maxY, node.y + radius);
|
|
311
|
+
}
|
|
312
|
+
if (!isFinite(minX))
|
|
313
|
+
return null;
|
|
314
|
+
return { minX, minY, maxX, maxY };
|
|
315
|
+
}
|
|
316
|
+
|
|
274
317
|
function pointerGetter(mouseEvent, areaRect, areaTransform) {
|
|
275
318
|
const clientX = "clientX" in mouseEvent
|
|
276
319
|
? mouseEvent.clientX
|
|
@@ -735,42 +778,52 @@ function isNodeVisible(opts) {
|
|
|
735
778
|
}
|
|
736
779
|
}
|
|
737
780
|
|
|
781
|
+
const FRAME_INTERVAL = 1000 / 60;
|
|
738
782
|
function getParticlePosition(opts) {
|
|
739
|
-
const
|
|
740
|
-
const
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
opts.particle.prev.step !== 0 &&
|
|
746
|
-
opts.particle.prev.step < opts.particle.step &&
|
|
747
|
-
prevStepDifference < opts.distance;
|
|
748
|
-
if (opts.particle.step === 0 && needWait) {
|
|
749
|
-
opts.particle.x = undefined;
|
|
750
|
-
opts.particle.y = undefined;
|
|
751
|
-
return;
|
|
783
|
+
const now = performance.now();
|
|
784
|
+
const particle = opts.particle;
|
|
785
|
+
if (particle._lastTime == undefined) {
|
|
786
|
+
particle._distanceTraveled = (opts.distance / opts.totalCount) * particle.index;
|
|
787
|
+
particle._lastTime = now;
|
|
788
|
+
particle._lastDistance = opts.distance;
|
|
752
789
|
}
|
|
753
|
-
const
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
opts.particle.step = 0;
|
|
759
|
-
return;
|
|
790
|
+
const lastDistance = particle._lastDistance ?? 0;
|
|
791
|
+
if (lastDistance !== opts.distance && lastDistance > 0) {
|
|
792
|
+
const scale = opts.distance / lastDistance;
|
|
793
|
+
particle._distanceTraveled = ((particle._distanceTraveled ?? 0) * scale) % opts.distance;
|
|
794
|
+
particle._lastDistance = opts.distance;
|
|
760
795
|
}
|
|
761
|
-
const
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
opts.
|
|
767
|
-
|
|
768
|
-
|
|
796
|
+
const delta = Math.min(now - particle._lastTime, FRAME_INTERVAL);
|
|
797
|
+
particle._lastTime = now;
|
|
798
|
+
particle._distanceTraveled =
|
|
799
|
+
((particle._distanceTraveled ?? 0) + opts.speed * delta) % opts.distance;
|
|
800
|
+
const progress = particle._distanceTraveled / opts.distance;
|
|
801
|
+
if (opts.xControl !== 0 && opts.yControl !== 0) {
|
|
802
|
+
const t = 1 - progress;
|
|
803
|
+
particle.x =
|
|
804
|
+
t * t * opts.xStart + 2 * t * progress * opts.xControl + progress * progress * opts.xEnd;
|
|
805
|
+
particle.y =
|
|
806
|
+
t * t * opts.yStart + 2 * t * progress * opts.yControl + progress * progress * opts.yEnd;
|
|
769
807
|
}
|
|
770
808
|
else {
|
|
771
|
-
opts.
|
|
809
|
+
const dx = opts.xEnd - opts.xStart;
|
|
810
|
+
const dy = opts.yEnd - opts.yStart;
|
|
811
|
+
particle.x = opts.xStart + dx * progress;
|
|
812
|
+
particle.y = opts.yStart + dy * progress;
|
|
772
813
|
}
|
|
773
814
|
}
|
|
815
|
+
function approximateQuadraticBezierLength(x0, y0, x1, y1, x2, y2) {
|
|
816
|
+
const dx01 = x1 - x0;
|
|
817
|
+
const dy01 = y1 - y0;
|
|
818
|
+
const dx12 = x2 - x1;
|
|
819
|
+
const dy12 = y2 - y1;
|
|
820
|
+
const dx02 = x2 - x0;
|
|
821
|
+
const dy02 = y2 - y0;
|
|
822
|
+
const a = Math.sqrt(dx01 * dx01 + dy01 * dy01);
|
|
823
|
+
const b = Math.sqrt(dx12 * dx12 + dy12 * dy12);
|
|
824
|
+
const c = Math.sqrt(dx02 * dx02 + dy02 * dy02);
|
|
825
|
+
return (a + b + c) / 2;
|
|
826
|
+
}
|
|
774
827
|
|
|
775
828
|
function linkByPointerGetter({ areaRect, areaTransform, mouseEvent, links, linkHoverExtraZone, curve, }) {
|
|
776
829
|
if (!areaRect)
|
|
@@ -1046,22 +1099,38 @@ function extractLinkPointIds(link) {
|
|
|
1046
1099
|
return { sourceId, targetId };
|
|
1047
1100
|
}
|
|
1048
1101
|
|
|
1102
|
+
function isEmptyObject(obj) {
|
|
1103
|
+
for (const key in obj) {
|
|
1104
|
+
if (Object.hasOwn(obj, key)) {
|
|
1105
|
+
return false;
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
return true;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1049
1111
|
const GRAPH_SETTINGS = {
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1112
|
+
zoomAnimation: true,
|
|
1113
|
+
zoomAnimationDuration: 300,
|
|
1114
|
+
zoomToNodeScale: 5,
|
|
1115
|
+
zoomToFitMargin: 0.25,
|
|
1116
|
+
zoomExtent: null,
|
|
1117
|
+
zoomExtentMargin: 0.3,
|
|
1118
|
+
translateExtent: null,
|
|
1119
|
+
translateExtentCoefficient: null,
|
|
1120
|
+
translateExtentOverlap: 0.3,
|
|
1054
1121
|
dragPlaceCoefficient: dragPlaceCoefficientGetter,
|
|
1055
1122
|
zoomInitial: null,
|
|
1056
1123
|
showDrawTime: true,
|
|
1057
1124
|
showDrawTimeEveryTick: false,
|
|
1058
1125
|
};
|
|
1126
|
+
const PERFORMANCE_GRAPH_SETTINGS = {
|
|
1127
|
+
...GRAPH_SETTINGS,
|
|
1128
|
+
};
|
|
1059
1129
|
|
|
1060
1130
|
const HIGHLIGHT_SETTINGS = {
|
|
1061
1131
|
highlightByHoverNode: true,
|
|
1062
1132
|
highlightByHoverLink: true,
|
|
1063
|
-
|
|
1064
|
-
highlightDownFrames: 5,
|
|
1133
|
+
highlightDuration: 150,
|
|
1065
1134
|
linkHoverExtraZone: 2,
|
|
1066
1135
|
/** Node */
|
|
1067
1136
|
highlightByNodeOnlyRoot: true,
|
|
@@ -1116,37 +1185,51 @@ const HIGHLIGHT_SETTINGS = {
|
|
|
1116
1185
|
highlightByLinkForArrowBorderColor: null,
|
|
1117
1186
|
highlightByLinkForArrowBorderSizingAdditional: 0,
|
|
1118
1187
|
};
|
|
1188
|
+
const PERFORMANCE_HIGHLIGHT_SETTINGS = {
|
|
1189
|
+
...HIGHLIGHT_SETTINGS,
|
|
1190
|
+
};
|
|
1119
1191
|
|
|
1120
1192
|
const LINK_SETTINGS = {
|
|
1193
|
+
smartCache: true,
|
|
1121
1194
|
prettyDraw: true,
|
|
1122
|
-
curve:
|
|
1195
|
+
curve: true,
|
|
1123
1196
|
linkScaleSwitch: 1,
|
|
1124
|
-
linkColorAfterScaleSwitch: "#
|
|
1197
|
+
linkColorAfterScaleSwitch: "#C5C5C5FF",
|
|
1125
1198
|
linkColorBeforeScaleSwitch: "#999",
|
|
1126
1199
|
linkWidthAfterScaleSwitch: 0.1,
|
|
1127
1200
|
linkWidthBeforeScaleSwitch: 1,
|
|
1128
1201
|
arrow: true,
|
|
1129
1202
|
arrowByHighlight: true,
|
|
1130
1203
|
particles: true,
|
|
1131
|
-
|
|
1132
|
-
|
|
1204
|
+
// spawn one more particle for N px
|
|
1205
|
+
particleCountByDistance: 25,
|
|
1206
|
+
// speed for 1px
|
|
1207
|
+
particleSpeedByDistance: 50,
|
|
1133
1208
|
};
|
|
1134
1209
|
const LINK_OPTIONS = {
|
|
1135
1210
|
alpha: 1,
|
|
1136
1211
|
arrowAlpha: 1,
|
|
1137
1212
|
arrowSize: 2,
|
|
1138
|
-
arrowBorderColor: "#
|
|
1213
|
+
arrowBorderColor: "#C5C5C5FF",
|
|
1139
1214
|
arrowBorderWidth: 0.1,
|
|
1140
1215
|
particleAlpha: 1,
|
|
1141
|
-
particleColor: "#
|
|
1142
|
-
particleBorderColor: "#
|
|
1216
|
+
particleColor: "#C5C5C5FF",
|
|
1217
|
+
particleBorderColor: "#C5C5C5FF",
|
|
1143
1218
|
particleBorderWidth: 0.1,
|
|
1144
|
-
particleCount: 2,
|
|
1145
1219
|
particleRadius: 0.5,
|
|
1146
|
-
|
|
1220
|
+
};
|
|
1221
|
+
const PERFORMANCE_LINK_SETTINGS = {
|
|
1222
|
+
...LINK_SETTINGS,
|
|
1223
|
+
particles: false,
|
|
1224
|
+
prettyDraw: false,
|
|
1225
|
+
};
|
|
1226
|
+
const PERFORMANCE_LINK_OPTIONS = {
|
|
1227
|
+
...LINK_OPTIONS,
|
|
1147
1228
|
};
|
|
1148
1229
|
|
|
1149
1230
|
const NODE_SETTINGS = {
|
|
1231
|
+
smartCache: true,
|
|
1232
|
+
textScaleSteps: [],
|
|
1150
1233
|
nodeRadiusFlexible: true,
|
|
1151
1234
|
nodeRadiusLinkCountForStep: 5,
|
|
1152
1235
|
nodeRadiusIncrementByStep: 1,
|
|
@@ -1183,14 +1266,14 @@ const NODE_OPTIONS = {
|
|
|
1183
1266
|
textShiftX: 0,
|
|
1184
1267
|
textFont: "Arial",
|
|
1185
1268
|
textAlign: "center",
|
|
1186
|
-
textColor: "#
|
|
1269
|
+
textColor: "#d2d2d2",
|
|
1187
1270
|
textStyle: "normal",
|
|
1188
1271
|
textWeight: 500,
|
|
1189
1272
|
textGap: 0,
|
|
1190
1273
|
label: null,
|
|
1191
1274
|
labelAlpha: 1,
|
|
1192
1275
|
labelAlign: "center",
|
|
1193
|
-
labelColor: "#
|
|
1276
|
+
labelColor: "#ffffff",
|
|
1194
1277
|
labelFont: "Arial",
|
|
1195
1278
|
labelGap: 0,
|
|
1196
1279
|
labelSize: 3.5,
|
|
@@ -1198,6 +1281,14 @@ const NODE_OPTIONS = {
|
|
|
1198
1281
|
labelWeight: 500,
|
|
1199
1282
|
labelWidth: 20,
|
|
1200
1283
|
};
|
|
1284
|
+
const PERFORMANCE_NODE_SETTINGS = {
|
|
1285
|
+
...NODE_SETTINGS,
|
|
1286
|
+
nodeRadiusFlexible: false,
|
|
1287
|
+
nodeSizeFlexible: false,
|
|
1288
|
+
};
|
|
1289
|
+
const PERFOMANCE_NODE_OPTIONS = {
|
|
1290
|
+
...NODE_OPTIONS,
|
|
1291
|
+
};
|
|
1201
1292
|
|
|
1202
1293
|
const GRAPH_CACHE_TYPE = {
|
|
1203
1294
|
NodeOptions: "nodeOptions",
|
|
@@ -1264,8 +1355,14 @@ function initDnd() {
|
|
|
1264
1355
|
return;
|
|
1265
1356
|
const mouseEvent = event.sourceEvent;
|
|
1266
1357
|
const [pointerX, pointerY] = pointerGetter(mouseEvent, this.areaRect, this.areaTransform);
|
|
1267
|
-
|
|
1268
|
-
|
|
1358
|
+
if (this._translateExtent) {
|
|
1359
|
+
event.subject.fx = Math.max(this._translateExtent[0][0], Math.min(this._translateExtent[1][0], pointerX));
|
|
1360
|
+
event.subject.fy = Math.max(this._translateExtent[0][1], Math.min(this._translateExtent[1][1], pointerY));
|
|
1361
|
+
}
|
|
1362
|
+
else {
|
|
1363
|
+
event.subject.fx = pointerX;
|
|
1364
|
+
event.subject.fy = pointerY;
|
|
1365
|
+
}
|
|
1269
1366
|
this.listeners.onMoveDragFinished?.call?.(this, event);
|
|
1270
1367
|
})
|
|
1271
1368
|
.on("end", (event) => {
|
|
@@ -1275,8 +1372,14 @@ function initDnd() {
|
|
|
1275
1372
|
const sourceEvent = event.sourceEvent;
|
|
1276
1373
|
if (sourceEvent.altKey && this.areaRect) {
|
|
1277
1374
|
const [pointerX, pointerY] = pointerGetter(sourceEvent, this.areaRect, this.areaTransform);
|
|
1278
|
-
|
|
1279
|
-
|
|
1375
|
+
if (this._translateExtent) {
|
|
1376
|
+
event.subject.fx = Math.max(this._translateExtent[0][0], Math.min(this._translateExtent[1][0], pointerX));
|
|
1377
|
+
event.subject.fy = Math.max(this._translateExtent[0][1], Math.min(this._translateExtent[1][1], pointerY));
|
|
1378
|
+
}
|
|
1379
|
+
else {
|
|
1380
|
+
event.subject.fx = pointerX;
|
|
1381
|
+
event.subject.fy = pointerY;
|
|
1382
|
+
}
|
|
1280
1383
|
}
|
|
1281
1384
|
else {
|
|
1282
1385
|
event.subject.fx = null;
|
|
@@ -1324,7 +1427,7 @@ function adjustPoint(x, y, xControl, yControl, radius) {
|
|
|
1324
1427
|
}
|
|
1325
1428
|
|
|
1326
1429
|
function getDrawLink() {
|
|
1327
|
-
return function drawLink(link) {
|
|
1430
|
+
return function drawLink(link, index) {
|
|
1328
1431
|
if (!this.context ||
|
|
1329
1432
|
typeof link.source !== "object" ||
|
|
1330
1433
|
typeof link.target !== "object" ||
|
|
@@ -1339,8 +1442,7 @@ function getDrawLink() {
|
|
|
1339
1442
|
return;
|
|
1340
1443
|
if (!link.source._visible && !link.target._visible)
|
|
1341
1444
|
return;
|
|
1342
|
-
const
|
|
1343
|
-
const linkOptions = this.linkOptionsCache[id];
|
|
1445
|
+
const linkOptions = this.linkOptionsCache[index];
|
|
1344
1446
|
if (!linkOptions)
|
|
1345
1447
|
return;
|
|
1346
1448
|
if (linkOptions.drawLink) {
|
|
@@ -1355,10 +1457,12 @@ function getDrawLink() {
|
|
|
1355
1457
|
let arrowSize = linkOptions.arrowSize;
|
|
1356
1458
|
let arrowBorderWidth = linkOptions.arrowBorderWidth;
|
|
1357
1459
|
let arrowBorderColor = linkOptions.arrowBorderColor;
|
|
1460
|
+
const currentNodeHighlighted = this.highlightedNode &&
|
|
1461
|
+
(this.highlightedNode.id == link.source.id || this.highlightedNode.id == link.target.id);
|
|
1358
1462
|
/** Highlight */
|
|
1359
1463
|
if (this.highlightedNeighbors && this.highlightedNode) {
|
|
1360
1464
|
/** By Node Not Highlight */
|
|
1361
|
-
if (
|
|
1465
|
+
if (!currentNodeHighlighted) {
|
|
1362
1466
|
const fadeOptions = linkFade({
|
|
1363
1467
|
arrow: this.linkSettings.arrow,
|
|
1364
1468
|
arrowByHighlight: this.linkSettings.arrowByHighlight,
|
|
@@ -1392,9 +1496,10 @@ function getDrawLink() {
|
|
|
1392
1496
|
arrowBorderColor = highlightOptions.arrowBorderColor;
|
|
1393
1497
|
}
|
|
1394
1498
|
}
|
|
1499
|
+
const currentLinkHighlighted = this.highlightedLink === link;
|
|
1395
1500
|
if (this.highlightedNeighbors && this.highlightedLink) {
|
|
1396
1501
|
/** By Link Not Highlight */
|
|
1397
|
-
if (
|
|
1502
|
+
if (!currentLinkHighlighted) {
|
|
1398
1503
|
const fadeOptions = linkFade({
|
|
1399
1504
|
arrow: this.linkSettings.arrow,
|
|
1400
1505
|
arrowByHighlight: this.linkSettings.arrowByHighlight,
|
|
@@ -1446,8 +1551,8 @@ function getDrawLink() {
|
|
|
1446
1551
|
const isHasArrow = this.linkSettings.arrow && arrowAlpha > 0;
|
|
1447
1552
|
if (!this.linkSettings.curve) {
|
|
1448
1553
|
if (this.linkSettings.prettyDraw ||
|
|
1449
|
-
this.linkSettings.
|
|
1450
|
-
(this.
|
|
1554
|
+
(this.linkSettings.arrow && arrowAlpha > 0) ||
|
|
1555
|
+
(this.particles && (currentNodeHighlighted || currentLinkHighlighted))) {
|
|
1451
1556
|
const position = calculateLinkPositionByNode(xStart, yStart, xEnd, yEnd, link.source, link.target, isHasArrow ? arrowSize : 0);
|
|
1452
1557
|
xStart = position.xStart;
|
|
1453
1558
|
xEnd = position.xEnd;
|
|
@@ -1485,6 +1590,7 @@ function getDrawLink() {
|
|
|
1485
1590
|
link._cy = position.yControl;
|
|
1486
1591
|
link._ax = position.xEndArrow;
|
|
1487
1592
|
link._ay = position.yEndArrow;
|
|
1593
|
+
linkDistance = approximateQuadraticBezierLength(position.xStart, position.yStart, position.xControl, position.yControl, position.xEnd, position.yEnd);
|
|
1488
1594
|
this.context.beginPath();
|
|
1489
1595
|
this.context.moveTo(position.xStart, position.yStart);
|
|
1490
1596
|
this.context.quadraticCurveTo(position.xControl, position.yControl, position.xEnd, position.yEnd);
|
|
@@ -1495,69 +1601,46 @@ function getDrawLink() {
|
|
|
1495
1601
|
this.context.stroke();
|
|
1496
1602
|
}
|
|
1497
1603
|
/** Particle */
|
|
1498
|
-
if (this.linkSettings.particles &&
|
|
1499
|
-
(
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
(this.highlightedLink && this.highlightedLink === link))) {
|
|
1503
|
-
const particleSteps = this.linkSettings.particleFlexSpeed
|
|
1504
|
-
? linkDistance <= 0
|
|
1505
|
-
? 0
|
|
1506
|
-
: linkDistance * this.linkSettings.particleFlexSpeedCoefficient
|
|
1507
|
-
: linkOptions.particleSteps;
|
|
1508
|
-
const particleCount = linkOptions.particleCount;
|
|
1509
|
-
if (!this.particles[id]) {
|
|
1510
|
-
const sourceId = link.source.id;
|
|
1511
|
-
const targetId = link.target.id;
|
|
1604
|
+
if (this.linkSettings.particles && (currentLinkHighlighted || currentNodeHighlighted)) {
|
|
1605
|
+
const speed = (1 / this.linkSettings.particleSpeedByDistance) * (1 + 0.5);
|
|
1606
|
+
if (!this.particles[index]) {
|
|
1607
|
+
const particleCount = Math.max(1, Math.floor(linkDistance / this.linkSettings.particleCountByDistance));
|
|
1512
1608
|
const particles = [];
|
|
1513
|
-
let prevParticle;
|
|
1514
1609
|
for (let i = 0; i < particleCount; i++) {
|
|
1515
1610
|
const particle = {
|
|
1516
|
-
step: 0,
|
|
1517
|
-
sourceId,
|
|
1518
|
-
targetId,
|
|
1519
|
-
prev: prevParticle,
|
|
1520
|
-
next: undefined,
|
|
1521
1611
|
index: i,
|
|
1522
1612
|
};
|
|
1523
|
-
if (prevParticle)
|
|
1524
|
-
prevParticle.next = particle;
|
|
1525
1613
|
particles.push(particle);
|
|
1526
|
-
prevParticle = particle;
|
|
1527
|
-
}
|
|
1528
|
-
if (particles.length >= 2) {
|
|
1529
|
-
particles[0].prev = particles[particles.length - 1];
|
|
1530
|
-
particles[particles.length - 1].next = particles[0];
|
|
1531
1614
|
}
|
|
1532
|
-
this.particles[
|
|
1615
|
+
this.particles[index] = particles;
|
|
1533
1616
|
}
|
|
1534
|
-
|
|
1535
|
-
this.
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
if (particle.x != undefined && particle.y != undefined) {
|
|
1549
|
-
this.context.beginPath();
|
|
1550
|
-
this.context.strokeStyle = linkOptions.particleBorderColor;
|
|
1551
|
-
this.context.lineWidth = linkOptions.particleBorderWidth;
|
|
1552
|
-
this.context.arc(particle.x, particle.y, linkOptions.particleRadius, 0, Math.PI * 2);
|
|
1553
|
-
this.context.fillStyle = linkOptions.particleColor;
|
|
1554
|
-
this.context.fill();
|
|
1555
|
-
if (linkOptions.particleBorderWidth > 0) {
|
|
1556
|
-
this.context.stroke();
|
|
1557
|
-
}
|
|
1558
|
-
}
|
|
1617
|
+
this.particles[index].forEach((particle, _, particles) => {
|
|
1618
|
+
if (!this.context)
|
|
1619
|
+
return;
|
|
1620
|
+
getParticlePosition({
|
|
1621
|
+
distance: linkDistance,
|
|
1622
|
+
particle,
|
|
1623
|
+
totalCount: particles.length,
|
|
1624
|
+
xEnd,
|
|
1625
|
+
xStart,
|
|
1626
|
+
yEnd,
|
|
1627
|
+
yStart,
|
|
1628
|
+
xControl,
|
|
1629
|
+
yControl,
|
|
1630
|
+
speed,
|
|
1559
1631
|
});
|
|
1560
|
-
|
|
1632
|
+
if (particle.x != undefined && particle.y != undefined) {
|
|
1633
|
+
this.context.beginPath();
|
|
1634
|
+
this.context.strokeStyle = linkOptions.particleBorderColor;
|
|
1635
|
+
this.context.lineWidth = linkOptions.particleBorderWidth;
|
|
1636
|
+
this.context.arc(particle.x, particle.y, linkOptions.particleRadius, 0, Math.PI * 2);
|
|
1637
|
+
this.context.fillStyle = linkOptions.particleColor;
|
|
1638
|
+
this.context.fill();
|
|
1639
|
+
if (linkOptions.particleBorderWidth > 0) {
|
|
1640
|
+
this.context.stroke();
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
});
|
|
1561
1644
|
}
|
|
1562
1645
|
/** Arrow */
|
|
1563
1646
|
if (this.linkSettings.arrow && arrowAlpha > 0) {
|
|
@@ -1641,7 +1724,7 @@ function getTextLines({ context, textAlign, textColor, textFont, textStyle, text
|
|
|
1641
1724
|
}
|
|
1642
1725
|
|
|
1643
1726
|
function getDrawNode(nodeRenders, textRenders) {
|
|
1644
|
-
return function drawNode(node) {
|
|
1727
|
+
return function drawNode(node, index) {
|
|
1645
1728
|
if (!this.context || !node.x || !node.y)
|
|
1646
1729
|
return;
|
|
1647
1730
|
if (node.visible != undefined && !node.visible) {
|
|
@@ -1650,7 +1733,7 @@ function getDrawNode(nodeRenders, textRenders) {
|
|
|
1650
1733
|
node._height = 0;
|
|
1651
1734
|
return;
|
|
1652
1735
|
}
|
|
1653
|
-
const nodeOptions = this.nodeOptionsCache[
|
|
1736
|
+
const nodeOptions = this.nodeOptionsCache[index];
|
|
1654
1737
|
if (!nodeOptions)
|
|
1655
1738
|
return;
|
|
1656
1739
|
if (nodeOptions.nodeDraw && nodeOptions.textDraw) {
|
|
@@ -1809,7 +1892,7 @@ function getDrawNode(nodeRenders, textRenders) {
|
|
|
1809
1892
|
this.context.lineWidth = borderWidth;
|
|
1810
1893
|
this.context.strokeStyle = borderColor;
|
|
1811
1894
|
this.context.fillStyle = color;
|
|
1812
|
-
const labelLines = this.cachedNodeLabel[
|
|
1895
|
+
const labelLines = this.cachedNodeLabel[index];
|
|
1813
1896
|
switch (nodeOptions.shape) {
|
|
1814
1897
|
case "circle": {
|
|
1815
1898
|
if (!node.image) {
|
|
@@ -1935,7 +2018,7 @@ function getDrawNode(nodeRenders, textRenders) {
|
|
|
1935
2018
|
});
|
|
1936
2019
|
}
|
|
1937
2020
|
/** Text draw */
|
|
1938
|
-
const textLines = this.cachedNodeText[
|
|
2021
|
+
const textLines = this.cachedNodeText[index];
|
|
1939
2022
|
if (nodeOptions.textVisible && nodeOptions.text && textLines) {
|
|
1940
2023
|
textRenders.push(() => {
|
|
1941
2024
|
if (nodeOptions.textDraw) {
|
|
@@ -1995,57 +2078,7 @@ function getDrawNode(nodeRenders, textRenders) {
|
|
|
1995
2078
|
}
|
|
1996
2079
|
|
|
1997
2080
|
function initDraw() {
|
|
1998
|
-
|
|
1999
|
-
function calculateHighlight(recursive) {
|
|
2000
|
-
if (hasHighlight && !recursive)
|
|
2001
|
-
return;
|
|
2002
|
-
/** animation up */
|
|
2003
|
-
if (!this.highlightWorking && this.highlightProgress > 0) {
|
|
2004
|
-
const highlightDownStep = 1 / this.highlightSettings.highlightDownFrames;
|
|
2005
|
-
this.highlightProgress -= highlightDownStep;
|
|
2006
|
-
if (!this.simulationWorking) {
|
|
2007
|
-
hasHighlight = true;
|
|
2008
|
-
return void requestAnimationFrame(() => this.draw(true));
|
|
2009
|
-
}
|
|
2010
|
-
if (!this.linkSettings.particles) {
|
|
2011
|
-
hasHighlight = false;
|
|
2012
|
-
return;
|
|
2013
|
-
}
|
|
2014
|
-
}
|
|
2015
|
-
/** animation down */
|
|
2016
|
-
if (this.highlightWorking && this.highlightProgress < 1) {
|
|
2017
|
-
const highlightUpStep = 1 / this.highlightSettings.highlightUpFrames;
|
|
2018
|
-
this.highlightProgress += highlightUpStep;
|
|
2019
|
-
if (!this.simulationWorking) {
|
|
2020
|
-
hasHighlight = true;
|
|
2021
|
-
return void requestAnimationFrame(() => this.draw(true));
|
|
2022
|
-
}
|
|
2023
|
-
if (!this.linkSettings.particles) {
|
|
2024
|
-
hasHighlight = false;
|
|
2025
|
-
return;
|
|
2026
|
-
}
|
|
2027
|
-
}
|
|
2028
|
-
/** animation active */
|
|
2029
|
-
if (this.linkSettings.particles && this.highlightWorking && !this.simulationWorking) {
|
|
2030
|
-
hasHighlight = true;
|
|
2031
|
-
return void requestAnimationFrame(() => this.draw(true));
|
|
2032
|
-
}
|
|
2033
|
-
/** animation stop */
|
|
2034
|
-
if (!this.highlightWorking && this.highlightProgress <= 0) {
|
|
2035
|
-
if (this.highlightedNeighbors || this.highlightedNode || this.highlightedLink) {
|
|
2036
|
-
this.highlightedNeighbors = null;
|
|
2037
|
-
this.highlightedNode = null;
|
|
2038
|
-
this.highlightedLink = null;
|
|
2039
|
-
this.particles = {};
|
|
2040
|
-
if (!this.simulationWorking) {
|
|
2041
|
-
hasHighlight = true;
|
|
2042
|
-
return void requestAnimationFrame(() => this.draw(true));
|
|
2043
|
-
}
|
|
2044
|
-
}
|
|
2045
|
-
}
|
|
2046
|
-
hasHighlight = false;
|
|
2047
|
-
}
|
|
2048
|
-
function draw(recursive = false) {
|
|
2081
|
+
function draw() {
|
|
2049
2082
|
if (!this.context)
|
|
2050
2083
|
return;
|
|
2051
2084
|
if (this.listeners.onDraw) {
|
|
@@ -2066,7 +2099,6 @@ function initDraw() {
|
|
|
2066
2099
|
textRenders.forEach((render) => render());
|
|
2067
2100
|
this.context.restore();
|
|
2068
2101
|
this.listeners.onDrawFinished?.call?.(this);
|
|
2069
|
-
calculateHighlight.bind(this)(recursive);
|
|
2070
2102
|
}
|
|
2071
2103
|
if (this.graphSettings.showDrawTime) {
|
|
2072
2104
|
return setDrawTime(draw.bind(this), this.graphSettings.showDrawTimeEveryTick);
|
|
@@ -2120,38 +2152,7 @@ function initPointer() {
|
|
|
2120
2152
|
else {
|
|
2121
2153
|
this.area.style.cursor = "default";
|
|
2122
2154
|
}
|
|
2123
|
-
|
|
2124
|
-
this.highlightedNode = currentNode;
|
|
2125
|
-
this.highlightedLink = null;
|
|
2126
|
-
this.highlightedNeighbors = new Set(this.highlightedNode?.neighbors ?? []);
|
|
2127
|
-
this.highlightWorking = true;
|
|
2128
|
-
if (!this.simulationWorking)
|
|
2129
|
-
requestAnimationFrame(() => {
|
|
2130
|
-
this.draw();
|
|
2131
|
-
});
|
|
2132
|
-
}
|
|
2133
|
-
else if (currentLink &&
|
|
2134
|
-
highlightLink &&
|
|
2135
|
-
checkType(currentLink.source, lodash.isObject(currentLink.source)) &&
|
|
2136
|
-
checkType(currentLink.target, lodash.isObject(currentLink.target)) &&
|
|
2137
|
-
this.highlightedLink !== currentLink) {
|
|
2138
|
-
this.highlightProgress = 0;
|
|
2139
|
-
this.highlightedLink = currentLink;
|
|
2140
|
-
this.highlightedNode = null;
|
|
2141
|
-
this.highlightedNeighbors = new Set([currentLink.source.id, currentLink.target.id]);
|
|
2142
|
-
this.highlightWorking = true;
|
|
2143
|
-
if (!this.simulationWorking)
|
|
2144
|
-
requestAnimationFrame(() => {
|
|
2145
|
-
this.draw();
|
|
2146
|
-
});
|
|
2147
|
-
}
|
|
2148
|
-
else if (!currentNode && !currentLink && (this.highlightedNode || this.highlightedLink)) {
|
|
2149
|
-
this.highlightWorking = false;
|
|
2150
|
-
if (!this.simulationWorking)
|
|
2151
|
-
requestAnimationFrame(() => {
|
|
2152
|
-
this.draw();
|
|
2153
|
-
});
|
|
2154
|
-
}
|
|
2155
|
+
this.animateHighlight(highlightNode ? currentNode : undefined, highlightLink ? currentLink : undefined);
|
|
2155
2156
|
if (!this.listeners.onMove)
|
|
2156
2157
|
return;
|
|
2157
2158
|
if (!currentNode && !checkHighlightNode)
|
|
@@ -2321,132 +2322,42 @@ function initResize() {
|
|
|
2321
2322
|
observer.observe(this.area);
|
|
2322
2323
|
}
|
|
2323
2324
|
|
|
2324
|
-
function
|
|
2325
|
-
if (!this.
|
|
2326
|
-
this.simulation = d3Force.forceSimulation()
|
|
2327
|
-
.nodes(this.nodes)
|
|
2328
|
-
.force("link", d3Force.forceLink(this.links).id(this.nodeSettings.idGetter.bind(this)))
|
|
2329
|
-
.on("tick", () => {
|
|
2330
|
-
this.draw();
|
|
2331
|
-
})
|
|
2332
|
-
.on("end", () => {
|
|
2333
|
-
this.listeners.onSimulationEnd?.call?.(this);
|
|
2334
|
-
if (this.graphSettings.showDrawTime) {
|
|
2335
|
-
getDrawTime();
|
|
2336
|
-
// eslint-disable-next-line no-console
|
|
2337
|
-
console.log(`nodes: ${this.nodes.length} | links: ${this.links.length}`);
|
|
2338
|
-
resetDrawTime();
|
|
2339
|
-
}
|
|
2340
|
-
});
|
|
2341
|
-
initSimulationForces.call(this);
|
|
2342
|
-
}
|
|
2343
|
-
}
|
|
2344
|
-
function initSimulationForces() {
|
|
2345
|
-
if (!this.simulation)
|
|
2346
|
-
return;
|
|
2347
|
-
const linkForce = this.simulation.force("link");
|
|
2348
|
-
if (!linkForce)
|
|
2349
|
-
return;
|
|
2350
|
-
if ((!this.forceSettings.forces || !this.forceSettings.xForce) && this.simulation.force("x")) {
|
|
2351
|
-
this.simulation.force("x", null);
|
|
2352
|
-
}
|
|
2353
|
-
if ((!this.forceSettings.forces || !this.forceSettings.yForce) && this.simulation.force("y")) {
|
|
2354
|
-
this.simulation.force("y", null);
|
|
2355
|
-
}
|
|
2356
|
-
if ((!this.forceSettings.forces || !this.forceSettings.chargeForce) &&
|
|
2357
|
-
this.simulation.force("charge")) {
|
|
2358
|
-
this.simulation.force("charge", null);
|
|
2359
|
-
}
|
|
2360
|
-
if ((!this.forceSettings.forces || !this.forceSettings.centerForce) &&
|
|
2361
|
-
this.simulation.force("center")) {
|
|
2362
|
-
this.simulation.force("center", null);
|
|
2363
|
-
}
|
|
2364
|
-
if (!this.forceSettings.forces || !this.forceSettings.linkForce) {
|
|
2365
|
-
linkForce.distance(0).strength(0).iterations(0);
|
|
2366
|
-
}
|
|
2367
|
-
if (this.forceSettings.forces && this.forceSettings.linkForce) {
|
|
2368
|
-
linkForce
|
|
2369
|
-
.distance(this.forceSettings.linkDistance)
|
|
2370
|
-
.strength(this.forceSettings.linkStrength)
|
|
2371
|
-
.iterations(this.forceSettings.linkIterations);
|
|
2372
|
-
}
|
|
2373
|
-
if (this.forceSettings.forces && this.forceSettings.xForce) {
|
|
2374
|
-
this.simulation.force("x", d3Force.forceX(this.forceSettings.xPosition).strength(this.forceSettings.xStrength));
|
|
2375
|
-
}
|
|
2376
|
-
if (this.forceSettings.forces && this.forceSettings.yForce) {
|
|
2377
|
-
this.simulation.force("y", d3Force.forceY(this.forceSettings.yPosition).strength(this.forceSettings.yStrength));
|
|
2378
|
-
}
|
|
2379
|
-
if (this.forceSettings.forces && this.forceSettings.chargeForce) {
|
|
2380
|
-
this.simulation.force("charge", d3Force.forceManyBody()
|
|
2381
|
-
.strength(this.forceSettings.chargeStrength)
|
|
2382
|
-
.distanceMax(Infinity)
|
|
2383
|
-
.distanceMin(this.forceSettings.chargeDistanceMin));
|
|
2384
|
-
}
|
|
2385
|
-
if (this.forceSettings.forces && this.forceSettings.centerForce) {
|
|
2386
|
-
this.simulation.force("center", d3Force.forceCenter(this.forceSettings.centerPosition.x ?? 0, this.forceSettings.centerPosition.y ?? 0).strength(this.forceSettings.centerStrength));
|
|
2387
|
-
}
|
|
2388
|
-
initCollideForce.call(this, true);
|
|
2389
|
-
}
|
|
2390
|
-
function initCollideForce(forceUpdate) {
|
|
2391
|
-
if (!this.simulation)
|
|
2325
|
+
function updateLinkCache() {
|
|
2326
|
+
if (!this.context)
|
|
2392
2327
|
return;
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
this.
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
const
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
this.simulation.force("collide", null);
|
|
2328
|
+
const current = this.areaTransform.k;
|
|
2329
|
+
if (this.linkSettings.smartCache &&
|
|
2330
|
+
this._lastLinkZoomK !== undefined &&
|
|
2331
|
+
this.linkOptionsCache.length > 0) {
|
|
2332
|
+
const corner = this.linkSettings.linkScaleSwitch;
|
|
2333
|
+
const prev = this._lastLinkZoomK;
|
|
2334
|
+
this._lastLinkZoomK = current;
|
|
2335
|
+
if (!((prev <= corner && current >= corner) || (prev >= corner && current <= corner))) {
|
|
2336
|
+
return;
|
|
2403
2337
|
}
|
|
2404
|
-
|
|
2405
|
-
this.
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
return nodeIterationExtractor(node, index, this.nodes, this, this.forceSettings.collideRadius, undefined);
|
|
2414
|
-
}
|
|
2415
|
-
return nodeOptions.radius + this.forceSettings.collideAdditionalRadius;
|
|
2416
|
-
}
|
|
2417
|
-
case "square": {
|
|
2418
|
-
return (Math.sqrt(nodeOptions.width ** 2 + nodeOptions.height ** 2) / 2 +
|
|
2419
|
-
this.forceSettings.collideAdditionalRadius);
|
|
2420
|
-
}
|
|
2421
|
-
case "text": {
|
|
2422
|
-
return (Math.sqrt(nodeOptions.width ** 2 + nodeOptions.height ** 2) / 2 +
|
|
2423
|
-
this.forceSettings.collideAdditionalRadius);
|
|
2424
|
-
}
|
|
2425
|
-
default: {
|
|
2426
|
-
if (this.forceSettings.collideRadius) {
|
|
2427
|
-
return nodeIterationExtractor(node, index, this.nodes, this, this.forceSettings.collideRadius, undefined);
|
|
2428
|
-
}
|
|
2429
|
-
return nodeOptions.radius + this.forceSettings.collideAdditionalRadius;
|
|
2430
|
-
}
|
|
2431
|
-
}
|
|
2432
|
-
})
|
|
2433
|
-
.strength(this.forceSettings.collideStrength)
|
|
2434
|
-
.iterations(this.forceSettings.collideIterations));
|
|
2338
|
+
for (let i = 0; i < this.links.length; i++) {
|
|
2339
|
+
const link = this.links[i];
|
|
2340
|
+
const linkOptions = linkIterationExtractor(link, i, this.links, this, this.linkSettings.options ?? {}, linkOptionsGetter);
|
|
2341
|
+
const cache = this.linkOptionsCache[i];
|
|
2342
|
+
if (cache) {
|
|
2343
|
+
cache.color = linkOptions.color;
|
|
2344
|
+
cache.arrowColor = linkOptions.arrowColor;
|
|
2345
|
+
cache.width = linkOptions.width;
|
|
2346
|
+
}
|
|
2435
2347
|
}
|
|
2348
|
+
return;
|
|
2436
2349
|
}
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
function updateLinkCache() {
|
|
2440
|
-
this.linkOptionsCache = {};
|
|
2350
|
+
this._lastLinkZoomK = current;
|
|
2351
|
+
this.linkOptionsCache.length = 0;
|
|
2441
2352
|
const groupMap = {};
|
|
2442
2353
|
const groupSelfMap = {};
|
|
2443
2354
|
for (let i = 0; i < this.links.length; i++) {
|
|
2444
2355
|
const link = this.links[i];
|
|
2445
2356
|
const { sourceId, targetId } = extractLinkPointIds(link);
|
|
2446
2357
|
const linkOptions = linkIterationExtractor(link, i, this.links, this, this.linkSettings.options ?? {}, linkOptionsGetter);
|
|
2447
|
-
|
|
2448
|
-
this.linkOptionsCache[id] = linkOptions;
|
|
2358
|
+
this.linkOptionsCache[i] = linkOptions;
|
|
2449
2359
|
if (this.linkSettings.curve) {
|
|
2360
|
+
const id = `${targetId}${sourceId}`;
|
|
2450
2361
|
if (sourceId === targetId) {
|
|
2451
2362
|
groupSelfMap[id] ??= 0;
|
|
2452
2363
|
link._groupIndex = ++groupSelfMap[id];
|
|
@@ -2477,13 +2388,34 @@ function indexToPosition(n) {
|
|
|
2477
2388
|
// return n & 1 ? -(n >> 1) : n >> 1;
|
|
2478
2389
|
}
|
|
2479
2390
|
|
|
2480
|
-
function updateNodeCache(
|
|
2481
|
-
this.nodeOptionsCache = {};
|
|
2391
|
+
function updateNodeCache() {
|
|
2482
2392
|
if (!this.context)
|
|
2483
2393
|
return;
|
|
2394
|
+
const currentZoom = this.areaTransform.k;
|
|
2395
|
+
const options = this.nodeOptionsCache.length === 0;
|
|
2396
|
+
const label = this.cachedNodeLabel.length === 0;
|
|
2397
|
+
let text = this.cachedNodeText.length === 0;
|
|
2398
|
+
if (this.nodeSettings.smartCache &&
|
|
2399
|
+
this._lastNodeZoomK !== undefined &&
|
|
2400
|
+
!options &&
|
|
2401
|
+
!text &&
|
|
2402
|
+
!label) {
|
|
2403
|
+
const thresholds = this.nodeSettings.textScaleSteps;
|
|
2404
|
+
if (thresholds && thresholds.length > 0) {
|
|
2405
|
+
const min = Math.min(this._lastNodeZoomK, currentZoom);
|
|
2406
|
+
const max = Math.max(this._lastNodeZoomK, currentZoom);
|
|
2407
|
+
const crossed = thresholds.some((t) => t >= min && t <= max);
|
|
2408
|
+
this._lastNodeZoomK = currentZoom;
|
|
2409
|
+
if (!crossed)
|
|
2410
|
+
return;
|
|
2411
|
+
}
|
|
2412
|
+
this.cachedNodeText.length = 0;
|
|
2413
|
+
text = true;
|
|
2414
|
+
}
|
|
2415
|
+
this._lastNodeZoomK = currentZoom;
|
|
2484
2416
|
for (let i = 0; i < this.nodes.length; i++) {
|
|
2485
2417
|
const node = this.nodes[i];
|
|
2486
|
-
if (
|
|
2418
|
+
if (options) {
|
|
2487
2419
|
const nodeOptions = nodeIterationExtractor(node, i, this.nodes, this, this.nodeSettings.options ?? {}, nodeOptionsGetter);
|
|
2488
2420
|
const radius = nodeOptions.shape === "circle"
|
|
2489
2421
|
? nodeRadiusGetter({
|
|
@@ -2534,11 +2466,19 @@ function updateNodeCache(types) {
|
|
|
2534
2466
|
nodeOptions.height = node.visible === false ? 0 : height;
|
|
2535
2467
|
nodeOptions.radius = node.visible === false ? 0 : radius;
|
|
2536
2468
|
nodeOptions.labelSize = labelSize;
|
|
2537
|
-
this.nodeOptionsCache[
|
|
2469
|
+
this.nodeOptionsCache[i] = nodeOptions;
|
|
2538
2470
|
}
|
|
2539
|
-
|
|
2471
|
+
let nodeOptions = this.nodeOptionsCache[i];
|
|
2472
|
+
if (!nodeOptions)
|
|
2473
|
+
continue;
|
|
2540
2474
|
/** label */
|
|
2541
|
-
if (
|
|
2475
|
+
if (label) {
|
|
2476
|
+
if (!options) {
|
|
2477
|
+
nodeOptions = nodeIterationExtractor(node, i, this.nodes, this, this.nodeSettings.options ?? {}, nodeOptionsGetter);
|
|
2478
|
+
const cache = this.nodeOptionsCache[i];
|
|
2479
|
+
if (cache)
|
|
2480
|
+
cache.label = nodeOptions.label;
|
|
2481
|
+
}
|
|
2542
2482
|
/** label in not text shape */
|
|
2543
2483
|
if (nodeOptions.shape !== "text" && nodeOptions.label) {
|
|
2544
2484
|
this.context.font = `${nodeOptions.labelStyle} normal ${nodeOptions.labelWeight} ${nodeOptions.labelSize}px ${nodeOptions.labelFont}`;
|
|
@@ -2546,7 +2486,7 @@ function updateNodeCache(types) {
|
|
|
2546
2486
|
this.context.textAlign = nodeOptions.labelAlign;
|
|
2547
2487
|
if (nodeOptions.labelWidth == undefined ||
|
|
2548
2488
|
this.context.measureText(nodeOptions.label).width <= nodeOptions.labelWidth) {
|
|
2549
|
-
this.cachedNodeLabel[
|
|
2489
|
+
this.cachedNodeLabel[i] = [nodeOptions.label];
|
|
2550
2490
|
}
|
|
2551
2491
|
const { lines } = getTextLines({
|
|
2552
2492
|
context: this.context,
|
|
@@ -2559,7 +2499,7 @@ function updateNodeCache(types) {
|
|
|
2559
2499
|
textStyle: nodeOptions.labelStyle,
|
|
2560
2500
|
textWeight: nodeOptions.labelWeight,
|
|
2561
2501
|
});
|
|
2562
|
-
this.cachedNodeLabel[
|
|
2502
|
+
this.cachedNodeLabel[i] = lines;
|
|
2563
2503
|
/** label in text shape */
|
|
2564
2504
|
}
|
|
2565
2505
|
else if (nodeOptions.shape === "text" && nodeOptions.label) {
|
|
@@ -2583,18 +2523,29 @@ function updateNodeCache(types) {
|
|
|
2583
2523
|
(lines.length - 1) * nodeOptions.labelGap +
|
|
2584
2524
|
nodeOptions.labelYPadding;
|
|
2585
2525
|
nodeOptions.width = maxSize + nodeOptions.labelXPadding;
|
|
2586
|
-
this.cachedNodeLabel[
|
|
2526
|
+
this.cachedNodeLabel[i] = lines;
|
|
2527
|
+
}
|
|
2528
|
+
else {
|
|
2529
|
+
this.cachedNodeLabel[i] = [];
|
|
2587
2530
|
}
|
|
2588
2531
|
}
|
|
2589
2532
|
/** text */
|
|
2590
|
-
if (
|
|
2533
|
+
if (text) {
|
|
2534
|
+
if (!options) {
|
|
2535
|
+
nodeOptions = nodeIterationExtractor(node, i, this.nodes, this, this.nodeSettings.options ?? {}, nodeOptionsGetter);
|
|
2536
|
+
const cache = this.nodeOptionsCache[i];
|
|
2537
|
+
if (cache) {
|
|
2538
|
+
cache.text = nodeOptions.text;
|
|
2539
|
+
cache.textVisible = nodeOptions.textVisible;
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
if (!nodeOptions.text) {
|
|
2543
|
+
this.cachedNodeText[i] = [];
|
|
2544
|
+
return;
|
|
2545
|
+
}
|
|
2591
2546
|
this.context.font = `${nodeOptions.textStyle} normal ${nodeOptions.textWeight} ${nodeOptions.textSize}px ${nodeOptions.textFont}`;
|
|
2592
2547
|
this.context.fillStyle = nodeOptions.textColor;
|
|
2593
2548
|
this.context.textAlign = nodeOptions.textAlign;
|
|
2594
|
-
if (nodeOptions.textWidth == undefined ||
|
|
2595
|
-
this.context.measureText(nodeOptions.text).width <= nodeOptions.textWidth) {
|
|
2596
|
-
this.cachedNodeText[node.id] = [nodeOptions.text];
|
|
2597
|
-
}
|
|
2598
2549
|
const { lines } = getTextLines({
|
|
2599
2550
|
context: this.context,
|
|
2600
2551
|
maxWidth: nodeOptions.textWidth,
|
|
@@ -2606,49 +2557,230 @@ function updateNodeCache(types) {
|
|
|
2606
2557
|
textStyle: nodeOptions.textStyle,
|
|
2607
2558
|
textWeight: nodeOptions.textWeight,
|
|
2608
2559
|
});
|
|
2609
|
-
this.cachedNodeText[
|
|
2560
|
+
this.cachedNodeText[i] = lines;
|
|
2610
2561
|
}
|
|
2611
2562
|
}
|
|
2612
2563
|
}
|
|
2613
2564
|
|
|
2565
|
+
const DEFAULT_ZOOM_EXTENT = [0.3, 10];
|
|
2566
|
+
const DEFAULT_TRANSLATE_EXTENT_COEFFICIENT = 8;
|
|
2567
|
+
const DEFAULT_MARGIN = 0.25;
|
|
2614
2568
|
function initZoom(currentZoom) {
|
|
2615
2569
|
if (!this.area)
|
|
2616
2570
|
throw new Error("bad init data");
|
|
2571
|
+
const bounds = computeGraphBounds(this.nodes);
|
|
2572
|
+
const zoomExtent = resolveZoomExtent(this.graphSettings.zoomExtent, this.width, this.height, this.graphSettings.zoomExtentMargin ?? DEFAULT_MARGIN, bounds);
|
|
2573
|
+
const translateExtent = resolveTranslateExtent(this.graphSettings.translateExtent, this.graphSettings.translateExtentCoefficient, this.graphSettings.translateExtentOverlap, this.width, this.height, zoomExtent, bounds);
|
|
2574
|
+
this._translateExtent = translateExtent;
|
|
2617
2575
|
const zoomInstance = d3Zoom.zoom()
|
|
2618
|
-
.scaleExtent(
|
|
2576
|
+
.scaleExtent(zoomExtent)
|
|
2619
2577
|
.on("zoom", (event) => {
|
|
2578
|
+
if (this._zoomAnimating)
|
|
2579
|
+
return;
|
|
2620
2580
|
this.listeners.onZoom?.call?.(this, event);
|
|
2621
2581
|
const oldTransform = this.areaTransform;
|
|
2622
2582
|
this.areaTransform = event.transform;
|
|
2623
2583
|
if (this.areaTransform.k !== oldTransform.k) {
|
|
2624
2584
|
updateLinkCache.call(this);
|
|
2625
|
-
updateNodeCache.call(this
|
|
2585
|
+
updateNodeCache.call(this);
|
|
2626
2586
|
}
|
|
2627
|
-
|
|
2628
|
-
requestAnimationFrame(() => this.draw());
|
|
2587
|
+
this.tick();
|
|
2629
2588
|
});
|
|
2630
|
-
|
|
2631
|
-
const coefficient = this.graphSettings.translateExtentCoefficient;
|
|
2632
|
-
const [coefficientX, coefficientY] = jsHelpers.isArray(coefficient)
|
|
2633
|
-
? coefficient
|
|
2634
|
-
: [coefficient, coefficient];
|
|
2635
|
-
const [[minX = -this.width * coefficientX, minY = -this.height * coefficientY], [maxX = this.width * coefficientX, maxY = this.height * coefficientY],] = this.graphSettings.translateExtent;
|
|
2636
|
-
zoomInstance.translateExtent([
|
|
2637
|
-
[minX, minY],
|
|
2638
|
-
[maxX, maxY],
|
|
2639
|
-
]);
|
|
2640
|
-
}
|
|
2589
|
+
zoomInstance.translateExtent(translateExtent);
|
|
2641
2590
|
d3Selection.select(this.area).call(zoomInstance).on("dblclick.zoom", null);
|
|
2642
2591
|
const zoomInitial = currentZoom ?? this.graphSettings.zoomInitial;
|
|
2643
|
-
this.areaTransform = new d3Zoom.ZoomTransform(zoomInitial?.k ?? 1, zoomInitial?.x ?? this.width / 2, zoomInitial?.y ?? this.height / 2);
|
|
2592
|
+
this.areaTransform = new d3Zoom.ZoomTransform(Math.max(zoomInitial?.k ?? 1, zoomExtent[0]), zoomInitial?.x ?? this.width / 2, zoomInitial?.y ?? this.height / 2);
|
|
2644
2593
|
d3Zoom.zoom().transform(d3Selection.select(this.area), this.areaTransform);
|
|
2645
2594
|
}
|
|
2595
|
+
function resolveZoomExtent(userExtent, viewWidth, viewHeight, margin, bounds) {
|
|
2596
|
+
if (userExtent &&
|
|
2597
|
+
userExtent.length === 2 &&
|
|
2598
|
+
userExtent[0] != undefined &&
|
|
2599
|
+
userExtent[1] != undefined) {
|
|
2600
|
+
return userExtent;
|
|
2601
|
+
}
|
|
2602
|
+
if (!bounds)
|
|
2603
|
+
return DEFAULT_ZOOM_EXTENT;
|
|
2604
|
+
const graphWidth = bounds.maxX - bounds.minX;
|
|
2605
|
+
const graphHeight = bounds.maxY - bounds.minY;
|
|
2606
|
+
if (graphWidth === 0 || graphHeight === 0)
|
|
2607
|
+
return DEFAULT_ZOOM_EXTENT;
|
|
2608
|
+
const scaleToFit = (1 - margin) / Math.max(graphWidth / viewWidth, graphHeight / viewHeight);
|
|
2609
|
+
return [scaleToFit, DEFAULT_ZOOM_EXTENT[1]];
|
|
2610
|
+
}
|
|
2611
|
+
function resolveTranslateExtent(userExtent, userCoefficient, overlap, viewWidth, viewHeight, zoomExtent, bounds) {
|
|
2612
|
+
if (userExtent && userExtent.length >= 2 && jsHelpers.isArray(userExtent[0]) && jsHelpers.isArray(userExtent[1])) {
|
|
2613
|
+
return [
|
|
2614
|
+
[
|
|
2615
|
+
userExtent[0][0] ?? -viewWidth * DEFAULT_TRANSLATE_EXTENT_COEFFICIENT,
|
|
2616
|
+
userExtent[0][1] ?? -viewHeight * DEFAULT_TRANSLATE_EXTENT_COEFFICIENT,
|
|
2617
|
+
],
|
|
2618
|
+
[
|
|
2619
|
+
userExtent[1][0] ?? viewWidth * DEFAULT_TRANSLATE_EXTENT_COEFFICIENT,
|
|
2620
|
+
userExtent[1][1] ?? viewHeight * DEFAULT_TRANSLATE_EXTENT_COEFFICIENT,
|
|
2621
|
+
],
|
|
2622
|
+
];
|
|
2623
|
+
}
|
|
2624
|
+
if (userCoefficient) {
|
|
2625
|
+
const [cx, cy] = jsHelpers.isArray(userCoefficient)
|
|
2626
|
+
? userCoefficient
|
|
2627
|
+
: [userCoefficient, userCoefficient];
|
|
2628
|
+
return [
|
|
2629
|
+
[-viewWidth * cx, -viewHeight * cy],
|
|
2630
|
+
[viewWidth * cx, viewHeight * cy],
|
|
2631
|
+
];
|
|
2632
|
+
}
|
|
2633
|
+
if (!bounds) {
|
|
2634
|
+
return [
|
|
2635
|
+
[
|
|
2636
|
+
-viewWidth * DEFAULT_TRANSLATE_EXTENT_COEFFICIENT,
|
|
2637
|
+
-viewHeight * DEFAULT_TRANSLATE_EXTENT_COEFFICIENT,
|
|
2638
|
+
],
|
|
2639
|
+
[
|
|
2640
|
+
viewWidth * DEFAULT_TRANSLATE_EXTENT_COEFFICIENT,
|
|
2641
|
+
viewHeight * DEFAULT_TRANSLATE_EXTENT_COEFFICIENT,
|
|
2642
|
+
],
|
|
2643
|
+
];
|
|
2644
|
+
}
|
|
2645
|
+
const minZoom = zoomExtent[0];
|
|
2646
|
+
const zoomViewWidth = viewWidth / minZoom;
|
|
2647
|
+
const zoomViewHeight = viewHeight / minZoom;
|
|
2648
|
+
const graphWidth = bounds.maxX - bounds.minX;
|
|
2649
|
+
const graphHeight = bounds.maxY - bounds.minY;
|
|
2650
|
+
const minX = bounds.minX + overlap * graphWidth - zoomViewWidth;
|
|
2651
|
+
const maxX = bounds.maxX - overlap * graphWidth + zoomViewWidth;
|
|
2652
|
+
const minY = bounds.minY + overlap * graphHeight - zoomViewHeight;
|
|
2653
|
+
const maxY = bounds.maxY - overlap * graphHeight + zoomViewHeight;
|
|
2654
|
+
return [
|
|
2655
|
+
[minX, minY],
|
|
2656
|
+
[maxX, maxY],
|
|
2657
|
+
];
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
function initSimulation() {
|
|
2661
|
+
if (!this.simulation) {
|
|
2662
|
+
this.simulation = d3Force.forceSimulation()
|
|
2663
|
+
.nodes(this.nodes)
|
|
2664
|
+
.force("link", d3Force.forceLink(this.links).id(this.nodeSettings.idGetter.bind(this)))
|
|
2665
|
+
.on("tick", () => {
|
|
2666
|
+
this.draw();
|
|
2667
|
+
})
|
|
2668
|
+
.on("end", () => {
|
|
2669
|
+
this.listeners.onSimulationEnd?.call?.(this);
|
|
2670
|
+
if (this.area) {
|
|
2671
|
+
initZoom.call(this, this.areaTransform);
|
|
2672
|
+
}
|
|
2673
|
+
if (this.graphSettings.showDrawTime) {
|
|
2674
|
+
getDrawTime();
|
|
2675
|
+
// eslint-disable-next-line no-console
|
|
2676
|
+
console.log(`nodes: ${this.nodes.length} | links: ${this.links.length}`);
|
|
2677
|
+
resetDrawTime();
|
|
2678
|
+
}
|
|
2679
|
+
})
|
|
2680
|
+
.stop();
|
|
2681
|
+
initSimulationForces.call(this);
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
function initSimulationForces() {
|
|
2685
|
+
if (!this.simulation)
|
|
2686
|
+
return;
|
|
2687
|
+
const linkForce = this.simulation.force("link");
|
|
2688
|
+
if (!linkForce)
|
|
2689
|
+
return;
|
|
2690
|
+
if ((!this.forceSettings.forces || !this.forceSettings.xForce) && this.simulation.force("x")) {
|
|
2691
|
+
this.simulation.force("x", null);
|
|
2692
|
+
}
|
|
2693
|
+
if ((!this.forceSettings.forces || !this.forceSettings.yForce) && this.simulation.force("y")) {
|
|
2694
|
+
this.simulation.force("y", null);
|
|
2695
|
+
}
|
|
2696
|
+
if ((!this.forceSettings.forces || !this.forceSettings.chargeForce) &&
|
|
2697
|
+
this.simulation.force("charge")) {
|
|
2698
|
+
this.simulation.force("charge", null);
|
|
2699
|
+
}
|
|
2700
|
+
if ((!this.forceSettings.forces || !this.forceSettings.centerForce) &&
|
|
2701
|
+
this.simulation.force("center")) {
|
|
2702
|
+
this.simulation.force("center", null);
|
|
2703
|
+
}
|
|
2704
|
+
if (!this.forceSettings.forces || !this.forceSettings.linkForce) {
|
|
2705
|
+
linkForce.distance(0).strength(0).iterations(0);
|
|
2706
|
+
}
|
|
2707
|
+
if (this.forceSettings.forces && this.forceSettings.linkForce) {
|
|
2708
|
+
linkForce
|
|
2709
|
+
.distance(this.forceSettings.linkDistance)
|
|
2710
|
+
.strength(this.forceSettings.linkStrength)
|
|
2711
|
+
.iterations(this.forceSettings.linkIterations);
|
|
2712
|
+
}
|
|
2713
|
+
if (this.forceSettings.forces && this.forceSettings.xForce) {
|
|
2714
|
+
this.simulation.force("x", d3Force.forceX(this.forceSettings.xPosition).strength(this.forceSettings.xStrength));
|
|
2715
|
+
}
|
|
2716
|
+
if (this.forceSettings.forces && this.forceSettings.yForce) {
|
|
2717
|
+
this.simulation.force("y", d3Force.forceY(this.forceSettings.yPosition).strength(this.forceSettings.yStrength));
|
|
2718
|
+
}
|
|
2719
|
+
if (this.forceSettings.forces && this.forceSettings.chargeForce) {
|
|
2720
|
+
this.simulation.force("charge", d3Force.forceManyBody()
|
|
2721
|
+
.strength(this.forceSettings.chargeStrength)
|
|
2722
|
+
.distanceMax(Infinity)
|
|
2723
|
+
.distanceMin(this.forceSettings.chargeDistanceMin));
|
|
2724
|
+
}
|
|
2725
|
+
if (this.forceSettings.forces && this.forceSettings.centerForce) {
|
|
2726
|
+
this.simulation.force("center", d3Force.forceCenter(this.forceSettings.centerPosition.x ?? 0, this.forceSettings.centerPosition.y ?? 0).strength(this.forceSettings.centerStrength));
|
|
2727
|
+
}
|
|
2728
|
+
initCollideForce.call(this, true);
|
|
2729
|
+
}
|
|
2730
|
+
function initCollideForce(forceUpdate) {
|
|
2731
|
+
if (!this.simulation)
|
|
2732
|
+
return;
|
|
2733
|
+
if ((!this.forceSettings.collideForce || !this.forceSettings.forces) &&
|
|
2734
|
+
this.simulation.force("collide")) {
|
|
2735
|
+
this.simulation.force("collide", null);
|
|
2736
|
+
}
|
|
2737
|
+
if (this.forceSettings.forces && this.forceSettings.collideForce) {
|
|
2738
|
+
const isHasMax = this.forceSettings.collideOffMax.links != 0 && this.forceSettings.collideOffMax.nodes != 0;
|
|
2739
|
+
const isMaxCollideNodes = isHasMax && this.forceSettings.collideOffMax.nodes < this.nodes.length;
|
|
2740
|
+
const isMaxCollideLinks = isHasMax && this.forceSettings.collideOffMax.links < this.links.length;
|
|
2741
|
+
if (isMaxCollideNodes && isMaxCollideLinks) {
|
|
2742
|
+
this.simulation.force("collide", null);
|
|
2743
|
+
}
|
|
2744
|
+
else if (!this.simulation.force("collide") || forceUpdate) {
|
|
2745
|
+
this.simulation.force("collide", d3Force.forceCollide()
|
|
2746
|
+
.radius((node, index) => {
|
|
2747
|
+
const nodeOptions = this.nodeOptionsCache[index];
|
|
2748
|
+
if (!nodeOptions)
|
|
2749
|
+
return 0;
|
|
2750
|
+
switch (nodeOptions.shape) {
|
|
2751
|
+
case "circle": {
|
|
2752
|
+
if (this.forceSettings.collideRadius) {
|
|
2753
|
+
return nodeIterationExtractor(node, index, this.nodes, this, this.forceSettings.collideRadius, undefined);
|
|
2754
|
+
}
|
|
2755
|
+
return nodeOptions.radius + this.forceSettings.collideAdditionalRadius;
|
|
2756
|
+
}
|
|
2757
|
+
case "square": {
|
|
2758
|
+
return (Math.sqrt(nodeOptions.width ** 2 + nodeOptions.height ** 2) / 2 +
|
|
2759
|
+
this.forceSettings.collideAdditionalRadius);
|
|
2760
|
+
}
|
|
2761
|
+
case "text": {
|
|
2762
|
+
return (Math.sqrt(nodeOptions.width ** 2 + nodeOptions.height ** 2) / 2 +
|
|
2763
|
+
this.forceSettings.collideAdditionalRadius);
|
|
2764
|
+
}
|
|
2765
|
+
default: {
|
|
2766
|
+
if (this.forceSettings.collideRadius) {
|
|
2767
|
+
return nodeIterationExtractor(node, index, this.nodes, this, this.forceSettings.collideRadius, undefined);
|
|
2768
|
+
}
|
|
2769
|
+
return nodeOptions.radius + this.forceSettings.collideAdditionalRadius;
|
|
2770
|
+
}
|
|
2771
|
+
}
|
|
2772
|
+
})
|
|
2773
|
+
.strength(this.forceSettings.collideStrength)
|
|
2774
|
+
.iterations(this.forceSettings.collideIterations));
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2646
2778
|
|
|
2647
2779
|
class GraphCanvas {
|
|
2648
2780
|
/** initial data */
|
|
2649
2781
|
nodes;
|
|
2650
2782
|
links;
|
|
2651
|
-
particles =
|
|
2783
|
+
particles = [];
|
|
2652
2784
|
width;
|
|
2653
2785
|
height;
|
|
2654
2786
|
root;
|
|
@@ -2665,19 +2797,25 @@ class GraphCanvas {
|
|
|
2665
2797
|
context;
|
|
2666
2798
|
simulation;
|
|
2667
2799
|
areaTransform = d3Zoom.zoomIdentity;
|
|
2800
|
+
_translateExtent;
|
|
2668
2801
|
areaRect;
|
|
2669
2802
|
draw;
|
|
2670
2803
|
eventAbortController;
|
|
2671
|
-
cachedNodeText =
|
|
2672
|
-
cachedNodeLabel =
|
|
2673
|
-
linkOptionsCache =
|
|
2674
|
-
nodeOptionsCache =
|
|
2804
|
+
cachedNodeText = [];
|
|
2805
|
+
cachedNodeLabel = [];
|
|
2806
|
+
linkOptionsCache = [];
|
|
2807
|
+
nodeOptionsCache = [];
|
|
2675
2808
|
isDragging = false;
|
|
2676
2809
|
highlightedNode = null;
|
|
2677
2810
|
highlightedLink = null;
|
|
2678
2811
|
highlightedNeighbors = null;
|
|
2679
2812
|
highlightProgress = 1;
|
|
2680
|
-
|
|
2813
|
+
highlightStart = null;
|
|
2814
|
+
highlightPositive = false;
|
|
2815
|
+
highlightController;
|
|
2816
|
+
_lastNodeZoomK;
|
|
2817
|
+
_lastLinkZoomK;
|
|
2818
|
+
_zoomAnimating = false;
|
|
2681
2819
|
get simulationWorking() {
|
|
2682
2820
|
const simulationAlpha = this.simulation?.alpha?.() ?? 0;
|
|
2683
2821
|
const simulationAlphaMin = this.simulation?.alphaMin?.() ?? 0;
|
|
@@ -2712,13 +2850,148 @@ class GraphCanvas {
|
|
|
2712
2850
|
nodes: this.nodes,
|
|
2713
2851
|
};
|
|
2714
2852
|
}
|
|
2853
|
+
fitToView(margin = this.graphSettings.zoomToFitMargin, duration = this.graphSettings.zoomAnimationDuration) {
|
|
2854
|
+
const area = this.area;
|
|
2855
|
+
if (!area)
|
|
2856
|
+
return;
|
|
2857
|
+
const bounds = computeGraphBounds(this.nodes);
|
|
2858
|
+
if (!bounds)
|
|
2859
|
+
return;
|
|
2860
|
+
const graphWidth = bounds.maxX - bounds.minX;
|
|
2861
|
+
const graphHeight = bounds.maxY - bounds.minY;
|
|
2862
|
+
if (graphWidth === 0 || graphHeight === 0)
|
|
2863
|
+
return;
|
|
2864
|
+
const graphCenterX = bounds.minX + graphWidth / 2;
|
|
2865
|
+
const graphCenterY = bounds.minY + graphHeight / 2;
|
|
2866
|
+
const scale = (1 - margin) / Math.max(graphWidth / this.width, graphHeight / this.height);
|
|
2867
|
+
const clampedScale = Math.min(scale, this.graphSettings.zoomExtent?.[1] ?? scale);
|
|
2868
|
+
const target = d3Zoom.zoomIdentity
|
|
2869
|
+
.translate(this.width / 2, this.height / 2)
|
|
2870
|
+
.scale(clampedScale)
|
|
2871
|
+
.translate(-graphCenterX, -graphCenterY);
|
|
2872
|
+
if (!this.graphSettings.zoomAnimation) {
|
|
2873
|
+
this.areaTransform = target;
|
|
2874
|
+
d3Zoom.zoom().transform(d3Selection.select(area), target);
|
|
2875
|
+
this.clearCache(true);
|
|
2876
|
+
this.tick();
|
|
2877
|
+
return;
|
|
2878
|
+
}
|
|
2879
|
+
this.animateZoom(area, target, this.areaTransform, duration);
|
|
2880
|
+
}
|
|
2881
|
+
focusOnNode(nodeId, scale = this.graphSettings.zoomToNodeScale, duration = this.graphSettings.zoomAnimationDuration) {
|
|
2882
|
+
const area = this.area;
|
|
2883
|
+
if (!area)
|
|
2884
|
+
return;
|
|
2885
|
+
const node = this.nodes.find((n) => n.id === nodeId);
|
|
2886
|
+
if (!node)
|
|
2887
|
+
return;
|
|
2888
|
+
if (node.x == undefined || node.y == undefined)
|
|
2889
|
+
return;
|
|
2890
|
+
const target = d3Zoom.zoomIdentity
|
|
2891
|
+
.translate(this.width / 2, this.height / 2)
|
|
2892
|
+
.scale(scale)
|
|
2893
|
+
.translate(-node.x, -node.y);
|
|
2894
|
+
if (!this.graphSettings.zoomAnimation) {
|
|
2895
|
+
this.areaTransform = target;
|
|
2896
|
+
d3Zoom.zoom().transform(d3Selection.select(area), target);
|
|
2897
|
+
this.clearCache(true);
|
|
2898
|
+
this.tick();
|
|
2899
|
+
return;
|
|
2900
|
+
}
|
|
2901
|
+
this.animateZoom(area, target, this.areaTransform, duration);
|
|
2902
|
+
}
|
|
2903
|
+
animateHighlight(node, link, baseDuration = this.highlightSettings.highlightDuration) {
|
|
2904
|
+
let positive = true;
|
|
2905
|
+
if (node && (this.highlightedNode !== node || !this.highlightPositive)) {
|
|
2906
|
+
this.highlightedNode = node;
|
|
2907
|
+
this.highlightedNeighbors = new Set(node.neighbors);
|
|
2908
|
+
this.particles = [];
|
|
2909
|
+
this.highlightedLink = null;
|
|
2910
|
+
this.highlightStart = performance.now();
|
|
2911
|
+
}
|
|
2912
|
+
else if (link && (this.highlightedLink !== link || !this.highlightPositive)) {
|
|
2913
|
+
const { sourceId, targetId } = extractLinkPointIds(link);
|
|
2914
|
+
this.highlightProgress = 0;
|
|
2915
|
+
this.highlightedLink = link;
|
|
2916
|
+
this.highlightedNeighbors = new Set([sourceId, targetId]);
|
|
2917
|
+
this.particles = [];
|
|
2918
|
+
this.highlightedNode = null;
|
|
2919
|
+
this.highlightStart = performance.now();
|
|
2920
|
+
}
|
|
2921
|
+
else if (!node && !link && this.highlightPositive) {
|
|
2922
|
+
positive = false;
|
|
2923
|
+
}
|
|
2924
|
+
else {
|
|
2925
|
+
return;
|
|
2926
|
+
}
|
|
2927
|
+
if (this.highlightController) {
|
|
2928
|
+
this.highlightController.abort();
|
|
2929
|
+
}
|
|
2930
|
+
const controller = new AbortController();
|
|
2931
|
+
this.highlightPositive = positive;
|
|
2932
|
+
this.highlightController = controller;
|
|
2933
|
+
const startTime = performance.now();
|
|
2934
|
+
const startProgress = this.highlightProgress;
|
|
2935
|
+
const targetProgress = positive ? 1 : 0;
|
|
2936
|
+
const delta = targetProgress - startProgress;
|
|
2937
|
+
const duration = baseDuration * Math.abs(delta);
|
|
2938
|
+
const animate = () => {
|
|
2939
|
+
if (controller.signal.aborted)
|
|
2940
|
+
return;
|
|
2941
|
+
const elapsed = performance.now() - startTime;
|
|
2942
|
+
const t = Math.min(elapsed / duration, 1);
|
|
2943
|
+
const current = startProgress + delta * t;
|
|
2944
|
+
const eased = current < 0.5 ? 4 * current * current * current : 1 - (-2 * current + 2) ** 3 / 2;
|
|
2945
|
+
this.highlightProgress = eased;
|
|
2946
|
+
if (t < 1 || positive) {
|
|
2947
|
+
requestAnimationFrame(animate);
|
|
2948
|
+
this.draw();
|
|
2949
|
+
}
|
|
2950
|
+
else {
|
|
2951
|
+
this.highlightedNode = null;
|
|
2952
|
+
this.highlightedLink = null;
|
|
2953
|
+
this.highlightedNeighbors = null;
|
|
2954
|
+
this.highlightStart = null;
|
|
2955
|
+
this.particles = [];
|
|
2956
|
+
this.tick();
|
|
2957
|
+
}
|
|
2958
|
+
};
|
|
2959
|
+
requestAnimationFrame(animate);
|
|
2960
|
+
}
|
|
2961
|
+
animateZoom(area, target, start, duration) {
|
|
2962
|
+
this._zoomAnimating = true;
|
|
2963
|
+
const startTime = performance.now();
|
|
2964
|
+
const animate = () => {
|
|
2965
|
+
const elapsed = performance.now() - startTime;
|
|
2966
|
+
const t = Math.min(elapsed / duration, 1);
|
|
2967
|
+
const eased = t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2;
|
|
2968
|
+
const x = start.x + (target.x - start.x) * eased;
|
|
2969
|
+
const y = start.y + (target.y - start.y) * eased;
|
|
2970
|
+
const k = start.k + (target.k - start.k) * eased;
|
|
2971
|
+
this.areaTransform = new d3Zoom.ZoomTransform(k, x, y);
|
|
2972
|
+
d3Zoom.zoom().transform(d3Selection.select(area), this.areaTransform);
|
|
2973
|
+
updateLinkCache.call(this);
|
|
2974
|
+
updateNodeCache.call(this);
|
|
2975
|
+
this.tick();
|
|
2976
|
+
if (t < 1) {
|
|
2977
|
+
requestAnimationFrame(animate);
|
|
2978
|
+
}
|
|
2979
|
+
else {
|
|
2980
|
+
this._zoomAnimating = false;
|
|
2981
|
+
this.clearCache(true);
|
|
2982
|
+
this.tick();
|
|
2983
|
+
}
|
|
2984
|
+
};
|
|
2985
|
+
requestAnimationFrame(animate);
|
|
2986
|
+
}
|
|
2715
2987
|
changeData(options, alpha = 0.5, clearCache = true) {
|
|
2716
2988
|
if (options.links != undefined)
|
|
2717
2989
|
this.links = options.links;
|
|
2718
2990
|
if (options.nodes != undefined)
|
|
2719
2991
|
this.nodes = options.nodes;
|
|
2720
|
-
if (options.nodes != undefined || options.links != undefined)
|
|
2992
|
+
if (options.nodes != undefined || options.links != undefined) {
|
|
2721
2993
|
this.updateData(alpha, clearCache);
|
|
2994
|
+
}
|
|
2722
2995
|
}
|
|
2723
2996
|
changeSettings(options, clearCache = true) {
|
|
2724
2997
|
if (options.graphSettings) {
|
|
@@ -2793,31 +3066,76 @@ class GraphCanvas {
|
|
|
2793
3066
|
}
|
|
2794
3067
|
clearCache(keys) {
|
|
2795
3068
|
if (keys === true) {
|
|
2796
|
-
|
|
2797
|
-
|
|
3069
|
+
this.nodeOptionsCache.length = 0;
|
|
3070
|
+
this.linkOptionsCache.length = 0;
|
|
3071
|
+
this.cachedNodeLabel.length = 0;
|
|
3072
|
+
this.cachedNodeText.length = 0;
|
|
2798
3073
|
}
|
|
2799
3074
|
else if (jsHelpers.isArray(keys)) {
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
3075
|
+
for (const key of keys) {
|
|
3076
|
+
switch (key) {
|
|
3077
|
+
case GRAPH_CACHE_TYPE.NodeText: {
|
|
3078
|
+
this.cachedNodeText.length = 0;
|
|
3079
|
+
break;
|
|
3080
|
+
}
|
|
3081
|
+
case GRAPH_CACHE_TYPE.NodeLabel: {
|
|
3082
|
+
this.cachedNodeLabel.length = 0;
|
|
3083
|
+
break;
|
|
3084
|
+
}
|
|
3085
|
+
case GRAPH_CACHE_TYPE.NodeOptions: {
|
|
3086
|
+
this.nodeOptionsCache.length = 0;
|
|
3087
|
+
break;
|
|
3088
|
+
}
|
|
3089
|
+
case GRAPH_CACHE_TYPE.LinkOptions: {
|
|
3090
|
+
this.linkOptionsCache.length = 0;
|
|
3091
|
+
break;
|
|
3092
|
+
}
|
|
3093
|
+
}
|
|
2811
3094
|
}
|
|
2812
3095
|
}
|
|
3096
|
+
updateNodeCache.call(this);
|
|
3097
|
+
updateLinkCache.call(this);
|
|
2813
3098
|
}
|
|
2814
3099
|
tick() {
|
|
2815
|
-
if (!this.simulationWorking
|
|
3100
|
+
if (!this.simulationWorking)
|
|
2816
3101
|
this.draw();
|
|
2817
3102
|
}
|
|
2818
|
-
restart(alpha) {
|
|
2819
|
-
if (this.simulation)
|
|
3103
|
+
restart(alpha, options) {
|
|
3104
|
+
if (!this.simulation)
|
|
3105
|
+
return;
|
|
3106
|
+
const settings = {
|
|
3107
|
+
precompute: options?.precompute ?? this.forceSettings.precompute,
|
|
3108
|
+
precomputeMaxTimeMs: options?.precomputeMaxTimeMs ?? this.forceSettings?.precomputeMaxTimeMs,
|
|
3109
|
+
precomputeMaxTicks: options?.precomputeMaxTicks ?? this.forceSettings?.precomputeMaxTicks ?? 300,
|
|
3110
|
+
precomputeDisableForcesAfter: options?.precomputeDisableForcesAfter ??
|
|
3111
|
+
this.forceSettings?.precomputeDisableForcesAfter ??
|
|
3112
|
+
false,
|
|
3113
|
+
};
|
|
3114
|
+
if (!settings.precompute) {
|
|
2820
3115
|
this.simulation.alpha(alpha ?? 1).restart();
|
|
3116
|
+
return;
|
|
3117
|
+
}
|
|
3118
|
+
if (settings.precomputeDisableForcesAfter) {
|
|
3119
|
+
this.forceSettings = forceSettingsGetter({ forces: true }, this.forceSettings);
|
|
3120
|
+
}
|
|
3121
|
+
initSimulationForces.call(this);
|
|
3122
|
+
this.simulation.stop();
|
|
3123
|
+
this.simulation.alpha(alpha ?? 1);
|
|
3124
|
+
const startTime = performance.now();
|
|
3125
|
+
let ticks = 0;
|
|
3126
|
+
while (performance.now() - startTime < settings.precomputeMaxTimeMs &&
|
|
3127
|
+
ticks < settings.precomputeMaxTicks) {
|
|
3128
|
+
this.simulation.tick(1);
|
|
3129
|
+
ticks++;
|
|
3130
|
+
if (this.simulation.alpha() <= this.simulation.alphaMin())
|
|
3131
|
+
break;
|
|
3132
|
+
}
|
|
3133
|
+
if (settings.precomputeDisableForcesAfter) {
|
|
3134
|
+
this.forceSettings = forceSettingsGetter({ forces: false }, this.forceSettings);
|
|
3135
|
+
}
|
|
3136
|
+
initSimulationForces.call(this);
|
|
3137
|
+
this.simulation.restart();
|
|
3138
|
+
this.tick();
|
|
2821
3139
|
}
|
|
2822
3140
|
start() {
|
|
2823
3141
|
if (this.simulation)
|
|
@@ -2854,8 +3172,7 @@ class GraphCanvas {
|
|
|
2854
3172
|
updateSimulation() {
|
|
2855
3173
|
if (this.simulation) {
|
|
2856
3174
|
initSimulationForces.call(this);
|
|
2857
|
-
this.
|
|
2858
|
-
this.simulation.restart();
|
|
3175
|
+
this.restart(1);
|
|
2859
3176
|
}
|
|
2860
3177
|
}
|
|
2861
3178
|
clearState() {
|
|
@@ -2864,7 +3181,8 @@ class GraphCanvas {
|
|
|
2864
3181
|
this.highlightedLink = null;
|
|
2865
3182
|
this.highlightedNeighbors = null;
|
|
2866
3183
|
this.highlightProgress = 0;
|
|
2867
|
-
this.
|
|
3184
|
+
this.highlightStart = null;
|
|
3185
|
+
this.highlightPositive = false;
|
|
2868
3186
|
}
|
|
2869
3187
|
updateData(alpha = 0.5, clearCache = true) {
|
|
2870
3188
|
if (clearCache) {
|
|
@@ -2872,9 +3190,7 @@ class GraphCanvas {
|
|
|
2872
3190
|
}
|
|
2873
3191
|
if (this.simulation) {
|
|
2874
3192
|
initCollideForce.call(this, false);
|
|
2875
|
-
this.simulation
|
|
2876
|
-
.nodes(this.nodes)
|
|
2877
|
-
.force("link", d3Force.forceLink(this.links)
|
|
3193
|
+
this.simulation.nodes(this.nodes).force("link", d3Force.forceLink(this.links)
|
|
2878
3194
|
.id(this.nodeSettings.idGetter.bind(this))
|
|
2879
3195
|
.distance(this.forceSettings.forces && this.forceSettings.linkForce
|
|
2880
3196
|
? this.forceSettings.linkDistance
|
|
@@ -2884,16 +3200,17 @@ class GraphCanvas {
|
|
|
2884
3200
|
: 0)
|
|
2885
3201
|
.iterations(this.forceSettings.forces && this.forceSettings.linkForce
|
|
2886
3202
|
? this.forceSettings.linkIterations
|
|
2887
|
-
: 0))
|
|
2888
|
-
|
|
2889
|
-
|
|
3203
|
+
: 0));
|
|
3204
|
+
this.restart(alpha);
|
|
3205
|
+
initZoom.call(this, this.areaTransform);
|
|
2890
3206
|
}
|
|
2891
3207
|
}
|
|
2892
3208
|
init() {
|
|
2893
3209
|
initArea.call(this);
|
|
2894
|
-
updateNodeCache.call(this
|
|
3210
|
+
updateNodeCache.call(this);
|
|
2895
3211
|
updateLinkCache.call(this);
|
|
2896
3212
|
initSimulation.call(this);
|
|
3213
|
+
this.restart(1);
|
|
2897
3214
|
initDnd.call(this);
|
|
2898
3215
|
initZoom.call(this);
|
|
2899
3216
|
initResize.call(this);
|
|
@@ -3059,22 +3376,13 @@ const HIGHLIGHT_COMMON_CONTROLS = [
|
|
|
3059
3376
|
label: "Расширение границы связи для курсора",
|
|
3060
3377
|
},
|
|
3061
3378
|
{
|
|
3062
|
-
id: "
|
|
3063
|
-
initialValue: HIGHLIGHT_SETTINGS.
|
|
3064
|
-
max:
|
|
3065
|
-
min:
|
|
3066
|
-
step: 1,
|
|
3067
|
-
type: "range",
|
|
3068
|
-
label: "Скорость отмены анимации в кадрах",
|
|
3069
|
-
},
|
|
3070
|
-
{
|
|
3071
|
-
id: "highlightUpFrames",
|
|
3072
|
-
initialValue: HIGHLIGHT_SETTINGS.highlightUpFrames,
|
|
3073
|
-
max: 60,
|
|
3074
|
-
min: 1,
|
|
3379
|
+
id: "highlightDuration",
|
|
3380
|
+
initialValue: HIGHLIGHT_SETTINGS.highlightDuration,
|
|
3381
|
+
max: 1000,
|
|
3382
|
+
min: 10,
|
|
3075
3383
|
step: 1,
|
|
3076
3384
|
type: "range",
|
|
3077
|
-
label: "Скорость
|
|
3385
|
+
label: "Скорость анимации",
|
|
3078
3386
|
},
|
|
3079
3387
|
];
|
|
3080
3388
|
const HIGHLIGHT_BY_NODE_FOR_NODE_CONTROLS = [
|
|
@@ -3547,19 +3855,22 @@ const LINK_SETTINGS_CONTROLS = [
|
|
|
3547
3855
|
initialValue: LINK_SETTINGS.particles,
|
|
3548
3856
|
},
|
|
3549
3857
|
{
|
|
3550
|
-
id: "
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3858
|
+
id: "particleSpeedByDistance",
|
|
3859
|
+
initialValue: LINK_SETTINGS.particleSpeedByDistance,
|
|
3860
|
+
max: 500,
|
|
3861
|
+
min: 1,
|
|
3862
|
+
step: 1,
|
|
3863
|
+
type: "range",
|
|
3864
|
+
label: "Скорость частицы на один пиксель",
|
|
3554
3865
|
},
|
|
3555
3866
|
{
|
|
3556
|
-
id: "
|
|
3557
|
-
initialValue: LINK_SETTINGS.
|
|
3558
|
-
max:
|
|
3559
|
-
min:
|
|
3560
|
-
step:
|
|
3867
|
+
id: "particleCountByDistance",
|
|
3868
|
+
initialValue: LINK_SETTINGS.particleCountByDistance,
|
|
3869
|
+
max: 250,
|
|
3870
|
+
min: 1,
|
|
3871
|
+
step: 1,
|
|
3561
3872
|
type: "range",
|
|
3562
|
-
label: "
|
|
3873
|
+
label: "Количество пикселей для появления частицы",
|
|
3563
3874
|
},
|
|
3564
3875
|
];
|
|
3565
3876
|
const LINK_OPTIONS_LINK_CONTROLS = [
|
|
@@ -3654,24 +3965,6 @@ const LINK_OPTIONS_PARTICLE_CONTROLS = [
|
|
|
3654
3965
|
label: "Радиус",
|
|
3655
3966
|
initialValue: LINK_OPTIONS.particleRadius,
|
|
3656
3967
|
},
|
|
3657
|
-
{
|
|
3658
|
-
id: "particleCount",
|
|
3659
|
-
type: "range",
|
|
3660
|
-
max: 20,
|
|
3661
|
-
min: 1,
|
|
3662
|
-
step: 1,
|
|
3663
|
-
label: "Количество",
|
|
3664
|
-
initialValue: LINK_OPTIONS.particleCount,
|
|
3665
|
-
},
|
|
3666
|
-
{
|
|
3667
|
-
id: "particleSteps",
|
|
3668
|
-
type: "range",
|
|
3669
|
-
max: 200,
|
|
3670
|
-
min: 1,
|
|
3671
|
-
step: 1,
|
|
3672
|
-
label: "Количество кадров",
|
|
3673
|
-
initialValue: LINK_OPTIONS.particleSteps,
|
|
3674
|
-
},
|
|
3675
3968
|
{
|
|
3676
3969
|
id: "particleBorderColor",
|
|
3677
3970
|
type: "color",
|
|
@@ -4105,10 +4398,19 @@ exports.NODE_OPTIONS_NODE_CONTROLS = NODE_OPTIONS_NODE_CONTROLS;
|
|
|
4105
4398
|
exports.NODE_OPTIONS_TEXT_CONTROLS = NODE_OPTIONS_TEXT_CONTROLS;
|
|
4106
4399
|
exports.NODE_SETTINGS = NODE_SETTINGS;
|
|
4107
4400
|
exports.NODE_SETTINGS_CONTROLS = NODE_SETTINGS_CONTROLS;
|
|
4401
|
+
exports.PERFOMANCE_NODE_OPTIONS = PERFOMANCE_NODE_OPTIONS;
|
|
4402
|
+
exports.PERFORMANCE_FORCE_SETTINGS = PERFORMANCE_FORCE_SETTINGS;
|
|
4403
|
+
exports.PERFORMANCE_GRAPH_SETTINGS = PERFORMANCE_GRAPH_SETTINGS;
|
|
4404
|
+
exports.PERFORMANCE_HIGHLIGHT_SETTINGS = PERFORMANCE_HIGHLIGHT_SETTINGS;
|
|
4405
|
+
exports.PERFORMANCE_LINK_OPTIONS = PERFORMANCE_LINK_OPTIONS;
|
|
4406
|
+
exports.PERFORMANCE_LINK_SETTINGS = PERFORMANCE_LINK_SETTINGS;
|
|
4407
|
+
exports.PERFORMANCE_NODE_SETTINGS = PERFORMANCE_NODE_SETTINGS;
|
|
4108
4408
|
exports.animationByProgress = animationByProgress;
|
|
4409
|
+
exports.approximateQuadraticBezierLength = approximateQuadraticBezierLength;
|
|
4109
4410
|
exports.calculateLinkPositionByNode = calculateLinkPositionByNode;
|
|
4110
4411
|
exports.colorGetter = colorGetter;
|
|
4111
4412
|
exports.colorToRgb = colorToRgb;
|
|
4413
|
+
exports.computeGraphBounds = computeGraphBounds;
|
|
4112
4414
|
exports.dragPlaceCoefficientGetter = dragPlaceCoefficientGetter;
|
|
4113
4415
|
exports.drawText = drawText;
|
|
4114
4416
|
exports.extractLinkPointIds = extractLinkPointIds;
|
|
@@ -4120,6 +4422,7 @@ exports.getDrawNode = getDrawNode;
|
|
|
4120
4422
|
exports.getParticlePosition = getParticlePosition;
|
|
4121
4423
|
exports.graphSettingsGetter = graphSettingsGetter;
|
|
4122
4424
|
exports.highlightSettingsGetter = highlightSettingsGetter;
|
|
4425
|
+
exports.isEmptyObject = isEmptyObject;
|
|
4123
4426
|
exports.isNodeVisible = isNodeVisible;
|
|
4124
4427
|
exports.isOverlapsNode = isOverlapsNode;
|
|
4125
4428
|
exports.linkByPointerGetter = linkByPointerGetter;
|