@unovis/ts 1.4.2-alpha.4 → 1.4.2

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 (48) hide show
  1. package/components/axis/config.d.ts +2 -0
  2. package/components/axis/config.js.map +1 -1
  3. package/components/axis/index.js +15 -15
  4. package/components/axis/index.js.map +1 -1
  5. package/components/graph/config.d.ts +9 -9
  6. package/components/graph/config.js +2 -2
  7. package/components/graph/config.js.map +1 -1
  8. package/components/graph/index.d.ts +13 -2
  9. package/components/graph/index.js +173 -49
  10. package/components/graph/index.js.map +1 -1
  11. package/components/graph/modules/node/index.d.ts +3 -3
  12. package/components/graph/modules/node/index.js +24 -46
  13. package/components/graph/modules/node/index.js.map +1 -1
  14. package/components/graph/modules/node/style.d.ts +2 -0
  15. package/components/graph/modules/node/style.js +34 -4
  16. package/components/graph/modules/node/style.js.map +1 -1
  17. package/components/graph/style.d.ts +1 -0
  18. package/components/graph/style.js +22 -1
  19. package/components/graph/style.js.map +1 -1
  20. package/components/graph/types.d.ts +1 -0
  21. package/components/graph/types.js.map +1 -1
  22. package/components/tooltip/config.d.ts +0 -4
  23. package/components/tooltip/config.js +0 -2
  24. package/components/tooltip/config.js.map +1 -1
  25. package/components/tooltip/index.d.ts +0 -5
  26. package/components/tooltip/index.js +5 -61
  27. package/components/tooltip/index.js.map +1 -1
  28. package/components/tooltip/style.js +8 -6
  29. package/components/tooltip/style.js.map +1 -1
  30. package/containers/single-container/index.js +1 -0
  31. package/containers/single-container/index.js.map +1 -1
  32. package/containers/xy-container/index.js +1 -0
  33. package/containers/xy-container/index.js.map +1 -1
  34. package/core/container/index.d.ts +1 -0
  35. package/core/container/index.js +5 -4
  36. package/core/container/index.js.map +1 -1
  37. package/data-models/graph.d.ts +2 -0
  38. package/data-models/graph.js +6 -0
  39. package/data-models/graph.js.map +1 -1
  40. package/index.d.ts +0 -2
  41. package/index.js +0 -2
  42. package/index.js.map +1 -1
  43. package/package.json +1 -1
  44. package/types/text.d.ts +2 -0
  45. package/types/text.js.map +1 -1
  46. package/utils/text.d.ts +1 -1
  47. package/utils/text.js +27 -15
  48. package/utils/text.js.map +1 -1
@@ -1,6 +1,7 @@
1
1
  import { __awaiter } from 'tslib';
2
2
  import { min, max } from 'd3-array';
3
3
  import { select, pointer } from 'd3-selection';
4
+ import { brush as brush$1 } from 'd3-brush';
4
5
  import { zoom, zoomTransform, zoomIdentity } from 'd3-zoom';
5
6
  import { drag } from 'd3-drag';
6
7
  import { interval } from 'd3-timer';
@@ -10,12 +11,12 @@ import { isNumber, clamp, getBoolean, isFunction, shallowDiff, isPlainObject } f
10
11
  import { smartTransition } from '../../utils/d3.js';
11
12
  import { GraphLayoutType, GraphLinkArrowStyle } from './types.js';
12
13
  import { GraphDefaultConfig } from './config.js';
13
- import { background, graphGroup, root } from './style.js';
14
+ import { background, graphGroup, brush, root } from './style.js';
14
15
  import * as style from './modules/node/style.js';
15
- import { nodes, gNode, gNodeExit, node, nodeGauge, sideLabelGroup, label, greyedOutNode } from './modules/node/style.js';
16
+ import { nodes, gNode, gNodeExit, brushed, brushable, node, nodeGauge, sideLabelGroup, label, greyedOutNode } from './modules/node/style.js';
16
17
  import { links, gLink, gLinkExit, link, greyedOutLink } from './modules/link/style.js';
17
18
  import { panels, gPanel, panel, panelSelection, label as label$1, labelText, sideIconGroup, sideIconShape, sideIconSymbol } from './modules/panel/style.js';
