@unovis/ts 1.5.0-version.9 → 1.5.1-exf.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/axis/config.d.ts +10 -1
- package/components/axis/config.js +1 -1
- package/components/axis/config.js.map +1 -1
- package/components/axis/index.d.ts +19 -19
- package/components/axis/index.js +63 -8
- package/components/axis/index.js.map +1 -1
- package/components/axis/style.d.ts +1 -0
- package/components/axis/style.js +7 -2
- package/components/axis/style.js.map +1 -1
- package/components/crosshair/index.js +6 -0
- package/components/crosshair/index.js.map +1 -1
- package/components/donut/config.d.ts +4 -0
- package/components/donut/config.js +1 -1
- package/components/donut/config.js.map +1 -1
- package/components/donut/index.d.ts +2 -0
- package/components/donut/index.js +41 -6
- package/components/donut/index.js.map +1 -1
- package/components/graph/config.d.ts +39 -6
- package/components/graph/config.js +7 -4
- package/components/graph/config.js.map +1 -1
- package/components/graph/index.d.ts +22 -15
- package/components/graph/index.js +233 -98
- package/components/graph/index.js.map +1 -1
- package/components/graph/modules/link/index.d.ts +2 -1
- package/components/graph/modules/link/index.js +87 -51
- package/components/graph/modules/link/index.js.map +1 -1
- package/components/graph/modules/link/style.js +0 -2
- package/components/graph/modules/link/style.js.map +1 -1
- package/components/graph/modules/node/index.d.ts +2 -1
- package/components/graph/modules/node/index.js +47 -23
- package/components/graph/modules/node/index.js.map +1 -1
- package/components/graph/modules/node/style.d.ts +2 -0
- package/components/graph/modules/node/style.js +34 -4
- package/components/graph/modules/node/style.js.map +1 -1
- package/components/graph/modules/panel/index.js +1 -0
- package/components/graph/modules/panel/index.js.map +1 -1
- package/components/graph/style.d.ts +1 -0
- package/components/graph/style.js +22 -1
- package/components/graph/style.js.map +1 -1
- package/components/graph/types.d.ts +8 -0
- package/components/graph/types.js +8 -2
- package/components/graph/types.js.map +1 -1
- package/components/leaflet-map/modules/map.js +2 -1
- package/components/leaflet-map/modules/map.js.map +1 -1
- package/components/scatter/index.d.ts +1 -0
- package/components/scatter/index.js +19 -12
- package/components/scatter/index.js.map +1 -1
- package/components/scatter/modules/point.js +1 -3
- package/components/scatter/modules/point.js.map +1 -1
- package/components/scatter/types.d.ts +2 -0
- package/components/tooltip/index.d.ts +7 -0
- package/components/tooltip/index.js +17 -5
- package/components/tooltip/index.js.map +1 -1
- package/components/topojson-map/config.js +2 -2
- package/components/topojson-map/config.js.map +1 -1
- package/components/topojson-map/index.js +22 -5
- package/components/topojson-map/index.js.map +1 -1
- package/containers/single-container/index.js +2 -2
- package/containers/single-container/index.js.map +1 -1
- package/containers/xy-container/index.js +4 -2
- package/containers/xy-container/index.js.map +1 -1
- package/core/container/config.d.ts +2 -4
- package/core/container/config.js.map +1 -1
- package/core/container/index.d.ts +2 -1
- package/core/container/index.js +26 -19
- package/core/container/index.js.map +1 -1
- package/data-models/graph.d.ts +2 -0
- package/data-models/graph.js +6 -0
- package/data-models/graph.js.map +1 -1
- package/index.d.ts +1 -4
- package/index.js +13 -5
- package/index.js.map +1 -1
- package/maps/world-simple.json.js +2430 -42
- package/package.json +2 -2
- package/types/graph.d.ts +6 -0
- package/types.js +1 -1
- package/utils/data.d.ts +2 -1
- package/utils/data.js +18 -8
- package/utils/data.js.map +1 -1
- package/utils/index.d.ts +12 -0
- package/utils/index.js +13 -0
- package/utils/index.js.map +1 -0
- package/utils/scale.js +4 -0
- package/utils/scale.js.map +1 -0
- package/utils/type.js +2 -0
- package/utils/type.js.map +1 -0
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
2
|
import { min, max } from 'd3-array';
|
|
3
3
|
import { select, pointer } from 'd3-selection';
|
|
4
|
-
import {
|
|
4
|
+
import { brush as brush$1 } from 'd3-brush';
|
|
5
|
+
import { zoom, zoomIdentity, zoomTransform } from 'd3-zoom';
|
|
5
6
|
import { drag } from 'd3-drag';
|
|
6
7
|
import { interval } from 'd3-timer';
|
|
7
8
|
import { ComponentCore } from '../../core/component/index.js';
|
|
8
9
|
import { GraphDataModel } from '../../data-models/graph.js';
|
|
9
10
|
import { isNumber, isFunction, clamp, getBoolean, shallowDiff, isPlainObject, isEqual } from '../../utils/data.js';
|
|
10
11
|
import { smartTransition } from '../../utils/d3.js';
|
|
11
|
-
import { GraphLayoutType, GraphLinkArrowStyle } from './types.js';
|
|
12
|
+
import { GraphLayoutType, GraphNodeSelectionHighlightMode, 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 { links, gLink, gLinkExit, link, greyedOutLink } from './modules/link/style.js';
|
|
16
|
+
import { nodes, gNode, gNodeExit, brushed, brushable, node, nodeGauge, sideLabelGroup, label, greyedOutNode } from './modules/node/style.js';
|
|
17
|
+
import { links, gLink, gLinkExit, link, linkLabelGroup, 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,
|
|
19
|
+
import { createNodes, updateNodes, removeNodes, updateNodesPartial, zoomNodesThrottled, zoomNodes } from './modules/node/index.js';
|
|
19
20
|
import { getMaxNodeSize, getX, getY, getNodeSize } from './modules/node/helper.js';
|
|
20
|
-
import { createLinks, updateLinks, removeLinks,
|
|
21
|
+
import { createLinks, updateLinks, removeLinks, updateLinksPartial, animateLinkFlow, zoomLinksThrottled, zoomLinks } from './modules/link/index.js';
|
|
21
22
|
import { getArrowPath, getDoubleArrowPath } from './modules/link/helper.js';
|
|
22
23
|
import { removePanels, createPanels, updatePanels } from './modules/panel/index.js';
|
|
23
24
|
import { updatePanelNumNodes, updatePanelBBoxSize, initPanels, setPanelForNodes } from './modules/panel/helper.js';
|
|
@@ -53,9 +54,16 @@ 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
|
+
.on('start', (e) => this._onZoomStart(e.transform, e))
|
|
62
|
+
.on('end', (e) => this._onZoomEnd(e.transform, e));
|
|
63
|
+
this._brushBehavior = brush$1()
|
|
64
|
+
.on('start brush end', this._onBrush.bind(this))
|
|
65
|
+
.filter(event => event.shiftKey)
|
|
66
|
+
.keyModifiers(false);
|
|
59
67
|
this._panelsGroup = this._graphGroup.append('g').attr('class', panels);
|
|
60
68
|
this._linksGroup = this._graphGroup.append('g').attr('class', links);
|
|
61
69
|
this._nodesGroup = this._graphGroup.append('g').attr('class', nodes);
|
|
@@ -63,13 +71,19 @@ class Graph extends ComponentCore {
|
|
|
63
71
|
this._getLinkArrowDefId = this._getLinkArrowDefId.bind(this);
|
|
64
72
|
}
|
|
65
73
|
get selectedNode() {
|
|
66
|
-
|
|
74
|
+
var _a;
|
|
75
|
+
return (_a = this._selectedNodes) === null || _a === void 0 ? void 0 : _a[0];
|
|
76
|
+
}
|
|
77
|
+
get selectedNodes() {
|
|
78
|
+
return this._selectedNodes;
|
|
67
79
|
}
|
|
68
80
|
get selectedLink() {
|
|
69
81
|
return this._selectedLink;
|
|
70
82
|
}
|
|
71
83
|
setData(data) {
|
|
72
84
|
const { config } = this;
|
|
85
|
+
if (!config.shouldDataUpdate(this.datamodel.data, data))
|
|
86
|
+
return;
|
|
73
87
|
this.datamodel.nodeSort = config.nodeSort;
|
|
74
88
|
this.datamodel.data = data;
|
|
75
89
|
this._shouldRecalculateLayout = true;
|
|
@@ -95,7 +109,7 @@ class Graph extends ComponentCore {
|
|
|
95
109
|
return { top: extraPadding, bottom: extraPadding, left: extraPadding, right: extraPadding };
|
|
96
110
|
}
|
|
97
111
|
_render(customDuration) {
|
|
98
|
-
const { config: { disableZoom, duration, layoutAutofit, zoomEventFilter }, datamodel } = this;
|
|
112
|
+
const { config: { disableBrush, disableZoom, duration, layoutAutofit, zoomEventFilter }, datamodel } = this;
|
|
99
113
|
if (!datamodel.nodes && !datamodel.links)
|
|
100
114
|
return;
|
|
101
115
|
const animDuration = isNumber(customDuration) ? customDuration : duration;
|
|
@@ -109,6 +123,25 @@ class Graph extends ComponentCore {
|
|
|
109
123
|
this._prevWidth = this._width;
|
|
110
124
|
this._prevHeight = this._height;
|
|
111
125
|
}
|
|
126
|
+
// Handle brush behavior
|
|
127
|
+
if (!disableBrush) {
|
|
128
|
+
this._brushBehavior.extent([[0, 0], [this._width, this._height]]);
|
|
129
|
+
this._brush.call(this._brushBehavior);
|
|
130
|
+
// Activate the brush when the shift key is pressed
|
|
131
|
+
select(window)
|
|
132
|
+
.on('keydown.unovis-graph', e => e.key === 'Shift' && this._activateBrush())
|
|
133
|
+
.on('keyup.unovis-graph', e => e.key === 'Shift' && this._clearBrush());
|
|
134
|
+
this._zoomBehavior.filter(event => !event.shiftKey);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
this._brush.on('.brush', null);
|
|
138
|
+
select(window)
|
|
139
|
+
.on('keydown.unovis-graph', null)
|
|
140
|
+
.on('keyup.unovis-graph', null);
|
|
141
|
+
// Clear brush in case it was disabled in an active state
|
|
142
|
+
if (this._brush.classed('active'))
|
|
143
|
+
this._clearBrush();
|
|
144
|
+
}
|
|
112
145
|
// Apply layout and render
|
|
113
146
|
if (this._shouldRecalculateLayout || !this._layoutCalculationPromise) {
|
|
114
147
|
this._layoutCalculationPromise = this._calculateLayout();
|
|
@@ -119,20 +152,21 @@ class Graph extends ComponentCore {
|
|
|
119
152
|
(_b = (_a = this.config).onLayoutCalculated) === null || _b === void 0 ? void 0 : _b.call(_a, datamodel.nodes, datamodel.links);
|
|
120
153
|
});
|
|
121
154
|
}
|
|
122
|
-
//
|
|
123
|
-
//
|
|
155
|
+
// Redefining Zoom Behavior filter to the one specified in the config,
|
|
156
|
+
// or to the default one supporting `shiftKey` for node brushing
|
|
157
|
+
// See more: https://d3js.org/d3-zoom#zoom_filter
|
|
124
158
|
this._zoomBehavior.filter(isFunction(zoomEventFilter)
|
|
125
159
|
? zoomEventFilter
|
|
126
|
-
: (e) => !e.shiftKey); // Default filter
|
|
127
|
-
this._layoutCalculationPromise.then((
|
|
128
|
-
var _a, _b;
|
|
160
|
+
: (e) => (!e.ctrlKey || e.type === 'wheel') && !e.button && !e.shiftKey); // Default filter
|
|
161
|
+
this._layoutCalculationPromise.then(() => {
|
|
162
|
+
var _a, _b, _c;
|
|
129
163
|
// If the component has been destroyed while the layout calculation
|
|
130
164
|
// was in progress, we cancel the render
|
|
131
165
|
if (this.isDestroyed())
|
|
132
166
|
return;
|
|
133
167
|
this._initPanelsData();
|
|
134
168
|
// Fit the view
|
|
135
|
-
if (
|
|
169
|
+
if (this._isFirstRender) {
|
|
136
170
|
this._fit();
|
|
137
171
|
this._shouldFitLayout = false;
|
|
138
172
|
}
|
|
@@ -140,19 +174,20 @@ class Graph extends ComponentCore {
|
|
|
140
174
|
this._fit(duration);
|
|
141
175
|
this._shouldFitLayout = false;
|
|
142
176
|
}
|
|
143
|
-
//
|
|
144
|
-
this.
|
|
145
|
-
this.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const selectedNode = datamodel.nodes.find(node => node.id === this.config.selectedNodeId);
|
|
150
|
-
this._selectNode(selectedNode);
|
|
177
|
+
// Update Nodes and Links Selection State
|
|
178
|
+
this._resetSelectionGreyoutState();
|
|
179
|
+
if (this.config.selectedNodeId || this.config.selectedNodeIds) {
|
|
180
|
+
const selectedIds = (_a = this.config.selectedNodeIds) !== null && _a !== void 0 ? _a : [this.config.selectedNodeId];
|
|
181
|
+
const selectedNodes = selectedIds.map(id => datamodel.getNodeFromId(id));
|
|
182
|
+
this._setNodeSelectionState(selectedNodes);
|
|
151
183
|
}
|
|
152
184
|
if (this.config.selectedLinkId) {
|
|
153
185
|
const selectedLink = datamodel.links.find(link => link.id === this.config.selectedLinkId);
|
|
154
|
-
this.
|
|
186
|
+
this._setLinkSelectionState(selectedLink);
|
|
155
187
|
}
|
|
188
|
+
// Draw
|
|
189
|
+
this._drawNodes(animDuration);
|
|
190
|
+
this._drawLinks(animDuration);
|
|
156
191
|
// Link flow animation timer
|
|
157
192
|
if (!this._timer) {
|
|
158
193
|
const refreshRateMs = 35;
|
|
@@ -163,26 +198,14 @@ class Graph extends ComponentCore {
|
|
|
163
198
|
this.g.on('.zoom', null);
|
|
164
199
|
else
|
|
165
200
|
this.g.call(this._zoomBehavior).on('dblclick.zoom', null);
|
|
166
|
-
if (!this._isFirstRender && !disableZoom) {
|
|
167
|
-
const transform = zoomTransform(this.g.node());
|
|
168
|
-
this._onZoom(transform);
|
|
169
|
-
}
|
|
170
|
-
// While the graph is animating we disable pointer events on the graph group
|
|
171
|
-
if (animDuration) {
|
|
172
|
-
this._graphGroup.attr('pointer-events', 'none');
|
|
173
|
-
}
|
|
174
|
-
smartTransition(this._graphGroup, animDuration)
|
|
175
|
-
.on('end interrupt', () => {
|
|
176
|
-
this._graphGroup.attr('pointer-events', null);
|
|
177
|
-
});
|
|
178
201
|
// We need to set up events and attributes again because the rendering might have been delayed by the layout
|
|
179
202
|
// calculation and they were not set up properly (see the render function of `ComponentCore`)
|
|
180
203
|
this._setUpComponentEventsThrottled();
|
|
181
204
|
this._setCustomAttributesThrottled();
|
|
182
205
|
// On render complete callback
|
|
183
|
-
(
|
|
206
|
+
(_c = (_b = this.config).onRenderComplete) === null || _c === void 0 ? void 0 : _c.call(_b, this.g, datamodel.nodes, datamodel.links, this.config, animDuration, this._scale, this._containerWidth, this._containerHeight);
|
|
207
|
+
this._isFirstRender = false;
|
|
184
208
|
});
|
|
185
|
-
this._isFirstRender = false;
|
|
186
209
|
}
|
|
187
210
|
_drawNodes(duration) {
|
|
188
211
|
const { config, datamodel } = this;
|
|
@@ -204,9 +227,9 @@ class Graph extends ComponentCore {
|
|
|
204
227
|
const thisRef = this;
|
|
205
228
|
if (!config.disableDrag) {
|
|
206
229
|
const dragBehaviour = drag()
|
|
207
|
-
.on('start', function (event, d) {
|
|
208
|
-
|
|
209
|
-
|
|
230
|
+
.on('start drag end', function (event, d) {
|
|
231
|
+
thisRef._handleDrag(d, event, select(this));
|
|
232
|
+
});
|
|
210
233
|
nodeGroupsMerged.call(dragBehaviour);
|
|
211
234
|
}
|
|
212
235
|
else {
|
|
@@ -261,7 +284,6 @@ class Graph extends ComponentCore {
|
|
|
261
284
|
_calculateLayout() {
|
|
262
285
|
return __awaiter(this, void 0, void 0, function* () {
|
|
263
286
|
const { config, datamodel } = this;
|
|
264
|
-
const firstRender = this._isFirstRender;
|
|
265
287
|
// If the layout type has changed, we need to reset the node positions if they were fixed before
|
|
266
288
|
if (this._currentLayoutType !== config.layoutType) {
|
|
267
289
|
for (const node of datamodel.nodes) {
|
|
@@ -300,7 +322,6 @@ class Graph extends ComponentCore {
|
|
|
300
322
|
this._initPanelsData();
|
|
301
323
|
this._shouldRecalculateLayout = false;
|
|
302
324
|
this._currentLayoutType = config.layoutType;
|
|
303
|
-
return firstRender;
|
|
304
325
|
});
|
|
305
326
|
}
|
|
306
327
|
_initPanelsData() {
|
|
@@ -311,9 +332,10 @@ class Graph extends ComponentCore {
|
|
|
311
332
|
this._shouldSetPanels = false;
|
|
312
333
|
}
|
|
313
334
|
}
|
|
314
|
-
_fit(duration = 0) {
|
|
335
|
+
_fit(duration = 0, nodeIds) {
|
|
315
336
|
const { datamodel: { nodes } } = this;
|
|
316
|
-
const
|
|
337
|
+
const fitViewNodes = (nodeIds === null || nodeIds === void 0 ? void 0 : nodeIds.length) ? nodes.filter(n => nodeIds.includes(n.id)) : nodes;
|
|
338
|
+
const transform = this._getTransform(fitViewNodes);
|
|
317
339
|
smartTransition(this.g, duration)
|
|
318
340
|
.call(this._zoomBehavior.transform, transform);
|
|
319
341
|
this._onZoom(transform);
|
|
@@ -348,38 +370,45 @@ class Graph extends ComponentCore {
|
|
|
348
370
|
.scale(clampedScale);
|
|
349
371
|
return transform;
|
|
350
372
|
}
|
|
351
|
-
|
|
352
|
-
const {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
this._selectedNode = node;
|
|
356
|
-
// Apply grey out
|
|
357
|
-
// Grey out all nodes
|
|
358
|
-
nodes.forEach(n => {
|
|
373
|
+
_setNodeSelectionState(nodesToSelect) {
|
|
374
|
+
const { config, datamodel } = this;
|
|
375
|
+
// Grey out all nodes and set us unselected
|
|
376
|
+
for (const n of datamodel.nodes) {
|
|
359
377
|
n._state.selected = false;
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
378
|
+
if (config.nodeSelectionHighlightMode !== GraphNodeSelectionHighlightMode.None) {
|
|
379
|
+
n._state.greyout = true;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
// Grey out all links and set us unselected
|
|
383
|
+
for (const l of datamodel.links) {
|
|
365
384
|
l._state.selected = false;
|
|
385
|
+
if (config.nodeSelectionHighlightMode !== GraphNodeSelectionHighlightMode.None) {
|
|
386
|
+
l._state.greyout = true;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
// Filter out non-existing nodes
|
|
390
|
+
this._selectedNodes = nodesToSelect.filter(n => {
|
|
391
|
+
const doesNodeExist = Boolean(n);
|
|
392
|
+
if (!doesNodeExist)
|
|
393
|
+
console.warn('Unovis | Graph: Select Node: Not found');
|
|
394
|
+
return doesNodeExist;
|
|
366
395
|
});
|
|
367
|
-
//
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
396
|
+
// Set provided nodes as selected and ungreyout
|
|
397
|
+
for (const n of this._selectedNodes) {
|
|
398
|
+
n._state.selected = true;
|
|
399
|
+
n._state.greyout = false;
|
|
400
|
+
}
|
|
401
|
+
// Highlight connected links and nodes
|
|
402
|
+
if (config.nodeSelectionHighlightMode === GraphNodeSelectionHighlightMode.GreyoutNonConnected) {
|
|
403
|
+
const connectedLinks = datamodel.links.filter(l => this._selectedNodes.includes(l.source) || this._selectedNodes.includes(l.target));
|
|
372
404
|
connectedLinks.forEach(l => {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
source._state.greyout = false;
|
|
376
|
-
target._state.greyout = false;
|
|
405
|
+
l.source._state.greyout = false;
|
|
406
|
+
l.target._state.greyout = false;
|
|
377
407
|
l._state.greyout = false;
|
|
378
408
|
});
|
|
379
409
|
}
|
|
380
|
-
this._updateSelectedElements();
|
|
381
410
|
}
|
|
382
|
-
|
|
411
|
+
_setLinkSelectionState(link) {
|
|
383
412
|
const { datamodel: { nodes, links } } = this;
|
|
384
413
|
if (!link)
|
|
385
414
|
console.warn('Unovis: Graph: Select Link: Not found');
|
|
@@ -409,13 +438,12 @@ class Graph extends ComponentCore {
|
|
|
409
438
|
});
|
|
410
439
|
if (link)
|
|
411
440
|
link._state.selected = true;
|
|
412
|
-
this._updateSelectedElements();
|
|
413
441
|
}
|
|
414
|
-
|
|
442
|
+
_resetSelectionGreyoutState() {
|
|
415
443
|
const { datamodel: { nodes, links } } = this;
|
|
416
|
-
this.
|
|
444
|
+
this._selectedNodes = [];
|
|
417
445
|
this._selectedLink = undefined;
|
|
418
|
-
// Disable
|
|
446
|
+
// Disable Greyout
|
|
419
447
|
nodes.forEach(n => {
|
|
420
448
|
delete n._state.selected;
|
|
421
449
|
delete n._state.greyout;
|
|
@@ -424,27 +452,28 @@ class Graph extends ComponentCore {
|
|
|
424
452
|
delete l._state.greyout;
|
|
425
453
|
delete l._state.selected;
|
|
426
454
|
});
|
|
427
|
-
this._updateSelectedElements();
|
|
428
455
|
}
|
|
429
|
-
|
|
456
|
+
_updateNodesLinksPartial() {
|
|
430
457
|
const { config } = this;
|
|
431
458
|
const linkElements = this._linksGroup.selectAll(`.${gLink}`);
|
|
432
|
-
linkElements.call(
|
|
459
|
+
linkElements.call(updateLinksPartial, config, this._scale);
|
|
433
460
|
const nodeElements = this._nodesGroup.selectAll(`.${gNode}`);
|
|
434
|
-
nodeElements.call(
|
|
435
|
-
// this._drawPanels(nodeElements, 0)
|
|
461
|
+
nodeElements.call(updateNodesPartial, config, config.duration, this._scale);
|
|
436
462
|
}
|
|
437
463
|
_onBackgroundClick() {
|
|
438
|
-
this.
|
|
464
|
+
this._resetSelectionGreyoutState();
|
|
465
|
+
this._updateNodesLinksPartial();
|
|
439
466
|
}
|
|
440
467
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
441
468
|
_onNodeClick(d) {
|
|
442
469
|
}
|
|
443
470
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
444
471
|
_onNodeMouseOut(d) {
|
|
472
|
+
this._updateNodesLinksPartial();
|
|
445
473
|
}
|
|
446
474
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
447
475
|
_onNodeMouseOver(d) {
|
|
476
|
+
this._updateNodesLinksPartial();
|
|
448
477
|
}
|
|
449
478
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
450
479
|
_onLinkClick(d) {
|
|
@@ -452,14 +481,15 @@ class Graph extends ComponentCore {
|
|
|
452
481
|
_onLinkMouseOver(d) {
|
|
453
482
|
if (this._isDragging)
|
|
454
483
|
return;
|
|
455
|
-
|
|
456
|
-
|
|
484
|
+
if (this.config.linkHighlightOnHover)
|
|
485
|
+
d._state.hovered = true;
|
|
486
|
+
this._updateNodesLinksPartial();
|
|
457
487
|
}
|
|
458
488
|
_onLinkMouseOut(d) {
|
|
459
489
|
if (this._isDragging)
|
|
460
490
|
return;
|
|
461
491
|
delete d._state.hovered;
|
|
462
|
-
this.
|
|
492
|
+
this._updateNodesLinksPartial();
|
|
463
493
|
}
|
|
464
494
|
_onLinkFlowTimerFrame(elapsed = 0) {
|
|
465
495
|
const { config: { linkFlow, linkFlowAnimDuration }, datamodel: { links } } = this;
|
|
@@ -478,7 +508,7 @@ class Graph extends ComponentCore {
|
|
|
478
508
|
this._scale = transform.k;
|
|
479
509
|
this._graphGroup.attr('transform', transform.toString());
|
|
480
510
|
if (isFunction(config.onZoom))
|
|
481
|
-
config.onZoom(this._scale, config.zoomScaleExtent, event);
|
|
511
|
+
config.onZoom(this._scale, config.zoomScaleExtent, event, transform);
|
|
482
512
|
// console.warn('Unovis | Graph: Zoom: ', transform)
|
|
483
513
|
if (!this._initialTransform)
|
|
484
514
|
this._initialTransform = transform;
|
|
@@ -503,27 +533,31 @@ class Graph extends ComponentCore {
|
|
|
503
533
|
this._linksGroup.selectAll(`.${gLink}`)
|
|
504
534
|
.call((nodes.length > config.zoomThrottledUpdateNodeThreshold ? zoomLinksThrottled : zoomLinks), config, this._scale, this._getLinkArrowDefId);
|
|
505
535
|
}
|
|
506
|
-
|
|
507
|
-
var _a;
|
|
536
|
+
_onZoomStart(t, event) {
|
|
508
537
|
const { config } = this;
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
538
|
+
const transform = t || event.transform;
|
|
539
|
+
this._scale = transform.k;
|
|
540
|
+
if (isFunction(config.onZoomStart))
|
|
541
|
+
config.onZoomStart(this._scale, config.zoomScaleExtent, event, transform);
|
|
513
542
|
}
|
|
514
|
-
|
|
515
|
-
var _a, _b, _c;
|
|
543
|
+
_onZoomEnd(t, event) {
|
|
516
544
|
const { config } = this;
|
|
545
|
+
const transform = t || event.transform;
|
|
546
|
+
this._scale = transform.k;
|
|
547
|
+
if (isFunction(config.onZoomEnd))
|
|
548
|
+
config.onZoomEnd(this._scale, config.zoomScaleExtent, event, transform);
|
|
549
|
+
}
|
|
550
|
+
_updateNodePosition(d, x, y) {
|
|
551
|
+
var _a, _b;
|
|
517
552
|
const transform = zoomTransform(this.g.node());
|
|
518
553
|
const scale = transform.k;
|
|
519
554
|
// Prevent the node from being dragged offscreen or outside its panel
|
|
520
555
|
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 : [];
|
|
521
|
-
const nodeSizeValue = getNodeSize(d, config.nodeSize, d._index);
|
|
556
|
+
const nodeSizeValue = getNodeSize(d, this.config.nodeSize, d._index);
|
|
522
557
|
const maxY = min([(this._height - transform.y) / scale, ...panels.map(p => p._y + p._height)]) - nodeSizeValue / 2;
|
|
523
558
|
const maxX = min([(this._width - transform.x) / scale, ...panels.map(p => p._x + p._width)]) - nodeSizeValue / 2;
|
|
524
559
|
const minY = max([-transform.y / scale, ...panels.map(p => p._y)]) + nodeSizeValue / 2;
|
|
525
560
|
const minX = max([-transform.x / scale, ...panels.map(p => p._x)]) + nodeSizeValue / 2;
|
|
526
|
-
let [x, y] = pointer(event, this._graphGroup.node());
|
|
527
561
|
if (y < minY)
|
|
528
562
|
y = minY;
|
|
529
563
|
else if (y > maxY)
|
|
@@ -544,6 +578,62 @@ class Graph extends ComponentCore {
|
|
|
544
578
|
delete d._state.fx;
|
|
545
579
|
if (d._state.fy === d.y)
|
|
546
580
|
delete d._state.fy;
|
|
581
|
+
}
|
|
582
|
+
_onBrush(event) {
|
|
583
|
+
var _a;
|
|
584
|
+
if (!event.selection || !event.sourceEvent)
|
|
585
|
+
return;
|
|
586
|
+
const { config } = this;
|
|
587
|
+
const transform = zoomTransform(this._graphGroup.node());
|
|
588
|
+
const [xMin, yMin] = transform.invert(event.selection[0]);
|
|
589
|
+
const [xMax, yMax] = transform.invert(event.selection[1]);
|
|
590
|
+
// Update brushed nodes
|
|
591
|
+
this._nodesGroup.selectAll(`.${gNode}`)
|
|
592
|
+
.each(n => {
|
|
593
|
+
const x = getX(n);
|
|
594
|
+
const y = getY(n);
|
|
595
|
+
n._state.brushed = x >= xMin && x <= xMax && y >= yMin && y <= yMax;
|
|
596
|
+
})
|
|
597
|
+
.classed(brushed, n => n._state.brushed);
|
|
598
|
+
const brushedNodes = this._nodesGroup.selectAll(`.${brushed}`)
|
|
599
|
+
.call(updateNodesPartial, config, 0, this._scale);
|
|
600
|
+
this._brush.classed('active', event.type !== 'end');
|
|
601
|
+
(_a = config.onNodeSelectionBrush) === null || _a === void 0 ? void 0 : _a.call(config, brushedNodes.data(), event);
|
|
602
|
+
}
|
|
603
|
+
_handleDrag(d, event, nodeSelection) {
|
|
604
|
+
if (event.sourceEvent.shiftKey && d._state.brushed) {
|
|
605
|
+
this._dragSelectedNodes(event);
|
|
606
|
+
}
|
|
607
|
+
else if (!event.sourceEvent.shiftKey) {
|
|
608
|
+
switch (event.type) {
|
|
609
|
+
case 'start':
|
|
610
|
+
this._onDragStarted(d, event, nodeSelection);
|
|
611
|
+
break;
|
|
612
|
+
case 'drag':
|
|
613
|
+
this._onDragged(d, event);
|
|
614
|
+
break;
|
|
615
|
+
case 'end':
|
|
616
|
+
this._onDragEnded(d, event, nodeSelection);
|
|
617
|
+
break;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
_onDragStarted(d, event, nodeSelection) {
|
|
622
|
+
var _a;
|
|
623
|
+
const { config } = this;
|
|
624
|
+
this._isDragging = true;
|
|
625
|
+
d._state.isDragged = true;
|
|
626
|
+
nodeSelection.call(updateNodes, config, 0, this._scale);
|
|
627
|
+
(_a = config.onNodeDragStart) === null || _a === void 0 ? void 0 : _a.call(config, d, event);
|
|
628
|
+
}
|
|
629
|
+
_onDragged(d, event) {
|
|
630
|
+
var _a;
|
|
631
|
+
const { config } = this;
|
|
632
|
+
const transform = zoomTransform(this.g.node());
|
|
633
|
+
const scale = transform.k;
|
|
634
|
+
// Update node position
|
|
635
|
+
const [x, y] = pointer(event, this._graphGroup.node());
|
|
636
|
+
this._updateNodePosition(d, x, y);
|
|
547
637
|
// Update affected DOM elements
|
|
548
638
|
const nodeSelection = this._nodesGroup.selectAll(`.${gNode}`);
|
|
549
639
|
const nodeToUpdate = nodeSelection.filter((n) => n._id === d._id);
|
|
@@ -558,7 +648,7 @@ class Graph extends ComponentCore {
|
|
|
558
648
|
const linksToAnimate = linksToUpdate.filter(d => d._state.greyout);
|
|
559
649
|
if (linksToAnimate.size())
|
|
560
650
|
animateLinkFlow(linksToAnimate, config, this._scale);
|
|
561
|
-
(
|
|
651
|
+
(_a = config.onNodeDrag) === null || _a === void 0 ? void 0 : _a.call(config, d, event);
|
|
562
652
|
}
|
|
563
653
|
_onDragEnded(d, event, nodeSelection) {
|
|
564
654
|
var _a;
|
|
@@ -568,6 +658,49 @@ class Graph extends ComponentCore {
|
|
|
568
658
|
nodeSelection.call(updateNodes, config, 0, this._scale);
|
|
569
659
|
(_a = config.onNodeDragEnd) === null || _a === void 0 ? void 0 : _a.call(config, d, event);
|
|
570
660
|
}
|
|
661
|
+
_dragSelectedNodes(event) {
|
|
662
|
+
var _a, _b;
|
|
663
|
+
const { config } = this;
|
|
664
|
+
const curr = pointer(event, this._graphGroup.node());
|
|
665
|
+
const selectedNodes = smartTransition(this._nodesGroup.selectAll(`.${brushed}`));
|
|
666
|
+
if (event.type === 'start') {
|
|
667
|
+
this._groupDragInit = curr;
|
|
668
|
+
this._isDragging = true;
|
|
669
|
+
selectedNodes.each(n => {
|
|
670
|
+
n.x = getX(n);
|
|
671
|
+
n.y = getY(n);
|
|
672
|
+
n._state.isDragged = true;
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
else if (event.type === 'drag') {
|
|
676
|
+
const dx = curr[0] - this._groupDragInit[0];
|
|
677
|
+
const dy = curr[1] - this._groupDragInit[1];
|
|
678
|
+
selectedNodes.each(n => this._updateNodePosition(n, n.x + dx, n.y + dy));
|
|
679
|
+
const connectedLinks = smartTransition(this._linksGroup.selectAll(`.${gLink}`)
|
|
680
|
+
.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); }));
|
|
681
|
+
connectedLinks.call(updateLinks, this.config, 0, this._scale, this._getLinkArrowDefId);
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
this._isDragging = false;
|
|
685
|
+
selectedNodes.each(n => { n._state.isDragged = false; });
|
|
686
|
+
}
|
|
687
|
+
selectedNodes.call(updateNodes, config, 0, this._scale);
|
|
688
|
+
(_b = (_a = this.config).onNodeSelectionDrag) === null || _b === void 0 ? void 0 : _b.call(_a, selectedNodes.data(), event);
|
|
689
|
+
}
|
|
690
|
+
_activateBrush() {
|
|
691
|
+
this._brush.classed('active', true);
|
|
692
|
+
this._nodesGroup.selectAll(`.${gNode}`)
|
|
693
|
+
.classed(brushable, true);
|
|
694
|
+
}
|
|
695
|
+
_clearBrush() {
|
|
696
|
+
var _a;
|
|
697
|
+
this._brush.classed('active', false).call((_a = this._brushBehavior) === null || _a === void 0 ? void 0 : _a.clear);
|
|
698
|
+
this._nodesGroup.selectAll(`.${gNode}`)
|
|
699
|
+
.classed(brushable, false)
|
|
700
|
+
.classed(brushed, false)
|
|
701
|
+
.each(n => { n._state.brushed = false; })
|
|
702
|
+
.call(updateNodesPartial, this.config, 0, this._scale);
|
|
703
|
+
}
|
|
571
704
|
_shouldLayoutRecalculate() {
|
|
572
705
|
const { prevConfig, config } = this;
|
|
573
706
|
if (prevConfig.layoutType !== config.layoutType)
|
|
@@ -637,9 +770,10 @@ class Graph extends ComponentCore {
|
|
|
637
770
|
getZoom() {
|
|
638
771
|
return zoomTransform(this.g.node()).k;
|
|
639
772
|
}
|
|
640
|
-
fitView(duration = this.config.duration) {
|
|
641
|
-
|
|
642
|
-
|
|
773
|
+
fitView(duration = this.config.duration, nodeIds) {
|
|
774
|
+
var _a;
|
|
775
|
+
(_a = this._layoutCalculationPromise) === null || _a === void 0 ? void 0 : _a.then(() => {
|
|
776
|
+
this._fit(duration, nodeIds);
|
|
643
777
|
});
|
|
644
778
|
}
|
|
645
779
|
/** Enable automatic fitting to container if it was disabled due to previous zoom / pan interactions */
|
|
@@ -684,6 +818,7 @@ Graph.selectors = {
|
|
|
684
818
|
dimmedNode: greyedOutNode,
|
|
685
819
|
link: gLink,
|
|
686
820
|
linkLine: link,
|
|
821
|
+
linkLabel: linkLabelGroup,
|
|
687
822
|
dimmedLink: greyedOutLink,
|
|
688
823
|
panel: gPanel,
|
|
689
824
|
panelRect: panel,
|