@krainovsd/graph 0.9.0 → 0.10.0-rc1

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 (53) hide show
  1. package/lib/cjs/index.cjs +2633 -1795
  2. package/lib/cjs/index.cjs.map +1 -1
  3. package/lib/esm/index.js +12 -3
  4. package/lib/esm/index.js.map +1 -1
  5. package/lib/esm/lib/draw-time.js +5 -1
  6. package/lib/esm/lib/draw-time.js.map +1 -1
  7. package/lib/esm/lib/get-controls-info.js +451 -224
  8. package/lib/esm/lib/get-controls-info.js.map +1 -1
  9. package/lib/esm/module/GraphCanvas/GraphCanvas.js +39 -927
  10. package/lib/esm/module/GraphCanvas/GraphCanvas.js.map +1 -1
  11. package/lib/esm/module/GraphCanvas/constants/settings.js +70 -47
  12. package/lib/esm/module/GraphCanvas/constants/settings.js.map +1 -1
  13. package/lib/esm/module/GraphCanvas/lib/settings/node-settings-getter.js +10 -1
  14. package/lib/esm/module/GraphCanvas/lib/settings/node-settings-getter.js.map +1 -1
  15. package/lib/esm/module/GraphCanvas/lib/utils/calculate-link-position-by-node.js +270 -0
  16. package/lib/esm/module/GraphCanvas/lib/utils/calculate-link-position-by-node.js.map +1 -0
  17. package/lib/esm/module/GraphCanvas/lib/utils/drag-place-coefficient-getter.js +2 -2
  18. package/lib/esm/module/GraphCanvas/lib/utils/drag-place-coefficient-getter.js.map +1 -1
  19. package/lib/esm/module/GraphCanvas/lib/utils/get-particle-position.js +19 -4
  20. package/lib/esm/module/GraphCanvas/lib/utils/get-particle-position.js.map +1 -1
  21. package/lib/esm/module/GraphCanvas/lib/utils/is-node-visible.js +29 -4
  22. package/lib/esm/module/GraphCanvas/lib/utils/is-node-visible.js.map +1 -1
  23. package/lib/esm/module/GraphCanvas/lib/utils/is-overlaps-node.js +53 -4
  24. package/lib/esm/module/GraphCanvas/lib/utils/is-overlaps-node.js.map +1 -1
  25. package/lib/esm/module/GraphCanvas/lib/utils/link-by-pointer-getter.js +2 -2
  26. package/lib/esm/module/GraphCanvas/lib/utils/link-by-pointer-getter.js.map +1 -1
  27. package/lib/esm/module/GraphCanvas/lib/utils/node-by-pointer-getter.js +3 -13
  28. package/lib/esm/module/GraphCanvas/lib/utils/node-by-pointer-getter.js.map +1 -1
  29. package/lib/esm/module/GraphCanvas/slices/draw-links.js +207 -0
  30. package/lib/esm/module/GraphCanvas/slices/draw-links.js.map +1 -0
  31. package/lib/esm/module/GraphCanvas/slices/draw-nodes.js +342 -0
  32. package/lib/esm/module/GraphCanvas/slices/draw-nodes.js.map +1 -0
  33. package/lib/esm/module/GraphCanvas/{lib/utils → slices}/draw-text.js +23 -6
  34. package/lib/esm/module/GraphCanvas/slices/draw-text.js.map +1 -0
  35. package/lib/esm/module/GraphCanvas/slices/init-area.js +31 -0
  36. package/lib/esm/module/GraphCanvas/slices/init-area.js.map +1 -0
  37. package/lib/esm/module/GraphCanvas/slices/init-dnd.js +62 -0
  38. package/lib/esm/module/GraphCanvas/slices/init-dnd.js.map +1 -0
  39. package/lib/esm/module/GraphCanvas/slices/init-draw.js +84 -0
  40. package/lib/esm/module/GraphCanvas/slices/init-draw.js.map +1 -0
  41. package/lib/esm/module/GraphCanvas/slices/init-pointer.js +211 -0
  42. package/lib/esm/module/GraphCanvas/slices/init-pointer.js.map +1 -0
  43. package/lib/esm/module/GraphCanvas/slices/init-resize.js +28 -0
  44. package/lib/esm/module/GraphCanvas/slices/init-resize.js.map +1 -0
  45. package/lib/esm/module/GraphCanvas/slices/init-simulation.js +172 -0
  46. package/lib/esm/module/GraphCanvas/slices/init-simulation.js.map +1 -0
  47. package/lib/esm/module/GraphCanvas/slices/init-zoom.js +36 -0
  48. package/lib/esm/module/GraphCanvas/slices/init-zoom.js.map +1 -0
  49. package/lib/index.d.ts +169 -132
  50. package/package.json +1 -1
  51. package/lib/esm/module/GraphCanvas/lib/utils/calculate-link-position-by-radius.js +0 -20
  52. package/lib/esm/module/GraphCanvas/lib/utils/calculate-link-position-by-radius.js.map +0 -1
  53. package/lib/esm/module/GraphCanvas/lib/utils/draw-text.js.map +0 -1
@@ -1,30 +1,19 @@
1
- import { isBoolean, isArray, isObject } from '@krainovsd/js-helpers';
2
- import { greatest } from 'd3-array';
3
- import { drag } from 'd3-drag';
4
- import { forceLink, forceSimulation, forceX, forceY, forceManyBody, forceCenter, forceCollide } from 'd3-force';
5
- import { create, select } from 'd3-selection';
6
- import { zoomIdentity, zoom, ZoomTransform } from 'd3-zoom';
7
- import { checkType } from '../../lib/check-type.js';
8
- import { colorToRgb } from '../../lib/color-to-rgb.js';
9
- import { extractRgb } from '../../lib/extract-rgb.js';
10
- import { fadeRgb } from '../../lib/fade-rgb.js';
11
- import { rgbAnimationByProgress } from '../../lib/rgb-animation-by-progress.js';
1
+ import { forceLink } from 'd3-force';
2
+ import { zoomIdentity } from 'd3-zoom';
12
3
  import { forceSettingsGetter } from './lib/settings/force-settings-getter.js';
13
4
  import { graphSettingsGetter } from './lib/settings/graph-settings-getter.js';
14
- import { linkSettingsGetter, linkOptionsGetter } from './lib/settings/link-settings-getter.js';
5
+ import { linkSettingsGetter } from './lib/settings/link-settings-getter.js';
15
6
  import { listenersGetter } from './lib/settings/listeners-getter.js';
