@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.
Files changed (78) hide show
  1. package/lib/cjs/index.cjs +636 -375
  2. package/lib/cjs/index.cjs.map +1 -1
  3. package/lib/esm/constants/force-controls.js +6 -4
  4. package/lib/esm/constants/force-controls.js.map +1 -1
  5. package/lib/esm/constants/highlight-controls.js +6 -3
  6. package/lib/esm/constants/highlight-controls.js.map +1 -1
  7. package/lib/esm/constants/link-controls.js +6 -3
  8. package/lib/esm/constants/link-controls.js.map +1 -1
  9. package/lib/esm/constants/node-controls.js +6 -3
  10. package/lib/esm/constants/node-controls.js.map +1 -1
  11. package/lib/esm/index.js +8 -6
  12. package/lib/esm/index.js.map +1 -1
  13. package/lib/esm/module/GraphCanvas/GraphCanvas.js +36 -17
  14. package/lib/esm/module/GraphCanvas/GraphCanvas.js.map +1 -1
  15. package/lib/esm/module/GraphCanvas/StaticGraphCanvas.js +127 -0
  16. package/lib/esm/module/GraphCanvas/StaticGraphCanvas.js.map +1 -0
  17. package/lib/esm/module/GraphCanvas/constants/graph-settings.js +6 -7
  18. package/lib/esm/module/GraphCanvas/constants/graph-settings.js.map +1 -1
  19. package/lib/esm/module/GraphCanvas/constants/highlight-settings.js +1 -4
  20. package/lib/esm/module/GraphCanvas/constants/highlight-settings.js.map +1 -1
  21. package/lib/esm/module/GraphCanvas/constants/index.js +6 -4
  22. package/lib/esm/module/GraphCanvas/constants/index.js.map +1 -1
  23. package/lib/esm/module/GraphCanvas/constants/link-settings.js +1 -9
  24. package/lib/esm/module/GraphCanvas/constants/link-settings.js.map +1 -1
  25. package/lib/esm/module/GraphCanvas/constants/node-settings.js +1 -10
  26. package/lib/esm/module/GraphCanvas/constants/node-settings.js.map +1 -1
  27. package/lib/esm/module/GraphCanvas/lib/settings/force-settings-getter.js +6 -4
  28. package/lib/esm/module/GraphCanvas/lib/settings/force-settings-getter.js.map +1 -1
  29. package/lib/esm/module/GraphCanvas/lib/settings/graph-settings-getter.js +0 -3
  30. package/lib/esm/module/GraphCanvas/lib/settings/graph-settings-getter.js.map +1 -1
  31. package/lib/esm/module/GraphCanvas/lib/settings/highlight-settings-getter.js +6 -3
  32. package/lib/esm/module/GraphCanvas/lib/settings/highlight-settings-getter.js.map +1 -1
  33. package/lib/esm/module/GraphCanvas/lib/settings/link-settings-getter.js +6 -3
  34. package/lib/esm/module/GraphCanvas/lib/settings/link-settings-getter.js.map +1 -1
  35. package/lib/esm/module/GraphCanvas/lib/settings/node-settings-getter.js +20 -6
  36. package/lib/esm/module/GraphCanvas/lib/settings/node-settings-getter.js.map +1 -1
  37. package/lib/esm/module/GraphCanvas/lib/utils/calculate-curve-link-position-by-node.js +6 -4
  38. package/lib/esm/module/GraphCanvas/lib/utils/calculate-curve-link-position-by-node.js.map +1 -1
  39. package/lib/esm/module/GraphCanvas/lib/utils/calculate-link-position-by-node.js +6 -4
  40. package/lib/esm/module/GraphCanvas/lib/utils/calculate-link-position-by-node.js.map +1 -1
  41. package/lib/esm/module/GraphCanvas/lib/utils/get-particle-position.js +1 -1
  42. package/lib/esm/module/GraphCanvas/lib/utils/get-particle-position.js.map +1 -1
  43. package/lib/esm/module/GraphCanvas/lib/utils/is-node-visible.js +25 -27
  44. package/lib/esm/module/GraphCanvas/lib/utils/is-node-visible.js.map +1 -1
  45. package/lib/esm/module/GraphCanvas/lib/utils/is-overlaps-node.js.map +1 -1
  46. package/lib/esm/module/GraphCanvas/lib/utils/node-by-pointer-getter.js +2 -1
  47. package/lib/esm/module/GraphCanvas/lib/utils/node-by-pointer-getter.js.map +1 -1
  48. package/lib/esm/module/GraphCanvas/lib/utils/node-highlight.js +7 -11
  49. package/lib/esm/module/GraphCanvas/lib/utils/node-highlight.js.map +1 -1
  50. package/lib/esm/module/GraphCanvas/lib/utils/node-iteration-extractor.js +3 -0
  51. package/lib/esm/module/GraphCanvas/lib/utils/node-iteration-extractor.js.map +1 -1
  52. package/lib/esm/module/GraphCanvas/lib/utils/precompute-graph.js +24 -0
  53. package/lib/esm/module/GraphCanvas/lib/utils/precompute-graph.js.map +1 -0
  54. package/lib/esm/module/GraphCanvas/lib/utils/prepare-graph-data.js +49 -0
  55. package/lib/esm/module/GraphCanvas/lib/utils/prepare-graph-data.js.map +1 -0
  56. package/lib/esm/module/GraphCanvas/slices/draw-links.js +24 -42
  57. package/lib/esm/module/GraphCanvas/slices/draw-links.js.map +1 -1
  58. package/lib/esm/module/GraphCanvas/slices/draw-nodes.js +80 -168
  59. package/lib/esm/module/GraphCanvas/slices/draw-nodes.js.map +1 -1
  60. package/lib/esm/module/GraphCanvas/slices/draw-text.js +1 -9
  61. package/lib/esm/module/GraphCanvas/slices/draw-text.js.map +1 -1
  62. package/lib/esm/module/GraphCanvas/slices/export-svg.js +4 -5
  63. package/lib/esm/module/GraphCanvas/slices/export-svg.js.map +1 -1
  64. package/lib/esm/module/GraphCanvas/slices/init-dnd.js +15 -3
  65. package/lib/esm/module/GraphCanvas/slices/init-dnd.js.map +1 -1
  66. package/lib/esm/module/GraphCanvas/slices/init-draw.js +212 -8
  67. package/lib/esm/module/GraphCanvas/slices/init-draw.js.map +1 -1
  68. package/lib/esm/module/GraphCanvas/slices/init-pointer.js +6 -8
  69. package/lib/esm/module/GraphCanvas/slices/init-pointer.js.map +1 -1
  70. package/lib/esm/module/GraphCanvas/slices/init-simulation.js +3 -4
  71. package/lib/esm/module/GraphCanvas/slices/init-simulation.js.map +1 -1
  72. package/lib/esm/module/GraphCanvas/slices/init-zoom.js +2 -4
  73. package/lib/esm/module/GraphCanvas/slices/init-zoom.js.map +1 -1
  74. package/lib/esm/module/GraphCanvas/slices/update-link-cache.js +5 -5
  75. package/lib/esm/module/GraphCanvas/slices/update-node-cache.js +17 -29
  76. package/lib/esm/module/GraphCanvas/slices/update-node-cache.js.map +1 -1
  77. package/lib/index.d.ts +94 -43
  78. 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(opts) {
753
- const left = -opts.transform.x / opts.transform.k;
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 (opts.node._shape) {
822
+ switch (node._shape) {
760
823
  case "circle": {
761
- const radius = opts.node._radius ?? COMMON_SETTINGS.nodeRadius;
762
- return (left < opts.node.x + radius + ADDITIONAL_VIEWPORT &&
763
- opts.node.x - radius - ADDITIONAL_VIEWPORT < right &&
764
- top < opts.node.y + radius + ADDITIONAL_VIEWPORT &&
765
- opts.node.y - radius - ADDITIONAL_VIEWPORT < bottom);
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 = opts.node._width ?? COMMON_SETTINGS.nodeSize;
770
- const height = opts.node._height ?? COMMON_SETTINGS.nodeSize;
771
- return (left < opts.node.x + width + ADDITIONAL_VIEWPORT &&
772
- opts.node.x - width - ADDITIONAL_VIEWPORT < right &&
773
- top < opts.node.y + height + ADDITIONAL_VIEWPORT &&
774
- opts.node.y - height - ADDITIONAL_VIEWPORT < bottom);
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 = opts.node._radius ?? COMMON_SETTINGS.nodeRadius;
778
- return (left < opts.node.x + radius + ADDITIONAL_VIEWPORT &&
779
- opts.node.x - radius - ADDITIONAL_VIEWPORT < right &&
780
- top < opts.node.y + radius + ADDITIONAL_VIEWPORT &&
781
- opts.node.y - radius - ADDITIONAL_VIEWPORT < bottom);
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 = performance.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
- if (opts.nodeOptions.label) {
984
- /** Label Size */
985
- labelSize = animationByProgress(labelSize, opts.highlightForLabelSizingAdditional, opts.highlightProgress);
986
- /** Label Weight */
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
- if (opts.nodeOptions.label) {
1017
- /** Label Alpha */
1018
- const labelAlphaMin = opts.highlightForLabelFadingMin < labelAlpha ? opts.highlightForLabelFadingMin : labelAlpha;
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
- event.subject.fx = Math.max(this._translateExtent[0][0], Math.min(this._translateExtent[1][0], pointerX));
1358
- event.subject.fy = Math.max(this._translateExtent[0][1], Math.min(this._translateExtent[1][1], pointerY));
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
- this.context.beginPath();
1537
- this.context.globalAlpha = alpha;
1538
- this.context.strokeStyle = color;
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
- this.context.moveTo(xStart, yStart);
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
- this.context.beginPath();
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
- this.context.beginPath();
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
- this.context.beginPath();
1660
- this.context.globalAlpha = arrowAlpha;
1661
- this.context.strokeStyle = arrowBorderColor;
1662
- this.context.lineWidth = arrowBorderWidth;
1663
- this.context.fillStyle = arrowColor;
1664
- this.context.moveTo(xEndArrow, yEndArrow);
1665
- this.context.lineTo(xEndArrow - arrowSize * Math.cos(angle - Math.PI / 6), yEndArrow - arrowSize * Math.sin(angle - Math.PI / 6));
1666
- this.context.lineTo(xEndArrow - arrowSize * Math.cos(angle + Math.PI / 6), yEndArrow - arrowSize * Math.sin(angle + Math.PI / 6));
1667
- this.context.closePath();
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
- const SPACE = " ";
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
- nodeRenders.push(() => {
1738
+ deferredNodeRender.push(() => {
1739
1739
  if (nodeOptions.nodeDraw) {
1740
1740
  nodeOptions.nodeDraw.bind(this)(node, nodeOptions);
1741
1741
  }
1742
1742
  });
1743
- textRenders.push(() => {
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
- /** Node Visibility */
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
- /** Node draw */
1885
- nodeRenders.push(() => {
1886
- if (!this.context || !node.x || !node.y)
1887
- return;
1888
- this.context.beginPath();
1889
- this.context.globalAlpha = alpha;
1890
- this.context.lineWidth = borderWidth;
1891
- this.context.strokeStyle = borderColor;
1892
- this.context.fillStyle = color;
1893
- const labelLines = this.cachedNodeLabel[index];
1894
- switch (nodeOptions.shape) {
1895
- case "circle": {
1896
- if (!node.image) {
1897
- this.context.arc(node.x, node.y, radius, 0, 2 * Math.PI);
1898
- this.context.fill();
1899
- if (borderWidth > 0) {
1900
- this.context.stroke();
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
- nodeRenders.push(() => {
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 (nodeOptions.textVisible && nodeOptions.text && textLines) {
2021
- textRenders.push(() => {
2022
- if (nodeOptions.textDraw) {
2023
- nodeOptions.textDraw.bind(this)(node, {
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
- return;
2035
- }
2036
- if (!this.context || !node.x || !node.y || !nodeOptions.text)
2037
- return;
2038
- this.context.beginPath();
2039
- this.context.globalAlpha = textAlpha;
2040
- let y = node.y + textShiftY;
2041
- if (nodeOptions.shape === "circle") {
2042
- y += radius;
2043
- }
2044
- if (nodeOptions.shape === "square" || nodeOptions.shape === "text") {
2045
- y += height / 2;
2046
- }
2047
- drawText({
2048
- lines: textLines,
2049
- context: this.context,
2050
- textAlign: nodeOptions.textAlign,
2051
- textColor: nodeOptions.textColor,
2052
- textFont: nodeOptions.textFont,
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
- if (nodeOptions.textExtraDraw) {
2061
- nodeOptions.textExtraDraw.bind(this)(node, {
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
- const textRenders = [];
2091
- const nodeRenders = [];
2092
- this.nodes.forEach(getDrawNode(nodeRenders, textRenders).bind(this));
2093
- /** links */
2094
- this.links.forEach(getDrawLink().bind(this));
2095
- /** nodes */
2096
- nodeRenders.forEach((render) => render());
2097
- textRenders.forEach((render) => render());
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
- let nodeOptions = this.nodeOptionsCache[i];
2795
+ const nodeOptions = this.nodeOptionsCache[i];
2645
2796
  if (!nodeOptions)
2646
2797
  continue;
2647
2798
  /** label */
2648
2799
  if (label) {
2649
- if (!options) {
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" && nodeOptions.label) {
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(nodeOptions.label).width <= nodeOptions.labelWidth) {
2662
- this.cachedNodeLabel[i] = [nodeOptions.label];
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: nodeOptions.label,
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" && nodeOptions.label) {
2824
+ else if (nodeOptions.shape === "text" && label) {
2679
2825
  const textInfo = getTextLines({
2680
2826
  context: this.context,
2681
- text: nodeOptions.label,
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
- if (!options) {
2708
- nodeOptions = nodeIterationExtractor(node, i, this.nodes, this, this.nodeSettings.options ?? {}, nodeOptionsGetter);
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
- return;
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: nodeOptions.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
- this.draw = initDraw.call(this);
3229
- this.init();
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
- this.draw = initDraw.call(this);
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.draw();
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.PERFORMANCE_GRAPH_SETTINGS = PERFORMANCE_GRAPH_SETTINGS;
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