@krainovsd/graph 0.7.0 → 0.8.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 (30) hide show
  1. package/lib/cjs/index.cjs +962 -178
  2. package/lib/cjs/index.cjs.map +1 -1
  3. package/lib/esm/index.js +3 -0
  4. package/lib/esm/index.js.map +1 -1
  5. package/lib/esm/lib/draw-time.js +25 -0
  6. package/lib/esm/lib/draw-time.js.map +1 -0
  7. package/lib/esm/lib/get-controls-info.js +541 -0
  8. package/lib/esm/lib/get-controls-info.js.map +1 -0
  9. package/lib/esm/module/GraphCanvas/GraphCanvas.js +235 -80
  10. package/lib/esm/module/GraphCanvas/GraphCanvas.js.map +1 -1
  11. package/lib/esm/module/GraphCanvas/constants/settings.js +26 -7
  12. package/lib/esm/module/GraphCanvas/constants/settings.js.map +1 -1
  13. package/lib/esm/module/GraphCanvas/lib/settings/link-settings-getter.js +7 -4
  14. package/lib/esm/module/GraphCanvas/lib/settings/link-settings-getter.js.map +1 -1
  15. package/lib/esm/module/GraphCanvas/lib/settings/node-settings-getter.js +6 -5
  16. package/lib/esm/module/GraphCanvas/lib/settings/node-settings-getter.js.map +1 -1
  17. package/lib/esm/module/GraphCanvas/lib/utils/animation-by-progress.js +12 -0
  18. package/lib/esm/module/GraphCanvas/lib/utils/animation-by-progress.js.map +1 -0
  19. package/lib/esm/module/GraphCanvas/lib/utils/calculate-link-position-by-radius.js +2 -2
  20. package/lib/esm/module/GraphCanvas/lib/utils/calculate-link-position-by-radius.js.map +1 -1
  21. package/lib/esm/module/GraphCanvas/lib/utils/get-particle-position.js +24 -0
  22. package/lib/esm/module/GraphCanvas/lib/utils/get-particle-position.js.map +1 -0
  23. package/lib/esm/module/GraphCanvas/lib/utils/is-node-visible.js +14 -0
  24. package/lib/esm/module/GraphCanvas/lib/utils/is-node-visible.js.map +1 -0
  25. package/lib/esm/module/GraphCanvas/lib/utils/link-iteration-extractor.js +1 -0
  26. package/lib/esm/module/GraphCanvas/lib/utils/link-iteration-extractor.js.map +1 -1
  27. package/lib/esm/module/GraphCanvas/lib/utils/node-iteration-extractor.js +1 -0
  28. package/lib/esm/module/GraphCanvas/lib/utils/node-iteration-extractor.js.map +1 -1
  29. package/lib/index.d.ts +72 -3
  30. package/package.json +4 -2
@@ -19,11 +19,16 @@ import { nodeByPointerGetter } from './lib/utils/node-by-pointer-getter.js';
19
19
  import { nodeIterationExtractor } from './lib/utils/node-iteration-extractor.js';
20
20
  import { drawText } from './lib/utils/draw-text.js';
21
21
  import { calculateLinkPositionByRadius } from './lib/utils/calculate-link-position-by-radius.js';
22
+ import { animationByProgress } from './lib/utils/animation-by-progress.js';
23
+ import { isNodeVisible } from './lib/utils/is-node-visible.js';
24
+ import { getParticlePosition } from './lib/utils/get-particle-position.js';
25
+ import { getDrawTime, setDrawTime } from '../../lib/draw-time.js';
22
26
 