16
- import { nodeSettingsGetter, nodeRadiusGetter, nodeOptionsGetter } from './lib/settings/node-settings-getter.js';
17
- import { pointerGetter } from './lib/utils/pointer-getter.js';
18
- import { linkIterationExtractor } from './lib/utils/link-iteration-extractor.js';
19
- import { nodeByPointerGetter } from './lib/utils/node-by-pointer-getter.js';
20
- import { nodeIterationExtractor } from './lib/utils/node-iteration-extractor.js';
21
- import { drawText } from './lib/utils/draw-text.js';
22
- import { calculateLinkPositionByRadius } from './lib/utils/calculate-link-position-by-radius.js';
23
- import { animationByProgress } from './lib/utils/animation-by-progress.js';
24
- import { isNodeVisible } from './lib/utils/is-node-visible.js';
25
- import { getParticlePosition } from './lib/utils/get-particle-position.js';
26
- import { linkByPointerGetter } from './lib/utils/link-by-pointer-getter.js';
27
- import { getDrawTime, setDrawTime } from '../../lib/draw-time.js';
7
+ import { nodeSettingsGetter } from './lib/settings/node-settings-getter.js';
8
+ import '@krainovsd/js-helpers';
9
+ import 'd3-array';
10
+ import { initArea } from './slices/init-area.js';
11
+ import { initDnd } from './slices/init-dnd.js';
12
+ import { initDraw } from './slices/init-draw.js';
13
+ import { initPointer } from './slices/init-pointer.js';
14
+ import { initResize } from './slices/init-resize.js';
15
+ import { initCollideForce, initSimulationForces, initSimulation } from './slices/init-simulation.js';
16
+ import { initZoom } from './slices/init-zoom.js';
28
17
 
