@krainovsd/graph 0.14.0-beta.9 → 0.15.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 +636 -375
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/esm/constants/force-controls.js +6 -4
- package/lib/esm/constants/force-controls.js.map +1 -1
- package/lib/esm/constants/highlight-controls.js +6 -3
- package/lib/esm/constants/highlight-controls.js.map +1 -1
- package/lib/esm/constants/link-controls.js +6 -3
- package/lib/esm/constants/link-controls.js.map +1 -1
- package/lib/esm/constants/node-controls.js +6 -3
- package/lib/esm/constants/node-controls.js.map +1 -1
- package/lib/esm/index.js +8 -6
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/module/GraphCanvas/GraphCanvas.js +36 -17
- package/lib/esm/module/GraphCanvas/GraphCanvas.js.map +1 -1
- package/lib/esm/module/GraphCanvas/StaticGraphCanvas.js +127 -0
- package/lib/esm/module/GraphCanvas/StaticGraphCanvas.js.map +1 -0
- package/lib/esm/module/GraphCanvas/constants/graph-settings.js +6 -7
- package/lib/esm/module/GraphCanvas/constants/graph-settings.js.map +1 -1
- package/lib/esm/module/GraphCanvas/constants/highlight-settings.js +1 -4
- package/lib/esm/module/GraphCanvas/constants/highlight-settings.js.map +1 -1
- package/lib/esm/module/GraphCanvas/constants/index.js +6 -4
- package/lib/esm/module/GraphCanvas/constants/index.js.map +1 -1
- package/lib/esm/module/GraphCanvas/constants/link-settings.js +1 -9
- package/lib/esm/module/GraphCanvas/constants/link-settings.js.map +1 -1
- package/lib/esm/module/GraphCanvas/constants/node-settings.js +1 -10
- package/lib/esm/module/GraphCanvas/constants/node-settings.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/settings/force-settings-getter.js +6 -4
- 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 +0 -3
- 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 +6 -3
- 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 +6 -3
- 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 +20 -6
- 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 +6 -4
- 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 +6 -4
- package/lib/esm/module/GraphCanvas/lib/utils/calculate-link-position-by-node.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/utils/get-particle-position.js +1 -1
- package/lib/esm/module/GraphCanvas/lib/utils/get-particle-position.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/utils/is-node-visible.js +25 -27
- package/lib/esm/module/GraphCanvas/lib/utils/is-node-visible.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/utils/is-overlaps-node.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/utils/node-by-pointer-getter.js +2 -1
- package/lib/esm/module/GraphCanvas/lib/utils/node-by-pointer-getter.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/utils/node-highlight.js +7 -11
- package/lib/esm/module/GraphCanvas/lib/utils/node-highlight.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/utils/node-iteration-extractor.js +3 -0
- package/lib/esm/module/GraphCanvas/lib/utils/node-iteration-extractor.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/utils/precompute-graph.js +24 -0
- package/lib/esm/module/GraphCanvas/lib/utils/precompute-graph.js.map +1 -0
- package/lib/esm/module/GraphCanvas/lib/utils/prepare-graph-data.js +49 -0
- package/lib/esm/module/GraphCanvas/lib/utils/prepare-graph-data.js.map +1 -0
- package/lib/esm/module/GraphCanvas/slices/draw-links.js +24 -42
- package/lib/esm/module/GraphCanvas/slices/draw-links.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/draw-nodes.js +80 -168
- package/lib/esm/module/GraphCanvas/slices/draw-nodes.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/draw-text.js +1 -9
- package/lib/esm/module/GraphCanvas/slices/draw-text.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/export-svg.js +4 -5
- package/lib/esm/module/GraphCanvas/slices/export-svg.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/init-dnd.js +15 -3
- package/lib/esm/module/GraphCanvas/slices/init-dnd.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/init-draw.js +212 -8
- package/lib/esm/module/GraphCanvas/slices/init-draw.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/init-pointer.js +6 -8
- package/lib/esm/module/GraphCanvas/slices/init-pointer.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/init-simulation.js +3 -4
- package/lib/esm/module/GraphCanvas/slices/init-simulation.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/init-zoom.js +2 -4
- package/lib/esm/module/GraphCanvas/slices/init-zoom.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/update-link-cache.js +5 -5
- package/lib/esm/module/GraphCanvas/slices/update-node-cache.js +17 -29
- package/lib/esm/module/GraphCanvas/slices/update-node-cache.js.map +1 -1
- package/lib/index.d.ts +94 -43
- package/package.json +1 -1
package/lib/cjs/index.cjs
CHANGED
|
@@ -220,12 +220,24 @@ function nodeOptionsGetter(node) {
|
|
|
220
220
|
textDraw: null,
|
|
221
221
|
textExtraDraw: null,
|
|
222
222
|
color: color(String(node.group ?? "_DEFAULT")),
|
|
223
|
-
textVisible: Boolean(this.areaTransform.k > this.nodeSettings.textScaleMin),
|
|
224
|
-
text: node.name ?? node.id.toString(),
|
|
225
223
|
textShiftY,
|
|
226
224
|
textSize,
|
|
227
225
|
};
|
|
228
226
|
}
|
|
227
|
+
function nodeTextGetter(node, index) {
|
|
228
|
+
const cache = this.nodeOptionsCache[index];
|
|
229
|
+
if (cache?.shape == "text")
|
|
230
|
+
return null;
|
|
231
|
+
return this.areaTransform.k > this.nodeSettings.textScaleMin
|
|
232
|
+
? (node.name ?? node.id.toString())
|
|
233
|
+
: null;
|
|
234
|
+
}
|
|
235
|
+
function nodeLabelGetter(node, index) {
|
|
236
|
+
const cache = this.nodeOptionsCache[index];
|
|
237
|
+
if (cache?.shape == "text")
|
|
238
|
+
return node.name ?? null;
|
|
239
|
+
return node.label ?? null;
|
|
240
|
+
}
|
|
229
241
|
function nodeTextSizeGetter(transform, nodeSettings) {
|
|
230
242
|
let textSize = nodeSettings.textSizeMin;
|
|
231
243
|
let textShiftY = nodeSettings.textShiftYMin;
|
|
@@ -314,6 +326,57 @@ function computeGraphBounds(nodes) {
|
|
|
314
326
|
return { minX, minY, maxX, maxY };
|
|
315
327
|
}
|
|
316
328
|
|
|
329
|
+
function extractLinkPointIds(link) {
|
|
330
|
+
const sourceId = typeof link.source === "object" ? link.source.id : link.source;
|
|
331
|
+
const targetId = typeof link.target === "object" ? link.target.id : link.target;
|
|
332
|
+
return { sourceId, targetId };
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function prepareGraph(opts) {
|
|
336
|
+
const nodes = opts.nodes;
|
|
337
|
+
const links = opts.links;
|
|
338
|
+
const map = new Map();
|
|
339
|
+
const neighbors = new Map();
|
|
340
|
+
for (let i = 0; i < links.length; i++) {
|
|
341
|
+
const link = links[i];
|
|
342
|
+
const { sourceId, targetId } = extractLinkPointIds(link);
|
|
343
|
+
const sources = neighbors.get(sourceId);
|
|
344
|
+
if (sources) {
|
|
345
|
+
sources.push(targetId);
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
neighbors.set(sourceId, [targetId]);
|
|
349
|
+
}
|
|
350
|
+
const targets = neighbors.get(targetId);
|
|
351
|
+
if (targets) {
|
|
352
|
+
targets.push(sourceId);
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
neighbors.set(targetId, [sourceId]);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
359
|
+
const node = nodes[i];
|
|
360
|
+
map.set(node.id, node);
|
|
361
|
+
node.index = i;
|
|
362
|
+
node.x ??= 0;
|
|
363
|
+
node.y ??= 0;
|
|
364
|
+
if (opts.neighbors) {
|
|
365
|
+
const n = neighbors.get(node.id);
|
|
366
|
+
if (n) {
|
|
367
|
+
node.neighbors = [...new Set(n)];
|
|
368
|
+
node.linkCount = node.neighbors.length;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
for (let i = 0; i < links.length; i++) {
|
|
373
|
+
const link = links[i];
|
|
374
|
+
const { sourceId, targetId } = extractLinkPointIds(link);
|
|
375
|
+
link.source = map.get(sourceId) ?? link.source;
|
|
376
|
+
link.target = map.get(targetId) ?? link.target;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
317
380
|
function pointerGetter(mouseEvent, areaRect, areaTransform) {
|
|
318
381
|
let localX;
|
|
319
382
|
let localY;
|
|
@@ -432,8 +495,9 @@ function linkIterationExtractor(link, i, links, state, option, optionConstantGet
|
|
|
432
495
|
|
|
433
496
|
function nodeByPointerGetter({ pointerX, pointerY, nodes, }) {
|
|
434
497
|
return d3Array.greatest(nodes, (node) => {
|
|
435
|
-
if (isOverlapsNode(node, pointerX, pointerY, undefined))
|
|
498
|
+
if (isOverlapsNode(node, pointerX, pointerY, undefined)) {
|
|
436
499
|
return node.index;
|
|
500
|
+
}
|
|
437
501
|
});
|
|
438
502
|
}
|
|
439
503
|
|
|
@@ -455,6 +519,9 @@ function nodeIterationExtractor(node, i, nodes, state, option, optionConstantGet
|
|
|
455
519
|
constantOptions = optionConstantGetter.call(state, node, i, nodes);
|
|
456
520
|
else
|
|
457
521
|
constantOptions = optionConstantGetter;
|
|
522
|
+
if (customOptions === undefined) {
|
|
523
|
+
return constantOptions;
|
|
524
|
+
}
|
|
458
525
|
if (constantOptions &&
|
|
459
526
|
typeof constantOptions === "object" &&
|
|
460
527
|
!Array.isArray(constantOptions) &&
|
|
@@ -749,43 +816,39 @@ function animationByProgress(initial, additional, progress) {
|
|
|
749
816
|
}
|
|
750
817
|
|
|
751
818
|
const ADDITIONAL_VIEWPORT = 10;
|
|
752
|
-
function isNodeVisible(
|
|
753
|
-
|
|
754
|
-
const right = (opts.width - opts.transform.x) / opts.transform.k;
|
|
755
|
-
const top = -opts.transform.y / opts.transform.k;
|
|
756
|
-
const bottom = (opts.height - opts.transform.y) / opts.transform.k;
|
|
757
|
-
if (opts.node.x == undefined || opts.node.y == undefined)
|
|
819
|
+
function isNodeVisible(node, area) {
|
|
820
|
+
if (node.x == undefined || node.y == undefined)
|
|
758
821
|
return false;
|
|
759
|
-
switch (
|
|
822
|
+
switch (node._shape) {
|
|
760
823
|
case "circle": {
|
|
761
|
-
const radius =
|
|
762
|
-
return (left <
|
|
763
|
-
|
|
764
|
-
top <
|
|
765
|
-
|
|
824
|
+
const radius = node._radius ?? COMMON_SETTINGS.nodeRadius;
|
|
825
|
+
return (area.left < node.x + radius + ADDITIONAL_VIEWPORT &&
|
|
826
|
+
node.x - radius - ADDITIONAL_VIEWPORT < area.right &&
|
|
827
|
+
area.top < node.y + radius + ADDITIONAL_VIEWPORT &&
|
|
828
|
+
node.y - radius - ADDITIONAL_VIEWPORT < area.bottom);
|
|
766
829
|
}
|
|
767
830
|
case "square":
|
|
768
831
|
case "text": {
|
|
769
|
-
const width =
|
|
770
|
-
const height =
|
|
771
|
-
return (left <
|
|
772
|
-
|
|
773
|
-
top <
|
|
774
|
-
|
|
832
|
+
const width = node._width ?? COMMON_SETTINGS.nodeSize;
|
|
833
|
+
const height = node._height ?? COMMON_SETTINGS.nodeSize;
|
|
834
|
+
return (area.left < node.x + width + ADDITIONAL_VIEWPORT &&
|
|
835
|
+
node.x - width - ADDITIONAL_VIEWPORT < area.right &&
|
|
836
|
+
area.top < node.y + height + ADDITIONAL_VIEWPORT &&
|
|
837
|
+
node.y - height - ADDITIONAL_VIEWPORT < area.bottom);
|
|
775
838
|
}
|
|
776
839
|
default: {
|
|
777
|
-
const radius =
|
|
778
|
-
return (left <
|
|
779
|
-
|
|
780
|
-
top <
|
|
781
|
-
|
|
840
|
+
const radius = node._radius ?? COMMON_SETTINGS.nodeRadius;
|
|
841
|
+
return (area.left < node.x + radius + ADDITIONAL_VIEWPORT &&
|
|
842
|
+
node.x - radius - ADDITIONAL_VIEWPORT < area.right &&
|
|
843
|
+
area.top < node.y + radius + ADDITIONAL_VIEWPORT &&
|
|
844
|
+
node.y - radius - ADDITIONAL_VIEWPORT < area.bottom);
|
|
782
845
|
}
|
|
783
846
|
}
|
|
784
847
|
}
|
|
785
848
|
|
|
786
849
|
const FRAME_INTERVAL = 1000 / 60;
|
|
787
850
|
function getParticlePosition(opts) {
|
|
788
|
-
const now =
|
|
851
|
+
const now = opts.now;
|
|
789
852
|
const particle = opts.particle;
|
|
790
853
|
if (particle._lastTime == undefined) {
|
|
791
854
|
particle._distanceTraveled = (opts.distance / opts.totalCount) * particle.index;
|
|
@@ -980,12 +1043,10 @@ function nodeHighlight(opts) {
|
|
|
980
1043
|
textShiftY = animationByProgress(textShiftY, opts.highlightForTextShiftYAdditional, opts.highlightProgress);
|
|
981
1044
|
/** Text Weight */
|
|
982
1045
|
textWeight = animationByProgress(textWeight, opts.highlightForTextWeightAdditional, opts.highlightProgress);
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
labelWeight = animationByProgress(labelWeight, opts.highlightForLabelWeightAdditional, opts.highlightProgress);
|
|
988
|
-
}
|
|
1046
|
+
/** Label Size */
|
|
1047
|
+
labelSize = animationByProgress(labelSize, opts.highlightForLabelSizingAdditional, opts.highlightProgress);
|
|
1048
|
+
/** Label Weight */
|
|
1049
|
+
labelWeight = animationByProgress(labelWeight, opts.highlightForLabelWeightAdditional, opts.highlightProgress);
|
|
989
1050
|
return {
|
|
990
1051
|
color,
|
|
991
1052
|
borderColor,
|
|
@@ -1013,11 +1074,9 @@ function nodeFade(opts) {
|
|
|
1013
1074
|
/** Text Alpha */
|
|
1014
1075
|
const textAlphaMin = opts.highlightForTextFadingMin < textAlpha ? opts.highlightForTextFadingMin : textAlpha;
|
|
1015
1076
|
textAlpha = animationByProgress(textAlphaMin, textAlpha - textAlphaMin, 1 - opts.highlightProgress);
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
labelAlpha = animationByProgress(labelAlphaMin, labelAlpha - labelAlphaMin, 1 - opts.highlightProgress);
|
|
1020
|
-
}
|
|
1077
|
+
/** Label Alpha */
|
|
1078
|
+
const labelAlphaMin = opts.highlightForLabelFadingMin < labelAlpha ? opts.highlightForLabelFadingMin : labelAlpha;
|
|
1079
|
+
labelAlpha = animationByProgress(labelAlphaMin, labelAlpha - labelAlphaMin, 1 - opts.highlightProgress);
|
|
1021
1080
|
if (opts.highlightForNodeColorFading) {
|
|
1022
1081
|
/** Color Fading */
|
|
1023
1082
|
const colorRgb = extractRgb(colorToRgb(color));
|
|
@@ -1095,12 +1154,6 @@ function linkFade(opts) {
|
|
|
1095
1154
|
return { alpha, arrowAlpha };
|
|
1096
1155
|
}
|
|
1097
1156
|
|
|
1098
|
-
function extractLinkPointIds(link) {
|
|
1099
|
-
const sourceId = typeof link.source === "object" ? link.source.id : link.source;
|
|
1100
|
-
const targetId = typeof link.target === "object" ? link.target.id : link.target;
|
|
1101
|
-
return { sourceId, targetId };
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
1157
|
function isEmptyObject(obj) {
|
|
1105
1158
|
for (const key in obj) {
|
|
1106
1159
|
if (Object.hasOwn(obj, key)) {
|
|
@@ -1110,6 +1163,26 @@ function isEmptyObject(obj) {
|
|
|
1110
1163
|
return true;
|
|
1111
1164
|
}
|
|
1112
1165
|
|
|
1166
|
+
function precomputeGraph(opts) {
|
|
1167
|
+
const div = document.createElement("div");
|
|
1168
|
+
const graph = new GraphCanvas({
|
|
1169
|
+
root: div,
|
|
1170
|
+
nodes: opts.nodes,
|
|
1171
|
+
links: opts.links,
|
|
1172
|
+
nodeSettings: opts.nodeSettings,
|
|
1173
|
+
linkSettings: opts.linkSettings,
|
|
1174
|
+
forceSettings: {
|
|
1175
|
+
...opts.forceSettings,
|
|
1176
|
+
precompute: true,
|
|
1177
|
+
precomputeDisableForcesAfter: true,
|
|
1178
|
+
precomputeMaxTicks: Infinity,
|
|
1179
|
+
precomputeMaxTimeMs: opts.maxMs ?? Infinity,
|
|
1180
|
+
},
|
|
1181
|
+
});
|
|
1182
|
+
graph.precompute();
|
|
1183
|
+
graph.destroy();
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1113
1186
|
const GRAPH_SETTINGS = {
|
|
1114
1187
|
zoomAnimation: true,
|
|
1115
1188
|
zoomAnimationDuration: 300,
|
|
@@ -1124,9 +1197,7 @@ const GRAPH_SETTINGS = {
|
|
|
1124
1197
|
zoomInitial: null,
|
|
1125
1198
|
showDrawTime: true,
|
|
1126
1199
|
showDrawTimeEveryTick: false,
|
|
1127
|
-
|
|
1128
|
-
const PERFORMANCE_GRAPH_SETTINGS = {
|
|
1129
|
-
...GRAPH_SETTINGS,
|
|
1200
|
+
maxFps: 120,
|
|
1130
1201
|
};
|
|
1131
1202
|
|
|
1132
1203
|
const HIGHLIGHT_SETTINGS = {
|
|
@@ -1187,9 +1258,6 @@ const HIGHLIGHT_SETTINGS = {
|
|
|
1187
1258
|
highlightByLinkForArrowBorderColor: null,
|
|
1188
1259
|
highlightByLinkForArrowBorderSizingAdditional: 0,
|
|
1189
1260
|
};
|
|
1190
|
-
const PERFORMANCE_HIGHLIGHT_SETTINGS = {
|
|
1191
|
-
...HIGHLIGHT_SETTINGS,
|
|
1192
|
-
};
|
|
1193
1261
|
|
|
1194
1262
|
const LINK_SETTINGS = {
|
|
1195
1263
|
smartCache: true,
|
|
@@ -1220,14 +1288,6 @@ const LINK_OPTIONS = {
|
|
|
1220
1288
|
particleBorderWidth: 0.1,
|
|
1221
1289
|
particleRadius: 0.5,
|
|
1222
1290
|
};
|
|
1223
|
-
const PERFORMANCE_LINK_SETTINGS = {
|
|
1224
|
-
...LINK_SETTINGS,
|
|
1225
|
-
particles: false,
|
|
1226
|
-
prettyDraw: false,
|
|
1227
|
-
};
|
|
1228
|
-
const PERFORMANCE_LINK_OPTIONS = {
|
|
1229
|
-
...LINK_OPTIONS,
|
|
1230
|
-
};
|
|
1231
1291
|
|
|
1232
1292
|
const NODE_SETTINGS = {
|
|
1233
1293
|
smartCache: true,
|
|
@@ -1272,7 +1332,6 @@ const NODE_OPTIONS = {
|
|
|
1272
1332
|
textStyle: "normal",
|
|
1273
1333
|
textWeight: 500,
|
|
1274
1334
|
textGap: 0,
|
|
1275
|
-
label: null,
|
|
1276
1335
|
labelAlpha: 1,
|
|
1277
1336
|
labelAlign: "center",
|
|
1278
1337
|
labelColor: "#ffffff",
|
|
@@ -1283,14 +1342,6 @@ const NODE_OPTIONS = {
|
|
|
1283
1342
|
labelWeight: 500,
|
|
1284
1343
|
labelWidth: 20,
|
|
1285
1344
|
};
|
|
1286
|
-
const PERFORMANCE_NODE_SETTINGS = {
|
|
1287
|
-
...NODE_SETTINGS,
|
|
1288
|
-
nodeRadiusFlexible: false,
|
|
1289
|
-
nodeSizeFlexible: false,
|
|
1290
|
-
};
|
|
1291
|
-
const PERFOMANCE_NODE_OPTIONS = {
|
|
1292
|
-
...NODE_OPTIONS,
|
|
1293
|
-
};
|
|
1294
1345
|
|
|
1295
1346
|
const GRAPH_CACHE_TYPE = {
|
|
1296
1347
|
NodeOptions: "nodeOptions",
|
|
@@ -1326,7 +1377,7 @@ function initArea() {
|
|
|
1326
1377
|
}
|
|
1327
1378
|
}
|
|
1328
1379
|
|
|
1329
|
-
function initDnd() {
|
|
1380
|
+
function initDnd(staticMode = false) {
|
|
1330
1381
|
if (!this.area || !this.nodes)
|
|
1331
1382
|
throw new Error("bad init data");
|
|
1332
1383
|
const dragHandler = d3Drag.drag()
|
|
@@ -1354,8 +1405,20 @@ function initDnd() {
|
|
|
1354
1405
|
const mouseEvent = event.sourceEvent;
|
|
1355
1406
|
const [pointerX, pointerY] = this.getPointerAreaPosition(mouseEvent);
|
|
1356
1407
|
if (this._translateExtent) {
|
|
1357
|
-
|
|
1358
|
-
|
|
1408
|
+
const x = Math.max(this._translateExtent[0][0], Math.min(this._translateExtent[1][0], pointerX));
|
|
1409
|
+
const y = Math.max(this._translateExtent[0][1], Math.min(this._translateExtent[1][1], pointerY));
|
|
1410
|
+
if (staticMode) {
|
|
1411
|
+
event.subject.x = x;
|
|
1412
|
+
event.subject.y = y;
|
|
1413
|
+
}
|
|
1414
|
+
else {
|
|
1415
|
+
event.subject.fx = x;
|
|
1416
|
+
event.subject.fy = y;
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
else if (staticMode) {
|
|
1420
|
+
event.subject.x = pointerX;
|
|
1421
|
+
event.subject.y = pointerY;
|
|
1359
1422
|
}
|
|
1360
1423
|
else {
|
|
1361
1424
|
event.subject.fx = pointerX;
|
|
@@ -1424,7 +1487,7 @@ function adjustPoint(x, y, xControl, yControl, radius) {
|
|
|
1424
1487
|
return [x + (dxToControl / distToControl) * radius, y + (dyToControl / distToControl) * radius];
|
|
1425
1488
|
}
|
|
1426
1489
|
|
|
1427
|
-
function getDrawLink() {
|
|
1490
|
+
function getDrawLink(linkBatch, particleBatch, arrowBatch, now) {
|
|
1428
1491
|
return function drawLink(link, index) {
|
|
1429
1492
|
if (!this.context ||
|
|
1430
1493
|
typeof link.source !== "object" ||
|
|
@@ -1533,10 +1596,9 @@ function getDrawLink() {
|
|
|
1533
1596
|
}
|
|
1534
1597
|
}
|
|
1535
1598
|
/** Link */
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
this.context.lineWidth = width;
|
|
1599
|
+
const linkBatchKey = `${alpha}|${color}|${width}`;
|
|
1600
|
+
linkBatch[linkBatchKey] ??= [];
|
|
1601
|
+
const linkGroup = linkBatch[linkBatchKey];
|
|
1540
1602
|
let xStart = link.source.x;
|
|
1541
1603
|
let yStart = link.source.y;
|
|
1542
1604
|
let xEnd = link.target.x;
|
|
@@ -1566,9 +1628,7 @@ function getDrawLink() {
|
|
|
1566
1628
|
link._y2 = yEnd;
|
|
1567
1629
|
link._ax = xEndArrow;
|
|
1568
1630
|
link._ay = yEndArrow;
|
|
1569
|
-
|
|
1570
|
-
this.context.lineTo(xEnd, yEnd);
|
|
1571
|
-
this.context.stroke();
|
|
1631
|
+
linkGroup.push({ curve: false, xStart, yStart, xEnd, yEnd, xControl, yControl });
|
|
1572
1632
|
}
|
|
1573
1633
|
else {
|
|
1574
1634
|
const position = calculateCurveLinkPositionByNode(xStart, yStart, xEnd, yEnd, link.source, link.target, link._groupIndex ?? 0, isHasArrow ? arrowSize : 0);
|
|
@@ -1589,14 +1649,7 @@ function getDrawLink() {
|
|
|
1589
1649
|
link._ax = position.xEndArrow;
|
|
1590
1650
|
link._ay = position.yEndArrow;
|
|
1591
1651
|
linkDistance = approximateQuadraticBezierLength(position.xStart, position.yStart, position.xControl, position.yControl, position.xEnd, position.yEnd);
|
|
1592
|
-
|
|
1593
|
-
this.context.moveTo(position.xStart, position.yStart);
|
|
1594
|
-
this.context.quadraticCurveTo(position.xControl, position.yControl, position.xEnd, position.yEnd);
|
|
1595
|
-
this.context.setLineDash([]);
|
|
1596
|
-
// if (isDashed) {
|
|
1597
|
-
// this.context.setLineDash([10, 5]);
|
|
1598
|
-
// }
|
|
1599
|
-
this.context.stroke();
|
|
1652
|
+
linkGroup.push({ curve: true, xStart, yStart, xEnd, yEnd, xControl, yControl });
|
|
1600
1653
|
}
|
|
1601
1654
|
/** Particle */
|
|
1602
1655
|
if (this.linkSettings.particles && (currentLinkHighlighted || currentNodeHighlighted)) {
|
|
@@ -1612,6 +1665,9 @@ function getDrawLink() {
|
|
|
1612
1665
|
}
|
|
1613
1666
|
this.particles[index] = particles;
|
|
1614
1667
|
}
|
|
1668
|
+
const particleBatchKey = `${linkOptions.particleBorderColor}|${linkOptions.particleBorderWidth}|${linkOptions.particleColor}`;
|
|
1669
|
+
particleBatch[particleBatchKey] ??= [];
|
|
1670
|
+
const particleGroup = particleBatch[particleBatchKey];
|
|
1615
1671
|
this.particles[index].forEach((particle, _, particles) => {
|
|
1616
1672
|
if (!this.context)
|
|
1617
1673
|
return;
|
|
@@ -1626,17 +1682,10 @@ function getDrawLink() {
|
|
|
1626
1682
|
xControl,
|
|
1627
1683
|
yControl,
|
|
1628
1684
|
speed,
|
|
1685
|
+
now,
|
|
1629
1686
|
});
|
|
1630
1687
|
if (particle.x != undefined && particle.y != undefined) {
|
|
1631
|
-
|
|
1632
|
-
this.context.strokeStyle = linkOptions.particleBorderColor;
|
|
1633
|
-
this.context.lineWidth = linkOptions.particleBorderWidth;
|
|
1634
|
-
this.context.arc(particle.x, particle.y, linkOptions.particleRadius, 0, Math.PI * 2);
|
|
1635
|
-
this.context.fillStyle = linkOptions.particleColor;
|
|
1636
|
-
this.context.fill();
|
|
1637
|
-
if (linkOptions.particleBorderWidth > 0) {
|
|
1638
|
-
this.context.stroke();
|
|
1639
|
-
}
|
|
1688
|
+
particleGroup.push({ x: particle.x, y: particle.y, r: linkOptions.particleRadius });
|
|
1640
1689
|
}
|
|
1641
1690
|
});
|
|
1642
1691
|
}
|
|
@@ -1656,19 +1705,15 @@ function getDrawLink() {
|
|
|
1656
1705
|
angle = Math.atan2(tangentY, tangentX);
|
|
1657
1706
|
}
|
|
1658
1707
|
}
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
this.context.fill();
|
|
1669
|
-
if (arrowBorderWidth > 0) {
|
|
1670
|
-
this.context.stroke();
|
|
1671
|
-
}
|
|
1708
|
+
const arrowBatchKey = `${arrowAlpha}|${arrowBorderColor}|${arrowBorderWidth}|${arrowColor}`;
|
|
1709
|
+
arrowBatch[arrowBatchKey] ??= [];
|
|
1710
|
+
const arrowGroup = arrowBatch[arrowBatchKey];
|
|
1711
|
+
arrowGroup.push({
|
|
1712
|
+
x: xEndArrow,
|
|
1713
|
+
y: yEndArrow,
|
|
1714
|
+
size: arrowSize,
|
|
1715
|
+
angle,
|
|
1716
|
+
});
|
|
1672
1717
|
}
|
|
1673
1718
|
if (linkOptions.drawExtraLink) {
|
|
1674
1719
|
linkOptions.drawExtraLink.call(this, link, { ...linkOptions, alpha });
|
|
@@ -1676,52 +1721,7 @@ function getDrawLink() {
|
|
|
1676
1721
|
};
|
|
1677
1722
|
}
|
|
1678
1723
|
|
|
1679
|
-
|
|
1680
|
-
function drawText({ context, textAlign, textColor, textFont, textStyle, textGap, textWeight, textSize, x, y, lines, }) {
|
|
1681
|
-
context.font = `${textStyle} normal ${textWeight} ${textSize}px ${textFont}`;
|
|
1682
|
-
context.fillStyle = textColor;
|
|
1683
|
-
context.textAlign = textAlign;
|
|
1684
|
-
lines.forEach((line, index) => {
|
|
1685
|
-
context.fillText(line, x, y + index * textSize + index * textGap);
|
|
1686
|
-
});
|
|
1687
|
-
}
|
|
1688
|
-
function getTextLines({ context, textAlign, textColor, textFont, textStyle, textWeight, textSize, text, maxWidth, }) {
|
|
1689
|
-
context.font = `${textStyle} normal ${textWeight} ${textSize}px ${textFont}`;
|
|
1690
|
-
context.fillStyle = textColor;
|
|
1691
|
-
context.textAlign = textAlign;
|
|
1692
|
-
const spaceWidth = context.measureText(" ").width;
|
|
1693
|
-
const lines = [];
|
|
1694
|
-
let lineWidth = 0;
|
|
1695
|
-
let line = "";
|
|
1696
|
-
let currentMaxSize = 0;
|
|
1697
|
-
for (const word of text.split(" ")) {
|
|
1698
|
-
const size = context.measureText(word).width;
|
|
1699
|
-
lineWidth += size + spaceWidth;
|
|
1700
|
-
if (line === "") {
|
|
1701
|
-
line = word;
|
|
1702
|
-
continue;
|
|
1703
|
-
}
|
|
1704
|
-
if (lineWidth > maxWidth) {
|
|
1705
|
-
const initialSize = lineWidth - size - spaceWidth;
|
|
1706
|
-
if (initialSize > currentMaxSize)
|
|
1707
|
-
currentMaxSize = initialSize;
|
|
1708
|
-
lineWidth = size;
|
|
1709
|
-
lines.push(line);
|
|
1710
|
-
line = word;
|
|
1711
|
-
}
|
|
1712
|
-
else {
|
|
1713
|
-
lineWidth += spaceWidth;
|
|
1714
|
-
line += `${SPACE}${word}`;
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
if (line !== "")
|
|
1718
|
-
lines.push(line);
|
|
1719
|
-
if (lineWidth > currentMaxSize)
|
|
1720
|
-
currentMaxSize = lineWidth;
|
|
1721
|
-
return { lines, currentMaxSize };
|
|
1722
|
-
}
|
|
1723
|
-
|
|
1724
|
-
function getDrawNode(nodeRenders, textRenders) {
|
|
1724
|
+
function getDrawNode(nodeBatch, nodeImageBatch, textBatch, deferredNodeRender, deferredTextRender, area) {
|
|
1725
1725
|
return function drawNode(node, index) {
|
|
1726
1726
|
if (!this.context || !node.x || !node.y)
|
|
1727
1727
|
return;
|
|
@@ -1735,12 +1735,12 @@ function getDrawNode(nodeRenders, textRenders) {
|
|
|
1735
1735
|
if (!nodeOptions)
|
|
1736
1736
|
return;
|
|
1737
1737
|
if (nodeOptions.nodeDraw && nodeOptions.textDraw) {
|
|
1738
|
-
|
|
1738
|
+
deferredNodeRender.push(() => {
|
|
1739
1739
|
if (nodeOptions.nodeDraw) {
|
|
1740
1740
|
nodeOptions.nodeDraw.bind(this)(node, nodeOptions);
|
|
1741
1741
|
}
|
|
1742
1742
|
});
|
|
1743
|
-
|
|
1743
|
+
deferredTextRender.push(() => {
|
|
1744
1744
|
if (nodeOptions.textDraw) {
|
|
1745
1745
|
nodeOptions.textDraw.bind(this)(node, nodeOptions);
|
|
1746
1746
|
}
|
|
@@ -1860,7 +1860,6 @@ function getDrawNode(nodeRenders, textRenders) {
|
|
|
1860
1860
|
labelWeight = highlightOptions.labelWeight;
|
|
1861
1861
|
}
|
|
1862
1862
|
}
|
|
1863
|
-
/** Node parameters */
|
|
1864
1863
|
node._radius = radius;
|
|
1865
1864
|
node._borderWidth = borderWidth;
|
|
1866
1865
|
node._width = width;
|
|
@@ -1870,138 +1869,55 @@ function getDrawNode(nodeRenders, textRenders) {
|
|
|
1870
1869
|
? Math.min(nodeOptions.borderRadius, nodeOptions.width / 2, nodeOptions.height / 2)
|
|
1871
1870
|
: 0;
|
|
1872
1871
|
node._shape = nodeOptions.shape ?? "circle";
|
|
1873
|
-
|
|
1874
|
-
if (!isNodeVisible({
|
|
1875
|
-
height: this.height,
|
|
1876
|
-
width: this.width,
|
|
1877
|
-
transform: this.areaTransform,
|
|
1878
|
-
node,
|
|
1879
|
-
})) {
|
|
1872
|
+
if (!isNodeVisible(node, area)) {
|
|
1880
1873
|
node._visible = false;
|
|
1881
1874
|
return;
|
|
1882
1875
|
}
|
|
1883
1876
|
node._visible = true;
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
}
|
|
1903
|
-
else {
|
|
1904
|
-
this.context.arc(node.x, node.y, radius, 0, 2 * Math.PI);
|
|
1905
|
-
this.context.closePath();
|
|
1906
|
-
this.context.save();
|
|
1907
|
-
this.context.clip();
|
|
1908
|
-
this.context.drawImage(node.image, node.x - radius, node.y - radius, radius * 2, radius * 2);
|
|
1909
|
-
this.context.restore();
|
|
1910
|
-
if (borderWidth > 0) {
|
|
1911
|
-
this.context.stroke();
|
|
1912
|
-
}
|
|
1913
|
-
}
|
|
1914
|
-
if (node.label && labelLines) {
|
|
1915
|
-
this.context.globalAlpha = labelAlpha;
|
|
1916
|
-
drawText({
|
|
1917
|
-
context: this.context,
|
|
1918
|
-
lines: labelLines,
|
|
1919
|
-
textAlign: nodeOptions.labelAlign,
|
|
1920
|
-
textColor: nodeOptions.labelColor,
|
|
1921
|
-
textFont: nodeOptions.labelFont,
|
|
1922
|
-
textGap: nodeOptions.labelGap,
|
|
1923
|
-
textSize: labelSize,
|
|
1924
|
-
textStyle: nodeOptions.labelStyle,
|
|
1925
|
-
textWeight: labelWeight,
|
|
1926
|
-
x: node.x,
|
|
1927
|
-
y: node.y + labelSize / 3,
|
|
1928
|
-
});
|
|
1929
|
-
}
|
|
1930
|
-
break;
|
|
1931
|
-
}
|
|
1932
|
-
case "square": {
|
|
1933
|
-
if (!node.image) {
|
|
1934
|
-
this.context.roundRect(node.x - width / 2, node.y - height / 2, width, height, node._borderRadius);
|
|
1935
|
-
this.context.fill();
|
|
1936
|
-
if (borderWidth > 0) {
|
|
1937
|
-
this.context.stroke();
|
|
1938
|
-
}
|
|
1939
|
-
}
|
|
1940
|
-
else {
|
|
1941
|
-
this.context.roundRect(node.x - width / 2, node.y - height / 2, width, height, node._borderRadius);
|
|
1942
|
-
this.context.closePath();
|
|
1943
|
-
this.context.save();
|
|
1944
|
-
this.context.clip();
|
|
1945
|
-
this.context.drawImage(node.image, node.x - width / 2, node.y - height / 2, width, height);
|
|
1946
|
-
this.context.restore();
|
|
1947
|
-
if (borderWidth > 0) {
|
|
1948
|
-
this.context.stroke();
|
|
1949
|
-
}
|
|
1950
|
-
}
|
|
1951
|
-
if (node.label && labelLines) {
|
|
1952
|
-
this.context.globalAlpha = labelAlpha;
|
|
1953
|
-
drawText({
|
|
1954
|
-
context: this.context,
|
|
1955
|
-
lines: labelLines,
|
|
1956
|
-
textAlign: nodeOptions.labelAlign,
|
|
1957
|
-
textColor: nodeOptions.labelColor,
|
|
1958
|
-
textFont: nodeOptions.labelFont,
|
|
1959
|
-
textGap: nodeOptions.labelGap,
|
|
1960
|
-
textSize: labelSize,
|
|
1961
|
-
textStyle: nodeOptions.labelStyle,
|
|
1962
|
-
textWeight: labelWeight,
|
|
1963
|
-
x: node.x,
|
|
1964
|
-
y: node.y + labelSize / 3,
|
|
1965
|
-
});
|
|
1966
|
-
}
|
|
1967
|
-
break;
|
|
1968
|
-
}
|
|
1969
|
-
case "text": {
|
|
1970
|
-
if (this.nodeSettings.textNodeDebug) {
|
|
1971
|
-
this.context.strokeRect(node.x - width / 2, node.y - height / 2, width, height);
|
|
1972
|
-
}
|
|
1973
|
-
if (nodeOptions.label && labelLines)
|
|
1974
|
-
drawText({
|
|
1975
|
-
lines: labelLines,
|
|
1976
|
-
context: this.context,
|
|
1977
|
-
textAlign: nodeOptions.labelAlign,
|
|
1978
|
-
textColor: nodeOptions.labelColor,
|
|
1979
|
-
textFont: nodeOptions.labelFont,
|
|
1980
|
-
textSize: labelSize,
|
|
1981
|
-
x: node.x,
|
|
1982
|
-
y: node.y + textSize / 4 - (labelLines.length - 1) * (textSize / 2),
|
|
1983
|
-
textStyle: nodeOptions.labelStyle,
|
|
1984
|
-
textWeight,
|
|
1985
|
-
textGap: nodeOptions.labelGap,
|
|
1986
|
-
});
|
|
1987
|
-
this.context.fill();
|
|
1988
|
-
if (borderWidth > 0) {
|
|
1989
|
-
this.context.stroke();
|
|
1990
|
-
}
|
|
1991
|
-
break;
|
|
1992
|
-
}
|
|
1993
|
-
default: {
|
|
1994
|
-
this.context.arc(node.x, node.y, radius, 0, 2 * Math.PI);
|
|
1995
|
-
this.context.fill();
|
|
1996
|
-
if (borderWidth > 0) {
|
|
1997
|
-
this.context.stroke();
|
|
1998
|
-
}
|
|
1999
|
-
break;
|
|
2000
|
-
}
|
|
2001
|
-
}
|
|
1877
|
+
const nodeBatchKey = `${alpha}|${borderColor}|${borderWidth}|${color}`;
|
|
1878
|
+
let nodeGroup;
|
|
1879
|
+
if (!node.image) {
|
|
1880
|
+
nodeBatch[nodeBatchKey] ??= [];
|
|
1881
|
+
nodeGroup = nodeBatch[nodeBatchKey];
|
|
1882
|
+
}
|
|
1883
|
+
else {
|
|
1884
|
+
nodeImageBatch[nodeBatchKey] ??= [];
|
|
1885
|
+
nodeGroup = nodeImageBatch[nodeBatchKey];
|
|
1886
|
+
}
|
|
1887
|
+
nodeGroup.push({
|
|
1888
|
+
shape: nodeOptions.shape,
|
|
1889
|
+
x: node.x,
|
|
1890
|
+
y: node.y,
|
|
1891
|
+
radius,
|
|
1892
|
+
width,
|
|
1893
|
+
height,
|
|
1894
|
+
image: node.image,
|
|
2002
1895
|
});
|
|
1896
|
+
const labelLines = this.cachedNodeLabel[index];
|
|
1897
|
+
if (labelLines && labelLines.length > 0) {
|
|
1898
|
+
let y = node.y + labelSize / 3;
|
|
1899
|
+
let weight = labelWeight;
|
|
1900
|
+
if (nodeOptions.shape == "text") {
|
|
1901
|
+
y = node.y + textSize / 4 - (labelLines.length - 1) * (textSize / 2);
|
|
1902
|
+
weight = textWeight;
|
|
1903
|
+
}
|
|
1904
|
+
const font = `${nodeOptions.labelStyle} normal ${weight} ${labelSize}px ${nodeOptions.labelFont}`;
|
|
1905
|
+
textBatch[font] ??= {};
|
|
1906
|
+
const fontBatch = textBatch[font];
|
|
1907
|
+
const textBatchKey = `${labelAlpha}|${nodeOptions.labelAlign}|${nodeOptions.labelColor}`;
|
|
1908
|
+
fontBatch[textBatchKey] ??= [];
|
|
1909
|
+
const textGroup = fontBatch[textBatchKey];
|
|
1910
|
+
for (let i = 0; i < labelLines.length; i++) {
|
|
1911
|
+
const line = labelLines[i];
|
|
1912
|
+
textGroup.push({
|
|
1913
|
+
text: line,
|
|
1914
|
+
x: node.x,
|
|
1915
|
+
y: y + i * textSize + i * nodeOptions.textGap,
|
|
1916
|
+
});
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
2003
1919
|
if (nodeOptions.nodeExtraDraw) {
|
|
2004
|
-
|
|
1920
|
+
deferredNodeRender.push(() => {
|
|
2005
1921
|
nodeOptions?.nodeExtraDraw?.bind?.(this)?.(node, {
|
|
2006
1922
|
...nodeOptions,
|
|
2007
1923
|
radius,
|
|
@@ -2015,12 +1931,11 @@ function getDrawNode(nodeRenders, textRenders) {
|
|
|
2015
1931
|
});
|
|
2016
1932
|
});
|
|
2017
1933
|
}
|
|
2018
|
-
/** Text draw */
|
|
2019
1934
|
const textLines = this.cachedNodeText[index];
|
|
2020
|
-
if (
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
nodeOptions
|
|
1935
|
+
if (textLines && textLines.length > 0) {
|
|
1936
|
+
if (nodeOptions.textDraw) {
|
|
1937
|
+
deferredTextRender.push(() => {
|
|
1938
|
+
nodeOptions?.textDraw?.bind?.(this)?.(node, {
|
|
2024
1939
|
...nodeOptions,
|
|
2025
1940
|
radius,
|
|
2026
1941
|
alpha,
|
|
@@ -2031,34 +1946,32 @@ function getDrawNode(nodeRenders, textRenders) {
|
|
|
2031
1946
|
textShiftY,
|
|
2032
1947
|
textWeight,
|
|
2033
1948
|
});
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
textSize,
|
|
1949
|
+
});
|
|
1950
|
+
}
|
|
1951
|
+
let y = node.y + textShiftY;
|
|
1952
|
+
if (nodeOptions.shape === "circle") {
|
|
1953
|
+
y += radius;
|
|
1954
|
+
}
|
|
1955
|
+
if (nodeOptions.shape === "square" || nodeOptions.shape === "text") {
|
|
1956
|
+
y += height / 2;
|
|
1957
|
+
}
|
|
1958
|
+
const font = `${nodeOptions.textStyle} normal ${textWeight} ${textSize}px ${nodeOptions.textFont}`;
|
|
1959
|
+
textBatch[font] ??= {};
|
|
1960
|
+
const fontBatch = textBatch[font];
|
|
1961
|
+
const textBatchKey = `${textAlpha}|${nodeOptions.textAlign}|${nodeOptions.textColor}`;
|
|
1962
|
+
fontBatch[textBatchKey] ??= [];
|
|
1963
|
+
const textGroup = fontBatch[textBatchKey];
|
|
1964
|
+
for (let i = 0; i < textLines.length; i++) {
|
|
1965
|
+
const line = textLines[i];
|
|
1966
|
+
textGroup.push({
|
|
1967
|
+
text: line,
|
|
2054
1968
|
x: node.x + textShiftX,
|
|
2055
|
-
y,
|
|
2056
|
-
textStyle: nodeOptions.textStyle,
|
|
2057
|
-
textWeight,
|
|
2058
|
-
textGap: nodeOptions.textGap,
|
|
1969
|
+
y: y + i * textSize + i * nodeOptions.textGap,
|
|
2059
1970
|
});
|
|
2060
|
-
|
|
2061
|
-
|
|
1971
|
+
}
|
|
1972
|
+
if (nodeOptions.textExtraDraw) {
|
|
1973
|
+
deferredTextRender.push(() => {
|
|
1974
|
+
nodeOptions?.textExtraDraw?.bind?.(this)?.(node, {
|
|
2062
1975
|
...nodeOptions,
|
|
2063
1976
|
radius,
|
|
2064
1977
|
alpha,
|
|
@@ -2069,13 +1982,39 @@ function getDrawNode(nodeRenders, textRenders) {
|
|
|
2069
1982
|
textShiftY,
|
|
2070
1983
|
textWeight,
|
|
2071
1984
|
});
|
|
2072
|
-
}
|
|
2073
|
-
}
|
|
1985
|
+
});
|
|
1986
|
+
}
|
|
2074
1987
|
}
|
|
2075
1988
|
};
|
|
2076
1989
|
}
|
|
2077
1990
|
|
|
1991
|
+
const COS_PI_6 = 0.8660254037844386;
|
|
1992
|
+
const SIN_PI_6 = 0.5;
|
|
1993
|
+
function clearBatch(batch) {
|
|
1994
|
+
// eslint-disable-next-line guard-for-in
|
|
1995
|
+
for (const key in batch) {
|
|
1996
|
+
batch[key].length = 0;
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
function clearNestedBatch(batch) {
|
|
2000
|
+
// eslint-disable-next-line guard-for-in
|
|
2001
|
+
for (const outerKey in batch) {
|
|
2002
|
+
const inner = batch[outerKey];
|
|
2003
|
+
// eslint-disable-next-line guard-for-in
|
|
2004
|
+
for (const innerKey in inner) {
|
|
2005
|
+
inner[innerKey].length = 0;
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2078
2009
|
function initDraw() {
|
|
2010
|
+
const nodeBatch = {};
|
|
2011
|
+
const nodeImageBatch = {};
|
|
2012
|
+
const textBatch = {};
|
|
2013
|
+
const deferredNodeDraw = [];
|
|
2014
|
+
const deferredTextDraw = [];
|
|
2015
|
+
const linkBatch = {};
|
|
2016
|
+
const particleBatch = {};
|
|
2017
|
+
const arrowBatch = {};
|
|
2079
2018
|
function draw() {
|
|
2080
2019
|
if (!this.context)
|
|
2081
2020
|
return;
|
|
@@ -2083,18 +2022,196 @@ function initDraw() {
|
|
|
2083
2022
|
this.listeners.onDraw.call(this);
|
|
2084
2023
|
return;
|
|
2085
2024
|
}
|
|
2025
|
+
clearBatch(nodeBatch);
|
|
2026
|
+
clearBatch(nodeImageBatch);
|
|
2027
|
+
clearNestedBatch(textBatch);
|
|
2028
|
+
deferredNodeDraw.length = 0;
|
|
2029
|
+
deferredTextDraw.length = 0;
|
|
2030
|
+
clearBatch(linkBatch);
|
|
2031
|
+
clearBatch(particleBatch);
|
|
2032
|
+
clearBatch(arrowBatch);
|
|
2033
|
+
const k = this.areaTransform.k;
|
|
2034
|
+
const area = {
|
|
2035
|
+
left: -this.areaTransform.x / k,
|
|
2036
|
+
right: (this.width - this.areaTransform.x) / k,
|
|
2037
|
+
top: -this.areaTransform.y / k,
|
|
2038
|
+
bottom: (this.height - this.areaTransform.y) / k,
|
|
2039
|
+
};
|
|
2086
2040
|
this.context.save();
|
|
2087
2041
|
this.context.clearRect(0, 0, this.width, this.height);
|
|
2088
2042
|
this.context.translate(this.areaTransform.x, this.areaTransform.y);
|
|
2089
2043
|
this.context.scale(this.areaTransform.k, this.areaTransform.k);
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2044
|
+
this.nodes.forEach(getDrawNode(nodeBatch, nodeImageBatch, textBatch, deferredNodeDraw, deferredTextDraw, area), this);
|
|
2045
|
+
this.links.forEach(getDrawLink(linkBatch, particleBatch, arrowBatch, performance.now()), this);
|
|
2046
|
+
const linkKeys = Object.keys(linkBatch);
|
|
2047
|
+
for (let i = 0; i < linkKeys.length; i++) {
|
|
2048
|
+
const key = linkKeys[i];
|
|
2049
|
+
const group = linkBatch[key];
|
|
2050
|
+
const [alpha, color, width] = key.split("|");
|
|
2051
|
+
this.context.beginPath();
|
|
2052
|
+
this.context.globalAlpha = +alpha;
|
|
2053
|
+
this.context.strokeStyle = color;
|
|
2054
|
+
this.context.lineWidth = +width;
|
|
2055
|
+
this.context.setLineDash([]);
|
|
2056
|
+
for (let j = 0; j < group.length; j++) {
|
|
2057
|
+
const item = group[j];
|
|
2058
|
+
if (!item.curve) {
|
|
2059
|
+
this.context.moveTo(item.xStart, item.yStart);
|
|
2060
|
+
this.context.lineTo(item.xEnd, item.yEnd);
|
|
2061
|
+
}
|
|
2062
|
+
else {
|
|
2063
|
+
this.context.moveTo(item.xStart, item.yStart);
|
|
2064
|
+
this.context.quadraticCurveTo(item.xControl, item.yControl, item.xEnd, item.yEnd);
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
this.context.stroke();
|
|
2068
|
+
}
|
|
2069
|
+
const particleKeys = Object.keys(particleBatch);
|
|
2070
|
+
for (let i = 0; i < particleKeys.length; i++) {
|
|
2071
|
+
const key = particleKeys[i];
|
|
2072
|
+
const group = particleBatch[key];
|
|
2073
|
+
const [bcolor, width, color] = key.split("|");
|
|
2074
|
+
this.context.beginPath();
|
|
2075
|
+
this.context.globalAlpha = 1;
|
|
2076
|
+
this.context.strokeStyle = bcolor;
|
|
2077
|
+
this.context.lineWidth = +width;
|
|
2078
|
+
this.context.fillStyle = color;
|
|
2079
|
+
for (let j = 0; j < group.length; j++) {
|
|
2080
|
+
const item = group[j];
|
|
2081
|
+
this.context.moveTo(item.x + item.r, item.y);
|
|
2082
|
+
this.context.arc(item.x, item.y, item.r, 0, Math.PI * 2);
|
|
2083
|
+
}
|
|
2084
|
+
this.context.fill();
|
|
2085
|
+
if (+width > 0) {
|
|
2086
|
+
this.context.stroke();
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
const arrowKeys = Object.keys(arrowBatch);
|
|
2090
|
+
for (let i = 0; i < arrowKeys.length; i++) {
|
|
2091
|
+
const key = arrowKeys[i];
|
|
2092
|
+
const group = arrowBatch[key];
|
|
2093
|
+
const [alpha, bcolor, width, color] = key.split("|");
|
|
2094
|
+
this.context.beginPath();
|
|
2095
|
+
this.context.globalAlpha = +alpha;
|
|
2096
|
+
this.context.strokeStyle = bcolor;
|
|
2097
|
+
this.context.lineWidth = +width;
|
|
2098
|
+
this.context.fillStyle = color;
|
|
2099
|
+
for (let j = 0; j < group.length; j++) {
|
|
2100
|
+
const item = group[j];
|
|
2101
|
+
this.context.moveTo(item.x, item.y);
|
|
2102
|
+
const cosA = Math.cos(item.angle);
|
|
2103
|
+
const sinA = Math.sin(item.angle);
|
|
2104
|
+
const cos1 = cosA * COS_PI_6 + sinA * SIN_PI_6;
|
|
2105
|
+
const sin1 = sinA * COS_PI_6 - cosA * SIN_PI_6;
|
|
2106
|
+
const cos2 = cosA * COS_PI_6 - sinA * SIN_PI_6;
|
|
2107
|
+
const sin2 = sinA * COS_PI_6 + cosA * SIN_PI_6;
|
|
2108
|
+
this.context.lineTo(item.x - item.size * cos1, item.y - item.size * sin1);
|
|
2109
|
+
this.context.lineTo(item.x - item.size * cos2, item.y - item.size * sin2);
|
|
2110
|
+
this.context.closePath();
|
|
2111
|
+
}
|
|
2112
|
+
this.context.fill();
|
|
2113
|
+
if (+width > 0) {
|
|
2114
|
+
this.context.stroke();
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
const nodeKeys = Object.keys(nodeBatch);
|
|
2118
|
+
for (let i = 0; i < nodeKeys.length; i++) {
|
|
2119
|
+
const key = nodeKeys[i];
|
|
2120
|
+
const group = nodeBatch[key];
|
|
2121
|
+
const [alpha, bcolor, width, color] = key.split("|");
|
|
2122
|
+
this.context.beginPath();
|
|
2123
|
+
this.context.globalAlpha = +alpha;
|
|
2124
|
+
this.context.strokeStyle = bcolor;
|
|
2125
|
+
this.context.lineWidth = +width;
|
|
2126
|
+
this.context.fillStyle = color;
|
|
2127
|
+
for (let j = 0; j < group.length; j++) {
|
|
2128
|
+
const item = group[j];
|
|
2129
|
+
switch (item.shape) {
|
|
2130
|
+
case "circle": {
|
|
2131
|
+
this.context.moveTo(item.x + item.radius, item.y);
|
|
2132
|
+
this.context.arc(item.x, item.y, item.radius, 0, 2 * Math.PI);
|
|
2133
|
+
break;
|
|
2134
|
+
}
|
|
2135
|
+
case "square": {
|
|
2136
|
+
this.context.roundRect(item.x - item.width / 2, item.y - item.height / 2, item.width, item.height, item.radius);
|
|
2137
|
+
break;
|
|
2138
|
+
}
|
|
2139
|
+
case "text": {
|
|
2140
|
+
if (this.nodeSettings.textNodeDebug) {
|
|
2141
|
+
this.context.rect(item.x - item.width / 2, item.y - item.height / 2, item.width, item.height);
|
|
2142
|
+
}
|
|
2143
|
+
break;
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
this.context.fill();
|
|
2148
|
+
if (+width > 0) {
|
|
2149
|
+
this.context.stroke();
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
const nodeImageKeys = Object.keys(nodeImageBatch);
|
|
2153
|
+
for (let i = 0; i < nodeImageKeys.length; i++) {
|
|
2154
|
+
const key = nodeImageKeys[i];
|
|
2155
|
+
const group = nodeImageBatch[key];
|
|
2156
|
+
const [alpha, bcolor, width, color] = key.split("|");
|
|
2157
|
+
this.context.globalAlpha = +alpha;
|
|
2158
|
+
this.context.strokeStyle = bcolor;
|
|
2159
|
+
this.context.lineWidth = +width;
|
|
2160
|
+
this.context.fillStyle = color;
|
|
2161
|
+
for (let j = 0; j < group.length; j++) {
|
|
2162
|
+
const item = group[j];
|
|
2163
|
+
if (!item.image)
|
|
2164
|
+
continue;
|
|
2165
|
+
this.context.beginPath();
|
|
2166
|
+
switch (item.shape) {
|
|
2167
|
+
case "circle": {
|
|
2168
|
+
this.context.arc(item.x, item.y, item.radius, 0, 2 * Math.PI);
|
|
2169
|
+
this.context.closePath();
|
|
2170
|
+
this.context.save();
|
|
2171
|
+
this.context.clip();
|
|
2172
|
+
this.context.drawImage(item.image, item.x - item.radius, item.y - item.radius, item.radius * 2, item.radius * 2);
|
|
2173
|
+
this.context.restore();
|
|
2174
|
+
break;
|
|
2175
|
+
}
|
|
2176
|
+
case "square": {
|
|
2177
|
+
this.context.roundRect(item.x - item.width / 2, item.y - item.height / 2, item.width, item.height, item.radius);
|
|
2178
|
+
this.context.closePath();
|
|
2179
|
+
this.context.save();
|
|
2180
|
+
this.context.clip();
|
|
2181
|
+
this.context.drawImage(item.image, item.x - item.width / 2, item.y - item.height / 2, item.width, item.height);
|
|
2182
|
+
this.context.restore();
|
|
2183
|
+
break;
|
|
2184
|
+
}
|
|
2185
|
+
default: {
|
|
2186
|
+
continue;
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
if (+width > 0) {
|
|
2190
|
+
this.context.stroke();
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
const textKeys = Object.keys(textBatch);
|
|
2195
|
+
for (let i = 0; i < textKeys.length; i++) {
|
|
2196
|
+
const font = textKeys[i];
|
|
2197
|
+
const fontGroup = textBatch[font];
|
|
2198
|
+
const textInnerKeys = Object.keys(fontGroup);
|
|
2199
|
+
this.context.font = font;
|
|
2200
|
+
for (let j = 0; j < textInnerKeys.length; j++) {
|
|
2201
|
+
const key = textInnerKeys[j];
|
|
2202
|
+
const group = fontGroup[key];
|
|
2203
|
+
const [alpha, align, color] = key.split("|");
|
|
2204
|
+
this.context.globalAlpha = +alpha;
|
|
2205
|
+
this.context.textAlign = align;
|
|
2206
|
+
this.context.fillStyle = color;
|
|
2207
|
+
for (let k = 0; k < group.length; k++) {
|
|
2208
|
+
const item = group[k];
|
|
2209
|
+
this.context.fillText(item.text, item.x, item.y);
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
deferredNodeDraw.forEach((draw) => draw());
|
|
2214
|
+
deferredTextDraw.forEach((draw) => draw());
|
|
2098
2215
|
this.context.restore();
|
|
2099
2216
|
/** selection rectangle */
|
|
2100
2217
|
if (this.isSelecting && this.selectionRect) {
|
|
@@ -2123,6 +2240,7 @@ function initPointer() {
|
|
|
2123
2240
|
function onHover(event) {
|
|
2124
2241
|
if (!this.area || this.isSelecting)
|
|
2125
2242
|
return;
|
|
2243
|
+
const [pointerX, pointerY] = this.getPointerAreaPosition(event);
|
|
2126
2244
|
let currentNode;
|
|
2127
2245
|
let currentLink;
|
|
2128
2246
|
const checkHighlightNode = this.highlightSettings.highlightByHoverNode && !this.isDragging;
|
|
@@ -2130,7 +2248,6 @@ function initPointer() {
|
|
|
2130
2248
|
let highlightNode = true;
|
|
2131
2249
|
let highlightLink = true;
|
|
2132
2250
|
if (checkHighlightNode) {
|
|
2133
|
-
const [pointerX, pointerY] = this.getPointerAreaPosition(event);
|
|
2134
2251
|
currentNode = nodeByPointerGetter({
|
|
2135
2252
|
pointerX,
|
|
2136
2253
|
pointerY,
|
|
@@ -2143,7 +2260,6 @@ function initPointer() {
|
|
|
2143
2260
|
this.area.style.cursor = "pointer";
|
|
2144
2261
|
}
|
|
2145
2262
|
else if (checkHighlightLink) {
|
|
2146
|
-
const [pointerX, pointerY] = this.getPointerAreaPosition(event);
|
|
2147
2263
|
currentLink = linkByPointerGetter({
|
|
2148
2264
|
pointerX,
|
|
2149
2265
|
pointerY,
|
|
@@ -2167,7 +2283,6 @@ function initPointer() {
|
|
|
2167
2283
|
if (!this.listeners.onHover)
|
|
2168
2284
|
return;
|
|
2169
2285
|
if (!currentNode && !checkHighlightNode) {
|
|
2170
|
-
const [pointerX, pointerY] = this.getPointerAreaPosition(event);
|
|
2171
2286
|
currentNode = nodeByPointerGetter({
|
|
2172
2287
|
pointerX,
|
|
2173
2288
|
pointerY,
|
|
@@ -2175,7 +2290,6 @@ function initPointer() {
|
|
|
2175
2290
|
});
|
|
2176
2291
|
}
|
|
2177
2292
|
if (!currentNode && (!checkHighlightNode || (!checkHighlightLink && !currentLink))) {
|
|
2178
|
-
const [pointerX, pointerY] = this.getPointerAreaPosition(event);
|
|
2179
2293
|
currentLink = linkByPointerGetter({
|
|
2180
2294
|
pointerX,
|
|
2181
2295
|
pointerY,
|
|
@@ -2561,6 +2675,43 @@ function indexToPosition(n) {
|
|
|
2561
2675
|
// return n & 1 ? -(n >> 1) : n >> 1;
|
|
2562
2676
|
}
|
|
2563
2677
|
|
|
2678
|
+
const SPACE = " ";
|
|
2679
|
+
function getTextLines({ context, textAlign, textColor, textFont, textStyle, textWeight, textSize, text, maxWidth, }) {
|
|
2680
|
+
context.font = `${textStyle} normal ${textWeight} ${textSize}px ${textFont}`;
|
|
2681
|
+
context.fillStyle = textColor;
|
|
2682
|
+
context.textAlign = textAlign;
|
|
2683
|
+
const spaceWidth = context.measureText(" ").width;
|
|
2684
|
+
const lines = [];
|
|
2685
|
+
let lineWidth = 0;
|
|
2686
|
+
let line = "";
|
|
2687
|
+
let currentMaxSize = 0;
|
|
2688
|
+
for (const word of text.split(" ")) {
|
|
2689
|
+
const size = context.measureText(word).width;
|
|
2690
|
+
lineWidth += size + spaceWidth;
|
|
2691
|
+
if (line === "") {
|
|
2692
|
+
line = word;
|
|
2693
|
+
continue;
|
|
2694
|
+
}
|
|
2695
|
+
if (lineWidth > maxWidth) {
|
|
2696
|
+
const initialSize = lineWidth - size - spaceWidth;
|
|
2697
|
+
if (initialSize > currentMaxSize)
|
|
2698
|
+
currentMaxSize = initialSize;
|
|
2699
|
+
lineWidth = size;
|
|
2700
|
+
lines.push(line);
|
|
2701
|
+
line = word;
|
|
2702
|
+
}
|
|
2703
|
+
else {
|
|
2704
|
+
lineWidth += spaceWidth;
|
|
2705
|
+
line += `${SPACE}${word}`;
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
if (line !== "")
|
|
2709
|
+
lines.push(line);
|
|
2710
|
+
if (lineWidth > currentMaxSize)
|
|
2711
|
+
currentMaxSize = lineWidth;
|
|
2712
|
+
return { lines, currentMaxSize };
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2564
2715
|
function updateNodeCache() {
|
|
2565
2716
|
if (!this.context)
|
|
2566
2717
|
return;
|
|
@@ -2641,30 +2792,25 @@ function updateNodeCache() {
|
|
|
2641
2792
|
nodeOptions.labelSize = labelSize;
|
|
2642
2793
|
this.nodeOptionsCache[i] = nodeOptions;
|
|
2643
2794
|
}
|
|
2644
|
-
|
|
2795
|
+
const nodeOptions = this.nodeOptionsCache[i];
|
|
2645
2796
|
if (!nodeOptions)
|
|
2646
2797
|
continue;
|
|
2647
2798
|
/** label */
|
|
2648
2799
|
if (label) {
|
|
2649
|
-
|
|
2650
|
-
nodeOptions = nodeIterationExtractor(node, i, this.nodes, this, this.nodeSettings.options ?? {}, nodeOptionsGetter);
|
|
2651
|
-
const cache = this.nodeOptionsCache[i];
|
|
2652
|
-
if (cache)
|
|
2653
|
-
cache.label = nodeOptions.label;
|
|
2654
|
-
}
|
|
2800
|
+
const label = nodeIterationExtractor(node, i, this.nodes, this, this.nodeSettings.label, nodeLabelGetter);
|
|
2655
2801
|
/** label in not text shape */
|
|
2656
|
-
if (nodeOptions.shape !== "text" &&
|
|
2802
|
+
if (nodeOptions.shape !== "text" && label) {
|
|
2657
2803
|
this.context.font = `${nodeOptions.labelStyle} normal ${nodeOptions.labelWeight} ${nodeOptions.labelSize}px ${nodeOptions.labelFont}`;
|
|
2658
2804
|
this.context.fillStyle = nodeOptions.labelColor;
|
|
2659
2805
|
this.context.textAlign = nodeOptions.labelAlign;
|
|
2660
2806
|
if (nodeOptions.labelWidth == undefined ||
|
|
2661
|
-
this.context.measureText(
|
|
2662
|
-
this.cachedNodeLabel[i] = [
|
|
2807
|
+
this.context.measureText(label).width <= nodeOptions.labelWidth) {
|
|
2808
|
+
this.cachedNodeLabel[i] = [label];
|
|
2663
2809
|
}
|
|
2664
2810
|
const { lines } = getTextLines({
|
|
2665
2811
|
context: this.context,
|
|
2666
2812
|
maxWidth: nodeOptions.labelWidth,
|
|
2667
|
-
text:
|
|
2813
|
+
text: label,
|
|
2668
2814
|
textAlign: nodeOptions.labelAlign,
|
|
2669
2815
|
textColor: nodeOptions.labelColor,
|
|
2670
2816
|
textFont: nodeOptions.labelFont,
|
|
@@ -2675,10 +2821,10 @@ function updateNodeCache() {
|
|
|
2675
2821
|
this.cachedNodeLabel[i] = lines;
|
|
2676
2822
|
/** label in text shape */
|
|
2677
2823
|
}
|
|
2678
|
-
else if (nodeOptions.shape === "text" &&
|
|
2824
|
+
else if (nodeOptions.shape === "text" && label) {
|
|
2679
2825
|
const textInfo = getTextLines({
|
|
2680
2826
|
context: this.context,
|
|
2681
|
-
text:
|
|
2827
|
+
text: label,
|
|
2682
2828
|
textAlign: nodeOptions.labelAlign,
|
|
2683
2829
|
textColor: nodeOptions.labelColor,
|
|
2684
2830
|
textFont: nodeOptions.labelFont,
|
|
@@ -2704,17 +2850,10 @@ function updateNodeCache() {
|
|
|
2704
2850
|
}
|
|
2705
2851
|
/** text */
|
|
2706
2852
|
if (text) {
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
const cache = this.nodeOptionsCache[i];
|
|
2710
|
-
if (cache) {
|
|
2711
|
-
cache.text = nodeOptions.text;
|
|
2712
|
-
cache.textVisible = nodeOptions.textVisible;
|
|
2713
|
-
}
|
|
2714
|
-
}
|
|
2715
|
-
if (!nodeOptions.text) {
|
|
2853
|
+
const text = nodeIterationExtractor(node, i, this.nodes, this, this.nodeSettings.text, nodeTextGetter);
|
|
2854
|
+
if (!text) {
|
|
2716
2855
|
this.cachedNodeText[i] = [];
|
|
2717
|
-
|
|
2856
|
+
continue;
|
|
2718
2857
|
}
|
|
2719
2858
|
this.context.font = `${nodeOptions.textStyle} normal ${nodeOptions.textWeight} ${nodeOptions.textSize}px ${nodeOptions.textFont}`;
|
|
2720
2859
|
this.context.fillStyle = nodeOptions.textColor;
|
|
@@ -2722,7 +2861,7 @@ function updateNodeCache() {
|
|
|
2722
2861
|
const { lines } = getTextLines({
|
|
2723
2862
|
context: this.context,
|
|
2724
2863
|
maxWidth: nodeOptions.textWidth,
|
|
2725
|
-
text
|
|
2864
|
+
text,
|
|
2726
2865
|
textAlign: nodeOptions.textAlign,
|
|
2727
2866
|
textColor: nodeOptions.textColor,
|
|
2728
2867
|
textFont: nodeOptions.textFont,
|
|
@@ -3181,6 +3320,7 @@ class GraphCanvas {
|
|
|
3181
3320
|
areaTransform = d3Zoom.zoomIdentity;
|
|
3182
3321
|
_translateExtent;
|
|
3183
3322
|
draw;
|
|
3323
|
+
instantDraw;
|
|
3184
3324
|
eventAbortController;
|
|
3185
3325
|
cachedNodeText = [];
|
|
3186
3326
|
cachedNodeLabel = [];
|
|
@@ -3225,8 +3365,9 @@ class GraphCanvas {
|
|
|
3225
3365
|
this.links = links;
|
|
3226
3366
|
this.height = 0;
|
|
3227
3367
|
this.width = 0;
|
|
3228
|
-
|
|
3229
|
-
this.
|
|
3368
|
+
const draw = initDraw.call(this);
|
|
3369
|
+
this.draw = this.initSmartDraw(draw);
|
|
3370
|
+
this.instantDraw = draw;
|
|
3230
3371
|
}
|
|
3231
3372
|
get dpi() {
|
|
3232
3373
|
return devicePixelRatio;
|
|
@@ -3302,7 +3443,9 @@ class GraphCanvas {
|
|
|
3302
3443
|
changeSettings = (options, clearCache = true, precompute = false) => {
|
|
3303
3444
|
if (options.graphSettings) {
|
|
3304
3445
|
this.graphSettings = graphSettingsGetter(options.graphSettings, this.graphSettings);
|
|
3305
|
-
|
|
3446
|
+
const draw = initDraw.call(this);
|
|
3447
|
+
this.draw = this.initSmartDraw(draw);
|
|
3448
|
+
this.instantDraw = draw;
|
|
3306
3449
|
initZoom.call(this, this.areaTransform);
|
|
3307
3450
|
}
|
|
3308
3451
|
if (options.forceSettings) {
|
|
@@ -3368,7 +3511,7 @@ class GraphCanvas {
|
|
|
3368
3511
|
if (!this.context)
|
|
3369
3512
|
throw new Error("couldn't create canvas context");
|
|
3370
3513
|
this.context.scale(this.dpi, this.dpi);
|
|
3371
|
-
this.
|
|
3514
|
+
this.instantDraw();
|
|
3372
3515
|
};
|
|
3373
3516
|
clearCache = (keys) => {
|
|
3374
3517
|
if (keys === true) {
|
|
@@ -3443,18 +3586,6 @@ class GraphCanvas {
|
|
|
3443
3586
|
this.simulation.restart();
|
|
3444
3587
|
this.tick();
|
|
3445
3588
|
};
|
|
3446
|
-
start = () => {
|
|
3447
|
-
if (this.simulation)
|
|
3448
|
-
this.simulation.alpha(1).restart();
|
|
3449
|
-
if (this.container)
|
|
3450
|
-
this.container.style.display = "block";
|
|
3451
|
-
};
|
|
3452
|
-
stop = () => {
|
|
3453
|
-
if (this.simulation)
|
|
3454
|
-
this.simulation.stop();
|
|
3455
|
-
if (this.container)
|
|
3456
|
-
this.container.style.display = "none";
|
|
3457
|
-
};
|
|
3458
3589
|
create = () => {
|
|
3459
3590
|
this.init();
|
|
3460
3591
|
};
|
|
@@ -3467,6 +3598,33 @@ class GraphCanvas {
|
|
|
3467
3598
|
this.clearState();
|
|
3468
3599
|
this.clearCache(true);
|
|
3469
3600
|
};
|
|
3601
|
+
precompute = () => {
|
|
3602
|
+
initArea.call(this);
|
|
3603
|
+
updateNodeCache.call(this);
|
|
3604
|
+
updateLinkCache.call(this);
|
|
3605
|
+
initSimulation.call(this);
|
|
3606
|
+
this.restart(1);
|
|
3607
|
+
};
|
|
3608
|
+
initSmartDraw = (draw) => {
|
|
3609
|
+
const frameInterval = 1000 / this.graphSettings.maxFps;
|
|
3610
|
+
let debouncedDrawId;
|
|
3611
|
+
let lastDraw = 0;
|
|
3612
|
+
return () => {
|
|
3613
|
+
if (debouncedDrawId != undefined) {
|
|
3614
|
+
clearTimeout(debouncedDrawId);
|
|
3615
|
+
}
|
|
3616
|
+
const elapsed = performance.now() - lastDraw;
|
|
3617
|
+
if (elapsed < frameInterval) {
|
|
3618
|
+
debouncedDrawId = setTimeout(() => {
|
|
3619
|
+
debouncedDrawId = undefined;
|
|
3620
|
+
this.tick();
|
|
3621
|
+
}, frameInterval * 2);
|
|
3622
|
+
return;
|
|
3623
|
+
}
|
|
3624
|
+
lastDraw = performance.now();
|
|
3625
|
+
draw();
|
|
3626
|
+
};
|
|
3627
|
+
};
|
|
3470
3628
|
getPointerAreaPosition = (event) => {
|
|
3471
3629
|
let localX;
|
|
3472
3630
|
let localY;
|
|
@@ -3639,6 +3797,111 @@ class GraphCanvas {
|
|
|
3639
3797
|
};
|
|
3640
3798
|
}
|
|
3641
3799
|
|
|
3800
|
+
class StaticGraphCanvas extends GraphCanvas {
|
|
3801
|
+
get simulationWorking() {
|
|
3802
|
+
return false;
|
|
3803
|
+
}
|
|
3804
|
+
_rafTickId;
|
|
3805
|
+
init = () => {
|
|
3806
|
+
initArea.call(this);
|
|
3807
|
+
updateNodeCache.call(this);
|
|
3808
|
+
updateLinkCache.call(this);
|
|
3809
|
+
initDnd.call(this, true);
|
|
3810
|
+
initZoom.call(this);
|
|
3811
|
+
initResize.call(this);
|
|
3812
|
+
initSelection.call(this);
|
|
3813
|
+
initPointer.call(this);
|
|
3814
|
+
updateNodeCache.call(this);
|
|
3815
|
+
updateLinkCache.call(this);
|
|
3816
|
+
this.fitToView();
|
|
3817
|
+
this.tick();
|
|
3818
|
+
};
|
|
3819
|
+
tick = () => {
|
|
3820
|
+
if (this._rafTickId != undefined)
|
|
3821
|
+
return;
|
|
3822
|
+
this._rafTickId = requestAnimationFrame(() => {
|
|
3823
|
+
this._rafTickId = undefined;
|
|
3824
|
+
this.draw();
|
|
3825
|
+
});
|
|
3826
|
+
};
|
|
3827
|
+
restart = () => { };
|
|
3828
|
+
changeData = (options, _alpha, clearCache = true) => {
|
|
3829
|
+
if (options.links != undefined)
|
|
3830
|
+
this.links = options.links;
|
|
3831
|
+
if (options.nodes != undefined)
|
|
3832
|
+
this.nodes = options.nodes;
|
|
3833
|
+
if (options.nodes != undefined || options.links != undefined) {
|
|
3834
|
+
this.updateData(undefined, clearCache);
|
|
3835
|
+
}
|
|
3836
|
+
};
|
|
3837
|
+
changeSettings = (options, clearCache = true) => {
|
|
3838
|
+
if (options.graphSettings) {
|
|
3839
|
+
this.graphSettings = graphSettingsGetter(options.graphSettings, this.graphSettings);
|
|
3840
|
+
const draw = initDraw.call(this);
|
|
3841
|
+
this.draw = this.initSmartDraw(draw);
|
|
3842
|
+
this.instantDraw = draw;
|
|
3843
|
+
initZoom.call(this, this.areaTransform);
|
|
3844
|
+
}
|
|
3845
|
+
if (options.highlightSettings) {
|
|
3846
|
+
this.highlightSettings = highlightSettingsGetter(options.highlightSettings, this.highlightSettings);
|
|
3847
|
+
if (clearCache === true) {
|
|
3848
|
+
this.clearCache([
|
|
3849
|
+
GRAPH_CACHE_TYPE.NodeOptions,
|
|
3850
|
+
GRAPH_CACHE_TYPE.NodeText,
|
|
3851
|
+
GRAPH_CACHE_TYPE.NodeLabel,
|
|
3852
|
+
GRAPH_CACHE_TYPE.LinkOptions,
|
|
3853
|
+
]);
|
|
3854
|
+
}
|
|
3855
|
+
else {
|
|
3856
|
+
this.clearCache(clearCache);
|
|
3857
|
+
}
|
|
3858
|
+
}
|
|
3859
|
+
if (options.linkSettings) {
|
|
3860
|
+
this.linkSettings = linkSettingsGetter(options.linkSettings, this.linkSettings);
|
|
3861
|
+
if (clearCache) {
|
|
3862
|
+
this.clearCache([GRAPH_CACHE_TYPE.LinkOptions]);
|
|
3863
|
+
}
|
|
3864
|
+
else {
|
|
3865
|
+
this.clearCache(clearCache);
|
|
3866
|
+
}
|
|
3867
|
+
}
|
|
3868
|
+
if (options.nodeSettings) {
|
|
3869
|
+
this.nodeSettings = nodeSettingsGetter(options.nodeSettings, this.nodeSettings);
|
|
3870
|
+
if (clearCache) {
|
|
3871
|
+
this.clearCache([
|
|
3872
|
+
GRAPH_CACHE_TYPE.NodeOptions,
|
|
3873
|
+
GRAPH_CACHE_TYPE.NodeText,
|
|
3874
|
+
GRAPH_CACHE_TYPE.NodeLabel,
|
|
3875
|
+
]);
|
|
3876
|
+
}
|
|
3877
|
+
else {
|
|
3878
|
+
this.clearCache(clearCache);
|
|
3879
|
+
}
|
|
3880
|
+
}
|
|
3881
|
+
this.tick();
|
|
3882
|
+
return undefined;
|
|
3883
|
+
};
|
|
3884
|
+
destroy = () => {
|
|
3885
|
+
if (this._rafTickId != undefined) {
|
|
3886
|
+
cancelAnimationFrame(this._rafTickId);
|
|
3887
|
+
this._rafTickId = undefined;
|
|
3888
|
+
}
|
|
3889
|
+
this.clearHTMLElements();
|
|
3890
|
+
this.clearState();
|
|
3891
|
+
this.clearCache(true);
|
|
3892
|
+
};
|
|
3893
|
+
updateData = (_alpha, clearCache = true) => {
|
|
3894
|
+
if (clearCache) {
|
|
3895
|
+
this.clearCache(clearCache);
|
|
3896
|
+
}
|
|
3897
|
+
updateNodeCache.call(this);
|
|
3898
|
+
updateLinkCache.call(this);
|
|
3899
|
+
initZoom.call(this, this.areaTransform);
|
|
3900
|
+
this.fitToView();
|
|
3901
|
+
this.tick();
|
|
3902
|
+
};
|
|
3903
|
+
}
|
|
3904
|
+
|
|
3642
3905
|
const FORCE_CONTROLS = [
|
|
3643
3906
|
{
|
|
3644
3907
|
id: "forces",
|
|
@@ -4819,13 +5082,8 @@ exports.NODE_OPTIONS_NODE_CONTROLS = NODE_OPTIONS_NODE_CONTROLS;
|
|
|
4819
5082
|
exports.NODE_OPTIONS_TEXT_CONTROLS = NODE_OPTIONS_TEXT_CONTROLS;
|
|
4820
5083
|
exports.NODE_SETTINGS = NODE_SETTINGS;
|
|
4821
5084
|
exports.NODE_SETTINGS_CONTROLS = NODE_SETTINGS_CONTROLS;
|
|
4822
|
-
exports.PERFOMANCE_NODE_OPTIONS = PERFOMANCE_NODE_OPTIONS;
|
|
4823
5085
|
exports.PERFORMANCE_FORCE_SETTINGS = PERFORMANCE_FORCE_SETTINGS;
|
|
4824
|
-
exports.
|
|
4825
|
-
exports.PERFORMANCE_HIGHLIGHT_SETTINGS = PERFORMANCE_HIGHLIGHT_SETTINGS;
|
|
4826
|
-
exports.PERFORMANCE_LINK_OPTIONS = PERFORMANCE_LINK_OPTIONS;
|
|
4827
|
-
exports.PERFORMANCE_LINK_SETTINGS = PERFORMANCE_LINK_SETTINGS;
|
|
4828
|
-
exports.PERFORMANCE_NODE_SETTINGS = PERFORMANCE_NODE_SETTINGS;
|
|
5086
|
+
exports.StaticGraphCanvas = StaticGraphCanvas;
|
|
4829
5087
|
exports.animationByProgress = animationByProgress;
|
|
4830
5088
|
exports.approximateQuadraticBezierLength = approximateQuadraticBezierLength;
|
|
4831
5089
|
exports.calculateLinkPositionByNode = calculateLinkPositionByNode;
|
|
@@ -4833,7 +5091,6 @@ exports.colorGetter = colorGetter;
|
|
|
4833
5091
|
exports.colorToRgb = colorToRgb;
|
|
4834
5092
|
exports.computeGraphBounds = computeGraphBounds;
|
|
4835
5093
|
exports.dragPlaceCoefficientGetter = dragPlaceCoefficientGetter;
|
|
4836
|
-
exports.drawText = drawText;
|
|
4837
5094
|
exports.extractLinkPointIds = extractLinkPointIds;
|
|
4838
5095
|
exports.extractRgb = extractRgb;
|
|
4839
5096
|
exports.fadeRgb = fadeRgb;
|
|
@@ -4858,11 +5115,15 @@ exports.nodeFade = nodeFade;
|
|
|
4858
5115
|
exports.nodeHighlight = nodeHighlight;
|
|
4859
5116
|
exports.nodeIdGetter = nodeIdGetter;
|
|
4860
5117
|
exports.nodeIterationExtractor = nodeIterationExtractor;
|
|
5118
|
+
exports.nodeLabelGetter = nodeLabelGetter;
|
|
4861
5119
|
exports.nodeOptionsGetter = nodeOptionsGetter;
|
|
4862
5120
|
exports.nodeRadiusGetter = nodeRadiusGetter;
|
|
4863
5121
|
exports.nodeSettingsGetter = nodeSettingsGetter;
|
|
4864
5122
|
exports.nodeSizeGetter = nodeSizeGetter;
|
|
5123
|
+
exports.nodeTextGetter = nodeTextGetter;
|
|
4865
5124
|
exports.nodeTextSizeGetter = nodeTextSizeGetter;
|
|
4866
5125
|
exports.pointerGetter = pointerGetter;
|
|
5126
|
+
exports.precomputeGraph = precomputeGraph;
|
|
5127
|
+
exports.prepareGraph = prepareGraph;
|
|
4867
5128
|
exports.rgbAnimationByProgress = rgbAnimationByProgress;
|
|
4868
5129
|
//# sourceMappingURL=index.cjs.map
|