@krainovsd/graph 0.6.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/index.cjs +1098 -253
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/esm/index.js +3 -0
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/lib/draw-time.js +25 -0
- package/lib/esm/lib/draw-time.js.map +1 -0
- package/lib/esm/lib/get-controls-info.js +541 -0
- package/lib/esm/lib/get-controls-info.js.map +1 -0
- package/lib/esm/module/GraphCanvas/GraphCanvas.js +365 -155
- package/lib/esm/module/GraphCanvas/GraphCanvas.js.map +1 -1
- package/lib/esm/module/GraphCanvas/constants/settings.js +26 -7
- package/lib/esm/module/GraphCanvas/constants/settings.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/settings/link-settings-getter.js +9 -4
- 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 +10 -5
- package/lib/esm/module/GraphCanvas/lib/settings/node-settings-getter.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/utils/animation-by-progress.js +12 -0
- package/lib/esm/module/GraphCanvas/lib/utils/animation-by-progress.js.map +1 -0
- package/lib/esm/module/GraphCanvas/lib/utils/calculate-link-position-by-radius.js +2 -2
- package/lib/esm/module/GraphCanvas/lib/utils/calculate-link-position-by-radius.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/utils/get-particle-position.js +24 -0
- package/lib/esm/module/GraphCanvas/lib/utils/get-particle-position.js.map +1 -0
- package/lib/esm/module/GraphCanvas/lib/utils/is-node-visible.js +14 -0
- package/lib/esm/module/GraphCanvas/lib/utils/is-node-visible.js.map +1 -0
- package/lib/esm/module/GraphCanvas/lib/utils/link-iteration-extractor.js +1 -0
- package/lib/esm/module/GraphCanvas/lib/utils/link-iteration-extractor.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/utils/node-iteration-extractor.js +1 -0
- package/lib/esm/module/GraphCanvas/lib/utils/node-iteration-extractor.js.map +1 -1
- package/lib/index.d.ts +84 -9
- package/package.json +4 -2
package/lib/cjs/index.cjs
CHANGED
|
@@ -87,95 +87,6 @@ function rgbAnimationByProgress(start, end, progress) {
|
|
|
87
87
|
};
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
const FORCE_SETTINGS = {
|
|
91
|
-
centerPosition: {},
|
|
92
|
-
centerStrength: 1,
|
|
93
|
-
collideStrength: 0.1,
|
|
94
|
-
collideAdditionalRadius: 4,
|
|
95
|
-
collideIterations: 2,
|
|
96
|
-
collideOffMax: { links: 0, nodes: 0 },
|
|
97
|
-
collideOn: true,
|
|
98
|
-
chargeStrength: -40,
|
|
99
|
-
chargeDistanceMax: Infinity,
|
|
100
|
-
chargeDistanceMin: 1,
|
|
101
|
-
xForce: 0,
|
|
102
|
-
xStrength: 0.1,
|
|
103
|
-
yForce: 0,
|
|
104
|
-
yStrength: 0.1,
|
|
105
|
-
linkDistance: 30,
|
|
106
|
-
linkIterations: 1,
|
|
107
|
-
linkStrength: 1,
|
|
108
|
-
collideRadius: null,
|
|
109
|
-
};
|
|
110
|
-
const GRAPH_SETTINGS = {
|
|
111
|
-
zoomExtent: [0.1, 20],
|
|
112
|
-
translateExtent: [[], []],
|
|
113
|
-
translateExtentEnable: true,
|
|
114
|
-
translateExtentCoefficient: [1.2, 1.1],
|
|
115
|
-
highlightSizingAdditional: 0.5,
|
|
116
|
-
highlightColorFadingMin: 0.15,
|
|
117
|
-
highlightTextShiftXAdditional: 0,
|
|
118
|
-
highlightTextShiftYAdditional: 2,
|
|
119
|
-
highlightTextSizingAdditional: 1,
|
|
120
|
-
highlightTextWeightAdditional: 0,
|
|
121
|
-
highlightTextWidthAdditional: 10,
|
|
122
|
-
highlightOnlyRoot: true,
|
|
123
|
-
stickAfterDrag: false,
|
|
124
|
-
highlightByHover: false,
|
|
125
|
-
highlightLinkFadingMin: 0.21,
|
|
126
|
-
highlightFadingMin: 0.21,
|
|
127
|
-
highlightTextFadingMin: 0.21,
|
|
128
|
-
highlightDownStep: 0.2,
|
|
129
|
-
highlightUpStep: 0.2,
|
|
130
|
-
dragPlaceCoefficient: dragPlaceCoefficientGetter,
|
|
131
|
-
nodeRadiusInitial: 4,
|
|
132
|
-
nodeRadiusCoefficient: 5,
|
|
133
|
-
nodeRadiusFactor: 1,
|
|
134
|
-
nodeRadiusFlexible: true,
|
|
135
|
-
zoomInitial: null,
|
|
136
|
-
};
|
|
137
|
-
const NODE_SETTINGS = {
|
|
138
|
-
alpha: 1,
|
|
139
|
-
textAlpha: 1,
|
|
140
|
-
borderColor: "#000000FF",
|
|
141
|
-
borderWidth: 0.1,
|
|
142
|
-
textWidth: 20,
|
|
143
|
-
textShiftX: 0,
|
|
144
|
-
textFont: "Arial",
|
|
145
|
-
textAlign: "center",
|
|
146
|
-
textColor: "#333",
|
|
147
|
-
width: 1,
|
|
148
|
-
radius: 4,
|
|
149
|
-
textStyle: "normal",
|
|
150
|
-
textWeight: 500,
|
|
151
|
-
textGap: 1,
|
|
152
|
-
highlightFading: false,
|
|
153
|
-
highlightColor: true,
|
|
154
|
-
highlightSizing: true,
|
|
155
|
-
highlightTextFading: true,
|
|
156
|
-
highlightTextSizing: true,
|
|
157
|
-
};
|
|
158
|
-
const LINK_SETTINGS = {
|
|
159
|
-
alpha: 1,
|
|
160
|
-
highlightFading: true,
|
|
161
|
-
pretty: true,
|
|
162
|
-
};
|
|
163
|
-
const COMMON_SETTINGS = {
|
|
164
|
-
linkColorZoomFar: "#999",
|
|
165
|
-
linkColorZoomNear: "#000000FF",
|
|
166
|
-
linkWidthZoomFar: 1,
|
|
167
|
-
linkWidthZoomNear: 0.1,
|
|
168
|
-
linkWidthZoomBorder: 1,
|
|
169
|
-
linkColorZoomBorder: 1,
|
|
170
|
-
nodeTextScaleMin: 1.5,
|
|
171
|
-
nodeTextScaleMax: 20,
|
|
172
|
-
nodeTextSizeMin: 1.5,
|
|
173
|
-
nodeTextSizeMax: 3.5,
|
|
174
|
-
nodeTextShiftYMin: 2.5,
|
|
175
|
-
nodeTextShiftYMax: 4,
|
|
176
|
-
nodeTextChangeStepCount: 200,
|
|
177
|
-
};
|
|
178
|
-
|
|
179
90
|
function forceSettingsGetter(settings, prevSettings) {
|
|
180
91
|
return {
|
|
181
92
|
...(prevSettings ?? FORCE_SETTINGS),
|
|
@@ -190,15 +101,20 @@ function graphSettingsGetter(settings, prevSettings) {
|
|
|
190
101
|
};
|
|
191
102
|
}
|
|
192
103
|
|
|
193
|
-
function linkSettingsGetter(settings) {
|
|
194
|
-
return {
|
|
104
|
+
function linkSettingsGetter(settings, prevSettings) {
|
|
105
|
+
return { ...(prevSettings ?? LINK_SETTINGS), ...settings };
|
|
195
106
|
}
|
|
196
107
|
function linkOptionsGetter(_, __, ___, state) {
|
|
197
108
|
return {
|
|
198
|
-
...
|
|
109
|
+
...LINK_OPTIONS,
|
|
110
|
+
drawExtraLink: null,
|
|
111
|
+
drawLink: null,
|
|
199
112
|
color: state?.areaTransform && state?.areaTransform.k > COMMON_SETTINGS.linkColorZoomBorder
|
|
200
113
|
? COMMON_SETTINGS.linkColorZoomNear
|
|
201
114
|
: COMMON_SETTINGS.linkColorZoomFar,
|
|
115
|
+
arrowColor: state?.areaTransform && state?.areaTransform.k > COMMON_SETTINGS.linkColorZoomBorder
|
|
116
|
+
? COMMON_SETTINGS.linkColorZoomNear
|
|
117
|
+
: COMMON_SETTINGS.linkColorZoomFar,
|
|
202
118
|
width: state?.areaTransform && state?.areaTransform.k > COMMON_SETTINGS.linkWidthZoomBorder
|
|
203
119
|
? COMMON_SETTINGS.linkWidthZoomNear
|
|
204
120
|
: COMMON_SETTINGS.linkWidthZoomFar,
|
|
@@ -209,17 +125,22 @@ function listenersGetter(settings) {
|
|
|
209
125
|
return settings ?? {};
|
|
210
126
|
}
|
|
211
127
|
|
|
212
|
-
function nodeSettingsGetter(settings) {
|
|
128
|
+
function nodeSettingsGetter(settings, prevNodeSettings) {
|
|
213
129
|
return {
|
|
214
|
-
|
|
215
|
-
|
|
130
|
+
...(prevNodeSettings ?? NODE_SETTINGS),
|
|
131
|
+
idGetter: nodeIdGetter,
|
|
132
|
+
...settings,
|
|
216
133
|
};
|
|
217
134
|
}
|
|
218
135
|
const color = colorGetter();
|
|
219
136
|
function nodeOptionsGetter(node, _, __, state) {
|
|
220
137
|
const { textShiftY, textSize } = nodeTextSizeGetter(state?.areaTransform);
|
|
221
138
|
return {
|
|
222
|
-
...
|
|
139
|
+
...NODE_OPTIONS,
|
|
140
|
+
nodeDraw: null,
|
|
141
|
+
nodeExtraDraw: null,
|
|
142
|
+
textDraw: null,
|
|
143
|
+
textExtraDraw: null,
|
|
223
144
|
color: color(String(node.group ?? "_DEFAULT")),
|
|
224
145
|
textVisible: Boolean(state?.areaTransform && state.areaTransform.k > COMMON_SETTINGS.nodeTextScaleMin),
|
|
225
146
|
text: node.name ?? node.id.toString(),
|
|
@@ -404,7 +325,7 @@ function drawText({ context, id, textAlign, textColor, textFont, textStyle, text
|
|
|
404
325
|
});
|
|
405
326
|
}
|
|
406
327
|
|
|
407
|
-
function calculateLinkPositionByRadius(link) {
|
|
328
|
+
function calculateLinkPositionByRadius(link, arrowSize = 0) {
|
|
408
329
|
const source = link.source;
|
|
409
330
|
const target = link.target;
|
|
410
331
|
if (typeof source != "object" || typeof target != "object")
|
|
@@ -413,7 +334,7 @@ function calculateLinkPositionByRadius(link) {
|
|
|
413
334
|
const dy = (target.y ?? 0) - (source.y ?? 0);
|
|
414
335
|
const dr = Math.sqrt(dx * dx + dy * dy);
|
|
415
336
|
const sourceRadius = source._radius ?? 0;
|
|
416
|
-
const targetRadius = target._radius ?? 0;
|
|
337
|
+
const targetRadius = (target._radius ?? 0) + (arrowSize > 0 ? arrowSize * 0.85 : 0);
|
|
417
338
|
return {
|
|
418
339
|
x1: (source.x ?? 0) + (dx * sourceRadius) / dr,
|
|
419
340
|
y1: (source.y ?? 0) + (dy * sourceRadius) / dr,
|
|
@@ -422,10 +343,723 @@ function calculateLinkPositionByRadius(link) {
|
|
|
422
343
|
};
|
|
423
344
|
}
|
|
424
345
|
|
|
346
|
+
function animationByProgress(initial, additional, progress) {
|
|
347
|
+
const max = initial + additional;
|
|
348
|
+
let current = initial + (max - initial) * progress;
|
|
349
|
+
if (current > max)
|
|
350
|
+
current = max;
|
|
351
|
+
if (current < initial)
|
|
352
|
+
current = initial;
|
|
353
|
+
return current;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const ADDITIONAL_VIEWPORT = 10;
|
|
357
|
+
function isNodeVisible(opts) {
|
|
358
|
+
const left = -opts.transform.x / opts.transform.k;
|
|
359
|
+
const right = (opts.width - opts.transform.x) / opts.transform.k;
|
|
360
|
+
const top = -opts.transform.y / opts.transform.k;
|
|
361
|
+
const bottom = (opts.height - opts.transform.y) / opts.transform.k;
|
|
362
|
+
return (left < opts.x + opts.radius + ADDITIONAL_VIEWPORT &&
|
|
363
|
+
opts.x - opts.radius - ADDITIONAL_VIEWPORT < right &&
|
|
364
|
+
top < opts.y + opts.radius + ADDITIONAL_VIEWPORT &&
|
|
365
|
+
opts.y - opts.radius - ADDITIONAL_VIEWPORT < bottom);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function getParticlePosition(opts) {
|
|
369
|
+
if (opts.particle.wait > 0) {
|
|
370
|
+
opts.particle.wait--;
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
const remainingSteps = opts.totalSteps - opts.particle.step;
|
|
374
|
+
const progress = opts.particle.step / opts.totalSteps;
|
|
375
|
+
if (remainingSteps === 0) {
|
|
376
|
+
opts.particle.x = opts.xEnd;
|
|
377
|
+
opts.particle.y = opts.yEnd;
|
|
378
|
+
opts.particle.step = 0;
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
const dx = opts.xEnd - opts.xStart;
|
|
382
|
+
const dy = opts.yEnd - opts.yStart;
|
|
383
|
+
const newX = opts.xStart + dx * progress;
|
|
384
|
+
const newY = opts.yStart + dy * progress;
|
|
385
|
+
opts.particle.x = newX;
|
|
386
|
+
opts.particle.y = newY;
|
|
387
|
+
opts.particle.step++;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const FORCE_SETTINGS = {
|
|
391
|
+
centerPosition: {},
|
|
392
|
+
centerStrength: 1,
|
|
393
|
+
collideStrength: 0.1,
|
|
394
|
+
collideAdditionalRadius: 4,
|
|
395
|
+
collideIterations: 2,
|
|
396
|
+
collideOffMax: { links: 0, nodes: 0 },
|
|
397
|
+
collideOn: true,
|
|
398
|
+
chargeStrength: -40,
|
|
399
|
+
chargeDistanceMax: Infinity,
|
|
400
|
+
chargeDistanceMin: 1,
|
|
401
|
+
xForce: 0,
|
|
402
|
+
xStrength: 0.1,
|
|
403
|
+
yForce: 0,
|
|
404
|
+
yStrength: 0.1,
|
|
405
|
+
linkDistance: 30,
|
|
406
|
+
linkIterations: 1,
|
|
407
|
+
linkStrength: 1,
|
|
408
|
+
collideRadius: null,
|
|
409
|
+
};
|
|
410
|
+
const GRAPH_SETTINGS = {
|
|
411
|
+
zoomExtent: [0.3, 10],
|
|
412
|
+
translateExtent: [[], []],
|
|
413
|
+
translateExtentEnable: true,
|
|
414
|
+
translateExtentCoefficient: [3, 3],
|
|
415
|
+
highlightSizingAdditional: 0.5,
|
|
416
|
+
highlightColorFadingMin: 0.15,
|
|
417
|
+
highlightTextShiftXAdditional: 0,
|
|
418
|
+
highlightTextShiftYAdditional: 2,
|
|
419
|
+
highlightTextSizingAdditional: 1,
|
|
420
|
+
highlightTextWeightAdditional: 0,
|
|
421
|
+
highlightTextWidthAdditional: 10,
|
|
422
|
+
highlightOnlyRoot: true,
|
|
423
|
+
stickAfterDrag: false,
|
|
424
|
+
highlightByHover: true,
|
|
425
|
+
highlightLinkFadingMin: 0.21,
|
|
426
|
+
highlightFadingMin: 0.21,
|
|
427
|
+
highlightTextFadingMin: 0.21,
|
|
428
|
+
highlightArrowFadingMin: 0.21,
|
|
429
|
+
highlightDownStep: 0.2,
|
|
430
|
+
highlightUpStep: 0.2,
|
|
431
|
+
dragPlaceCoefficient: dragPlaceCoefficientGetter,
|
|
432
|
+
nodeRadiusInitial: 4,
|
|
433
|
+
nodeRadiusCoefficient: 5,
|
|
434
|
+
nodeRadiusFactor: 1,
|
|
435
|
+
nodeRadiusFlexible: true,
|
|
436
|
+
zoomInitial: null,
|
|
437
|
+
showDrawTime: true,
|
|
438
|
+
showDrawTimeEveryTick: false,
|
|
439
|
+
};
|
|
440
|
+
const NODE_SETTINGS = {
|
|
441
|
+
cache: false,
|
|
442
|
+
};
|
|
443
|
+
const NODE_OPTIONS = {
|
|
444
|
+
alpha: 1,
|
|
445
|
+
textAlpha: 1,
|
|
446
|
+
borderColor: "#000000FF",
|
|
447
|
+
borderWidth: 0.1,
|
|
448
|
+
textWidth: 20,
|
|
449
|
+
textShiftX: 0,
|
|
450
|
+
textFont: "Arial",
|
|
451
|
+
textAlign: "center",
|
|
452
|
+
textColor: "#333",
|
|
453
|
+
radius: 4,
|
|
454
|
+
textStyle: "normal",
|
|
455
|
+
textWeight: 500,
|
|
456
|
+
textGap: 1,
|
|
457
|
+
highlightFading: true,
|
|
458
|
+
highlightColor: false,
|
|
459
|
+
highlightSizing: true,
|
|
460
|
+
highlightTextFading: true,
|
|
461
|
+
highlightTextSizing: true,
|
|
462
|
+
};
|
|
463
|
+
const LINK_SETTINGS = {
|
|
464
|
+
cache: false,
|
|
465
|
+
particles: true,
|
|
466
|
+
};
|
|
467
|
+
const LINK_OPTIONS = {
|
|
468
|
+
alpha: 1,
|
|
469
|
+
highlightFading: true,
|
|
470
|
+
pretty: true,
|
|
471
|
+
arrow: true,
|
|
472
|
+
arrowAlpha: 1,
|
|
473
|
+
arrowSize: 2,
|
|
474
|
+
arrowHighlightFading: true,
|
|
475
|
+
arrowReverseAppear: true,
|
|
476
|
+
particleAlpha: 1,
|
|
477
|
+
particleColor: "#000000FF",
|
|
478
|
+
particleCount: 2,
|
|
479
|
+
particleRadius: 0.5,
|
|
480
|
+
particleSteps: 60,
|
|
481
|
+
};
|
|
482
|
+
const COMMON_SETTINGS = {
|
|
483
|
+
linkColorZoomFar: "#999",
|
|
484
|
+
linkColorZoomNear: "#000000FF",
|
|
485
|
+
linkWidthZoomFar: 1,
|
|
486
|
+
linkWidthZoomNear: 0.1,
|
|
487
|
+
linkWidthZoomBorder: 1,
|
|
488
|
+
linkColorZoomBorder: 1,
|
|
489
|
+
nodeTextScaleMin: 1.5,
|
|
490
|
+
nodeTextScaleMax: 20,
|
|
491
|
+
nodeTextSizeMin: 1.5,
|
|
492
|
+
nodeTextSizeMax: 3.5,
|
|
493
|
+
nodeTextShiftYMin: 2.5,
|
|
494
|
+
nodeTextShiftYMax: 4,
|
|
495
|
+
nodeTextChangeStepCount: 200,
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
function getForceControls(keys) {
|
|
499
|
+
const FORCE_CONTROLS = [
|
|
500
|
+
{
|
|
501
|
+
id: "centerStrength",
|
|
502
|
+
initialValue: FORCE_SETTINGS.centerStrength,
|
|
503
|
+
label: "Граница центра",
|
|
504
|
+
max: 1,
|
|
505
|
+
min: 0,
|
|
506
|
+
step: 0.01,
|
|
507
|
+
type: "range",
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
id: "collideStrength",
|
|
511
|
+
initialValue: FORCE_SETTINGS.collideStrength,
|
|
512
|
+
label: "Сила отталкивания",
|
|
513
|
+
max: 1,
|
|
514
|
+
min: 0,
|
|
515
|
+
step: 0.01,
|
|
516
|
+
type: "range",
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
id: "collideAdditionalRadius",
|
|
520
|
+
initialValue: FORCE_SETTINGS.collideAdditionalRadius,
|
|
521
|
+
label: "Радиус отталкивания",
|
|
522
|
+
max: 300,
|
|
523
|
+
min: 0,
|
|
524
|
+
step: 0.1,
|
|
525
|
+
type: "range",
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
id: "collideIterations",
|
|
529
|
+
initialValue: FORCE_SETTINGS.collideIterations,
|
|
530
|
+
label: "Итерации отталкивания",
|
|
531
|
+
max: 10,
|
|
532
|
+
min: 0,
|
|
533
|
+
step: 1,
|
|
534
|
+
type: "range",
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
id: "chargeStrength",
|
|
538
|
+
initialValue: FORCE_SETTINGS.chargeStrength ,
|
|
539
|
+
label: "Гравитация",
|
|
540
|
+
max: 0,
|
|
541
|
+
min: -300,
|
|
542
|
+
step: 0.1,
|
|
543
|
+
type: "range",
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
type: "range",
|
|
547
|
+
id: "xForce",
|
|
548
|
+
min: 0,
|
|
549
|
+
max: 1,
|
|
550
|
+
step: 0.01,
|
|
551
|
+
label: "Граница X",
|
|
552
|
+
initialValue: FORCE_SETTINGS.xForce ,
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
type: "range",
|
|
556
|
+
id: "yForce",
|
|
557
|
+
min: 0,
|
|
558
|
+
max: 1,
|
|
559
|
+
step: 0.01,
|
|
560
|
+
label: "Граница Y",
|
|
561
|
+
initialValue: FORCE_SETTINGS.yForce ,
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
type: "range",
|
|
565
|
+
id: "xStrength",
|
|
566
|
+
min: 0,
|
|
567
|
+
max: 1,
|
|
568
|
+
step: 0.01,
|
|
569
|
+
label: "Гравитация X",
|
|
570
|
+
initialValue: FORCE_SETTINGS.xStrength ,
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
type: "range",
|
|
574
|
+
id: "yStrength",
|
|
575
|
+
min: 0,
|
|
576
|
+
max: 1,
|
|
577
|
+
step: 0.01,
|
|
578
|
+
label: "Гравитация Y",
|
|
579
|
+
initialValue: FORCE_SETTINGS.yStrength ,
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
type: "range",
|
|
583
|
+
id: "linkStrength",
|
|
584
|
+
min: 0,
|
|
585
|
+
max: 1,
|
|
586
|
+
step: 0.01,
|
|
587
|
+
label: "Натяжение связей",
|
|
588
|
+
initialValue: FORCE_SETTINGS.linkStrength ,
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
type: "range",
|
|
592
|
+
id: "linkDistance",
|
|
593
|
+
min: 0,
|
|
594
|
+
max: 300,
|
|
595
|
+
step: 0.1,
|
|
596
|
+
label: "Расстояние связей",
|
|
597
|
+
initialValue: FORCE_SETTINGS.linkDistance ,
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
id: "collideOn",
|
|
601
|
+
type: "checkbox",
|
|
602
|
+
initialValue: FORCE_SETTINGS.collideOn,
|
|
603
|
+
label: "Отталкивание",
|
|
604
|
+
},
|
|
605
|
+
];
|
|
606
|
+
return keys ? FORCE_CONTROLS.filter((control) => keys.includes(control.id)) : FORCE_CONTROLS;
|
|
607
|
+
}
|
|
608
|
+
function getGraphControls(keys) {
|
|
609
|
+
const GRAPH_CONTROLS = [
|
|
610
|
+
{
|
|
611
|
+
id: "highlightSizingAdditional",
|
|
612
|
+
initialValue: GRAPH_SETTINGS.highlightSizingAdditional,
|
|
613
|
+
max: 10,
|
|
614
|
+
min: 0.1,
|
|
615
|
+
step: 0.01,
|
|
616
|
+
type: "range",
|
|
617
|
+
label: "Дополнительный размер при анимации",
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
id: "highlightColorFadingMin",
|
|
621
|
+
initialValue: GRAPH_SETTINGS.highlightColorFadingMin,
|
|
622
|
+
max: 1,
|
|
623
|
+
min: 0.01,
|
|
624
|
+
step: 0.01,
|
|
625
|
+
type: "range",
|
|
626
|
+
label: "Граница затухания цвета",
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
id: "highlightTextShiftXAdditional",
|
|
630
|
+
initialValue: GRAPH_SETTINGS.highlightTextShiftXAdditional,
|
|
631
|
+
max: 50,
|
|
632
|
+
min: 0,
|
|
633
|
+
step: 0.1,
|
|
634
|
+
type: "range",
|
|
635
|
+
label: "Смещение текста по X при анимации",
|
|
636
|
+
},
|
|
637
|
+
{
|
|
638
|
+
id: "highlightTextShiftYAdditional",
|
|
639
|
+
initialValue: GRAPH_SETTINGS.highlightTextShiftYAdditional,
|
|
640
|
+
max: 50,
|
|
641
|
+
min: 0,
|
|
642
|
+
step: 0.1,
|
|
643
|
+
type: "range",
|
|
644
|
+
label: "Смещение текста по Y при анимации",
|
|
645
|
+
},
|
|
646
|
+
{
|
|
647
|
+
id: "highlightTextSizingAdditional",
|
|
648
|
+
initialValue: GRAPH_SETTINGS.highlightTextSizingAdditional,
|
|
649
|
+
max: 10,
|
|
650
|
+
min: 0.1,
|
|
651
|
+
step: 0.1,
|
|
652
|
+
type: "range",
|
|
653
|
+
label: "Увеличение текста при анимации",
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
id: "highlightTextWeightAdditional",
|
|
657
|
+
initialValue: GRAPH_SETTINGS.highlightTextWeightAdditional,
|
|
658
|
+
max: 1000,
|
|
659
|
+
min: 0,
|
|
660
|
+
step: 100,
|
|
661
|
+
type: "range",
|
|
662
|
+
label: "Увеличение жирности текста при анимации",
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
id: "highlightTextWidthAdditional",
|
|
666
|
+
initialValue: GRAPH_SETTINGS.highlightTextWidthAdditional,
|
|
667
|
+
max: 100,
|
|
668
|
+
min: 0,
|
|
669
|
+
step: 0.1,
|
|
670
|
+
type: "range",
|
|
671
|
+
label: "Увеличение ширины текста при анимации",
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
id: "highlightTextFadingMin",
|
|
675
|
+
initialValue: GRAPH_SETTINGS.highlightTextFadingMin,
|
|
676
|
+
max: 1,
|
|
677
|
+
min: 0,
|
|
678
|
+
step: 0.01,
|
|
679
|
+
type: "range",
|
|
680
|
+
label: "Граница затухания текста при анимации",
|
|
681
|
+
},
|
|
682
|
+
{
|
|
683
|
+
id: "highlightLinkFadingMin",
|
|
684
|
+
initialValue: GRAPH_SETTINGS.highlightLinkFadingMin,
|
|
685
|
+
max: 1,
|
|
686
|
+
min: 0,
|
|
687
|
+
step: 0.01,
|
|
688
|
+
type: "range",
|
|
689
|
+
label: "Граница затухания связи при анимации",
|
|
690
|
+
},
|
|
691
|
+
{
|
|
692
|
+
id: "highlightFadingMin",
|
|
693
|
+
initialValue: GRAPH_SETTINGS.highlightFadingMin,
|
|
694
|
+
max: 1,
|
|
695
|
+
min: 0,
|
|
696
|
+
step: 0.01,
|
|
697
|
+
type: "range",
|
|
698
|
+
label: "Граница затухания ноды при анимации",
|
|
699
|
+
},
|
|
700
|
+
{
|
|
701
|
+
id: "highlightArrowFadingMin",
|
|
702
|
+
initialValue: GRAPH_SETTINGS.highlightArrowFadingMin,
|
|
703
|
+
max: 1,
|
|
704
|
+
min: 0,
|
|
705
|
+
step: 0.01,
|
|
706
|
+
type: "range",
|
|
707
|
+
label: "Граница затухания стрелки при анимации",
|
|
708
|
+
},
|
|
709
|
+
{
|
|
710
|
+
id: "highlightDownStep",
|
|
711
|
+
initialValue: GRAPH_SETTINGS.highlightDownStep,
|
|
712
|
+
max: 1,
|
|
713
|
+
min: 0.01,
|
|
714
|
+
step: 0.01,
|
|
715
|
+
type: "range",
|
|
716
|
+
label: "Скорость отмены анимации",
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
id: "highlightUpStep",
|
|
720
|
+
initialValue: GRAPH_SETTINGS.highlightUpStep,
|
|
721
|
+
max: 1,
|
|
722
|
+
min: 0.01,
|
|
723
|
+
step: 0.01,
|
|
724
|
+
type: "range",
|
|
725
|
+
label: "Скорость применения анимации",
|
|
726
|
+
},
|
|
727
|
+
{
|
|
728
|
+
id: "nodeRadiusInitial",
|
|
729
|
+
initialValue: GRAPH_SETTINGS.nodeRadiusInitial,
|
|
730
|
+
max: 50,
|
|
731
|
+
min: 0.1,
|
|
732
|
+
step: 0.1,
|
|
733
|
+
type: "range",
|
|
734
|
+
label: "Изначальный радиус ноды",
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
id: "nodeRadiusCoefficient",
|
|
738
|
+
initialValue: GRAPH_SETTINGS.nodeRadiusCoefficient,
|
|
739
|
+
max: 100,
|
|
740
|
+
min: 0.1,
|
|
741
|
+
step: 0.1,
|
|
742
|
+
type: "range",
|
|
743
|
+
label: "Количество связей для увеличения радиуса",
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
id: "nodeRadiusFactor",
|
|
747
|
+
initialValue: GRAPH_SETTINGS.nodeRadiusFactor,
|
|
748
|
+
max: 50,
|
|
749
|
+
min: 0.1,
|
|
750
|
+
step: 0.1,
|
|
751
|
+
type: "range",
|
|
752
|
+
label: "Коэффициент увеличения радиуса",
|
|
753
|
+
},
|
|
754
|
+
{
|
|
755
|
+
id: "highlightOnlyRoot",
|
|
756
|
+
type: "checkbox",
|
|
757
|
+
initialValue: GRAPH_SETTINGS.highlightOnlyRoot,
|
|
758
|
+
label: "Дополнительная анимация только главное цели",
|
|
759
|
+
},
|
|
760
|
+
{
|
|
761
|
+
id: "stickAfterDrag",
|
|
762
|
+
type: "checkbox",
|
|
763
|
+
initialValue: GRAPH_SETTINGS.stickAfterDrag,
|
|
764
|
+
label: "Фиксировании ноды после перетаскивания",
|
|
765
|
+
},
|
|
766
|
+
{
|
|
767
|
+
id: "highlightByHover",
|
|
768
|
+
type: "checkbox",
|
|
769
|
+
initialValue: GRAPH_SETTINGS.highlightByHover,
|
|
770
|
+
label: "Анимации при наведении",
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
id: "nodeRadiusFlexible",
|
|
774
|
+
type: "checkbox",
|
|
775
|
+
initialValue: GRAPH_SETTINGS.nodeRadiusFlexible,
|
|
776
|
+
label: "Гибкий радиус ноды",
|
|
777
|
+
},
|
|
778
|
+
];
|
|
779
|
+
return keys ? GRAPH_CONTROLS.filter((control) => keys.includes(control.id)) : GRAPH_CONTROLS;
|
|
780
|
+
}
|
|
781
|
+
function getNodeControls(keys) {
|
|
782
|
+
const NODE_CONTROLS = [
|
|
783
|
+
{
|
|
784
|
+
id: "alpha",
|
|
785
|
+
type: "range",
|
|
786
|
+
max: 1,
|
|
787
|
+
min: 0,
|
|
788
|
+
step: 0.1,
|
|
789
|
+
label: "Прозрачность",
|
|
790
|
+
initialValue: NODE_OPTIONS.alpha,
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
id: "radius",
|
|
794
|
+
type: "range",
|
|
795
|
+
max: 50,
|
|
796
|
+
min: 1,
|
|
797
|
+
step: 1,
|
|
798
|
+
label: "Радиус",
|
|
799
|
+
initialValue: NODE_OPTIONS.radius,
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
id: "borderWidth",
|
|
803
|
+
type: "range",
|
|
804
|
+
max: 5,
|
|
805
|
+
min: 0,
|
|
806
|
+
step: 0.1,
|
|
807
|
+
label: "Толщина границы",
|
|
808
|
+
initialValue: NODE_OPTIONS.borderWidth,
|
|
809
|
+
},
|
|
810
|
+
{
|
|
811
|
+
id: "borderColor",
|
|
812
|
+
type: "color",
|
|
813
|
+
initialValue: "#000000FF",
|
|
814
|
+
label: "Цвет границы",
|
|
815
|
+
},
|
|
816
|
+
{
|
|
817
|
+
id: "color",
|
|
818
|
+
type: "color",
|
|
819
|
+
initialValue: "#000000FF",
|
|
820
|
+
label: "Цвет",
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
id: "textAlpha",
|
|
824
|
+
type: "range",
|
|
825
|
+
max: 1,
|
|
826
|
+
min: 0,
|
|
827
|
+
step: 0.1,
|
|
828
|
+
label: "Прозрачность текста",
|
|
829
|
+
initialValue: NODE_OPTIONS.textAlpha,
|
|
830
|
+
},
|
|
831
|
+
{
|
|
832
|
+
id: "textWidth",
|
|
833
|
+
type: "range",
|
|
834
|
+
max: 200,
|
|
835
|
+
min: 5,
|
|
836
|
+
step: 1,
|
|
837
|
+
label: "Ширина текста",
|
|
838
|
+
initialValue: NODE_OPTIONS.textWidth,
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
id: "textShiftX",
|
|
842
|
+
type: "range",
|
|
843
|
+
max: 100,
|
|
844
|
+
min: 0,
|
|
845
|
+
step: 0.1,
|
|
846
|
+
label: "Смещение X текста",
|
|
847
|
+
initialValue: NODE_OPTIONS.textShiftX,
|
|
848
|
+
},
|
|
849
|
+
{
|
|
850
|
+
id: "textShiftY",
|
|
851
|
+
type: "range",
|
|
852
|
+
max: 100,
|
|
853
|
+
min: 0,
|
|
854
|
+
step: 0.1,
|
|
855
|
+
label: "Смещение Y текста",
|
|
856
|
+
initialValue: 4,
|
|
857
|
+
},
|
|
858
|
+
{
|
|
859
|
+
id: "textWeight",
|
|
860
|
+
type: "range",
|
|
861
|
+
max: 1000,
|
|
862
|
+
min: 100,
|
|
863
|
+
step: 100,
|
|
864
|
+
label: "Жирность текста",
|
|
865
|
+
initialValue: NODE_OPTIONS.textWeight,
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
id: "textGap",
|
|
869
|
+
type: "range",
|
|
870
|
+
max: 30,
|
|
871
|
+
min: 0,
|
|
872
|
+
step: 0.1,
|
|
873
|
+
label: "Расстояние между строками",
|
|
874
|
+
initialValue: NODE_OPTIONS.textGap,
|
|
875
|
+
},
|
|
876
|
+
{
|
|
877
|
+
id: "highlightFading",
|
|
878
|
+
type: "checkbox",
|
|
879
|
+
initialValue: NODE_OPTIONS.highlightFading,
|
|
880
|
+
label: "Анимация затухания",
|
|
881
|
+
},
|
|
882
|
+
{
|
|
883
|
+
id: "highlightColor",
|
|
884
|
+
type: "checkbox",
|
|
885
|
+
initialValue: NODE_OPTIONS.highlightColor,
|
|
886
|
+
label: "Анимация затухания цвета",
|
|
887
|
+
},
|
|
888
|
+
{
|
|
889
|
+
id: "highlightSizing",
|
|
890
|
+
type: "checkbox",
|
|
891
|
+
initialValue: NODE_OPTIONS.highlightSizing,
|
|
892
|
+
label: "Анимация размера",
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
id: "highlightTextFading",
|
|
896
|
+
type: "checkbox",
|
|
897
|
+
initialValue: NODE_OPTIONS.highlightTextFading,
|
|
898
|
+
label: "Анимация затухания текста",
|
|
899
|
+
},
|
|
900
|
+
{
|
|
901
|
+
id: "highlightTextSizing",
|
|
902
|
+
type: "checkbox",
|
|
903
|
+
initialValue: NODE_OPTIONS.highlightTextSizing,
|
|
904
|
+
label: "Анимация размера текста",
|
|
905
|
+
},
|
|
906
|
+
];
|
|
907
|
+
return keys ? NODE_CONTROLS.filter((control) => keys.includes(control.id)) : NODE_CONTROLS;
|
|
908
|
+
}
|
|
909
|
+
function getLinkControls(keys) {
|
|
910
|
+
const LINK_CONTROLS = [
|
|
911
|
+
{
|
|
912
|
+
id: "alpha",
|
|
913
|
+
type: "range",
|
|
914
|
+
max: 1,
|
|
915
|
+
min: 0,
|
|
916
|
+
step: 0.1,
|
|
917
|
+
label: "Прозрачность",
|
|
918
|
+
initialValue: LINK_OPTIONS.alpha,
|
|
919
|
+
},
|
|
920
|
+
{
|
|
921
|
+
id: "width",
|
|
922
|
+
type: "range",
|
|
923
|
+
max: 10,
|
|
924
|
+
min: 0.1,
|
|
925
|
+
step: 0.1,
|
|
926
|
+
label: "Толщина",
|
|
927
|
+
initialValue: 0.1,
|
|
928
|
+
},
|
|
929
|
+
{
|
|
930
|
+
id: "arrowAlpha",
|
|
931
|
+
type: "range",
|
|
932
|
+
max: 1,
|
|
933
|
+
min: 0,
|
|
934
|
+
step: 0.1,
|
|
935
|
+
label: "Прозрачность стрелки",
|
|
936
|
+
initialValue: LINK_OPTIONS.arrowAlpha,
|
|
937
|
+
},
|
|
938
|
+
{
|
|
939
|
+
id: "arrowSize",
|
|
940
|
+
type: "range",
|
|
941
|
+
max: 10,
|
|
942
|
+
min: 0.1,
|
|
943
|
+
step: 0.1,
|
|
944
|
+
label: "Размер стрелки",
|
|
945
|
+
initialValue: LINK_OPTIONS.arrowSize,
|
|
946
|
+
},
|
|
947
|
+
{
|
|
948
|
+
id: "particleAlpha",
|
|
949
|
+
type: "range",
|
|
950
|
+
max: 1,
|
|
951
|
+
min: 0,
|
|
952
|
+
step: 0.1,
|
|
953
|
+
label: "Прозрачность частиц",
|
|
954
|
+
initialValue: LINK_OPTIONS.particleAlpha,
|
|
955
|
+
},
|
|
956
|
+
{
|
|
957
|
+
id: "particleRadius",
|
|
958
|
+
type: "range",
|
|
959
|
+
max: 10,
|
|
960
|
+
min: 0.1,
|
|
961
|
+
step: 0.1,
|
|
962
|
+
label: "Радиус частиц",
|
|
963
|
+
initialValue: LINK_OPTIONS.particleRadius,
|
|
964
|
+
},
|
|
965
|
+
{
|
|
966
|
+
id: "particleCount",
|
|
967
|
+
type: "range",
|
|
968
|
+
max: 20,
|
|
969
|
+
min: 1,
|
|
970
|
+
step: 1,
|
|
971
|
+
label: "Количество частиц",
|
|
972
|
+
initialValue: LINK_OPTIONS.particleCount,
|
|
973
|
+
},
|
|
974
|
+
{
|
|
975
|
+
id: "particleSteps",
|
|
976
|
+
type: "range",
|
|
977
|
+
max: 200,
|
|
978
|
+
min: 1,
|
|
979
|
+
step: 1,
|
|
980
|
+
label: "Количество кадров у частиц",
|
|
981
|
+
initialValue: LINK_OPTIONS.particleSteps,
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
id: "color",
|
|
985
|
+
type: "color",
|
|
986
|
+
initialValue: "#000000FF",
|
|
987
|
+
label: "Цвет",
|
|
988
|
+
},
|
|
989
|
+
{
|
|
990
|
+
id: "arrowColor",
|
|
991
|
+
type: "color",
|
|
992
|
+
initialValue: "#000000FF",
|
|
993
|
+
label: "Цвет стрелки",
|
|
994
|
+
},
|
|
995
|
+
{
|
|
996
|
+
id: "particleColor",
|
|
997
|
+
type: "color",
|
|
998
|
+
initialValue: "#000000FF",
|
|
999
|
+
label: "Цвет частиц",
|
|
1000
|
+
},
|
|
1001
|
+
{
|
|
1002
|
+
id: "highlightFading",
|
|
1003
|
+
type: "checkbox",
|
|
1004
|
+
label: "Анимация Затухания",
|
|
1005
|
+
initialValue: LINK_OPTIONS.highlightFading,
|
|
1006
|
+
},
|
|
1007
|
+
{
|
|
1008
|
+
id: "pretty",
|
|
1009
|
+
type: "checkbox",
|
|
1010
|
+
label: "Обсчет соединения",
|
|
1011
|
+
initialValue: LINK_OPTIONS.pretty,
|
|
1012
|
+
},
|
|
1013
|
+
{
|
|
1014
|
+
id: "arrow",
|
|
1015
|
+
type: "checkbox",
|
|
1016
|
+
label: "Стрелка",
|
|
1017
|
+
initialValue: LINK_OPTIONS.arrow,
|
|
1018
|
+
},
|
|
1019
|
+
{
|
|
1020
|
+
id: "arrowHighlightFading",
|
|
1021
|
+
type: "checkbox",
|
|
1022
|
+
label: "Анимация затухания стрелки",
|
|
1023
|
+
initialValue: LINK_OPTIONS.arrowHighlightFading,
|
|
1024
|
+
},
|
|
1025
|
+
{
|
|
1026
|
+
id: "arrowReverseAppear",
|
|
1027
|
+
type: "checkbox",
|
|
1028
|
+
label: "Появление стрелки при анимации",
|
|
1029
|
+
initialValue: LINK_OPTIONS.arrowReverseAppear,
|
|
1030
|
+
},
|
|
1031
|
+
];
|
|
1032
|
+
return keys ? LINK_CONTROLS.filter((control) => keys.includes(control.id)) : LINK_CONTROLS;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
let countTime = 0;
|
|
1036
|
+
let countOperation = 0;
|
|
1037
|
+
function setDrawTime(cb, showEveryTick) {
|
|
1038
|
+
return () => {
|
|
1039
|
+
const start = performance.now();
|
|
1040
|
+
cb();
|
|
1041
|
+
const end = performance.now();
|
|
1042
|
+
const result = end - start;
|
|
1043
|
+
countTime += result;
|
|
1044
|
+
countOperation++;
|
|
1045
|
+
if (showEveryTick) {
|
|
1046
|
+
const average = countTime / countOperation;
|
|
1047
|
+
// eslint-disable-next-line no-console
|
|
1048
|
+
console.log("average draw: ", average, "current draw: ", result);
|
|
1049
|
+
}
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
function getDrawTime() {
|
|
1053
|
+
const average = countTime / countOperation;
|
|
1054
|
+
// eslint-disable-next-line no-console
|
|
1055
|
+
console.log("average draw: ", average);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
425
1058
|
class GraphCanvas {
|
|
426
1059
|
/** initial data */
|
|
427
1060
|
nodes;
|
|
428
1061
|
links;
|
|
1062
|
+
particles = {};
|
|
429
1063
|
width;
|
|
430
1064
|
height;
|
|
431
1065
|
root;
|
|
@@ -445,6 +1079,8 @@ class GraphCanvas {
|
|
|
445
1079
|
draw;
|
|
446
1080
|
eventAbortController;
|
|
447
1081
|
cachedNodeText = {};
|
|
1082
|
+
linkOptionsCache = {};
|
|
1083
|
+
nodeOptionsCache = {};
|
|
448
1084
|
isDragging = false;
|
|
449
1085
|
highlightedNode = null;
|
|
450
1086
|
highlightedNeighbors = null;
|
|
@@ -517,20 +1153,35 @@ class GraphCanvas {
|
|
|
517
1153
|
this.updateData(alpha);
|
|
518
1154
|
}
|
|
519
1155
|
changeSettings(options) {
|
|
520
|
-
if (options.graphSettings)
|
|
1156
|
+
if (options.graphSettings) {
|
|
521
1157
|
this.graphSettings = graphSettingsGetter(options.graphSettings, this.graphSettings);
|
|
522
|
-
|
|
1158
|
+
this.draw = this.initDraw();
|
|
1159
|
+
this.initZoom(this.areaTransform);
|
|
1160
|
+
}
|
|
1161
|
+
if (options.forceSettings) {
|
|
523
1162
|
this.forceSettings = forceSettingsGetter(options.forceSettings, this.forceSettings);
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
this.
|
|
528
|
-
|
|
1163
|
+
}
|
|
1164
|
+
if (options.linkSettings) {
|
|
1165
|
+
this.linkSettings = linkSettingsGetter(options.linkSettings, this.linkSettings);
|
|
1166
|
+
this.linkOptionsCache = {};
|
|
1167
|
+
}
|
|
1168
|
+
if (options.nodeSettings) {
|
|
1169
|
+
this.nodeSettings = nodeSettingsGetter(options.nodeSettings, this.nodeSettings);
|
|
1170
|
+
this.cachedNodeText = {};
|
|
1171
|
+
this.nodeOptionsCache = {};
|
|
1172
|
+
}
|
|
1173
|
+
if (options.forceSettings) {
|
|
529
1174
|
return void this.updateSimulation();
|
|
1175
|
+
}
|
|
530
1176
|
this.tick();
|
|
531
1177
|
}
|
|
1178
|
+
clearCache() {
|
|
1179
|
+
this.nodeOptionsCache = {};
|
|
1180
|
+
this.linkOptionsCache = {};
|
|
1181
|
+
this.cachedNodeText = {};
|
|
1182
|
+
}
|
|
532
1183
|
tick() {
|
|
533
|
-
if (!this.simulationWorking)
|
|
1184
|
+
if (!this.simulationWorking && !this.highlightWorking)
|
|
534
1185
|
this.draw();
|
|
535
1186
|
}
|
|
536
1187
|
restart(alpha) {
|
|
@@ -586,6 +1237,8 @@ class GraphCanvas {
|
|
|
586
1237
|
}
|
|
587
1238
|
clearDataDependencies() {
|
|
588
1239
|
this.cachedNodeText = {};
|
|
1240
|
+
this.nodeOptionsCache = {};
|
|
1241
|
+
this.linkOptionsCache = {};
|
|
589
1242
|
}
|
|
590
1243
|
updateData(alpha) {
|
|
591
1244
|
this.clearDataDependencies();
|
|
@@ -609,7 +1262,7 @@ class GraphCanvas {
|
|
|
609
1262
|
this.initZoom();
|
|
610
1263
|
this.initResize();
|
|
611
1264
|
this.initPointer();
|
|
612
|
-
if (!this.simulationWorking)
|
|
1265
|
+
if (!this.simulationWorking && !this.highlightWorking)
|
|
613
1266
|
this.draw();
|
|
614
1267
|
}
|
|
615
1268
|
init() {
|
|
@@ -630,6 +1283,8 @@ class GraphCanvas {
|
|
|
630
1283
|
})
|
|
631
1284
|
.on("end", () => {
|
|
632
1285
|
this.listeners.onSimulationEnd?.(this.state);
|
|
1286
|
+
if (this.graphSettings.showDrawTime)
|
|
1287
|
+
getDrawTime();
|
|
633
1288
|
});
|
|
634
1289
|
this.initSimulationForces();
|
|
635
1290
|
}
|
|
@@ -652,9 +1307,9 @@ class GraphCanvas {
|
|
|
652
1307
|
.distanceMax(this.forceSettings.chargeDistanceMax)
|
|
653
1308
|
.distanceMin(this.forceSettings.chargeDistanceMin))
|
|
654
1309
|
.force("center", d3Force.forceCenter(this.forceSettings.centerPosition.x ?? 0, this.forceSettings.centerPosition.y ?? 0).strength(this.forceSettings.centerStrength));
|
|
655
|
-
this.initCollideForce();
|
|
1310
|
+
this.initCollideForce(true);
|
|
656
1311
|
}
|
|
657
|
-
initCollideForce() {
|
|
1312
|
+
initCollideForce(forceUpdate) {
|
|
658
1313
|
if (!this.simulation)
|
|
659
1314
|
return;
|
|
660
1315
|
if (!this.forceSettings.collideOn) {
|
|
@@ -665,9 +1320,10 @@ class GraphCanvas {
|
|
|
665
1320
|
const isHasMax = this.forceSettings.collideOffMax.links != 0 && this.forceSettings.collideOffMax.nodes != 0;
|
|
666
1321
|
const isMaxCollideNodes = isHasMax && this.forceSettings.collideOffMax.nodes < this.nodes.length;
|
|
667
1322
|
const isMaxCollideLinks = isHasMax && this.forceSettings.collideOffMax.links < this.links.length;
|
|
668
|
-
if (isMaxCollideNodes && isMaxCollideLinks)
|
|
1323
|
+
if (isMaxCollideNodes && isMaxCollideLinks) {
|
|
669
1324
|
this.simulation.force("collide", null);
|
|
670
|
-
|
|
1325
|
+
}
|
|
1326
|
+
else if (!this.simulation.force("collide") || forceUpdate) {
|
|
671
1327
|
this.simulation.force("collide", d3Force.forceCollide()
|
|
672
1328
|
.radius((node, index) => {
|
|
673
1329
|
if (this.forceSettings.collideRadius) {
|
|
@@ -685,6 +1341,7 @@ class GraphCanvas {
|
|
|
685
1341
|
})
|
|
686
1342
|
.strength(this.forceSettings.collideStrength)
|
|
687
1343
|
.iterations(this.forceSettings.collideIterations));
|
|
1344
|
+
}
|
|
688
1345
|
}
|
|
689
1346
|
initArea() {
|
|
690
1347
|
if (!this.area || !this.context || !this.container) {
|
|
@@ -719,27 +1376,36 @@ class GraphCanvas {
|
|
|
719
1376
|
this.highlightProgress -= this.graphSettings.highlightDownStep;
|
|
720
1377
|
if (!this.simulationWorking)
|
|
721
1378
|
return void requestAnimationFrame(() => this.draw());
|
|
722
|
-
|
|
1379
|
+
if (!this.linkSettings.particles)
|
|
1380
|
+
return;
|
|
723
1381
|
}
|
|
724
1382
|
if (this.highlightWorking && this.highlightProgress < 1) {
|
|
725
1383
|
this.highlightProgress += this.graphSettings.highlightUpStep;
|
|
726
1384
|
if (!this.simulationWorking)
|
|
727
1385
|
return void requestAnimationFrame(() => this.draw());
|
|
728
|
-
|
|
1386
|
+
if (!this.linkSettings.particles)
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
if (this.linkSettings.particles && this.highlightWorking && !this.simulationWorking) {
|
|
1390
|
+
return void requestAnimationFrame(() => this.draw());
|
|
729
1391
|
}
|
|
730
1392
|
if (!this.highlightWorking && this.highlightProgress <= 0) {
|
|
731
|
-
if (this.highlightedNeighbors)
|
|
1393
|
+
if (this.highlightedNeighbors || this.highlightedNode) {
|
|
732
1394
|
this.highlightedNeighbors = null;
|
|
733
|
-
if (this.highlightedNode)
|
|
734
1395
|
this.highlightedNode = null;
|
|
1396
|
+
this.particles = {};
|
|
1397
|
+
if (!this.simulationWorking)
|
|
1398
|
+
return void requestAnimationFrame(() => this.draw());
|
|
1399
|
+
}
|
|
735
1400
|
}
|
|
736
1401
|
this.highlightDrawing = false;
|
|
737
1402
|
}
|
|
738
1403
|
function draw() {
|
|
739
1404
|
if (!this.context)
|
|
740
1405
|
return;
|
|
1406
|
+
const state = this.state;
|
|
741
1407
|
if (this.listeners.onDraw) {
|
|
742
|
-
this.listeners.onDraw(
|
|
1408
|
+
this.listeners.onDraw(state, (status) => {
|
|
743
1409
|
this.highlightDrawing = status;
|
|
744
1410
|
}, () => {
|
|
745
1411
|
if (this.highlightedNeighbors)
|
|
@@ -753,160 +1419,331 @@ class GraphCanvas {
|
|
|
753
1419
|
this.context.clearRect(0, 0, this.width, this.height);
|
|
754
1420
|
this.context.translate(this.areaTransform.x, this.areaTransform.y);
|
|
755
1421
|
this.context.scale(this.areaTransform.k, this.areaTransform.k);
|
|
1422
|
+
const textRenders = [];
|
|
1423
|
+
const nodeRenders = [];
|
|
1424
|
+
this.nodes.forEach(getDrawNode(nodeRenders, textRenders, state).bind(this));
|
|
756
1425
|
/** links */
|
|
757
|
-
this.
|
|
758
|
-
this.links.forEach(drawLink.bind(this));
|
|
759
|
-
this.context.stroke();
|
|
1426
|
+
this.links.forEach(getDrawLink(state).bind(this));
|
|
760
1427
|
/** nodes */
|
|
761
|
-
|
|
762
|
-
this.nodes.forEach(drawNode(textRenders).bind(this));
|
|
1428
|
+
nodeRenders.forEach((render) => render());
|
|
763
1429
|
textRenders.forEach((render) => render());
|
|
764
1430
|
this.context.restore();
|
|
765
|
-
this.listeners.onDrawFinished?.(
|
|
1431
|
+
this.listeners.onDrawFinished?.(state);
|
|
766
1432
|
calculateHighlightFading.bind(this)();
|
|
767
1433
|
}
|
|
768
|
-
function
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
1434
|
+
function getDrawLink(state) {
|
|
1435
|
+
return function drawLink(link, index) {
|
|
1436
|
+
if (!this.context ||
|
|
1437
|
+
typeof link.source !== "object" ||
|
|
1438
|
+
typeof link.target !== "object" ||
|
|
1439
|
+
!link.source.x ||
|
|
1440
|
+
!link.source.y ||
|
|
1441
|
+
!link.target.x ||
|
|
1442
|
+
!link.target.y)
|
|
1443
|
+
return;
|
|
1444
|
+
if (!link.source._visible && !link.target._visible)
|
|
1445
|
+
return;
|
|
1446
|
+
const id = `${link.target.id}${link.source.id}`;
|
|
1447
|
+
let linkOptions;
|
|
1448
|
+
if (this.linkSettings.cache && this.linkOptionsCache[id]) {
|
|
1449
|
+
linkOptions = this.linkOptionsCache[id];
|
|
1450
|
+
}
|
|
1451
|
+
else {
|
|
1452
|
+
linkOptions = linkIterationExtractor(link, index, this.links, state, this.linkSettings.options ?? {}, linkOptionsGetter);
|
|
1453
|
+
if (this.linkSettings.cache) {
|
|
1454
|
+
this.linkOptionsCache[id] = linkOptions;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
if (linkOptions.drawLink) {
|
|
1458
|
+
linkOptions.drawLink(link, linkOptions, state);
|
|
1459
|
+
return;
|
|
1460
|
+
}
|
|
1461
|
+
let alpha = linkOptions.alpha;
|
|
1462
|
+
let arrowAlpha = linkOptions.arrowReverseAppear ? 0 : linkOptions.arrowAlpha;
|
|
1463
|
+
if (this.highlightedNeighbors && this.highlightedNode) {
|
|
1464
|
+
/** Not highlighted */
|
|
1465
|
+
if (this.highlightedNode.id != link.source.id &&
|
|
1466
|
+
this.highlightedNode.id != link.target.id) {
|
|
1467
|
+
if (linkOptions.highlightFading) {
|
|
1468
|
+
const min = this.graphSettings.highlightLinkFadingMin < alpha
|
|
1469
|
+
? this.graphSettings.highlightLinkFadingMin
|
|
1470
|
+
: alpha;
|
|
1471
|
+
alpha = animationByProgress(min, alpha - min, 1 - this.highlightProgress);
|
|
1472
|
+
}
|
|
1473
|
+
if (linkOptions.arrow &&
|
|
1474
|
+
linkOptions.arrowHighlightFading &&
|
|
1475
|
+
!linkOptions.arrowReverseAppear) {
|
|
1476
|
+
const min = this.graphSettings.highlightArrowFadingMin < arrowAlpha
|
|
1477
|
+
? this.graphSettings.highlightArrowFadingMin
|
|
1478
|
+
: arrowAlpha;
|
|
1479
|
+
arrowAlpha = animationByProgress(min, arrowAlpha - min, 1 - this.highlightProgress);
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
else {
|
|
1483
|
+
// eslint-disable-next-line no-lonely-if
|
|
1484
|
+
if (linkOptions.arrow && linkOptions.arrowReverseAppear) {
|
|
1485
|
+
/** Highlighted */
|
|
1486
|
+
arrowAlpha = animationByProgress(0, linkOptions.arrowAlpha, this.highlightProgress);
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
787
1489
|
}
|
|
1490
|
+
/** Link */
|
|
788
1491
|
this.context.beginPath();
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
y2: 0
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
1492
|
+
this.context.globalAlpha = alpha;
|
|
1493
|
+
this.context.strokeStyle = linkOptions.color;
|
|
1494
|
+
this.context.lineWidth = linkOptions.width;
|
|
1495
|
+
let xStart = link.source.x;
|
|
1496
|
+
let yStart = link.source.y;
|
|
1497
|
+
let xEnd = link.target.x;
|
|
1498
|
+
let yEnd = link.target.y;
|
|
1499
|
+
if (linkOptions.pretty) {
|
|
1500
|
+
const isHasArrow = linkOptions.arrow && arrowAlpha > 0;
|
|
1501
|
+
const { x1, x2, y1, y2 } = calculateLinkPositionByRadius(link, isHasArrow ? linkOptions.arrowSize : 0) ?? {
|
|
1502
|
+
x1: 0,
|
|
1503
|
+
x2: 0,
|
|
1504
|
+
y1: 0,
|
|
1505
|
+
y2: 0,
|
|
1506
|
+
};
|
|
1507
|
+
xStart = x1;
|
|
1508
|
+
xEnd = x2;
|
|
1509
|
+
yStart = y1;
|
|
1510
|
+
yEnd = y2;
|
|
1511
|
+
}
|
|
1512
|
+
this.context.moveTo(xStart, yStart);
|
|
1513
|
+
this.context.lineTo(xEnd, yEnd);
|
|
808
1514
|
this.context.stroke();
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
/** Not highlighted */
|
|
825
|
-
if (!this.highlightedNeighbors.has(node.id) && this.highlightedNode.id != node.id) {
|
|
826
|
-
if (nodeOptions.highlightFading) {
|
|
827
|
-
alpha =
|
|
828
|
-
this.graphSettings.highlightFadingMin +
|
|
829
|
-
(alpha - this.graphSettings.highlightFadingMin) * (1 - this.highlightProgress);
|
|
830
|
-
}
|
|
831
|
-
if (nodeOptions.highlightTextFading) {
|
|
832
|
-
textAlpha =
|
|
833
|
-
this.graphSettings.highlightTextFadingMin +
|
|
834
|
-
(textAlpha - this.graphSettings.highlightTextFadingMin) *
|
|
835
|
-
(1 - this.highlightProgress);
|
|
1515
|
+
/** Particle */
|
|
1516
|
+
if (this.linkSettings.particles &&
|
|
1517
|
+
this.highlightedNode &&
|
|
1518
|
+
(this.highlightedNode.id === link.source.id || this.highlightedNode.id === link.target.id)) {
|
|
1519
|
+
if (!this.particles[id]) {
|
|
1520
|
+
const sourceId = link.source.id;
|
|
1521
|
+
const targetId = link.target.id;
|
|
1522
|
+
this.particles[id] = Array.from({ length: linkOptions.particleCount }, (_, index) => {
|
|
1523
|
+
return {
|
|
1524
|
+
step: 0,
|
|
1525
|
+
wait: index * (linkOptions.particleSteps / linkOptions.particleCount),
|
|
1526
|
+
sourceId,
|
|
1527
|
+
targetId,
|
|
1528
|
+
};
|
|
1529
|
+
});
|
|
836
1530
|
}
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
1531
|
+
this.particles[id].forEach((particle) => {
|
|
1532
|
+
if (!this.context)
|
|
1533
|
+
return;
|
|
1534
|
+
getParticlePosition({
|
|
1535
|
+
particle,
|
|
1536
|
+
totalSteps: linkOptions.particleSteps,
|
|
1537
|
+
xEnd,
|
|
1538
|
+
xStart,
|
|
1539
|
+
yEnd,
|
|
1540
|
+
yStart,
|
|
1541
|
+
});
|
|
1542
|
+
if (particle.x != undefined && particle.y != undefined) {
|
|
1543
|
+
this.context.beginPath();
|
|
1544
|
+
this.context.arc(particle.x, particle.y, linkOptions.particleRadius, 0, Math.PI * 2);
|
|
1545
|
+
this.context.fillStyle = linkOptions.particleColor;
|
|
1546
|
+
this.context.fill();
|
|
1547
|
+
this.context.stroke();
|
|
843
1548
|
}
|
|
1549
|
+
});
|
|
1550
|
+
}
|
|
1551
|
+
/** Arrow */
|
|
1552
|
+
if (linkOptions.arrow && arrowAlpha > 0) {
|
|
1553
|
+
const { x1: xStart, x2: xEnd, y1: yStart, y2: yEnd, } = calculateLinkPositionByRadius(link) ?? {
|
|
1554
|
+
x1: 0,
|
|
1555
|
+
x2: 0,
|
|
1556
|
+
y1: 0,
|
|
1557
|
+
y2: 0,
|
|
1558
|
+
};
|
|
1559
|
+
const angle = Math.atan2(yEnd - yStart, xEnd - xStart);
|
|
1560
|
+
this.context.beginPath();
|
|
1561
|
+
this.context.globalAlpha = arrowAlpha;
|
|
1562
|
+
this.context.moveTo(xEnd, yEnd);
|
|
1563
|
+
this.context.lineTo(xEnd - linkOptions.arrowSize * Math.cos(angle - Math.PI / 6), yEnd - linkOptions.arrowSize * Math.sin(angle - Math.PI / 6));
|
|
1564
|
+
this.context.lineTo(xEnd - linkOptions.arrowSize * Math.cos(angle + Math.PI / 6), yEnd - linkOptions.arrowSize * Math.sin(angle + Math.PI / 6));
|
|
1565
|
+
this.context.closePath();
|
|
1566
|
+
this.context.fillStyle = linkOptions.arrowColor;
|
|
1567
|
+
this.context.fill();
|
|
1568
|
+
this.context.stroke();
|
|
1569
|
+
}
|
|
1570
|
+
if (linkOptions.drawExtraLink) {
|
|
1571
|
+
linkOptions.drawExtraLink(link, { ...linkOptions, alpha }, state);
|
|
1572
|
+
}
|
|
1573
|
+
};
|
|
1574
|
+
}
|
|
1575
|
+
function getDrawNode(nodeRenders, textRenders, state) {
|
|
1576
|
+
return function drawNode(node, index) {
|
|
1577
|
+
if (!this.context || !node.x || !node.y)
|
|
1578
|
+
return;
|
|
1579
|
+
let nodeOptions;
|
|
1580
|
+
if (this.nodeSettings.cache && this.nodeOptionsCache[node.id]) {
|
|
1581
|
+
nodeOptions = this.nodeOptionsCache[node.id];
|
|
1582
|
+
}
|
|
1583
|
+
else {
|
|
1584
|
+
nodeOptions = nodeIterationExtractor(node, index, this.nodes, state, this.nodeSettings.options ?? {}, nodeOptionsGetter);
|
|
1585
|
+
if (this.nodeSettings.cache) {
|
|
1586
|
+
this.nodeOptionsCache[node.id] = nodeOptions;
|
|
844
1587
|
}
|
|
845
1588
|
}
|
|
846
|
-
|
|
847
|
-
(
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
1589
|
+
if (nodeOptions.nodeDraw) {
|
|
1590
|
+
nodeOptions.nodeDraw(node, nodeOptions, state);
|
|
1591
|
+
return;
|
|
1592
|
+
}
|
|
1593
|
+
let alpha = nodeOptions.alpha;
|
|
1594
|
+
let color = nodeOptions.color;
|
|
1595
|
+
let radiusInitial = nodeOptions.radius ?? this.graphSettings.nodeRadiusInitial;
|
|
1596
|
+
let textAlpha = nodeOptions.textAlpha;
|
|
1597
|
+
let textSize = nodeOptions.textSize;
|
|
1598
|
+
let textShiftX = nodeOptions.textShiftX;
|
|
1599
|
+
let textShiftY = nodeOptions.textShiftY;
|
|
1600
|
+
let textWeight = nodeOptions.textWeight;
|
|
1601
|
+
let textWidth = nodeOptions.textWidth;
|
|
1602
|
+
if (this.highlightedNeighbors && this.highlightedNode) {
|
|
1603
|
+
/** Not highlighted */
|
|
1604
|
+
if (!this.highlightedNeighbors.has(node.id) && this.highlightedNode.id != node.id) {
|
|
1605
|
+
if (nodeOptions.highlightFading) {
|
|
1606
|
+
const min = this.graphSettings.highlightFadingMin < alpha
|
|
1607
|
+
? this.graphSettings.highlightFadingMin
|
|
1608
|
+
: alpha;
|
|
1609
|
+
alpha = animationByProgress(min, alpha - min, 1 - this.highlightProgress);
|
|
1610
|
+
}
|
|
1611
|
+
if (nodeOptions.highlightTextFading) {
|
|
1612
|
+
const min = this.graphSettings.highlightTextFadingMin < textAlpha
|
|
1613
|
+
? this.graphSettings.highlightTextFadingMin
|
|
1614
|
+
: textAlpha;
|
|
1615
|
+
textAlpha = animationByProgress(min, textAlpha - min, 1 - this.highlightProgress);
|
|
1616
|
+
}
|
|
1617
|
+
if (nodeOptions.highlightColor) {
|
|
1618
|
+
const colorRgb = extractRgb(colorToRgb(color));
|
|
1619
|
+
if (colorRgb) {
|
|
1620
|
+
const colorRgbFade = fadeRgb(colorRgb, this.graphSettings.highlightColorFadingMin);
|
|
1621
|
+
const colorFadeAnimation = rgbAnimationByProgress(colorRgb, colorRgbFade, this.highlightProgress);
|
|
1622
|
+
color = `rgb(${colorFadeAnimation.r}, ${colorFadeAnimation.g}, ${colorFadeAnimation.b})`;
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
852
1625
|
}
|
|
853
|
-
if (
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
1626
|
+
else if (!this.graphSettings.highlightOnlyRoot ||
|
|
1627
|
+
(this.graphSettings.highlightOnlyRoot && this.highlightedNode.id === node.id)) {
|
|
1628
|
+
/** Highlighted */
|
|
1629
|
+
if (nodeOptions.highlightSizing) {
|
|
1630
|
+
radiusInitial = animationByProgress(radiusInitial, this.graphSettings.highlightSizingAdditional, this.highlightProgress);
|
|
1631
|
+
}
|
|
1632
|
+
if (nodeOptions.highlightTextSizing) {
|
|
1633
|
+
textSize = animationByProgress(textSize, this.graphSettings.highlightTextSizingAdditional, this.highlightProgress);
|
|
1634
|
+
textShiftX = animationByProgress(textShiftX, this.graphSettings.highlightTextShiftXAdditional, this.highlightProgress);
|
|
1635
|
+
textShiftY = animationByProgress(textShiftY, this.graphSettings.highlightTextShiftYAdditional, this.highlightProgress);
|
|
1636
|
+
textWeight = animationByProgress(textWeight, this.graphSettings.highlightTextWeightAdditional, this.highlightProgress);
|
|
1637
|
+
textWidth = animationByProgress(textWidth, this.graphSettings.highlightTextWidthAdditional, this.highlightProgress);
|
|
1638
|
+
}
|
|
864
1639
|
}
|
|
865
1640
|
}
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
1641
|
+
const radius = nodeRadiusGetter({
|
|
1642
|
+
radiusFlexible: this.graphSettings.nodeRadiusFlexible,
|
|
1643
|
+
radiusInitial,
|
|
1644
|
+
radiusCoefficient: this.graphSettings.nodeRadiusCoefficient,
|
|
1645
|
+
radiusFactor: this.graphSettings.nodeRadiusFactor,
|
|
1646
|
+
linkCount: node.linkCount,
|
|
1647
|
+
});
|
|
1648
|
+
node._radius = radius;
|
|
1649
|
+
if (!isNodeVisible({
|
|
1650
|
+
height: this.height,
|
|
1651
|
+
width: this.width,
|
|
1652
|
+
x: node.x,
|
|
1653
|
+
y: node.y,
|
|
1654
|
+
radius,
|
|
1655
|
+
transform: this.areaTransform,
|
|
1656
|
+
})) {
|
|
1657
|
+
node._visible = false;
|
|
1658
|
+
return;
|
|
1659
|
+
}
|
|
1660
|
+
node._visible = true;
|
|
1661
|
+
nodeRenders.push(() => {
|
|
1662
|
+
if (!this.context || !node.x || !node.y)
|
|
881
1663
|
return;
|
|
882
1664
|
this.context.beginPath();
|
|
883
|
-
this.context.globalAlpha =
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
1665
|
+
this.context.globalAlpha = alpha;
|
|
1666
|
+
/** circle */
|
|
1667
|
+
this.context.lineWidth = nodeOptions.borderWidth;
|
|
1668
|
+
this.context.strokeStyle = nodeOptions.borderColor;
|
|
1669
|
+
this.context.fillStyle = color;
|
|
1670
|
+
this.context.arc(node.x, node.y, radius, 0, 2 * Math.PI);
|
|
1671
|
+
this.context.fill();
|
|
1672
|
+
this.context.stroke();
|
|
1673
|
+
});
|
|
1674
|
+
/** text */
|
|
1675
|
+
if (nodeOptions.textVisible && nodeOptions.text) {
|
|
1676
|
+
textRenders.push(() => {
|
|
1677
|
+
if (nodeOptions.textDraw) {
|
|
1678
|
+
nodeOptions.textDraw(node, {
|
|
1679
|
+
...nodeOptions,
|
|
1680
|
+
radius,
|
|
1681
|
+
alpha,
|
|
1682
|
+
color,
|
|
1683
|
+
textAlpha,
|
|
1684
|
+
textSize,
|
|
1685
|
+
textShiftX,
|
|
1686
|
+
textShiftY,
|
|
1687
|
+
textWeight,
|
|
1688
|
+
textWidth,
|
|
1689
|
+
}, state);
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1692
|
+
if (!this.context || !node.x || !node.y || !nodeOptions.text)
|
|
1693
|
+
return;
|
|
1694
|
+
this.context.beginPath();
|
|
1695
|
+
this.context.globalAlpha = textAlpha;
|
|
1696
|
+
drawText({
|
|
1697
|
+
id: node.id,
|
|
1698
|
+
cachedNodeText: this.cachedNodeText,
|
|
1699
|
+
context: this.context,
|
|
1700
|
+
text: nodeOptions.text,
|
|
1701
|
+
textAlign: nodeOptions.textAlign,
|
|
1702
|
+
textColor: nodeOptions.textColor,
|
|
1703
|
+
textFont: nodeOptions.textFont,
|
|
1704
|
+
textSize,
|
|
1705
|
+
x: node.x + textShiftX,
|
|
1706
|
+
y: node.y + radius + textShiftY,
|
|
1707
|
+
maxWidth: textWidth,
|
|
1708
|
+
textStyle: nodeOptions.textStyle,
|
|
1709
|
+
textWeight,
|
|
1710
|
+
textGap: nodeOptions.textGap,
|
|
1711
|
+
});
|
|
1712
|
+
if (nodeOptions.textExtraDraw) {
|
|
1713
|
+
nodeOptions.textExtraDraw(node, {
|
|
1714
|
+
...nodeOptions,
|
|
1715
|
+
radius,
|
|
1716
|
+
alpha,
|
|
1717
|
+
color,
|
|
1718
|
+
textAlpha,
|
|
1719
|
+
textSize,
|
|
1720
|
+
textShiftX,
|
|
1721
|
+
textShiftY,
|
|
1722
|
+
textWeight,
|
|
1723
|
+
textWidth,
|
|
1724
|
+
}, state);
|
|
1725
|
+
}
|
|
1726
|
+
});
|
|
1727
|
+
}
|
|
1728
|
+
if (nodeOptions.nodeExtraDraw) {
|
|
1729
|
+
nodeOptions.nodeExtraDraw(node, {
|
|
1730
|
+
...nodeOptions,
|
|
1731
|
+
radius,
|
|
1732
|
+
alpha,
|
|
1733
|
+
color,
|
|
1734
|
+
textAlpha,
|
|
892
1735
|
textSize,
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
maxWidth: textWidth,
|
|
896
|
-
textStyle: nodeOptions.textStyle,
|
|
1736
|
+
textShiftX,
|
|
1737
|
+
textShiftY,
|
|
897
1738
|
textWeight,
|
|
898
|
-
|
|
899
|
-
});
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
this.
|
|
905
|
-
|
|
906
|
-
this.context.arc(node.x, node.y, radius, 0, 2 * Math.PI);
|
|
907
|
-
this.context.fill();
|
|
908
|
-
this.context.stroke();
|
|
909
|
-
};
|
|
1739
|
+
textWidth,
|
|
1740
|
+
}, state);
|
|
1741
|
+
}
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
if (this.graphSettings.showDrawTime) {
|
|
1745
|
+
return setDrawTime(draw.bind(this), this.graphSettings.showDrawTimeEveryTick);
|
|
1746
|
+
}
|
|
910
1747
|
return draw;
|
|
911
1748
|
}
|
|
912
1749
|
initResize() {
|
|
@@ -1100,7 +1937,7 @@ class GraphCanvas {
|
|
|
1100
1937
|
this.listeners.onEndDragFinished?.(event, this.state);
|
|
1101
1938
|
}));
|
|
1102
1939
|
}
|
|
1103
|
-
initZoom() {
|
|
1940
|
+
initZoom(currentZoom) {
|
|
1104
1941
|
if (!this.area)
|
|
1105
1942
|
throw new Error("bad init data");
|
|
1106
1943
|
const zoomInstance = d3Zoom.zoom()
|
|
@@ -1108,7 +1945,9 @@ class GraphCanvas {
|
|
|
1108
1945
|
.on("zoom", (event) => {
|
|
1109
1946
|
this.listeners.onZoom?.(event);
|
|
1110
1947
|
this.areaTransform = event.transform;
|
|
1111
|
-
|
|
1948
|
+
this.linkOptionsCache = {};
|
|
1949
|
+
this.nodeOptionsCache = {};
|
|
1950
|
+
if (!this.simulationWorking && !this.highlightWorking)
|
|
1112
1951
|
requestAnimationFrame(() => this.draw());
|
|
1113
1952
|
});
|
|
1114
1953
|
if (this.graphSettings.translateExtentEnable) {
|
|
@@ -1123,18 +1962,24 @@ class GraphCanvas {
|
|
|
1123
1962
|
]);
|
|
1124
1963
|
}
|
|
1125
1964
|
d3Selection.select(this.area).call(zoomInstance).on("dblclick.zoom", null);
|
|
1126
|
-
const zoomInitial = this.graphSettings.zoomInitial;
|
|
1965
|
+
const zoomInitial = currentZoom ?? this.graphSettings.zoomInitial;
|
|
1127
1966
|
this.areaTransform = new d3Zoom.ZoomTransform(zoomInitial?.k ?? 1, zoomInitial?.x ?? this.width / 2, zoomInitial?.y ?? this.height / 2);
|
|
1128
1967
|
d3Zoom.zoom().transform(d3Selection.select(this.area), this.areaTransform);
|
|
1129
1968
|
}
|
|
1130
1969
|
}
|
|
1131
1970
|
|
|
1132
1971
|
exports.GraphCanvas = GraphCanvas;
|
|
1972
|
+
exports.animationByProgress = animationByProgress;
|
|
1133
1973
|
exports.calculateLinkPositionByRadius = calculateLinkPositionByRadius;
|
|
1134
1974
|
exports.colorToRgb = colorToRgb;
|
|
1135
1975
|
exports.drawText = drawText;
|
|
1136
1976
|
exports.extractRgb = extractRgb;
|
|
1137
1977
|
exports.fadeRgb = fadeRgb;
|
|
1978
|
+
exports.getForceControls = getForceControls;
|
|
1979
|
+
exports.getGraphControls = getGraphControls;
|
|
1980
|
+
exports.getLinkControls = getLinkControls;
|
|
1981
|
+
exports.getNodeControls = getNodeControls;
|
|
1982
|
+
exports.getParticlePosition = getParticlePosition;
|
|
1138
1983
|
exports.linkIterationExtractor = linkIterationExtractor;
|
|
1139
1984
|
exports.linkOptionsGetter = linkOptionsGetter;
|
|
1140
1985
|
exports.nodeIterationExtractor = nodeIterationExtractor;
|