18
- import { createNodes, updateNodes, removeNodes, updateNodeSelectedGreyout, zoomNodesThrottled, zoomNodes } from './modules/node/index.js';
19
+ import { createNodes, updateNodes, removeNodes, updateSelectedNodes, zoomNodesThrottled, zoomNodes } from './modules/node/index.js';
19
20
  import { getMaxNodeSize, getX, getY, getNodeSize } from './modules/node/helper.js';
20
21
  import { createLinks, updateLinks, removeLinks, updateSelectedLinks, animateLinkFlow, zoomLinksThrottled, zoomLinks } from './modules/link/index.js';
21
22
  import { getArrowPath, getDoubleArrowPath } from './modules/link/helper.js';
@@ -53,9 +54,15 @@ class Graph extends ComponentCore {
53
54
  this.setConfig(config);
54
55
  this._backgroundRect = this.g.append('rect').attr('class', background);
55
56
  this._graphGroup = this.g.append('g').attr('class', graphGroup);
57
+ this._brush = this.g.append('g').attr('class', brush);
56
58
  this._zoomBehavior = zoom()
57
59
  .scaleExtent(this.config.zoomScaleExtent)
58
- .on('zoom', (e) => this._onZoom(e.transform, e));
60
+ .on('zoom', (e) => this._onZoom(e.transform, e))
61
+ .filter(event => !event.shiftKey);
62
+ this._brushBehavior = brush$1()
63
+ .on('start brush end', this._onBrush.bind(this))
64
+ .filter(event => event.shiftKey)
65
+ .keyModifiers(false);
59
66
  this._panelsGroup = this._graphGroup.append('g').attr('class', panels);
60
67
  this._linksGroup = this._graphGroup.append('g').attr('class', links);
61
68
  this._nodesGroup = this._graphGroup.append('g').attr('class', nodes);
@@ -63,7 +70,11 @@ class Graph extends ComponentCore {
63
70
  this._getLinkArrowDefId = this._getLinkArrowDefId.bind(this);
64
71
  }
65
72
  get selectedNode() {
66
- return this._selectedNode;
73
+ var _a;
74
+ return (_a = this._selectedNodes) === null || _a === void 0 ? void 0 : _a[0];
75
+ }
76
+ get selectedNodes() {
77
+ return this._selectedNodes;
67
78
  }
68
79
  get selectedLink() {
69
80
  return this._selectedLink;
@@ -91,7 +102,7 @@ class Graph extends ComponentCore {
91
102
  return { top: extraPadding, bottom: extraPadding, left: extraPadding, right: extraPadding };
92
103
  }
93
104
  _render(customDuration) {
94
- const { config: { disableZoom, duration, layoutAutofit }, datamodel } = this;
105
+ const { config: { disableBrush, disableZoom, duration, layoutAutofit }, datamodel } = this;
95
106
  if (!datamodel.nodes && !datamodel.links)
96
107
  return;
97
108
  const animDuration = isNumber(customDuration) ? customDuration : duration;
@@ -105,12 +116,31 @@ class Graph extends ComponentCore {
105
116
  this._prevWidth = this._width;
106
117
  this._prevHeight = this._height;
107
118
  }
119
+ // Handle brush behavior
120
+ if (!disableBrush) {
121
+ this._brushBehavior.extent([[0, 0], [this._width, this._height]]);
122
+ this._brush.call(this._brushBehavior);
123
+ // Activate the brush when the shift key is pressed
124
+ select(window)
125
+ .on('keydown.unovis-graph', e => e.key === 'Shift' && this._activateBrush())
126
+ .on('keyup.unovis-graph', e => e.key === 'Shift' && this._clearBrush());
127
+ this._zoomBehavior.filter(event => !event.shiftKey);
128
+ }
129
+ else {
130
+ this._brush.on('.brush', null);
131
+ select(window)
132
+ .on('keydown.unovis-graph', null)
133
+ .on('keyup.unovis-graph', null);
134
+ // Clear brush in case it was disabled in an active state
135
+ if (this._brush.classed('active'))
136
+ this._clearBrush();
137
+ }
108
138
  // Apply layout and render
109
139
  if (this._shouldRecalculateLayout || !this._layoutCalculationPromise) {
110
140
  this._layoutCalculationPromise = this._calculateLayout();
111
141
  }
112
142
  this._layoutCalculationPromise.then((isFirstRender) => {
113
- var _a, _b;
143
+ var _a;
114
144
  // If the component has been destroyed while the layout calculation
115
145
  // was in progress, we cancel the render
116
146
  if (this.isDestroyed())
@@ -130,9 +160,10 @@ class Graph extends ComponentCore {
130
160
  this._drawLinks(animDuration);
131
161
  // Select Links / Nodes
132
162
  this._resetSelection();
133
- if (this.config.selectedNodeId) {
134
- const selectedNode = datamodel.nodes.find(node => node.id === this.config.selectedNodeId);
135
- this._selectNode(selectedNode);
163
+ if (this.config.selectedNodeId || this.config.selectedNodeIds) {
164
+ const selectedIds = (_a = this.config.selectedNodeIds) !== null && _a !== void 0 ? _a : [this.config.selectedNodeId];
165
+ const selectedNodes = selectedIds.map(id => datamodel.getNodeFromId(id));
166
+ this._selectNodes(selectedNodes);
136
167
  }
137
168
  if (this.config.selectedLinkId) {
138
169
  const selectedLink = datamodel.links.find(link => link.id === this.config.selectedLinkId);
@@ -164,8 +195,6 @@ class Graph extends ComponentCore {
164
195
  // calculation and they were not set up properly (see the render function of `ComponentCore`)
165
196
  this._setUpComponentEventsThrottled();
166
197
  this._setCustomAttributesThrottled();
167
- // On render complete callback
168
- (_b = (_a = this.config).onRenderComplete) === null || _b === void 0 ? void 0 : _b.call(_a, this.g, datamodel.nodes, datamodel.links, this.config, animDuration, this._scale);
169
198
  });
170
199
  this._isFirstRender = false;
171
200
  }
@@ -177,21 +206,21 @@ class Graph extends ComponentCore {
177
206
  .data(nodes, d => String(d._id));
178
207
  const nodeGroupsEnter = nodeGroups.enter().append('g')
179
208
  .attr('class', gNode)
180
- .call(createNodes, config, duration, this._scale);
209
+ .call(createNodes, config, duration);
181
210
  const nodeGroupsMerged = nodeGroups.merge(nodeGroupsEnter);
182
211
  const nodeUpdateSelection = updateNodes(nodeGroupsMerged, config, duration, this._scale);
183
212
  this._drawPanels(nodeUpdateSelection, duration);
184
213
  const nodesGroupExit = nodeGroups.exit();
185
214
  nodesGroupExit
186
215
  .classed(gNodeExit, true)
187
- .call(removeNodes, config, duration, this._scale);
216
+ .call(removeNodes, config, duration);
188
217
  // eslint-disable-next-line @typescript-eslint/no-this-alias
189
218
  const thisRef = this;
190
219
  if (!config.disableDrag) {
191
220
  const dragBehaviour = drag()
192
- .on('start', function (event, d) { thisRef._onDragStarted(d, event, select(this)); })
193
- .on('drag', function (event, d) { thisRef._onDragged(d, event, nodeGroupsMerged); })
194
- .on('end', function (event, d) { thisRef._onDragEnded(d, event, select(this)); });
221
+ .on('start drag end', function (event, d) {
222
+ thisRef._handleDrag(d, event, select(this));
223
+ });
195
224
  nodeGroupsMerged.call(dragBehaviour);
196
225
  }
197
226
  else {
@@ -246,10 +275,10 @@ class Graph extends ComponentCore {
246
275
  _calculateLayout() {
247
276
  var _a, _b;
248
277
  return __awaiter(this, void 0, void 0, function* () {
249
- const { prevConfig, config, datamodel } = this;
278
+ const { config, datamodel } = this;
250
279
  const firstRender = this._isFirstRender;
251
280
  // If the layout type has changed, we need to reset the node positions if they were fixed before
252
- if (prevConfig.layoutType !== config.layoutType) {
281
+ if (this._currentLayoutType !== config.layoutType) {
253
282
  for (const node of datamodel.nodes) {
254
283
  delete node._state.fx;
255
284
  delete node._state.fy;
@@ -286,6 +315,7 @@ class Graph extends ComponentCore {
286
315
  this._initPanelsData();
287
316
  (_b = (_a = this.config).onLayoutCalculated) === null || _b === void 0 ? void 0 : _b.call(_a, datamodel.nodes, datamodel.links);
288
317
  this._shouldRecalculateLayout = false;
318
+ this._currentLayoutType = config.layoutType;
289
319
  return firstRender;
290
320
  });
291
321
  }
@@ -335,21 +365,9 @@ class Graph extends ComponentCore {
335
365
  return transform;
336
366
  }
337
367
  _selectNode(node) {
338
- const { datamodel: { nodes, links } } = this;
368
+ const { datamodel: { links } } = this;
339
369
  if (!node)
340
370
  console.warn('Unovis | Graph: Select Node: Not found');
341
- this._selectedNode = node;
342
- // Apply grey out
343
- // Grey out all nodes
344
- nodes.forEach(n => {
345
- n._state.selected = false;
346
- n._state.greyout = true;
347
- });
348
- // Grey out all links
349
- links.forEach(l => {
350
- l._state.greyout = true;
351
- l._state.selected = false;
352
- });
353
371
  // Highlight selected
354
372
  if (node) {
355
373
  node._state.selected = true;
@@ -365,6 +383,24 @@ class Graph extends ComponentCore {
365
383
  }
366
384
  this._updateSelectedElements();
367
385
  }
386
+ _selectNodes(nodes) {
387
+ // Apply grey out
388
+ // Grey out all nodes
389
+ this.datamodel.nodes.forEach(n => {
390
+ n._state.selected = false;
391
+ n._state.greyout = true;
392
+ });
393
+ // Grey out all links
394
+ this.datamodel.links.forEach(l => {
395
+ l._state.greyout = true;
396
+ l._state.selected = false;
397
+ });
398
+ nodes.forEach(n => {
399
+ this._selectedNodes.push(n);
400
+ this._selectNode(n);
401
+ });
402
+ this._updateSelectedElements();
403
+ }
368
404
  _selectLink(link) {
369
405
  const { datamodel: { nodes, links } } = this;
370
406
  if (!link)
@@ -399,7 +435,7 @@ class Graph extends ComponentCore {
399
435
  }
400
436
  _resetSelection() {
401
437
  const { datamodel: { nodes, links } } = this;
402
- this._selectedNode = undefined;
438
+ this._selectedNodes = [];
403
439
  this._selectedLink = undefined;
404
440
  // Disable Grayout
405
441
  nodes.forEach(n => {
@@ -417,7 +453,7 @@ class Graph extends ComponentCore {
417
453
  const linkElements = this._linksGroup.selectAll(`.${gLink}`);
418
454
  linkElements.call(updateSelectedLinks, config, this._scale);
419
455
  const nodeElements = this._nodesGroup.selectAll(`.${gNode}`);
420
- nodeElements.call(updateNodeSelectedGreyout, config);
456
+ nodeElements.call(updateSelectedNodes, config);
421
457
  // this._drawPanels(nodeElements, 0)
422
458
  }
423
459
  _onBackgroundClick() {
@@ -489,27 +525,17 @@ class Graph extends ComponentCore {
489
525
  this._linksGroup.selectAll(`.${gLink}`)
490
526
  .call((nodes.length > config.zoomThrottledUpdateNodeThreshold ? zoomLinksThrottled : zoomLinks), config, this._scale, this._getLinkArrowDefId);
491
527
  }
492
- _onDragStarted(d, event, nodeSelection) {
493
- var _a;
494
- const { config } = this;
495
- this._isDragging = true;
496
- d._state.isDragged = true;
497
- nodeSelection.call(updateNodes, config, 0, this._scale);
498
- (_a = config.onNodeDragStart) === null || _a === void 0 ? void 0 : _a.call(config, d, event);
499
- }
500
- _onDragged(d, event, allNodesSelection) {
501
- var _a, _b, _c;
502
- const { config } = this;
528
+ _updateNodePosition(d, x, y) {
529
+ var _a, _b;
503
530
  const transform = zoomTransform(this.g.node());
504
531
  const scale = transform.k;
505
532
  // Prevent the node from being dragged offscreen or outside its panel
506
533
  const panels = (_b = (_a = this._panels) === null || _a === void 0 ? void 0 : _a.filter(p => p.nodes.includes(d._id))) !== null && _b !== void 0 ? _b : [];
507
- const nodeSizeValue = getNodeSize(d, config.nodeSize, d._index);
534
+ const nodeSizeValue = getNodeSize(d, this.config.nodeSize, d._index);
508
535
  const maxY = min([(this._height - transform.y) / scale, ...panels.map(p => p._y + p._height)]) - nodeSizeValue / 2;
509
536
  const maxX = min([(this._width - transform.x) / scale, ...panels.map(p => p._x + p._width)]) - nodeSizeValue / 2;
510
537
  const minY = max([-transform.y / scale, ...panels.map(p => p._y)]) + nodeSizeValue / 2;
511
538
  const minX = max([-transform.x / scale, ...panels.map(p => p._x)]) + nodeSizeValue / 2;
512
- let [x, y] = pointer(event, this._graphGroup.node());
513
539
  if (y < minY)
514
540
  y = minY;
515
541
  else if (y > maxY)
@@ -530,6 +556,62 @@ class Graph extends ComponentCore {
530
556
  delete d._state.fx;
531
557
  if (d._state.fy === d.y)
532
558
  delete d._state.fy;
559
+ }
560
+ _onBrush(event) {
561
+ var _a;
562
+ if (!event.selection || !event.sourceEvent)
563
+ return;
564
+ const { config } = this;
565
+ const transform = zoomTransform(this._graphGroup.node());
566
+ const [xMin, yMin] = transform.invert(event.selection[0]);
567
+ const [xMax, yMax] = transform.invert(event.selection[1]);
568
+ // Update brushed nodes
569
+ this._nodesGroup.selectAll(`.${gNode}`)
570
+ .each(n => {
571
+ const x = getX(n);
572
+ const y = getY(n);
573
+ n._state.brushed = x >= xMin && x <= xMax && y >= yMin && y <= yMax;
574
+ })
575
+ .classed(brushed, n => n._state.brushed);
576
+ const brushedNodes = this._nodesGroup.selectAll(`.${brushed}`)
577
+ .call(updateSelectedNodes, config, 0, this._scale);
578
+ this._brush.classed('active', event.type !== 'end');
579
+ (_a = config.onNodeSelectionBrush) === null || _a === void 0 ? void 0 : _a.call(config, brushedNodes.data(), event);
580
+ }
581
+ _handleDrag(d, event, nodeSelection) {
582
+ if (event.sourceEvent.shiftKey && d._state.brushed) {
583
+ this._dragSelectedNodes(event);
584
+ }
585
+ else if (!event.sourceEvent.shiftKey) {
586
+ switch (event.type) {
587
+ case 'start':
588
+ this._onDragStarted(d, event, nodeSelection);
589
+ break;
590
+ case 'drag':
591
+ this._onDragged(d, event);
592
+ break;
593
+ case 'end':
594
+ this._onDragEnded(d, event, nodeSelection);
595
+ break;
596
+ }
597
+ }
598
+ }
599
+ _onDragStarted(d, event, nodeSelection) {
600
+ var _a;
601
+ const { config } = this;
602
+ this._isDragging = true;
603
+ d._state.isDragged = true;
604
+ nodeSelection.call(updateNodes, config, 0, this._scale);
605
+ (_a = config.onNodeDragStart) === null || _a === void 0 ? void 0 : _a.call(config, d, event);
606
+ }
607
+ _onDragged(d, event) {
608
+ var _a;
609
+ const { config } = this;
610
+ const transform = zoomTransform(this.g.node());
611
+ const scale = transform.k;
612
+ // Update node position
613
+ const [x, y] = pointer(event, this._graphGroup.node());
614
+ this._updateNodePosition(d, x, y);
533
615
  // Update affected DOM elements
534
616
  const nodeSelection = this._nodesGroup.selectAll(`.${gNode}`);
535
617
  const nodeToUpdate = nodeSelection.filter((n) => n._id === d._id);
@@ -544,7 +626,7 @@ class Graph extends ComponentCore {
544
626
  const linksToAnimate = linksToUpdate.filter(d => d._state.greyout);
545
627
  if (linksToAnimate.size())
546
628
  animateLinkFlow(linksToAnimate, config, this._scale);
547
- (_c = config.onNodeDrag) === null || _c === void 0 ? void 0 : _c.call(config, d, event);
629
+ (_a = config.onNodeDrag) === null || _a === void 0 ? void 0 : _a.call(config, d, event);
548
630
  }
549
631
  _onDragEnded(d, event, nodeSelection) {
550
632
  var _a;
@@ -554,6 +636,49 @@ class Graph extends ComponentCore {
554
636
  nodeSelection.call(updateNodes, config, 0, this._scale);
555
637
  (_a = config.onNodeDragEnd) === null || _a === void 0 ? void 0 : _a.call(config, d, event);
556
638
  }
639
+ _dragSelectedNodes(event) {
640
+ var _a, _b;
641
+ const { config } = this;
642
+ const curr = pointer(event, this._graphGroup.node());
643
+ const selectedNodes = smartTransition(this._nodesGroup.selectAll(`.${brushed}`));
644
+ if (event.type === 'start') {
645
+ this._groupDragInit = curr;
646
+ this._isDragging = true;
647
+ selectedNodes.each(n => {
648
+ n.x = getX(n);
649
+ n.y = getY(n);
650
+ n._state.isDragged = true;
651
+ });
652
+ }
653
+ else if (event.type === 'drag') {
654
+ const dx = curr[0] - this._groupDragInit[0];
655
+ const dy = curr[1] - this._groupDragInit[1];
656
+ selectedNodes.each(n => this._updateNodePosition(n, n.x + dx, n.y + dy));
657
+ const connectedLinks = smartTransition(this._linksGroup.selectAll(`.${gLink}`)
658
+ .filter(l => { var _a, _b, _c, _d; return ((_b = (_a = l.source) === null || _a === void 0 ? void 0 : _a._state) === null || _b === void 0 ? void 0 : _b.isDragged) || ((_d = (_c = l.target) === null || _c === void 0 ? void 0 : _c._state) === null || _d === void 0 ? void 0 : _d.isDragged); }));
659
+ connectedLinks.call(updateLinks, this.config, 0, this._scale, this._getLinkArrowDefId);
660
+ }
661
+ else {
662
+ this._isDragging = false;
663
+ selectedNodes.each(n => { n._state.isDragged = false; });
664
+ }
665
+ selectedNodes.call(updateNodes, config, 0, this._scale);
666
+ (_b = (_a = this.config).onNodeSelectionDrag) === null || _b === void 0 ? void 0 : _b.call(_a, selectedNodes.data(), event);
667
+ }
668
+ _activateBrush() {
669
+ this._brush.classed('active', true);
670
+ this._nodesGroup.selectAll(`.${gNode}`)
671
+ .classed(brushable, true);
672
+ }
673
+ _clearBrush() {
674
+ var _a;
675
+ this._brush.classed('active', false).call((_a = this._brushBehavior) === null || _a === void 0 ? void 0 : _a.clear);
676
+ this._nodesGroup.selectAll(`.${gNode}`)
677
+ .classed(brushable, false)
678
+ .classed(brushed, false)
679
+ .each(n => { n._state.brushed = false; })
680
+ .call(updateSelectedNodes, this.config, 0, this._scale);
681
+ }
557
682
  _shouldLayoutRecalculate() {
558
683
  const { prevConfig, config } = this;
559
684
  if (prevConfig.layoutType !== config.layoutType)
@@ -660,7 +785,6 @@ class Graph extends ComponentCore {
660
785
  }
661
786
  Graph.selectors = {
662
787
  root: root,
663
- graphGroup: graphGroup,
664
788
  background: background,
665
789
  node: gNode,
666
790
  nodeShape: node,