23
27
  class GraphCanvas {
24
28
  /** initial data */
25
29
  nodes;
26
30
  links;
31
+ particles = {};
27
32
  width;
28
33
  height;
29
34
  root;
@@ -43,6 +48,8 @@ class GraphCanvas {
43
48
  draw;
44
49
  eventAbortController;
45
50
  cachedNodeText = {};
51
+ linkOptionsCache = {};
52
+ nodeOptionsCache = {};
46
53
  isDragging = false;
47
54
  highlightedNode = null;
48
55
  highlightedNeighbors = null;
@@ -115,20 +122,35 @@ class GraphCanvas {
115
122
  this.updateData(alpha);
116
123
  }
117
124
  changeSettings(options) {
118
- if (options.graphSettings)
125
+ if (options.graphSettings) {
119
126
  this.graphSettings = graphSettingsGetter(options.graphSettings, this.graphSettings);
120
- if (options.forceSettings)
127
+ this.draw = this.initDraw();
128
+ this.initZoom(this.areaTransform);
129
+ }
130
+ if (options.forceSettings) {
121
131
  this.forceSettings = forceSettingsGetter(options.forceSettings, this.forceSettings);
122
- if (options.linkSettings)
123
- this.linkSettings = linkSettingsGetter(options.linkSettings);
124
- if (options.nodeSettings)
125
- this.nodeSettings = nodeSettingsGetter(options.nodeSettings);
126
- if (options.forceSettings)
132
+ }
133
+ if (options.linkSettings) {
134
+ this.linkSettings = linkSettingsGetter(options.linkSettings, this.linkSettings);
135
+ this.linkOptionsCache = {};
136
+ }
137
+ if (options.nodeSettings) {
138
+ this.nodeSettings = nodeSettingsGetter(options.nodeSettings, this.nodeSettings);
139
+ this.cachedNodeText = {};
140
+ this.nodeOptionsCache = {};
141
+ }
142
+ if (options.forceSettings) {
127
143
  return void this.updateSimulation();
144
+ }
128
145
  this.tick();
129
146
  }
147
+ clearCache() {
148
+ this.nodeOptionsCache = {};
149
+ this.linkOptionsCache = {};
150
+ this.cachedNodeText = {};
151
+ }
130
152
  tick() {
131
- if (!this.simulationWorking)
153
+ if (!this.simulationWorking && !this.highlightWorking)
132
154
  this.draw();
133
155
  }
134
156
  restart(alpha) {
@@ -184,6 +206,8 @@ class GraphCanvas {
184
206
  }
185
207
  clearDataDependencies() {
186
208
  this.cachedNodeText = {};
209
+ this.nodeOptionsCache = {};
210
+ this.linkOptionsCache = {};
187
211
  }
188
212
  updateData(alpha) {
189
213
  this.clearDataDependencies();
@@ -207,7 +231,7 @@ class GraphCanvas {
207
231
  this.initZoom();
208
232
  this.initResize();
209
233
  this.initPointer();
210
- if (!this.simulationWorking)
234
+ if (!this.simulationWorking && !this.highlightWorking)
211
235
  this.draw();
212
236
  }
213
237
  init() {
@@ -228,6 +252,8 @@ class GraphCanvas {
228
252
  })
229
253
  .on("end", () => {
230
254
  this.listeners.onSimulationEnd?.(this.state);
255
+ if (this.graphSettings.showDrawTime)
256
+ getDrawTime();
231
257
  });
232
258
  this.initSimulationForces();
233
259
  }
@@ -250,9 +276,9 @@ class GraphCanvas {
250
276
  .distanceMax(this.forceSettings.chargeDistanceMax)
251
277
  .distanceMin(this.forceSettings.chargeDistanceMin))
252
278
  .force("center", forceCenter(this.forceSettings.centerPosition.x ?? 0, this.forceSettings.centerPosition.y ?? 0).strength(this.forceSettings.centerStrength));
253
- this.initCollideForce();
279
+ this.initCollideForce(true);
254
280
  }
255
- initCollideForce() {
281
+ initCollideForce(forceUpdate) {
256
282
  if (!this.simulation)
257
283
  return;
258
284
  if (!this.forceSettings.collideOn) {
@@ -263,9 +289,10 @@ class GraphCanvas {
263
289
  const isHasMax = this.forceSettings.collideOffMax.links != 0 && this.forceSettings.collideOffMax.nodes != 0;
264
290
  const isMaxCollideNodes = isHasMax && this.forceSettings.collideOffMax.nodes < this.nodes.length;
265
291
  const isMaxCollideLinks = isHasMax && this.forceSettings.collideOffMax.links < this.links.length;
266
- if (isMaxCollideNodes && isMaxCollideLinks)
292
+ if (isMaxCollideNodes && isMaxCollideLinks) {
267
293
  this.simulation.force("collide", null);
268
- else if (!this.simulation.force("collide"))
294
+ }
295
+ else if (!this.simulation.force("collide") || forceUpdate) {
269
296
  this.simulation.force("collide", forceCollide()
270
297
  .radius((node, index) => {
271
298
  if (this.forceSettings.collideRadius) {
@@ -283,6 +310,7 @@ class GraphCanvas {
283
310
  })
284
311
  .strength(this.forceSettings.collideStrength)
285
312
  .iterations(this.forceSettings.collideIterations));
313
+ }
286
314
  }
287
315
  initArea() {
288
316
  if (!this.area || !this.context || !this.container) {
@@ -317,19 +345,27 @@ class GraphCanvas {
317
345
  this.highlightProgress -= this.graphSettings.highlightDownStep;
318
346
  if (!this.simulationWorking)
319
347
  return void requestAnimationFrame(() => this.draw());
320
- return;
348
+ if (!this.linkSettings.particles)
349
+ return;
321
350
  }
322
351
  if (this.highlightWorking && this.highlightProgress < 1) {
323
352
  this.highlightProgress += this.graphSettings.highlightUpStep;
324
353
  if (!this.simulationWorking)
325
354
  return void requestAnimationFrame(() => this.draw());
326
- return;
355
+ if (!this.linkSettings.particles)
356
+ return;
357
+ }
358
+ if (this.linkSettings.particles && this.highlightWorking && !this.simulationWorking) {
359
+ return void requestAnimationFrame(() => this.draw());
327
360
  }
328
361
  if (!this.highlightWorking && this.highlightProgress <= 0) {
329
- if (this.highlightedNeighbors)
362
+ if (this.highlightedNeighbors || this.highlightedNode) {
330
363
  this.highlightedNeighbors = null;
331
- if (this.highlightedNode)
332
364
  this.highlightedNode = null;
365
+ this.particles = {};
366
+ if (!this.simulationWorking)
367
+ return void requestAnimationFrame(() => this.draw());
368
+ }
333
369
  }
334
370
  this.highlightDrawing = false;
335
371
  }
@@ -352,13 +388,13 @@ class GraphCanvas {
352
388
  this.context.clearRect(0, 0, this.width, this.height);
353
389
  this.context.translate(this.areaTransform.x, this.areaTransform.y);
354
390
  this.context.scale(this.areaTransform.k, this.areaTransform.k);
391
+ const textRenders = [];
392
+ const nodeRenders = [];
393
+ this.nodes.forEach(getDrawNode(nodeRenders, textRenders, state).bind(this));
355
394
  /** links */
356
- this.context.beginPath();
357
395
  this.links.forEach(getDrawLink(state).bind(this));
358
- this.context.stroke();
359
396
  /** nodes */
360
- const textRenders = [];
361
- this.nodes.forEach(getDrawNode(textRenders, state).bind(this));
397
+ nodeRenders.forEach((render) => render());
362
398
  textRenders.forEach((render) => render());
363
399
  this.context.restore();
364
400
  this.listeners.onDrawFinished?.(state);
@@ -374,54 +410,155 @@ class GraphCanvas {
374
410
  !link.target.x ||
375
411
  !link.target.y)
376
412
  return;
377
- const linkOptions = linkIterationExtractor(link, index, this.links, state, this.linkSettings.options ?? {}, linkOptionsGetter);
413
+ if (!link.source._visible && !link.target._visible)
414
+ return;
415
+ const id = `${link.target.id}${link.source.id}`;
416
+ let linkOptions;
417
+ if (this.linkSettings.cache && this.linkOptionsCache[id]) {
418
+ linkOptions = this.linkOptionsCache[id];
419
+ }
420
+ else {
421
+ linkOptions = linkIterationExtractor(link, index, this.links, state, this.linkSettings.options ?? {}, linkOptionsGetter);
422
+ if (this.linkSettings.cache) {
423
+ this.linkOptionsCache[id] = linkOptions;
424
+ }
425
+ }
378
426
  if (linkOptions.drawLink) {
379
427
  linkOptions.drawLink(link, linkOptions, state);
380
428
  return;
381
429
  }
382
430
  let alpha = linkOptions.alpha;
431
+ let arrowAlpha = linkOptions.arrowReverseAppear ? 0 : linkOptions.arrowAlpha;
383
432
  if (this.highlightedNeighbors && this.highlightedNode) {
384
433
  /** Not highlighted */
385
434
  if (this.highlightedNode.id != link.source.id &&
386
435
  this.highlightedNode.id != link.target.id) {
387
- if (linkOptions.highlightFading)
388
- alpha =
389
- this.graphSettings.highlightLinkFadingMin +
390
- (alpha - this.graphSettings.highlightLinkFadingMin) * (1 - this.highlightProgress);
436
+ if (linkOptions.highlightFading) {
437
+ const min = this.graphSettings.highlightLinkFadingMin < alpha
438
+ ? this.graphSettings.highlightLinkFadingMin
439
+ : alpha;
440
+ alpha = animationByProgress(min, alpha - min, 1 - this.highlightProgress);
441
+ }
442
+ if (linkOptions.arrow &&
443
+ linkOptions.arrowHighlightFading &&
444
+ !linkOptions.arrowReverseAppear) {
445
+ const min = this.graphSettings.highlightArrowFadingMin < arrowAlpha
446
+ ? this.graphSettings.highlightArrowFadingMin
447
+ : arrowAlpha;
448
+ arrowAlpha = animationByProgress(min, arrowAlpha - min, 1 - this.highlightProgress);
449
+ }
450
+ }
451
+ else {
452
+ // eslint-disable-next-line no-lonely-if
453
+ if (linkOptions.arrow && linkOptions.arrowReverseAppear) {
454
+ /** Highlighted */
455
+ arrowAlpha = animationByProgress(0, linkOptions.arrowAlpha, this.highlightProgress);
456
+ }
391
457
  }
392
- this.context.beginPath();
393
458
  }
459
+ /** Link */
460
+ this.context.beginPath();
394
461
  this.context.globalAlpha = alpha;
395
462
  this.context.strokeStyle = linkOptions.color;
396
463
  this.context.lineWidth = linkOptions.width;
464
+ let xStart = link.source.x;
465
+ let yStart = link.source.y;
466
+ let xEnd = link.target.x;
467
+ let yEnd = link.target.y;
397
468
  if (linkOptions.pretty) {
398
- const { x1, x2, y1, y2 } = calculateLinkPositionByRadius(link) ?? {
469
+ const isHasArrow = linkOptions.arrow && arrowAlpha > 0;
470
+ const { x1, x2, y1, y2 } = calculateLinkPositionByRadius(link, isHasArrow ? linkOptions.arrowSize : 0) ?? {
399
471
  x1: 0,
400
472
  x2: 0,
401
473
  y1: 0,
402
474
  y2: 0,
403
475
  };
404
- this.context.moveTo(x1, y1);
405
- this.context.lineTo(x2, y2);
476
+ xStart = x1;
477
+ xEnd = x2;
478
+ yStart = y1;
479
+ yEnd = y2;
406
480
  }
407
- else {
408
- this.context.moveTo(link.source.x, link.source.y);
409
- this.context.lineTo(link.target.x, link.target.y);
481
+ this.context.moveTo(xStart, yStart);
482
+ this.context.lineTo(xEnd, yEnd);
483
+ this.context.stroke();
484
+ /** Particle */
485
+ if (this.linkSettings.particles &&
486
+ this.highlightedNode &&
487
+ (this.highlightedNode.id === link.source.id || this.highlightedNode.id === link.target.id)) {
488
+ if (!this.particles[id]) {
489
+ const sourceId = link.source.id;
490
+ const targetId = link.target.id;
491
+ this.particles[id] = Array.from({ length: linkOptions.particleCount }, (_, index) => {
492
+ return {
493
+ step: 0,
494
+ wait: index * (linkOptions.particleSteps / linkOptions.particleCount),
495
+ sourceId,
496
+ targetId,
497
+ };
498
+ });
499
+ }
500
+ this.particles[id].forEach((particle) => {
501
+ if (!this.context)
502
+ return;
503
+ getParticlePosition({
504
+ particle,
505
+ totalSteps: linkOptions.particleSteps,
506
+ xEnd,
507
+ xStart,
508
+ yEnd,
509
+ yStart,
510
+ });
511
+ if (particle.x != undefined && particle.y != undefined) {
512
+ this.context.beginPath();
513
+ this.context.arc(particle.x, particle.y, linkOptions.particleRadius, 0, Math.PI * 2);
514
+ this.context.fillStyle = linkOptions.particleColor;
515
+ this.context.fill();
516
+ this.context.stroke();
517
+ }
518
+ });
410
519
  }
411
- if (this.highlightedNeighbors && this.highlightedNode)
520
+ /** Arrow */
521
+ if (linkOptions.arrow && arrowAlpha > 0) {
522
+ const { x1: xStart, x2: xEnd, y1: yStart, y2: yEnd, } = calculateLinkPositionByRadius(link) ?? {
523
+ x1: 0,
524
+ x2: 0,
525
+ y1: 0,
526
+ y2: 0,
527
+ };
528
+ const angle = Math.atan2(yEnd - yStart, xEnd - xStart);
529
+ this.context.beginPath();
530
+ this.context.globalAlpha = arrowAlpha;
531
+ this.context.moveTo(xEnd, yEnd);
532
+ this.context.lineTo(xEnd - linkOptions.arrowSize * Math.cos(angle - Math.PI / 6), yEnd - linkOptions.arrowSize * Math.sin(angle - Math.PI / 6));
533
+ this.context.lineTo(xEnd - linkOptions.arrowSize * Math.cos(angle + Math.PI / 6), yEnd - linkOptions.arrowSize * Math.sin(angle + Math.PI / 6));
534
+ this.context.closePath();
535
+ this.context.fillStyle = linkOptions.arrowColor;
536
+ this.context.fill();
412
537
  this.context.stroke();
538
+ }
413
539
  if (linkOptions.drawExtraLink) {
414
540
  linkOptions.drawExtraLink(link, { ...linkOptions, alpha }, state);
415
541
  }
416
542
  };
417
543
  }
418
- function getDrawNode(textRenders, state) {
544
+ function getDrawNode(nodeRenders, textRenders, state) {
419
545
  return function drawNode(node, index) {
420
546
  if (!this.context || !node.x || !node.y)
421
547
  return;
422
- const nodeOptions = nodeIterationExtractor(node, index, this.nodes, state, this.nodeSettings.options ?? {}, nodeOptionsGetter);
548
+ let nodeOptions;
549
+ if (this.nodeSettings.cache && this.nodeOptionsCache[node.id]) {
550
+ nodeOptions = this.nodeOptionsCache[node.id];
551
+ }
552
+ else {
553
+ nodeOptions = nodeIterationExtractor(node, index, this.nodes, state, this.nodeSettings.options ?? {}, nodeOptionsGetter);
554
+ if (this.nodeSettings.cache) {
555
+ this.nodeOptionsCache[node.id] = nodeOptions;
556
+ }
557
+ }
423
558
  if (nodeOptions.nodeDraw) {
424
- nodeOptions.nodeDraw(node, nodeOptions, state);
559
+ nodeRenders.push(() => {
560
+ nodeOptions?.nodeDraw?.(node, nodeOptions, state);
561
+ });
425
562
  return;
426
563
  }
427
564
  let alpha = nodeOptions.alpha;
@@ -437,15 +574,16 @@ class GraphCanvas {
437
574
  /** Not highlighted */
438
575
  if (!this.highlightedNeighbors.has(node.id) && this.highlightedNode.id != node.id) {
439
576
  if (nodeOptions.highlightFading) {
440
- alpha =
441
- this.graphSettings.highlightFadingMin +
442
- (alpha - this.graphSettings.highlightFadingMin) * (1 - this.highlightProgress);
577
+ const min = this.graphSettings.highlightFadingMin < alpha
578
+ ? this.graphSettings.highlightFadingMin
579
+ : alpha;
580
+ alpha = animationByProgress(min, alpha - min, 1 - this.highlightProgress);
443
581
  }
444
582
  if (nodeOptions.highlightTextFading) {
445
- textAlpha =
446
- this.graphSettings.highlightTextFadingMin +
447
- (textAlpha - this.graphSettings.highlightTextFadingMin) *
448
- (1 - this.highlightProgress);
583
+ const min = this.graphSettings.highlightTextFadingMin < textAlpha
584
+ ? this.graphSettings.highlightTextFadingMin
585
+ : textAlpha;
586
+ textAlpha = animationByProgress(min, textAlpha - min, 1 - this.highlightProgress);
449
587
  }
450
588
  if (nodeOptions.highlightColor) {
451
589
  const colorRgb = extractRgb(colorToRgb(color));
@@ -460,20 +598,14 @@ class GraphCanvas {
460
598
  (this.graphSettings.highlightOnlyRoot && this.highlightedNode.id === node.id)) {
461
599
  /** Highlighted */
462
600
  if (nodeOptions.highlightSizing) {
463
- const radiusMax = radiusInitial + this.graphSettings.highlightSizingAdditional;
464
- radiusInitial += ((radiusMax - radiusInitial) / 100) * (this.highlightProgress * 100);
601
+ radiusInitial = animationByProgress(radiusInitial, this.graphSettings.highlightSizingAdditional, this.highlightProgress);
465
602
  }
466
603
  if (nodeOptions.highlightTextSizing) {
467
- const textSizeMax = textSize + this.graphSettings.highlightTextSizingAdditional;
468
- const textShiftXMax = textShiftX + this.graphSettings.highlightTextShiftXAdditional;
469
- const textShiftYMax = textShiftY + this.graphSettings.highlightTextShiftYAdditional;
470
- const textWeightMax = textWeight + this.graphSettings.highlightTextWeightAdditional;
471
- const textWidthMax = textWidth + this.graphSettings.highlightTextWidthAdditional;
472
- textSize += ((textSizeMax - textSize) / 100) * (this.highlightProgress * 100);
473
- textShiftX += ((textShiftXMax - textShiftX) / 100) * (this.highlightProgress * 100);
474
- textShiftY += ((textShiftYMax - textShiftY) / 100) * (this.highlightProgress * 100);
475
- textWeight += ((textWeightMax - textWeight) / 100) * (this.highlightProgress * 100);
476
- textWidth += ((textWidthMax - textWidth) / 100) * (this.highlightProgress * 100);
604
+ textSize = animationByProgress(textSize, this.graphSettings.highlightTextSizingAdditional, this.highlightProgress);
605
+ textShiftX = animationByProgress(textShiftX, this.graphSettings.highlightTextShiftXAdditional, this.highlightProgress);
606
+ textShiftY = animationByProgress(textShiftY, this.graphSettings.highlightTextShiftYAdditional, this.highlightProgress);
607
+ textWeight = animationByProgress(textWeight, this.graphSettings.highlightTextWeightAdditional, this.highlightProgress);
608
+ textWidth = animationByProgress(textWidth, this.graphSettings.highlightTextWidthAdditional, this.highlightProgress);
477
609
  }
478
610
  }
479
611
  }
@@ -485,8 +617,31 @@ class GraphCanvas {
485
617
  linkCount: node.linkCount,
486
618
  });
487
619
  node._radius = radius;
488
- this.context.beginPath();
489
- this.context.globalAlpha = alpha;
620
+ if (!isNodeVisible({
621
+ height: this.height,
622
+ width: this.width,
623
+ x: node.x,
624
+ y: node.y,
625
+ radius,
626
+ transform: this.areaTransform,
627
+ })) {
628
+ node._visible = false;
629
+ return;
630
+ }
631
+ node._visible = true;
632
+ nodeRenders.push(() => {
633
+ if (!this.context || !node.x || !node.y)
634
+ return;
635
+ this.context.beginPath();
636
+ this.context.globalAlpha = alpha;
637
+ /** circle */
638
+ this.context.lineWidth = nodeOptions.borderWidth;
639
+ this.context.strokeStyle = nodeOptions.borderColor;
640
+ this.context.fillStyle = color;
641
+ this.context.arc(node.x, node.y, radius, 0, 2 * Math.PI);
642
+ this.context.fill();
643
+ this.context.stroke();
644
+ });
490
645
  /** text */
491
646
  if (nodeOptions.textVisible && nodeOptions.text) {
492
647
  textRenders.push(() => {
@@ -541,29 +696,27 @@ class GraphCanvas {
541
696
  }
542
697
  });
543
698
  }
544
- /** circle */
545
- this.context.lineWidth = nodeOptions.borderWidth;
546
- this.context.strokeStyle = nodeOptions.borderColor;
547
- this.context.fillStyle = color;
548
- this.context.arc(node.x, node.y, radius, 0, 2 * Math.PI);
549
- this.context.fill();
550
- this.context.stroke();
551
699
  if (nodeOptions.nodeExtraDraw) {
552
- nodeOptions.nodeExtraDraw(node, {
553
- ...nodeOptions,
554
- radius,
555
- alpha,
556
- color,
557
- textAlpha,
558
- textSize,
559
- textShiftX,
560
- textShiftY,
561
- textWeight,
562
- textWidth,
563
- }, state);
700
+ nodeRenders.push(() => {
701
+ nodeOptions?.nodeExtraDraw?.(node, {
702
+ ...nodeOptions,
703
+ radius,
704
+ alpha,
705
+ color,
706
+ textAlpha,
707
+ textSize,
708
+ textShiftX,
709
+ textShiftY,
710
+ textWeight,
711
+ textWidth,
712
+ }, state);
713
+ });
564
714
  }
565
715
  };
566
716
  }
717
+ if (this.graphSettings.showDrawTime) {
718
+ return setDrawTime(draw.bind(this), this.graphSettings.showDrawTimeEveryTick);
719
+ }
567
720
  return draw;
568
721
  }
569
722
  initResize() {
@@ -757,7 +910,7 @@ class GraphCanvas {
757
910
  this.listeners.onEndDragFinished?.(event, this.state);
758
911
  }));
759
912
  }
760
- initZoom() {
913
+ initZoom(currentZoom) {
761
914
  if (!this.area)
762
915
  throw new Error("bad init data");
763
916
  const zoomInstance = zoom()
@@ -765,7 +918,9 @@ class GraphCanvas {
765
918
  .on("zoom", (event) => {
766
919
  this.listeners.onZoom?.(event);
767
920
  this.areaTransform = event.transform;
768
- if (!this.simulationWorking)
921
+ this.linkOptionsCache = {};
922
+ this.nodeOptionsCache = {};
923
+ if (!this.simulationWorking && !this.highlightWorking)
769
924
  requestAnimationFrame(() => this.draw());
770
925
  });
771
926
  if (this.graphSettings.translateExtentEnable) {
@@ -780,7 +935,7 @@ class GraphCanvas {
780
935
  ]);
781
936
  }
782
937
  select(this.area).call(zoomInstance).on("dblclick.zoom", null);
783
- const zoomInitial = this.graphSettings.zoomInitial;
938
+ const zoomInitial = currentZoom ?? this.graphSettings.zoomInitial;
784
939
  this.areaTransform = new ZoomTransform(zoomInitial?.k ?? 1, zoomInitial?.x ?? this.width / 2, zoomInitial?.y ?? this.height / 2);
785
940
  zoom().transform(select(this.area), this.areaTransform);
786
941
  }