29
18
  class GraphCanvas {
30
19
  /** initial data */
@@ -105,7 +94,7 @@ class GraphCanvas {
105
94
  this.links = links;
106
95
  this.height = 0;
107
96
  this.width = 0;
108
- this.draw = this.initDraw();
97
+ this.draw = initDraw.call(this);
109
98
  this.init();
110
99
  }
111
100
  get dpi() {
@@ -128,8 +117,8 @@ class GraphCanvas {
128
117
  changeSettings(options) {
129
118
  if (options.graphSettings) {
130
119
  this.graphSettings = graphSettingsGetter(options.graphSettings, this.graphSettings);
131
- this.draw = this.initDraw();
132
- this.initZoom(this.areaTransform);
120
+ this.draw = initDraw.call(this);
121
+ initZoom.call(this, this.areaTransform);
133
122
  }
134
123
  if (options.forceSettings) {
135
124
  this.forceSettings = forceSettingsGetter(options.forceSettings, this.forceSettings);
@@ -142,6 +131,7 @@ class GraphCanvas {
142
131
  this.nodeSettings = nodeSettingsGetter(options.nodeSettings, this.nodeSettings);
143
132
  this.cachedNodeText = {};
144
133
  this.nodeOptionsCache = {};
134
+ initCollideForce.call(this, true);
145
135
  }
146
136
  if (options.forceSettings) {
147
137
  return void this.updateSimulation();
@@ -199,7 +189,7 @@ class GraphCanvas {
199
189
  }
200
190
  updateSimulation() {
201
191
  if (this.simulation) {
202
- this.initSimulationForces();
192
+ initSimulationForces.call(this);
203
193
  this.simulation.alpha(1);
204
194
  this.simulation.restart();
205
195
  }
@@ -221,919 +211,41 @@ class GraphCanvas {
221
211
  updateData(alpha) {
222
212
  this.clearDataDependencies();
223
213
  if (this.simulation) {
224
- this.initCollideForce();
214
+ initCollideForce.call(this, false);
225
215
  this.simulation
226
216
  .nodes(this.nodes)
227
217
  .force("link", forceLink(this.links)
228
218
  .id(this.nodeSettings.idGetter)
229
- .distance(this.forceSettings.linkDistance)
230
- .strength(this.forceSettings.linkStrength)
231
- .iterations(this.forceSettings.linkIterations))
219
+ .distance(this.forceSettings.forces && this.forceSettings.linkForce
220
+ ? this.forceSettings.linkDistance
221
+ : 0)
222
+ .strength(this.forceSettings.forces && this.forceSettings.linkForce
223
+ ? this.forceSettings.linkStrength
224
+ : 0)
225
+ .iterations(this.forceSettings.forces && this.forceSettings.linkForce
226
+ ? this.forceSettings.linkIterations
227
+ : 0))
232
228
  .alpha(alpha ?? 0.5)
233
229
  .restart();
234
230
  }
235
231
  }
236
232
  updateSize() {
237
233
  this.clearHTMLElements();
238
- this.initArea();
239
- this.initDnd();
240
- this.initZoom();
241
- this.initResize();
242
- this.initPointer();
234
+ initArea.call(this);
235
+ initDnd.call(this);
236
+ initZoom.call(this);
237
+ initResize.call(this);
238
+ initPointer.call(this);
243
239
  if (!this.simulationWorking && !this.highlightWorking)
244
240
  this.draw();
245
241
  }
246
242
  init() {
247
- this.initArea();
248
- this.initSimulation();
249
- this.initDnd();
250
- this.initZoom();
251
- this.initResize();
252
- this.initPointer();
253
- }
254
- initSimulation() {
255
- if (!this.simulation) {
256
- this.simulation = forceSimulation()
257
- .nodes(this.nodes)
258
- .force("link", forceLink(this.links).id(this.nodeSettings.idGetter))
259
- .on("tick", () => {
260
- this.draw();
261
- })
262
- .on("end", () => {
263
- this.listeners.onSimulationEnd?.(this.state);
264
- if (this.graphSettings.showDrawTime)
265
- getDrawTime();
266
- });
267
- this.initSimulationForces();
268
- }
269
- }
270
- initSimulationForces() {
271
- if (!this.simulation)
272
- return;
273
- const linkForce = this.simulation.force("link");
274
- if (!linkForce)
275
- return;
276
- linkForce
277
- .distance(this.forceSettings.linkDistance)
278
- .strength(this.forceSettings.linkStrength)
279
- .iterations(this.forceSettings.linkIterations);
280
- this.simulation
281
- .force("x", forceX(this.forceSettings.xForce).strength(this.forceSettings.xStrength))
282
- .force("y", forceY(this.forceSettings.yForce).strength(this.forceSettings.yStrength))
283
- .force("charge", forceManyBody()
284
- .strength(this.forceSettings.chargeStrength)
285
- .distanceMax(this.forceSettings.chargeDistanceMax)
286
- .distanceMin(this.forceSettings.chargeDistanceMin))
287
- .force("center", forceCenter(this.forceSettings.centerPosition.x ?? 0, this.forceSettings.centerPosition.y ?? 0).strength(this.forceSettings.centerStrength));
288
- this.initCollideForce(true);
289
- }
290
- initCollideForce(forceUpdate) {
291
- if (!this.simulation)
292
- return;
293
- if (!this.forceSettings.collideOn) {
294
- if (this.simulation.force("collide"))
295
- this.simulation.force("collide", null);
296
- return;
297
- }
298
- const isHasMax = this.forceSettings.collideOffMax.links != 0 && this.forceSettings.collideOffMax.nodes != 0;
299
- const isMaxCollideNodes = isHasMax && this.forceSettings.collideOffMax.nodes < this.nodes.length;
300
- const isMaxCollideLinks = isHasMax && this.forceSettings.collideOffMax.links < this.links.length;
301
- if (isMaxCollideNodes && isMaxCollideLinks) {
302
- this.simulation.force("collide", null);
303
- }
304
- else if (!this.simulation.force("collide") || forceUpdate) {
305
- this.simulation.force("collide", forceCollide()
306
- .radius((node, index) => {
307
- if (this.forceSettings.collideRadius) {
308
- return nodeIterationExtractor(node, index, this.nodes, this.state, this.forceSettings.collideRadius, undefined);
309
- }
310
- const nodeOptions = nodeIterationExtractor(node, index, this.nodes, this.state, this.nodeSettings.options ?? {}, nodeOptionsGetter);
311
- const radius = nodeRadiusGetter({
312
- radiusFlexible: this.graphSettings.nodeRadiusFlexible,
313
- radiusInitial: nodeOptions.radius ?? this.graphSettings.nodeRadiusInitial,
314
- radiusCoefficient: this.graphSettings.nodeRadiusCoefficient,
315
- radiusFactor: this.graphSettings.nodeRadiusFactor,
316
- linkCount: node.linkCount,
317
- });
318
- return radius + this.forceSettings.collideAdditionalRadius;
319
- })
320
- .strength(this.forceSettings.collideStrength)
321
- .iterations(this.forceSettings.collideIterations));
322
- }
323
- }
324
- initArea() {
325
- if (!this.area || !this.context || !this.container) {
326
- this.container = create("div")
327
- .attr("style", "padding: 0 !important; width: 100%; height: 100%;")
328
- .node();
329
- if (!this.container)
330
- throw new Error("couldn't create container");
331
- this.root.appendChild(this.container);
332
- const { width, height } = this.root.getBoundingClientRect();
333
- this.width = width;
334
- this.height = height;
335
- this.area = create("canvas")
336
- .attr("width", this.dpi * this.width)
337
- .attr("height", this.dpi * this.height)
338
- .attr("style", `width: 100%; height: 100%; border: none !important;`)
339
- .node();
340
- if (!this.area)
341
- throw new Error("couldn't create canvas");
342
- this.container.appendChild(this.area);
343
- this.areaRect = this.area.getBoundingClientRect();
344
- this.context = this.area.getContext("2d");
345
- if (!this.context)
346
- throw new Error("couldn't create canvas context");
347
- this.context.scale(this.dpi, this.dpi);
348
- }
349
- }
350
- initDraw() {
351
- function calculateHighlightFading() {
352
- this.highlightDrawing = true;
353
- if (!this.highlightWorking && this.highlightProgress > 0) {
354
- this.highlightProgress -= this.graphSettings.highlightDownStep;
355
- if (!this.simulationWorking)
356
- return void requestAnimationFrame(() => this.draw());
357
- if (!this.linkSettings.particles)
358
- return;
359
- }
360
- if (this.highlightWorking && this.highlightProgress < 1) {
361
- this.highlightProgress += this.graphSettings.highlightUpStep;
362
- if (!this.simulationWorking)
363
- return void requestAnimationFrame(() => this.draw());
364
- if (!this.linkSettings.particles)
365
- return;
366
- }
367
- if (this.linkSettings.particles && this.highlightWorking && !this.simulationWorking) {
368
- return void requestAnimationFrame(() => this.draw());
369
- }
370
- if (!this.highlightWorking && this.highlightProgress <= 0) {
371
- if (this.highlightedNeighbors || this.highlightedNode || this.highlightedLink) {
372
- this.highlightedNeighbors = null;
373
- this.highlightedNode = null;
374
- this.highlightedLink = null;
375
- this.particles = {};
376
- if (!this.simulationWorking)
377
- return void requestAnimationFrame(() => this.draw());
378
- }
379
- }
380
- this.highlightDrawing = false;
381
- }
382
- function draw() {
383
- if (!this.context)
384
- return;
385
- const state = this.state;
386
- if (this.listeners.onDraw) {
387
- this.listeners.onDraw(state, (status) => {
388
- this.highlightDrawing = status;
389
- }, () => {
390
- if (this.highlightedNeighbors)
391
- this.highlightedNeighbors = null;
392
- if (this.highlightedNode)
393
- this.highlightedNode = null;
394
- if (this.highlightedLink)
395
- this.highlightedLink = null;
396
- });
397
- return;
398
- }
399
- this.context.save();
400
- this.context.clearRect(0, 0, this.width, this.height);
401
- this.context.translate(this.areaTransform.x, this.areaTransform.y);
402
- this.context.scale(this.areaTransform.k, this.areaTransform.k);
403
- const textRenders = [];
404
- const nodeRenders = [];
405
- this.nodes.forEach(getDrawNode(nodeRenders, textRenders, state).bind(this));
406
- /** links */
407
- this.links.forEach(getDrawLink(state).bind(this));
408
- /** nodes */
409
- nodeRenders.forEach((render) => render());
410
- textRenders.forEach((render) => render());
411
- this.context.restore();
412
- this.listeners.onDrawFinished?.(state);
413
- calculateHighlightFading.bind(this)();
414
- }
415
- function getDrawLink(state) {
416
- return function drawLink(link, index) {
417
- if (!this.context ||
418
- typeof link.source !== "object" ||
419
- typeof link.target !== "object" ||
420
- !link.source.x ||
421
- !link.source.y ||
422
- !link.target.x ||
423
- !link.target.y)
424
- return;
425
- if (!link.source._visible && !link.target._visible)
426
- return;
427
- const id = `${link.target.id}${link.source.id}`;
428
- let linkOptions;
429
- if (this.linkSettings.cache && this.linkOptionsCache[id]) {
430
- linkOptions = this.linkOptionsCache[id];
431
- }
432
- else {
433
- linkOptions = linkIterationExtractor(link, index, this.links, state, this.linkSettings.options ?? {}, linkOptionsGetter);
434
- if (this.linkSettings.cache) {
435
- this.linkOptionsCache[id] = linkOptions;
436
- }
437
- }
438
- if (linkOptions.drawLink) {
439
- linkOptions.drawLink(link, linkOptions, state);
440
- return;
441
- }
442
- let alpha = linkOptions.alpha;
443
- let arrowAlpha = linkOptions.arrowReverseAppear ? 0 : linkOptions.arrowAlpha;
444
- /** NODE HIGHLIGHT */
445
- if (this.highlightedNeighbors && this.highlightedNode) {
446
- /** Not highlighted */
447
- if (this.highlightedNode.id != link.source.id &&
448
- this.highlightedNode.id != link.target.id) {
449
- if (linkOptions.highlightByNodeLinkFading) {
450
- const min = this.graphSettings.highlightByNodeLinkFadingMin < alpha
451
- ? this.graphSettings.highlightByNodeLinkFadingMin
452
- : alpha;
453
- alpha = animationByProgress(min, alpha - min, 1 - this.highlightProgress);
454
- }
455
- if (linkOptions.arrow &&
456
- linkOptions.highlightByNodeArrowFading &&
457
- !linkOptions.arrowReverseAppear) {
458
- const min = this.graphSettings.highlightByNodeArrowFadingMin < arrowAlpha
459
- ? this.graphSettings.highlightByNodeArrowFadingMin
460
- : arrowAlpha;
461
- arrowAlpha = animationByProgress(min, arrowAlpha - min, 1 - this.highlightProgress);
462
- }
463
- }
464
- else {
465
- // eslint-disable-next-line no-lonely-if
466
- if (linkOptions.arrow && linkOptions.arrowReverseAppear) {
467
- /** Highlighted */
468
- arrowAlpha = animationByProgress(0, linkOptions.arrowAlpha, this.highlightProgress);
469
- }
470
- }
471
- }
472
- /** LINK HIGHLIGHT */
473
- if (this.highlightedNeighbors && this.highlightedLink) {
474
- /** Not highlighted */
475
- if (this.highlightedLink !== link) {
476
- if (linkOptions.highlightByLinkLinkFading) {
477
- const min = this.graphSettings.highlightByLinkLinkFadingMin < alpha
478
- ? this.graphSettings.highlightByLinkLinkFadingMin
479
- : alpha;
480
- alpha = animationByProgress(min, alpha - min, 1 - this.highlightProgress);
481
- }
482
- if (linkOptions.arrow &&
483
- linkOptions.highlightByLinkArrowFading &&
484
- !linkOptions.arrowReverseAppear) {
485
- const min = this.graphSettings.highlightByLinkArrowFadingMin < arrowAlpha
486
- ? this.graphSettings.highlightByLinkArrowFadingMin
487
- : arrowAlpha;
488
- arrowAlpha = animationByProgress(min, arrowAlpha - min, 1 - this.highlightProgress);
489
- }
490
- }
491
- else {
492
- // eslint-disable-next-line no-lonely-if
493
- if (linkOptions.arrow && linkOptions.arrowReverseAppear) {
494
- /** Highlighted */
495
- arrowAlpha = animationByProgress(0, linkOptions.arrowAlpha, this.highlightProgress);
496
- }
497
- }
498
- }
499
- /** Link */
500
- this.context.beginPath();
501
- this.context.globalAlpha = alpha;
502
- this.context.strokeStyle = linkOptions.color;
503
- this.context.lineWidth = linkOptions.width;
504
- let xStart = link.source.x;
505
- let yStart = link.source.y;
506
- let xEnd = link.target.x;
507
- let yEnd = link.target.y;
508
- if (linkOptions.pretty) {
509
- const isHasArrow = linkOptions.arrow && arrowAlpha > 0;
510
- const { x1, x2, y1, y2 } = calculateLinkPositionByRadius(link, isHasArrow ? linkOptions.arrowSize : 0) ?? {
511
- x1: 0,
512
- x2: 0,
513
- y1: 0,
514
- y2: 0,
515
- };
516
- xStart = x1;
517
- xEnd = x2;
518
- yStart = y1;
519
- yEnd = y2;
520
- }
521
- this.context.moveTo(xStart, yStart);
522
- this.context.lineTo(xEnd, yEnd);
523
- this.context.stroke();
524
- /** Particle */
525
- if (this.linkSettings.particles &&
526
- ((this.highlightedNode &&
527
- (this.highlightedNode.id === link.source.id ||
528
- this.highlightedNode.id === link.target.id)) ||
529
- (this.highlightedLink && this.highlightedLink === link))) {
530
- if (!this.particles[id]) {
531
- const sourceId = link.source.id;
532
- const targetId = link.target.id;
533
- this.particles[id] = Array.from({ length: linkOptions.particleCount }, (_, index) => {
534
- return {
535
- step: 0,
536
- wait: index * (linkOptions.particleSteps / linkOptions.particleCount),
537
- sourceId,
538
- targetId,
539
- };
540
- });
541
- }
542
- this.particles[id].forEach((particle) => {
543
- if (!this.context)
544
- return;
545
- getParticlePosition({
546
- particle,
547
- totalSteps: linkOptions.particleSteps,
548
- xEnd,
549
- xStart,
550
- yEnd,
551
- yStart,
552
- });
553
- if (particle.x != undefined && particle.y != undefined) {
554
- this.context.beginPath();
555
- this.context.arc(particle.x, particle.y, linkOptions.particleRadius, 0, Math.PI * 2);
556
- this.context.fillStyle = linkOptions.particleColor;
557
- this.context.fill();
558
- this.context.stroke();
559
- }
560
- });
561
- }
562
- /** Arrow */
563
- if (linkOptions.arrow && arrowAlpha > 0) {
564
- const { x1: xStart, x2: xEnd, y1: yStart, y2: yEnd, } = calculateLinkPositionByRadius(link) ?? {
565
- x1: 0,
566
- x2: 0,
567
- y1: 0,
568
- y2: 0,
569
- };
570
- const angle = Math.atan2(yEnd - yStart, xEnd - xStart);
571
- this.context.beginPath();
572
- this.context.globalAlpha = arrowAlpha;
573
- this.context.moveTo(xEnd, yEnd);
574
- this.context.lineTo(xEnd - linkOptions.arrowSize * Math.cos(angle - Math.PI / 6), yEnd - linkOptions.arrowSize * Math.sin(angle - Math.PI / 6));
575
- this.context.lineTo(xEnd - linkOptions.arrowSize * Math.cos(angle + Math.PI / 6), yEnd - linkOptions.arrowSize * Math.sin(angle + Math.PI / 6));
576
- this.context.closePath();
577
- this.context.fillStyle = linkOptions.arrowColor;
578
- this.context.fill();
579
- this.context.stroke();
580
- }
581
- if (linkOptions.drawExtraLink) {
582
- linkOptions.drawExtraLink(link, { ...linkOptions, alpha }, state);
583
- }
584
- };
585
- }
586
- function getDrawNode(nodeRenders, textRenders, state) {
587
- return function drawNode(node, index) {
588
- if (!this.context || !node.x || !node.y)
589
- return;
590
- let nodeOptions;
591
- if (this.nodeSettings.cache && this.nodeOptionsCache[node.id]) {
592
- nodeOptions = this.nodeOptionsCache[node.id];
593
- }
594
- else {
595
- nodeOptions = nodeIterationExtractor(node, index, this.nodes, state, this.nodeSettings.options ?? {}, nodeOptionsGetter);
596
- if (this.nodeSettings.cache) {
597
- this.nodeOptionsCache[node.id] = nodeOptions;
598
- }
599
- }
600
- if (nodeOptions.nodeDraw && nodeOptions.textDraw) {
601
- nodeRenders.push(() => {
602
- nodeOptions?.nodeDraw?.(node, nodeOptions, state);
603
- });
604
- textRenders.push(() => {
605
- nodeOptions?.textDraw?.(node, nodeOptions, state);
606
- });
607
- return;
608
- }
609
- let alpha = nodeOptions.alpha;
610
- let color = nodeOptions.color;
611
- let radiusInitial = nodeOptions.radius ?? this.graphSettings.nodeRadiusInitial;
612
- let textAlpha = nodeOptions.textAlpha;
613
- let textSize = nodeOptions.textSize;
614
- let textShiftX = nodeOptions.textShiftX;
615
- let textShiftY = nodeOptions.textShiftY;
616
- let textWeight = nodeOptions.textWeight;
617
- let textWidth = nodeOptions.textWidth;
618
- /** Node Highlight */
619
- if (this.highlightedNeighbors && this.highlightedNode) {
620
- /** Not highlighted */
621
- if (!this.highlightedNeighbors.has(node.id) && this.highlightedNode.id != node.id) {
622
- if (nodeOptions.highlightByNodeNodeFading) {
623
- const min = this.graphSettings.highlightByNodeNodeFadingMin < alpha
624
- ? this.graphSettings.highlightByNodeNodeFadingMin
625
- : alpha;
626
- alpha = animationByProgress(min, alpha - min, 1 - this.highlightProgress);
627
- }
628
- if (nodeOptions.highlightByNodeTextFading) {
629
- const min = this.graphSettings.highlightByNodeTextFadingMin < textAlpha
630
- ? this.graphSettings.highlightByNodeTextFadingMin
631
- : textAlpha;
632
- textAlpha = animationByProgress(min, textAlpha - min, 1 - this.highlightProgress);
633
- }
634
- if (nodeOptions.highlightByNodeNodeColor) {
635
- const colorRgb = extractRgb(colorToRgb(color));
636
- if (colorRgb) {
637
- const colorRgbFade = fadeRgb(colorRgb, this.graphSettings.highlightByNodeNodeColorFadingMin);
638
- const colorFadeAnimation = rgbAnimationByProgress(colorRgb, colorRgbFade, this.highlightProgress);
639
- color = `rgb(${colorFadeAnimation.r}, ${colorFadeAnimation.g}, ${colorFadeAnimation.b})`;
640
- }
641
- }
642
- }
643
- else if (!this.graphSettings.highlightByNodeOnlyRoot ||
644
- (this.graphSettings.highlightByNodeOnlyRoot && this.highlightedNode.id === node.id)) {
645
- /** Highlighted */
646
- if (nodeOptions.highlightByNodeNodeSizing) {
647
- radiusInitial = animationByProgress(radiusInitial, this.graphSettings.highlightByNodeNodeSizingAdditional, this.highlightProgress);
648
- }
649
- if (nodeOptions.highlightByNodeTextSizing) {
650
- textSize = animationByProgress(textSize, this.graphSettings.highlightByNodeTextSizingAdditional, this.highlightProgress);
651
- textShiftX = animationByProgress(textShiftX, this.graphSettings.highlightByNodeTextShiftXAdditional, this.highlightProgress);
652
- textShiftY = animationByProgress(textShiftY, this.graphSettings.highlightByNodeTextShiftYAdditional, this.highlightProgress);
653
- textWeight = animationByProgress(textWeight, this.graphSettings.highlightByNodeTextWeightAdditional, this.highlightProgress);
654
- textWidth = animationByProgress(textWidth, this.graphSettings.highlightByNodeTextWidthAdditional, this.highlightProgress);
655
- }
656
- }
657
- }
658
- /** LinkHighlight */
659
- if (this.highlightedNeighbors && this.highlightedLink) {
660
- /** Not highlighted */
661
- if (!this.highlightedNeighbors.has(node.id) &&
662
- this.highlightedLink.source !== node &&
663
- this.highlightedLink.target !== node) {
664
- if (nodeOptions.highlightByLinkNodeFading) {
665
- const min = this.graphSettings.highlightByLinkNodeFadingMin < alpha
666
- ? this.graphSettings.highlightByLinkNodeFadingMin
667
- : alpha;
668
- alpha = animationByProgress(min, alpha - min, 1 - this.highlightProgress);
669
- }
670
- if (nodeOptions.highlightByLinkTextFading) {
671
- const min = this.graphSettings.highlightByLinkTextFadingMin < textAlpha
672
- ? this.graphSettings.highlightByLinkTextFadingMin
673
- : textAlpha;
674
- textAlpha = animationByProgress(min, textAlpha - min, 1 - this.highlightProgress);
675
- }
676
- if (nodeOptions.highlightByLinkNodeColor) {
677
- const colorRgb = extractRgb(colorToRgb(color));
678
- if (colorRgb) {
679
- const colorRgbFade = fadeRgb(colorRgb, this.graphSettings.highlightByLinkNodeColorFadingMin);
680
- const colorFadeAnimation = rgbAnimationByProgress(colorRgb, colorRgbFade, this.highlightProgress);
681
- color = `rgb(${colorFadeAnimation.r}, ${colorFadeAnimation.g}, ${colorFadeAnimation.b})`;
682
- }
683
- }
684
- }
685
- else {
686
- /** Highlighted */
687
- if (nodeOptions.highlightByLinkNodeSizing) {
688
- radiusInitial = animationByProgress(radiusInitial, this.graphSettings.highlightByLinkNodeSizingAdditional, this.highlightProgress);
689
- }
690
- if (nodeOptions.highlightByLinkTextSizing) {
691
- textSize = animationByProgress(textSize, this.graphSettings.highlightByLinkTextSizingAdditional, this.highlightProgress);
692
- textShiftX = animationByProgress(textShiftX, this.graphSettings.highlightByLinkTextShiftXAdditional, this.highlightProgress);
693
- textShiftY = animationByProgress(textShiftY, this.graphSettings.highlightByLinkTextShiftYAdditional, this.highlightProgress);
694
- textWeight = animationByProgress(textWeight, this.graphSettings.highlightByLinkTextWeightAdditional, this.highlightProgress);
695
- textWidth = animationByProgress(textWidth, this.graphSettings.highlightByLinkTextWidthAdditional, this.highlightProgress);
696
- }
697
- }
698
- }
699
- const radius = nodeRadiusGetter({
700
- radiusFlexible: this.graphSettings.nodeRadiusFlexible,
701
- radiusInitial,
702
- radiusCoefficient: this.graphSettings.nodeRadiusCoefficient,
703
- radiusFactor: this.graphSettings.nodeRadiusFactor,
704
- linkCount: node.linkCount,
705
- });
706
- node._radius = radius;
707
- if (!isNodeVisible({
708
- height: this.height,
709
- width: this.width,
710
- x: node.x,
711
- y: node.y,
712
- radius,
713
- transform: this.areaTransform,
714
- })) {
715
- node._visible = false;
716
- return;
717
- }
718
- node._visible = true;
719
- nodeRenders.push(() => {
720
- if (!this.context || !node.x || !node.y)
721
- return;
722
- this.context.beginPath();
723
- this.context.globalAlpha = alpha;
724
- /** circle */
725
- this.context.lineWidth = nodeOptions.borderWidth;
726
- this.context.strokeStyle = nodeOptions.borderColor;
727
- this.context.fillStyle = color;
728
- this.context.arc(node.x, node.y, radius, 0, 2 * Math.PI);
729
- this.context.fill();
730
- this.context.stroke();
731
- });
732
- if (nodeOptions.nodeExtraDraw) {
733
- nodeRenders.push(() => {
734
- nodeOptions?.nodeExtraDraw?.(node, {
735
- ...nodeOptions,
736
- radius,
737
- alpha,
738
- color,
739
- textAlpha,
740
- textSize,
741
- textShiftX,
742
- textShiftY,
743
- textWeight,
744
- textWidth,
745
- }, state);
746
- });
747
- }
748
- /** text */
749
- if (nodeOptions.textVisible && nodeOptions.text) {
750
- textRenders.push(() => {
751
- if (nodeOptions.textDraw) {
752
- nodeOptions.textDraw(node, {
753
- ...nodeOptions,
754
- radius,
755
- alpha,
756
- color,
757
- textAlpha,
758
- textSize,
759
- textShiftX,
760
- textShiftY,
761
- textWeight,
762
- textWidth,
763
- }, state);
764
- return;
765
- }
766
- if (!this.context || !node.x || !node.y || !nodeOptions.text)
767
- return;
768
- this.context.beginPath();
769
- this.context.globalAlpha = textAlpha;
770
- drawText({
771
- id: node.id,
772
- cachedNodeText: this.cachedNodeText,
773
- context: this.context,
774
- text: nodeOptions.text,
775
- textAlign: nodeOptions.textAlign,
776
- textColor: nodeOptions.textColor,
777
- textFont: nodeOptions.textFont,
778
- textSize,
779
- x: node.x + textShiftX,
780
- y: node.y + radius + textShiftY,
781
- maxWidth: textWidth,
782
- textStyle: nodeOptions.textStyle,
783
- textWeight,
784
- textGap: nodeOptions.textGap,
785
- });
786
- if (nodeOptions.textExtraDraw) {
787
- nodeOptions.textExtraDraw(node, {
788
- ...nodeOptions,
789
- radius,
790
- alpha,
791
- color,
792
- textAlpha,
793
- textSize,
794
- textShiftX,
795
- textShiftY,
796
- textWeight,
797
- textWidth,
798
- }, state);
799
- }
800
- });
801
- }
802
- };
803
- }
804
- if (this.graphSettings.showDrawTime) {
805
- return setDrawTime(draw.bind(this), this.graphSettings.showDrawTimeEveryTick);
806
- }
807
- return draw;
808
- }
809
- initResize() {
810
- if (!this.area)
811
- throw new Error("bad init data");
812
- let initialResizeCall = true;
813
- const abortController = this.eventAbortController;
814
- const observer = new ResizeObserver(() => {
815
- if (initialResizeCall) {
816
- initialResizeCall = false;
817
- return;
818
- }
819
- if (abortController.signal.aborted) {
820
- observer.disconnect();
821
- return;
822
- }
823
- requestAnimationFrame(() => {
824
- this.updateSize();
825
- });
826
- });
827
- document.addEventListener("scroll", this.updateRect.bind(this), {
828
- capture: true,
829
- passive: true,
830
- signal: abortController.signal,
831
- });
832
- observer.observe(this.area);
833
- }
834
- initPointer() {
835
- if (!this.area || !this.nodes || !this.simulation)
836
- throw new Error("bad init data");
837
- function onHover(event) {
838
- if (!this.area)
839
- return;
840
- let currentNode;
841
- let currentLink;
842
- const checkHighlightNode = this.graphSettings.highlightByHoverNode && !this.isDragging;
843
- const checkHighlightLink = this.graphSettings.highlightByHoverLink && !this.isDragging;
844
- if (checkHighlightNode) {
845
- currentNode = nodeByPointerGetter({
846
- graphSettings: this.graphSettings,
847
- areaRect: this.areaRect,
848
- areaTransform: this.areaTransform,
849
- mouseEvent: event,
850
- nodes: this.nodes,
851
- });
852
- }
853
- if (currentNode) {
854
- this.area.style.cursor = "pointer";
855
- }
856
- else if (checkHighlightLink) {
857
- currentLink = linkByPointerGetter({
858
- graphSettings: this.graphSettings,
859
- areaRect: this.areaRect,
860
- areaTransform: this.areaTransform,
861
- mouseEvent: event,
862
- links: this.links,
863
- });
864
- if (currentLink) {
865
- this.area.style.cursor = "pointer";
866
- }
867
- else {
868
- this.area.style.cursor = "default";
869
- }
870
- }
871
- else {
872
- this.area.style.cursor = "default";
873
- }
874
- if (currentNode && this.highlightedNode !== currentNode) {
875
- this.highlightedNode = currentNode;
876
- this.highlightedLink = null;
877
- this.highlightedNeighbors = new Set(this.highlightedNode?.neighbors ?? []);
878
- this.highlightWorking = true;
879
- if (!this.simulationWorking && !this.highlightDrawing)
880
- requestAnimationFrame(() => {
881
- this.draw();
882
- });
883
- }
884
- else if (currentLink &&
885
- checkType(currentLink.source, isObject(currentLink.source)) &&
886
- checkType(currentLink.target, isObject(currentLink.target)) &&
887
- this.highlightedLink !== currentLink) {
888
- this.highlightedLink = currentLink;
889
- this.highlightedNode = null;
890
- this.highlightedNeighbors = new Set([currentLink.source.id, currentLink.target.id]);
891
- this.highlightWorking = true;
892
- if (!this.simulationWorking && !this.highlightDrawing)
893
- requestAnimationFrame(() => {
894
- this.draw();
895
- });
896
- }
897
- else if (!currentNode && !currentLink && (this.highlightedNode || this.highlightedLink)) {
898
- this.highlightWorking = false;
899
- if (!this.simulationWorking && !this.highlightDrawing)
900
- requestAnimationFrame(() => {
901
- this.draw();
902
- });
903
- }
904
- if (!this.listeners.onMove)
905
- return;
906
- if (!currentNode && !checkHighlightNode)
907
- currentNode = nodeByPointerGetter({
908
- graphSettings: this.graphSettings,
909
- areaRect: this.areaRect,
910
- areaTransform: this.areaTransform,
911
- mouseEvent: event,
912
- nodes: this.nodes,
913
- });
914
- if (!currentNode && (!checkHighlightNode || (!checkHighlightLink && !currentLink))) {
915
- currentLink = linkByPointerGetter({
916
- graphSettings: this.graphSettings,
917
- areaRect: this.areaRect,
918
- areaTransform: this.areaTransform,
919
- mouseEvent: event,
920
- links: this.links,
921
- });
922
- }
923
- if (!currentNode)
924
- return void this.listeners.onMove(event, currentNode, currentLink);
925
- }
926
- function onWheelClick(event) {
927
- if (this.isDragging ||
928
- !this.listeners.onWheelClick ||
929
- !("button" in event) ||
930
- event.button !== 1)
931
- return;
932
- const currentNode = nodeByPointerGetter({
933
- graphSettings: this.graphSettings,
934
- areaRect: this.areaRect,
935
- areaTransform: this.areaTransform,
936
- mouseEvent: event,
937
- nodes: this.nodes,
938
- });
939
- if (!currentNode) {
940
- const currentLink = linkByPointerGetter({
941
- graphSettings: this.graphSettings,
942
- areaRect: this.areaRect,
943
- areaTransform: this.areaTransform,
944
- mouseEvent: event,
945
- links: this.links,
946
- });
947
- return void this.listeners.onWheelClick(event, undefined, currentLink);
948
- }
949
- return void this.listeners.onWheelClick(event, currentNode, undefined);
950
- }
951
- function onRightClick(event) {
952
- if (!this.listeners.onContextMenu)
953
- return;
954
- const currentNode = nodeByPointerGetter({
955
- graphSettings: this.graphSettings,
956
- areaRect: this.areaRect,
957
- areaTransform: this.areaTransform,
958
- mouseEvent: event,
959
- nodes: this.nodes,
960
- });
961
- if (!currentNode) {
962
- const currentLink = linkByPointerGetter({
963
- graphSettings: this.graphSettings,
964
- areaRect: this.areaRect,
965
- areaTransform: this.areaTransform,
966
- mouseEvent: event,
967
- links: this.links,
968
- });
969
- return void this.listeners.onContextMenu(event, undefined, currentLink);
970
- }
971
- return void this.listeners.onContextMenu(event, currentNode, undefined);
972
- }
973
- function onDoubleClick(event) {
974
- if (!this.listeners.onDoubleClick)
975
- return;
976
- const currentNode = nodeByPointerGetter({
977
- graphSettings: this.graphSettings,
978
- areaRect: this.areaRect,
979
- areaTransform: this.areaTransform,
980
- mouseEvent: event,
981
- nodes: this.nodes,
982
- });
983
- if (!currentNode) {
984
- const currentLink = linkByPointerGetter({
985
- graphSettings: this.graphSettings,
986
- areaRect: this.areaRect,
987
- areaTransform: this.areaTransform,
988
- mouseEvent: event,
989
- links: this.links,
990
- });
991
- return void this.listeners.onDoubleClick(event, undefined, currentLink);
992
- }
993
- return void this.listeners.onDoubleClick(event, currentNode, undefined);
994
- }
995
- function onClick(event) {
996
- if (this.isDragging || !this.listeners.onClick || ("button" in event && event.button !== 0))
997
- return;
998
- const currentNode = nodeByPointerGetter({
999
- graphSettings: this.graphSettings,
1000
- areaRect: this.areaRect,
1001
- areaTransform: this.areaTransform,
1002
- mouseEvent: event,
1003
- nodes: this.nodes,
1004
- });
1005
- if (!currentNode) {
1006
- const currentLink = linkByPointerGetter({
1007
- graphSettings: this.graphSettings,
1008
- areaRect: this.areaRect,
1009
- areaTransform: this.areaTransform,
1010
- mouseEvent: event,
1011
- links: this.links,
1012
- });
1013
- return void this.listeners.onClick(event, undefined, currentLink);
1014
- }
1015
- return void this.listeners.onClick(event, currentNode, undefined);
1016
- }
1017
- /** hover */
1018
- this.area.addEventListener("mousemove", onHover.bind(this), {
1019
- signal: this.eventAbortController.signal,
1020
- });
1021
- this.area.addEventListener("touchmove", onHover.bind(this), {
1022
- signal: this.eventAbortController.signal,
1023
- });
1024
- /** dblclick */
1025
- this.area.addEventListener("dblclick", onDoubleClick.bind(this), {
1026
- signal: this.eventAbortController.signal,
1027
- });
1028
- /** wheel click */
1029
- this.area.addEventListener("mousedown", onWheelClick.bind(this), {
1030
- signal: this.eventAbortController.signal,
1031
- });
1032
- /** click */
1033
- this.area.addEventListener("click", onClick.bind(this), {
1034
- signal: this.eventAbortController.signal,
1035
- });
1036
- /** right click */
1037
- this.area.addEventListener("contextmenu", onRightClick.bind(this), {
1038
- signal: this.eventAbortController.signal,
1039
- });
1040
- }
1041
- initDnd() {
1042
- if (!this.area || !this.nodes || !this.simulation)
1043
- throw new Error("bad init data");
1044
- const dragHandler = drag()
1045
- .subject((event) => {
1046
- if (this.listeners.onDragSubject) {
1047
- return this.listeners.onDragSubject(event, this.state);
1048
- }
1049
- if (!this.areaRect)
1050
- return;
1051
- const mouseEvent = event.sourceEvent;
1052
- const [pointerX, pointerY] = pointerGetter(mouseEvent, this.areaRect, this.areaTransform);
1053
- let index = 0;
1054
- return greatest(this.nodes, (node) => {
1055
- if (!node.x || !node.y || (isBoolean(node.drag) && !node.drag))
1056
- return undefined;
1057
- let radius = node._radius;
1058
- if (!radius) {
1059
- const nodeOptions = nodeIterationExtractor(node, index, this.nodes, this.state, this.nodeSettings.options ?? {}, nodeOptionsGetter);
1060
- radius = nodeRadiusGetter({
1061
- radiusFlexible: this.graphSettings.nodeRadiusFlexible,
1062
- radiusInitial: nodeOptions.radius ?? this.graphSettings.nodeRadiusInitial,
1063
- radiusCoefficient: this.graphSettings.nodeRadiusCoefficient,
1064
- radiusFactor: this.graphSettings.nodeRadiusFactor,
1065
- linkCount: node.linkCount,
1066
- });
1067
- }
1068
- index++;
1069
- return this.graphSettings.dragPlaceCoefficient(node, pointerX, pointerY, radius);
1070
- });
1071
- })
1072
- .on("start", (event) => {
1073
- this.listeners.onStartDragFinished?.(event, this.state);
1074
- })
1075
- .on("drag", (event) => {
1076
- if (!this.isDragging) {
1077
- this.isDragging = true;
1078
- if (this.simulation)
1079
- this.simulation.alphaTarget(0.3).restart();
1080
- }
1081
- if (!this.areaRect)
1082
- return;
1083
- const mouseEvent = event.sourceEvent;
1084
- const [pointerX, pointerY] = pointerGetter(mouseEvent, this.areaRect, this.areaTransform);
1085
- event.subject.fx = pointerX;
1086
- event.subject.fy = pointerY;
1087
- this.listeners.onMoveDragFinished?.(event, this.state);
1088
- })
1089
- .on("end", (event) => {
1090
- this.isDragging = false;
1091
- if (!event.active && this.simulation)
1092
- this.simulation.alphaTarget(0);
1093
- if (this.graphSettings.stickAfterDrag && this.areaRect) {
1094
- if (!this.areaRect)
1095
- return;
1096
- const mouseEvent = event.sourceEvent;
1097
- const [pointerX, pointerY] = pointerGetter(mouseEvent, this.areaRect, this.areaTransform);
1098
- event.subject.fx = pointerX;
1099
- event.subject.fy = pointerY;
1100
- }
1101
- else {
1102
- event.subject.fx = null;
1103
- event.subject.fy = null;
1104
- }
1105
- this.listeners.onEndDragFinished?.(event, this.state);
1106
- });
1107
- select(this.area).call(dragHandler);
1108
- }
1109
- initZoom(currentZoom) {
1110
- if (!this.area)
1111
- throw new Error("bad init data");
1112
- const zoomInstance = zoom()
1113
- .scaleExtent(this.graphSettings.zoomExtent)
1114
- .on("zoom", (event) => {
1115
- this.listeners.onZoom?.(event);
1116
- this.areaTransform = event.transform;
1117
- this.linkOptionsCache = {};
1118
- this.nodeOptionsCache = {};
1119
- if (!this.simulationWorking && !this.highlightWorking)
1120
- requestAnimationFrame(() => this.draw());
1121
- });
1122
- if (this.graphSettings.translateExtentEnable) {
1123
- const coefficient = this.graphSettings.translateExtentCoefficient;
1124
- const [coefficientX, coefficientY] = isArray(coefficient)
1125
- ? coefficient
1126
- : [coefficient, coefficient];
1127
- const [[minX = -this.width * coefficientX, minY = -this.height * coefficientY], [maxX = this.width * coefficientX, maxY = this.height * coefficientY],] = this.graphSettings.translateExtent;
1128
- zoomInstance.translateExtent([
1129
- [minX, minY],
1130
- [maxX, maxY],
1131
- ]);
1132
- }
1133
- select(this.area).call(zoomInstance).on("dblclick.zoom", null);
1134
- const zoomInitial = currentZoom ?? this.graphSettings.zoomInitial;
1135
- this.areaTransform = new ZoomTransform(zoomInitial?.k ?? 1, zoomInitial?.x ?? this.width / 2, zoomInitial?.y ?? this.height / 2);
1136
- zoom().transform(select(this.area), this.areaTransform);
243
+ initArea.call(this);
244
+ initSimulation.call(this);
245
+ initDnd.call(this);
246
+ initZoom.call(this);
247
+ initResize.call(this);
248
+ initPointer.call(this);
1137
249
  }
1138
250
  }
1139
251