@xyflow/system 0.0.50 → 0.0.51
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/dist/esm/index.js +286 -90
- package/dist/esm/index.mjs +286 -90
- package/dist/esm/types/changes.d.ts +12 -1
- package/dist/esm/types/changes.d.ts.map +1 -1
- package/dist/esm/types/edges.d.ts +37 -4
- package/dist/esm/types/edges.d.ts.map +1 -1
- package/dist/esm/types/general.d.ts +63 -0
- package/dist/esm/types/general.d.ts.map +1 -1
- package/dist/esm/types/handles.d.ts +8 -4
- package/dist/esm/types/handles.d.ts.map +1 -1
- package/dist/esm/types/nodes.d.ts +28 -8
- package/dist/esm/types/nodes.d.ts.map +1 -1
- package/dist/esm/types/utils.d.ts +22 -0
- package/dist/esm/types/utils.d.ts.map +1 -1
- package/dist/esm/utils/dom.d.ts.map +1 -1
- package/dist/esm/utils/edges/bezier-edge.d.ts +18 -11
- package/dist/esm/utils/edges/bezier-edge.d.ts.map +1 -1
- package/dist/esm/utils/edges/general.d.ts +16 -3
- package/dist/esm/utils/edges/general.d.ts.map +1 -1
- package/dist/esm/utils/edges/smoothstep-edge.d.ts +17 -11
- package/dist/esm/utils/edges/smoothstep-edge.d.ts.map +1 -1
- package/dist/esm/utils/edges/straight-edge.d.ts +15 -11
- package/dist/esm/utils/edges/straight-edge.d.ts.map +1 -1
- package/dist/esm/utils/general.d.ts +2 -2
- package/dist/esm/utils/graph.d.ts +82 -4
- package/dist/esm/utils/graph.d.ts.map +1 -1
- package/dist/esm/utils/node-toolbar.d.ts.map +1 -1
- package/dist/esm/utils/store.d.ts.map +1 -1
- package/dist/esm/xydrag/XYDrag.d.ts.map +1 -1
- package/dist/esm/xydrag/utils.d.ts.map +1 -1
- package/dist/esm/xyhandle/XYHandle.d.ts.map +1 -1
- package/dist/esm/xyhandle/types.d.ts.map +1 -1
- package/dist/esm/xyhandle/utils.d.ts.map +1 -1
- package/dist/esm/xypanzoom/XYPanZoom.d.ts.map +1 -1
- package/dist/esm/xypanzoom/eventhandler.d.ts.map +1 -1
- package/dist/esm/xyresizer/XYResizer.d.ts.map +1 -1
- package/dist/esm/xyresizer/types.d.ts +15 -0
- package/dist/esm/xyresizer/types.d.ts.map +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/types/changes.d.ts +12 -1
- package/dist/umd/types/changes.d.ts.map +1 -1
- package/dist/umd/types/edges.d.ts +37 -4
- package/dist/umd/types/edges.d.ts.map +1 -1
- package/dist/umd/types/general.d.ts +63 -0
- package/dist/umd/types/general.d.ts.map +1 -1
- package/dist/umd/types/handles.d.ts +8 -4
- package/dist/umd/types/handles.d.ts.map +1 -1
- package/dist/umd/types/nodes.d.ts +28 -8
- package/dist/umd/types/nodes.d.ts.map +1 -1
- package/dist/umd/types/utils.d.ts +22 -0
- package/dist/umd/types/utils.d.ts.map +1 -1
- package/dist/umd/utils/dom.d.ts.map +1 -1
- package/dist/umd/utils/edges/bezier-edge.d.ts +18 -11
- package/dist/umd/utils/edges/bezier-edge.d.ts.map +1 -1
- package/dist/umd/utils/edges/general.d.ts +16 -3
- package/dist/umd/utils/edges/general.d.ts.map +1 -1
- package/dist/umd/utils/edges/smoothstep-edge.d.ts +17 -11
- package/dist/umd/utils/edges/smoothstep-edge.d.ts.map +1 -1
- package/dist/umd/utils/edges/straight-edge.d.ts +15 -11
- package/dist/umd/utils/edges/straight-edge.d.ts.map +1 -1
- package/dist/umd/utils/general.d.ts +2 -2
- package/dist/umd/utils/graph.d.ts +82 -4
- package/dist/umd/utils/graph.d.ts.map +1 -1
- package/dist/umd/utils/node-toolbar.d.ts.map +1 -1
- package/dist/umd/utils/store.d.ts.map +1 -1
- package/dist/umd/xydrag/XYDrag.d.ts.map +1 -1
- package/dist/umd/xydrag/utils.d.ts.map +1 -1
- package/dist/umd/xyhandle/XYHandle.d.ts.map +1 -1
- package/dist/umd/xyhandle/types.d.ts.map +1 -1
- package/dist/umd/xyhandle/utils.d.ts.map +1 -1
- package/dist/umd/xypanzoom/XYPanZoom.d.ts.map +1 -1
- package/dist/umd/xypanzoom/eventhandler.d.ts.map +1 -1
- package/dist/umd/xyresizer/XYResizer.d.ts.map +1 -1
- package/dist/umd/xyresizer/types.d.ts +15 -0
- package/dist/umd/xyresizer/types.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/esm/index.js
CHANGED
|
@@ -24,11 +24,26 @@ const infiniteExtent = [
|
|
|
24
24
|
];
|
|
25
25
|
const elementSelectionKeys = ['Enter', ' ', 'Escape'];
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* The `ConnectionMode` is used to set the mode of connection between nodes.
|
|
29
|
+
* The `Strict` mode is the default one and only allows source to target edges.
|
|
30
|
+
* `Loose` mode allows source to source and target to target edges as well.
|
|
31
|
+
*
|
|
32
|
+
* @public
|
|
33
|
+
*/
|
|
27
34
|
var ConnectionMode;
|
|
28
35
|
(function (ConnectionMode) {
|
|
29
36
|
ConnectionMode["Strict"] = "strict";
|
|
30
37
|
ConnectionMode["Loose"] = "loose";
|
|
31
38
|
})(ConnectionMode || (ConnectionMode = {}));
|
|
39
|
+
/**
|
|
40
|
+
* This enum is used to set the different modes of panning the viewport when the
|
|
41
|
+
* user scrolls. The `Free` mode allows the user to pan in any direction by scrolling
|
|
42
|
+
* with a device like a trackpad. The `Vertical` and `Horizontal` modes restrict
|
|
43
|
+
* scroll panning to only the vertical or horizontal axis, respectively.
|
|
44
|
+
*
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
32
47
|
var PanOnScrollMode;
|
|
33
48
|
(function (PanOnScrollMode) {
|
|
34
49
|
PanOnScrollMode["Free"] = "free";
|
|
@@ -53,6 +68,16 @@ const initialConnection = {
|
|
|
53
68
|
toNode: null,
|
|
54
69
|
};
|
|
55
70
|
|
|
71
|
+
/**
|
|
72
|
+
* If you set the `connectionLineType` prop on your [`<ReactFlow />`](/api-reference/react-flow#connection-connectionLineType)
|
|
73
|
+
*component, it will dictate the style of connection line rendered when creating
|
|
74
|
+
*new edges.
|
|
75
|
+
*
|
|
76
|
+
* @public
|
|
77
|
+
*
|
|
78
|
+
* @remarks If you choose to render a custom connection line component, this value will be
|
|
79
|
+
*passed to your component as part of its [`ConnectionLineComponentProps`](/api-reference/types/connection-line-component-props).
|
|
80
|
+
*/
|
|
56
81
|
var ConnectionLineType;
|
|
57
82
|
(function (ConnectionLineType) {
|
|
58
83
|
ConnectionLineType["Bezier"] = "default";
|
|
@@ -61,12 +86,25 @@ var ConnectionLineType;
|
|
|
61
86
|
ConnectionLineType["SmoothStep"] = "smoothstep";
|
|
62
87
|
ConnectionLineType["SimpleBezier"] = "simplebezier";
|
|
63
88
|
})(ConnectionLineType || (ConnectionLineType = {}));
|
|
89
|
+
/**
|
|
90
|
+
* Edges may optionally have a marker on either end. The MarkerType type enumerates
|
|
91
|
+
* the options available to you when configuring a given marker.
|
|
92
|
+
*
|
|
93
|
+
* @public
|
|
94
|
+
*/
|
|
64
95
|
var MarkerType;
|
|
65
96
|
(function (MarkerType) {
|
|
66
97
|
MarkerType["Arrow"] = "arrow";
|
|
67
98
|
MarkerType["ArrowClosed"] = "arrowclosed";
|
|
68
99
|
})(MarkerType || (MarkerType = {}));
|
|
69
100
|
|
|
101
|
+
/**
|
|
102
|
+
* While [`PanelPosition`](/api-reference/types/panel-position) can be used to place a
|
|
103
|
+
* component in the corners of a container, the `Position` enum is less precise and used
|
|
104
|
+
* primarily in relation to edges and handles.
|
|
105
|
+
*
|
|
106
|
+
* @public
|
|
107
|
+
*/
|
|
70
108
|
var Position;
|
|
71
109
|
(function (Position) {
|
|
72
110
|
Position["Left"] = "left";
|
|
@@ -143,12 +181,27 @@ const isEdgeBase = (element) => 'id' in element && 'source' in element && 'targe
|
|
|
143
181
|
const isNodeBase = (element) => 'id' in element && 'position' in element && !('source' in element) && !('target' in element);
|
|
144
182
|
const isInternalNodeBase = (element) => 'id' in element && 'internals' in element && !('source' in element) && !('target' in element);
|
|
145
183
|
/**
|
|
146
|
-
*
|
|
184
|
+
* This util is used to tell you what nodes, if any, are connected to the given node
|
|
185
|
+
* as the _target_ of an edge.
|
|
147
186
|
* @public
|
|
148
187
|
* @param node - The node to get the connected nodes from
|
|
149
188
|
* @param nodes - The array of all nodes
|
|
150
189
|
* @param edges - The array of all edges
|
|
151
190
|
* @returns An array of nodes that are connected over eges where the source is the given node
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```ts
|
|
194
|
+
*import { getOutgoers } from '@xyflow/react';
|
|
195
|
+
*
|
|
196
|
+
*const nodes = [];
|
|
197
|
+
*const edges = [];
|
|
198
|
+
*
|
|
199
|
+
*const outgoers = getOutgoers(
|
|
200
|
+
* { id: '1', position: { x: 0, y: 0 }, data: { label: 'node' } },
|
|
201
|
+
* nodes,
|
|
202
|
+
* edges,
|
|
203
|
+
*);
|
|
204
|
+
*```
|
|
152
205
|
*/
|
|
153
206
|
const getOutgoers = (node, nodes, edges) => {
|
|
154
207
|
if (!node.id) {
|
|
@@ -163,12 +216,27 @@ const getOutgoers = (node, nodes, edges) => {
|
|
|
163
216
|
return nodes.filter((n) => outgoerIds.has(n.id));
|
|
164
217
|
};
|
|
165
218
|
/**
|
|
166
|
-
*
|
|
219
|
+
* This util is used to tell you what nodes, if any, are connected to the given node
|
|
220
|
+
* as the _source_ of an edge.
|
|
167
221
|
* @public
|
|
168
222
|
* @param node - The node to get the connected nodes from
|
|
169
223
|
* @param nodes - The array of all nodes
|
|
170
224
|
* @param edges - The array of all edges
|
|
171
225
|
* @returns An array of nodes that are connected over eges where the target is the given node
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* ```ts
|
|
229
|
+
*import { getIncomers } from '@xyflow/react';
|
|
230
|
+
*
|
|
231
|
+
*const nodes = [];
|
|
232
|
+
*const edges = [];
|
|
233
|
+
*
|
|
234
|
+
*const incomers = getIncomers(
|
|
235
|
+
* { id: '1', position: { x: 0, y: 0 }, data: { label: 'node' } },
|
|
236
|
+
* nodes,
|
|
237
|
+
* edges,
|
|
238
|
+
*);
|
|
239
|
+
*```
|
|
172
240
|
*/
|
|
173
241
|
const getIncomers = (node, nodes, edges) => {
|
|
174
242
|
if (!node.id) {
|
|
@@ -193,12 +261,40 @@ const getNodePositionWithOrigin = (node, nodeOrigin = [0, 0]) => {
|
|
|
193
261
|
};
|
|
194
262
|
};
|
|
195
263
|
/**
|
|
196
|
-
*
|
|
264
|
+
* Returns the bounding box that contains all the given nodes in an array. This can
|
|
265
|
+
* be useful when combined with [`getViewportForBounds`](/api-reference/utils/get-viewport-for-bounds)
|
|
266
|
+
* to calculate the correct transform to fit the given nodes in a viewport.
|
|
197
267
|
* @public
|
|
198
268
|
* @remarks Useful when combined with {@link getViewportForBounds} to calculate the correct transform to fit the given nodes in a viewport.
|
|
199
269
|
* @param nodes - Nodes to calculate the bounds for
|
|
200
270
|
* @param params.nodeOrigin - Origin of the nodes: [0, 0] - top left, [0.5, 0.5] - center
|
|
201
271
|
* @returns Bounding box enclosing all nodes
|
|
272
|
+
*
|
|
273
|
+
* @remarks This function was previously called `getRectOfNodes`
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```js
|
|
277
|
+
*import { getNodesBounds } from '@xyflow/react';
|
|
278
|
+
*
|
|
279
|
+
*const nodes = [
|
|
280
|
+
* {
|
|
281
|
+
* id: 'a',
|
|
282
|
+
* position: { x: 0, y: 0 },
|
|
283
|
+
* data: { label: 'a' },
|
|
284
|
+
* width: 50,
|
|
285
|
+
* height: 25,
|
|
286
|
+
* },
|
|
287
|
+
* {
|
|
288
|
+
* id: 'b',
|
|
289
|
+
* position: { x: 100, y: 100 },
|
|
290
|
+
* data: { label: 'b' },
|
|
291
|
+
* width: 50,
|
|
292
|
+
* height: 25,
|
|
293
|
+
* },
|
|
294
|
+
*];
|
|
295
|
+
*
|
|
296
|
+
*const bounds = getNodesBounds(nodes);
|
|
297
|
+
*```
|
|
202
298
|
*/
|
|
203
299
|
const getNodesBounds = (nodes, params = { nodeOrigin: [0, 0], nodeLookup: undefined }) => {
|
|
204
300
|
if (process.env.NODE_ENV === 'development' && !params.nodeLookup) {
|
|
@@ -267,10 +363,30 @@ excludeNonSelectableNodes = false) => {
|
|
|
267
363
|
return visibleNodes;
|
|
268
364
|
};
|
|
269
365
|
/**
|
|
270
|
-
*
|
|
366
|
+
* This utility filters an array of edges, keeping only those where either the source or target
|
|
367
|
+
* node is present in the given array of nodes.
|
|
368
|
+
* @public
|
|
271
369
|
* @param nodes - Nodes you want to get the connected edges for
|
|
272
370
|
* @param edges - All edges
|
|
273
371
|
* @returns Array of edges that connect any of the given nodes with each other
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* ```js
|
|
375
|
+
*import { getConnectedEdges } from '@xyflow/react';
|
|
376
|
+
*
|
|
377
|
+
*const nodes = [
|
|
378
|
+
* { id: 'a', position: { x: 0, y: 0 } },
|
|
379
|
+
* { id: 'b', position: { x: 100, y: 0 } },
|
|
380
|
+
*];
|
|
381
|
+
*
|
|
382
|
+
*const edges = [
|
|
383
|
+
* { id: 'a->c', source: 'a', target: 'c' },
|
|
384
|
+
* { id: 'c->d', source: 'c', target: 'd' },
|
|
385
|
+
*];
|
|
386
|
+
*
|
|
387
|
+
*const connectedEdges = getConnectedEdges(nodes, edges);
|
|
388
|
+
* // => [{ id: 'a->c', source: 'a', target: 'c' }]
|
|
389
|
+
*```
|
|
274
390
|
*/
|
|
275
391
|
const getConnectedEdges = (nodes, edges) => {
|
|
276
392
|
const nodeIds = new Set();
|
|
@@ -515,8 +631,8 @@ const rendererPointToPoint = ({ x, y }, [tx, ty, tScale]) => {
|
|
|
515
631
|
* @returns A transforned {@link Viewport} that encloses the given bounds which you can pass to e.g. {@link setViewport}
|
|
516
632
|
* @example
|
|
517
633
|
* const { x, y, zoom } = getViewportForBounds(
|
|
518
|
-
|
|
519
|
-
|
|
634
|
+
*{ x: 0, y: 0, width: 100, height: 100},
|
|
635
|
+
*1200, 800, 0.5, 2);
|
|
520
636
|
*/
|
|
521
637
|
const getViewportForBounds = (bounds, width, height, minZoom, maxZoom, padding) => {
|
|
522
638
|
const xZoom = width / (bounds.width * (1 + padding));
|
|
@@ -611,9 +727,11 @@ const getEventPosition = (event, bounds) => {
|
|
|
611
727
|
y: evtY - (bounds?.top ?? 0),
|
|
612
728
|
};
|
|
613
729
|
};
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
730
|
+
/*
|
|
731
|
+
* The handle bounds are calculated relative to the node element.
|
|
732
|
+
* We store them in the internals object of the node in order to avoid
|
|
733
|
+
* unnecessary recalculations.
|
|
734
|
+
*/
|
|
617
735
|
const getHandleBounds = (type, nodeElement, nodeBounds, zoom, nodeId) => {
|
|
618
736
|
const handles = nodeElement.querySelectorAll(`.${type}`);
|
|
619
737
|
if (!handles || !handles.length) {
|
|
@@ -634,8 +752,10 @@ const getHandleBounds = (type, nodeElement, nodeBounds, zoom, nodeId) => {
|
|
|
634
752
|
};
|
|
635
753
|
|
|
636
754
|
function getBezierEdgeCenter({ sourceX, sourceY, targetX, targetY, sourceControlX, sourceControlY, targetControlX, targetControlY, }) {
|
|
637
|
-
|
|
638
|
-
|
|
755
|
+
/*
|
|
756
|
+
* cubic bezier t=0.5 mid point, not the actual mid point, but easy to calculate
|
|
757
|
+
* https://stackoverflow.com/questions/67516101/how-to-find-distance-mid-point-of-bezier-curve
|
|
758
|
+
*/
|
|
639
759
|
const centerX = sourceX * 0.125 + sourceControlX * 0.375 + targetControlX * 0.375 + targetX * 0.125;
|
|
640
760
|
const centerY = sourceY * 0.125 + sourceControlY * 0.375 + targetControlY * 0.375 + targetY * 0.125;
|
|
641
761
|
const offsetX = Math.abs(centerX - sourceX);
|
|
@@ -661,7 +781,9 @@ function getControlWithCurvature({ pos, x1, y1, x2, y2, c }) {
|
|
|
661
781
|
}
|
|
662
782
|
}
|
|
663
783
|
/**
|
|
664
|
-
*
|
|
784
|
+
* The `getBezierPath` util returns everything you need to render a bezier edge
|
|
785
|
+
*between two nodes.
|
|
786
|
+
* @public
|
|
665
787
|
* @param params.sourceX - The x position of the source handle
|
|
666
788
|
* @param params.sourceY - The y position of the source handle
|
|
667
789
|
* @param params.sourcePosition - The position of the source handle (default: Position.Bottom)
|
|
@@ -671,17 +793,22 @@ function getControlWithCurvature({ pos, x1, y1, x2, y2, c }) {
|
|
|
671
793
|
* @param params.curvature - The curvature of the bezier edge
|
|
672
794
|
* @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label
|
|
673
795
|
* @example
|
|
796
|
+
* ```js
|
|
674
797
|
* const source = { x: 0, y: 20 };
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
});
|
|
798
|
+
* const target = { x: 150, y: 100 };
|
|
799
|
+
*
|
|
800
|
+
* const [path, labelX, labelY, offsetX, offsetY] = getBezierPath({
|
|
801
|
+
* sourceX: source.x,
|
|
802
|
+
* sourceY: source.y,
|
|
803
|
+
* sourcePosition: Position.Right,
|
|
804
|
+
* targetX: target.x,
|
|
805
|
+
* targetY: target.y,
|
|
806
|
+
* targetPosition: Position.Left,
|
|
807
|
+
*});
|
|
808
|
+
*```
|
|
809
|
+
*
|
|
810
|
+
* @remarks This function returns a tuple (aka a fixed-size array) to make it easier to
|
|
811
|
+
*work with multiple edge paths at once.
|
|
685
812
|
*/
|
|
686
813
|
function getBezierPath({ sourceX, sourceY, sourcePosition = Position.Bottom, targetX, targetY, targetPosition = Position.Top, curvature = 0.25, }) {
|
|
687
814
|
const [sourceControlX, sourceControlY] = getControlWithCurvature({
|
|
@@ -759,12 +886,16 @@ const connectionExists = (edge, edges) => {
|
|
|
759
886
|
(el.targetHandle === edge.targetHandle || (!el.targetHandle && !edge.targetHandle)));
|
|
760
887
|
};
|
|
761
888
|
/**
|
|
762
|
-
* This util is a convenience function to add a new Edge to an array of edges
|
|
763
|
-
* @remarks It also performs some validation to make sure you don't add an invalid edge or duplicate an existing one.
|
|
889
|
+
* This util is a convenience function to add a new Edge to an array of edges. It also performs some validation to make sure you don't add an invalid edge or duplicate an existing one.
|
|
764
890
|
* @public
|
|
765
891
|
* @param edgeParams - Either an Edge or a Connection you want to add
|
|
766
892
|
* @param edges - The array of all current edges
|
|
767
893
|
* @returns A new array of edges with the new edge added
|
|
894
|
+
*
|
|
895
|
+
* @remarks If an edge with the same `target` and `source` already exists (and the same
|
|
896
|
+
*`targetHandle` and `sourceHandle` if those are set), then this util won't add
|
|
897
|
+
*a new edge even if the `id` property is different.
|
|
898
|
+
*
|
|
768
899
|
*/
|
|
769
900
|
const addEdge = (edgeParams, edges) => {
|
|
770
901
|
if (!edgeParams.source || !edgeParams.target) {
|
|
@@ -793,12 +924,21 @@ const addEdge = (edgeParams, edges) => {
|
|
|
793
924
|
return edges.concat(edge);
|
|
794
925
|
};
|
|
795
926
|
/**
|
|
796
|
-
* A handy utility to
|
|
927
|
+
* A handy utility to update an existing [`Edge`](/api-reference/types/edge) with new properties.
|
|
928
|
+
*This searches your edge array for an edge with a matching `id` and updates its
|
|
929
|
+
*properties with the connection you provide.
|
|
930
|
+
* @public
|
|
797
931
|
* @param oldEdge - The edge you want to update
|
|
798
932
|
* @param newConnection - The new connection you want to update the edge with
|
|
799
933
|
* @param edges - The array of all current edges
|
|
800
934
|
* @param options.shouldReplaceId - should the id of the old edge be replaced with the new connection id
|
|
801
935
|
* @returns the updated edges array
|
|
936
|
+
*
|
|
937
|
+
* @example
|
|
938
|
+
* ```js
|
|
939
|
+
*const onReconnect = useCallback(
|
|
940
|
+
* (oldEdge: Edge, newConnection: Connection) => setEdges((els) => reconnectEdge(oldEdge, newConnection, els)),[]);
|
|
941
|
+
*```
|
|
802
942
|
*/
|
|
803
943
|
const reconnectEdge = (oldEdge, newConnection, edges, options = { shouldReplaceId: true }) => {
|
|
804
944
|
const { id: oldEdgeId, ...rest } = oldEdge;
|
|
@@ -824,24 +964,28 @@ const reconnectEdge = (oldEdge, newConnection, edges, options = { shouldReplaceI
|
|
|
824
964
|
};
|
|
825
965
|
|
|
826
966
|
/**
|
|
827
|
-
*
|
|
967
|
+
* Calculates the straight line path between two points.
|
|
968
|
+
* @public
|
|
828
969
|
* @param params.sourceX - The x position of the source handle
|
|
829
970
|
* @param params.sourceY - The y position of the source handle
|
|
830
971
|
* @param params.targetX - The x position of the target handle
|
|
831
972
|
* @param params.targetY - The y position of the target handle
|
|
832
973
|
* @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label
|
|
833
974
|
* @example
|
|
975
|
+
* ```js
|
|
834
976
|
* const source = { x: 0, y: 20 };
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
977
|
+
* const target = { x: 150, y: 100 };
|
|
978
|
+
*
|
|
979
|
+
* const [path, labelX, labelY, offsetX, offsetY] = getStraightPath({
|
|
980
|
+
* sourceX: source.x,
|
|
981
|
+
* sourceY: source.y,
|
|
982
|
+
* sourcePosition: Position.Right,
|
|
983
|
+
* targetX: target.x,
|
|
984
|
+
* targetY: target.y,
|
|
985
|
+
* targetPosition: Position.Left,
|
|
986
|
+
* });
|
|
987
|
+
* ```
|
|
988
|
+
* @remarks This function returns a tuple (aka a fixed-size array) to make it easier to work with multiple edge paths at once.
|
|
845
989
|
*/
|
|
846
990
|
function getStraightPath({ sourceX, sourceY, targetX, targetY, }) {
|
|
847
991
|
const [labelX, labelY, offsetX, offsetY] = getEdgeCenter({
|
|
@@ -866,8 +1010,10 @@ const getDirection = ({ source, sourcePosition = Position.Bottom, target, }) =>
|
|
|
866
1010
|
return source.y < target.y ? { x: 0, y: 1 } : { x: 0, y: -1 };
|
|
867
1011
|
};
|
|
868
1012
|
const distance = (a, b) => Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));
|
|
869
|
-
|
|
870
|
-
|
|
1013
|
+
/*
|
|
1014
|
+
* ith this function we try to mimic a orthogonal edge routing behaviour
|
|
1015
|
+
* It's not as good as a real orthogonal edge routing but it's faster and good enough as a default for step and smooth step edges
|
|
1016
|
+
*/
|
|
871
1017
|
function getPoints({ source, sourcePosition = Position.Bottom, target, targetPosition = Position.Top, center, offset, }) {
|
|
872
1018
|
const sourceDir = handleDirections[sourcePosition];
|
|
873
1019
|
const targetDir = handleDirections[targetPosition];
|
|
@@ -894,16 +1040,20 @@ function getPoints({ source, sourcePosition = Position.Bottom, target, targetPos
|
|
|
894
1040
|
if (sourceDir[dirAccessor] * targetDir[dirAccessor] === -1) {
|
|
895
1041
|
centerX = center.x ?? defaultCenterX;
|
|
896
1042
|
centerY = center.y ?? defaultCenterY;
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
1043
|
+
/*
|
|
1044
|
+
* --->
|
|
1045
|
+
* |
|
|
1046
|
+
* >---
|
|
1047
|
+
*/
|
|
900
1048
|
const verticalSplit = [
|
|
901
1049
|
{ x: centerX, y: sourceGapped.y },
|
|
902
1050
|
{ x: centerX, y: targetGapped.y },
|
|
903
1051
|
];
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
1052
|
+
/*
|
|
1053
|
+
* |
|
|
1054
|
+
* ---
|
|
1055
|
+
* |
|
|
1056
|
+
*/
|
|
907
1057
|
const horizontalSplit = [
|
|
908
1058
|
{ x: sourceGapped.x, y: centerY },
|
|
909
1059
|
{ x: targetGapped.x, y: centerY },
|
|
@@ -992,7 +1142,10 @@ function getBend(a, b, c, size) {
|
|
|
992
1142
|
return `L ${x},${y + bendSize * yDir}Q ${x},${y} ${x + bendSize * xDir},${y}`;
|
|
993
1143
|
}
|
|
994
1144
|
/**
|
|
995
|
-
*
|
|
1145
|
+
* The `getSmoothStepPath` util returns everything you need to render a stepped path
|
|
1146
|
+
*between two nodes. The `borderRadius` property can be used to choose how rounded
|
|
1147
|
+
*the corners of those steps are.
|
|
1148
|
+
* @public
|
|
996
1149
|
* @param params.sourceX - The x position of the source handle
|
|
997
1150
|
* @param params.sourceY - The y position of the source handle
|
|
998
1151
|
* @param params.sourcePosition - The position of the source handle (default: Position.Bottom)
|
|
@@ -1001,17 +1154,20 @@ function getBend(a, b, c, size) {
|
|
|
1001
1154
|
* @param params.targetPosition - The position of the target handle (default: Position.Top)
|
|
1002
1155
|
* @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label
|
|
1003
1156
|
* @example
|
|
1157
|
+
* ```js
|
|
1004
1158
|
* const source = { x: 0, y: 20 };
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1159
|
+
* const target = { x: 150, y: 100 };
|
|
1160
|
+
*
|
|
1161
|
+
* const [path, labelX, labelY, offsetX, offsetY] = getSmoothStepPath({
|
|
1162
|
+
* sourceX: source.x,
|
|
1163
|
+
* sourceY: source.y,
|
|
1164
|
+
* sourcePosition: Position.Right,
|
|
1165
|
+
* targetX: target.x,
|
|
1166
|
+
* targetY: target.y,
|
|
1167
|
+
* targetPosition: Position.Left,
|
|
1168
|
+
* });
|
|
1169
|
+
* ```
|
|
1170
|
+
* @remarks This function returns a tuple (aka a fixed-size array) to make it easier to work with multiple edge paths at once.
|
|
1015
1171
|
*/
|
|
1016
1172
|
function getSmoothStepPath({ sourceX, sourceY, sourcePosition = Position.Bottom, targetX, targetY, targetPosition = Position.Top, borderRadius = 5, centerX, centerY, offset = 20, }) {
|
|
1017
1173
|
const [points, labelX, labelY, offsetX, offsetY] = getPoints({
|
|
@@ -1162,8 +1318,10 @@ function getNodeToolbarTransform(nodeRect, viewport, position, offset, align) {
|
|
|
1162
1318
|
else if (align === 'end') {
|
|
1163
1319
|
alignmentOffset = 1;
|
|
1164
1320
|
}
|
|
1165
|
-
|
|
1166
|
-
|
|
1321
|
+
/*
|
|
1322
|
+
* position === Position.Top
|
|
1323
|
+
* we set the x any y position of the toolbar based on the nodes position
|
|
1324
|
+
*/
|
|
1167
1325
|
let pos = [
|
|
1168
1326
|
(nodeRect.x + nodeRect.width * alignmentOffset) * viewport.zoom + viewport.x,
|
|
1169
1327
|
nodeRect.y * viewport.zoom + viewport.y - offset,
|
|
@@ -1362,8 +1520,10 @@ function handleExpandParent(children, nodeLookup, parentLookup, nodeOrigin = [0,
|
|
|
1362
1520
|
y: parent.position.y - yChange + heightChange,
|
|
1363
1521
|
},
|
|
1364
1522
|
});
|
|
1365
|
-
|
|
1366
|
-
|
|
1523
|
+
/*
|
|
1524
|
+
* We move all child nodes in the oppsite direction
|
|
1525
|
+
* so the x,y changes of the parent do not move the children
|
|
1526
|
+
*/
|
|
1367
1527
|
parentLookup.get(parentId)?.forEach((childNode) => {
|
|
1368
1528
|
if (!children.some((child) => child.id === childNode.id)) {
|
|
1369
1529
|
changes.push({
|
|
@@ -1501,9 +1661,11 @@ async function panBy({ delta, panZoom, transform, translateExtent, width, height
|
|
|
1501
1661
|
* @param handleId handleId of the conneciton
|
|
1502
1662
|
*/
|
|
1503
1663
|
function addConnectionToLookup(type, connection, connectionKey, connectionLookup, nodeId, handleId) {
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1664
|
+
/*
|
|
1665
|
+
* We add the connection to the connectionLookup at the following keys
|
|
1666
|
+
* 1. nodeId, 2. nodeId-type, 3. nodeId-type-handleId
|
|
1667
|
+
* If the key already exists, we add the connection to the existing map
|
|
1668
|
+
*/
|
|
1507
1669
|
let key = nodeId;
|
|
1508
1670
|
const nodeMap = connectionLookup.get(key) || new Map();
|
|
1509
1671
|
connectionLookup.set(key, nodeMap.set(connectionKey, connection));
|
|
@@ -1604,9 +1766,11 @@ function getDragItems(nodeLookup, nodesDraggable, mousePos, nodeId) {
|
|
|
1604
1766
|
}
|
|
1605
1767
|
return dragItems;
|
|
1606
1768
|
}
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1769
|
+
/*
|
|
1770
|
+
* returns two params:
|
|
1771
|
+
* 1. the dragged node (or the first of the list, if we are dragging a node selection)
|
|
1772
|
+
* 2. array of selected nodes (for multi selections)
|
|
1773
|
+
*/
|
|
1610
1774
|
function getEventHandlerParams({ nodeId, dragItems, nodeLookup, dragging = true, }) {
|
|
1611
1775
|
const nodesFromDragItems = [];
|
|
1612
1776
|
for (const [id, dragItem] of dragItems) {
|
|
@@ -1660,16 +1824,20 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
|
|
|
1660
1824
|
}
|
|
1661
1825
|
for (const [id, dragItem] of dragItems) {
|
|
1662
1826
|
if (!nodeLookup.has(id)) {
|
|
1663
|
-
|
|
1664
|
-
|
|
1827
|
+
/*
|
|
1828
|
+
* if the node is not in the nodeLookup anymore, it was probably deleted while dragging
|
|
1829
|
+
* and we don't need to update it anymore
|
|
1830
|
+
*/
|
|
1665
1831
|
continue;
|
|
1666
1832
|
}
|
|
1667
1833
|
let nextPosition = { x: x - dragItem.distance.x, y: y - dragItem.distance.y };
|
|
1668
1834
|
if (snapToGrid) {
|
|
1669
1835
|
nextPosition = snapPosition(nextPosition, snapGrid);
|
|
1670
1836
|
}
|
|
1671
|
-
|
|
1672
|
-
|
|
1837
|
+
/*
|
|
1838
|
+
* if there is selection with multiple nodes and a node extent is set, we need to adjust the node extent for each node
|
|
1839
|
+
* based on its position so that the node stays at it's position relative to the selection.
|
|
1840
|
+
*/
|
|
1673
1841
|
let adjustedNodeExtent = [
|
|
1674
1842
|
[nodeExtent[0][0], nodeExtent[0][1]],
|
|
1675
1843
|
[nodeExtent[1][0], nodeExtent[1][1]],
|
|
@@ -1719,7 +1887,12 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
|
|
|
1719
1887
|
if (!containerBounds) {
|
|
1720
1888
|
return;
|
|
1721
1889
|
}
|
|
1722
|
-
const { transform, panBy, autoPanSpeed } = getStoreItems();
|
|
1890
|
+
const { transform, panBy, autoPanSpeed, autoPanOnNodeDrag } = getStoreItems();
|
|
1891
|
+
if (!autoPanOnNodeDrag) {
|
|
1892
|
+
autoPanStarted = false;
|
|
1893
|
+
cancelAnimationFrame(autoPanId);
|
|
1894
|
+
return;
|
|
1895
|
+
}
|
|
1723
1896
|
const [xMovement, yMovement] = calcAutoPan(mousePosition, containerBounds, autoPanSpeed);
|
|
1724
1897
|
if (xMovement !== 0 || yMovement !== 0) {
|
|
1725
1898
|
lastPos.x = (lastPos.x ?? 0) - xMovement / transform[2];
|
|
@@ -1859,8 +2032,10 @@ function getNodesWithinDistance(position, nodeLookup, distance) {
|
|
|
1859
2032
|
}
|
|
1860
2033
|
return nodes;
|
|
1861
2034
|
}
|
|
1862
|
-
|
|
1863
|
-
|
|
2035
|
+
/*
|
|
2036
|
+
* this distance is used for the area around the user pointer
|
|
2037
|
+
* while doing a connection for finding the closest nodes
|
|
2038
|
+
*/
|
|
1864
2039
|
const ADDITIONAL_DISTANCE = 250;
|
|
1865
2040
|
function getClosestHandle(position, connectionRadius, nodeLookup, fromHandle) {
|
|
1866
2041
|
let closestHandles = [];
|
|
@@ -2028,8 +2203,10 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
|
|
|
2028
2203
|
toPosition: isValid && result.toHandle ? result.toHandle.position : oppositePosition[fromHandle.position],
|
|
2029
2204
|
toNode: result.toHandle ? nodeLookup.get(result.toHandle.nodeId) : null,
|
|
2030
2205
|
};
|
|
2031
|
-
|
|
2032
|
-
|
|
2206
|
+
/*
|
|
2207
|
+
* we don't want to trigger an update when the connection
|
|
2208
|
+
* is snapped to the same handle as before
|
|
2209
|
+
*/
|
|
2033
2210
|
if (isValid &&
|
|
2034
2211
|
closestHandle &&
|
|
2035
2212
|
previousConnection.toHandle &&
|
|
@@ -2048,8 +2225,10 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
|
|
|
2048
2225
|
if ((closestHandle || handleDomNode) && connection && isValid) {
|
|
2049
2226
|
onConnect?.(connection);
|
|
2050
2227
|
}
|
|
2051
|
-
|
|
2052
|
-
|
|
2228
|
+
/*
|
|
2229
|
+
* it's important to get a fresh reference from the store here
|
|
2230
|
+
* in order to get the latest state of onConnectEnd
|
|
2231
|
+
*/
|
|
2053
2232
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2054
2233
|
const { inProgress, ...connectionState } = previousConnection;
|
|
2055
2234
|
const finalConnectionState = {
|
|
@@ -2084,8 +2263,10 @@ function isValidHandle(event, { handle, connectionMode, fromNodeId, fromHandleId
|
|
|
2084
2263
|
: null;
|
|
2085
2264
|
const { x, y } = getEventPosition(event);
|
|
2086
2265
|
const handleBelow = doc.elementFromPoint(x, y);
|
|
2087
|
-
|
|
2088
|
-
|
|
2266
|
+
/*
|
|
2267
|
+
* we always want to prioritize the handle below the mouse cursor over the closest distance handle,
|
|
2268
|
+
* because it could be that the center of another handle is closer to the mouse pointer than the handle below the cursor
|
|
2269
|
+
*/
|
|
2089
2270
|
const handleToCheck = handleBelow?.classList.contains(`${lib}-flow__handle`) ? handleBelow : handleDomNode;
|
|
2090
2271
|
const result = {
|
|
2091
2272
|
handleDomNode: handleToCheck,
|
|
@@ -2236,8 +2417,10 @@ function createPanOnScrollHandler({ zoomPanValues, noWheelClassName, d3Selection
|
|
|
2236
2417
|
d3Zoom.scaleTo(d3Selection, zoom, point, event);
|
|
2237
2418
|
return;
|
|
2238
2419
|
}
|
|
2239
|
-
|
|
2240
|
-
|
|
2420
|
+
/*
|
|
2421
|
+
* increase scroll speed in firefox
|
|
2422
|
+
* firefox: deltaMode === 1; chrome: deltaMode === 0
|
|
2423
|
+
*/
|
|
2241
2424
|
const deltaNormalize = event.deltaMode === 1 ? 20 : 1;
|
|
2242
2425
|
let deltaX = panOnScrollMode === PanOnScrollMode.Vertical ? 0 : event.deltaX * deltaNormalize;
|
|
2243
2426
|
let deltaY = panOnScrollMode === PanOnScrollMode.Horizontal ? 0 : event.deltaY * deltaNormalize;
|
|
@@ -2251,9 +2434,11 @@ function createPanOnScrollHandler({ zoomPanValues, noWheelClassName, d3Selection
|
|
|
2251
2434
|
{ internal: true });
|
|
2252
2435
|
const nextViewport = transformToViewport(d3Selection.property('__zoom'));
|
|
2253
2436
|
clearTimeout(zoomPanValues.panScrollTimeout);
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2437
|
+
/*
|
|
2438
|
+
* for pan on scroll we need to handle the event calls on our own
|
|
2439
|
+
* we can't use the start, zoom and end events from d3-zoom
|
|
2440
|
+
* because start and move gets called on every scroll event and not once at the beginning
|
|
2441
|
+
*/
|
|
2257
2442
|
if (!zoomPanValues.isPanScrolling) {
|
|
2258
2443
|
zoomPanValues.isPanScrolling = true;
|
|
2259
2444
|
onPanZoomStart?.(event, nextViewport);
|
|
@@ -2488,9 +2673,11 @@ function XYPanZoom({ domNode, minZoom, maxZoom, paneClickDistance, translateExte
|
|
|
2488
2673
|
lib,
|
|
2489
2674
|
});
|
|
2490
2675
|
d3ZoomInstance.filter(filter);
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2676
|
+
/*
|
|
2677
|
+
* We cannot add zoomOnDoubleClick to the filter above because
|
|
2678
|
+
* double tapping on touch screens circumvents the filter and
|
|
2679
|
+
* dblclick.zoom is fired on the selection directly
|
|
2680
|
+
*/
|
|
2494
2681
|
if (zoomOnDoubleClick) {
|
|
2495
2682
|
d3Selection.on('dblclick.zoom', d3DblClickZoomHandler);
|
|
2496
2683
|
}
|
|
@@ -2572,6 +2759,11 @@ function XYPanZoom({ domNode, minZoom, maxZoom, paneClickDistance, translateExte
|
|
|
2572
2759
|
};
|
|
2573
2760
|
}
|
|
2574
2761
|
|
|
2762
|
+
/**
|
|
2763
|
+
* Used to determine the variant of the resize control
|
|
2764
|
+
*
|
|
2765
|
+
* @public
|
|
2766
|
+
*/
|
|
2575
2767
|
var ResizeControlVariant;
|
|
2576
2768
|
(function (ResizeControlVariant) {
|
|
2577
2769
|
ResizeControlVariant["Line"] = "line";
|
|
@@ -2867,8 +3059,10 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
|
|
|
2867
3059
|
parentNode = nodeLookup.get(node.parentId);
|
|
2868
3060
|
parentExtent = parentNode && node.extent === 'parent' ? nodeToParentExtent(parentNode) : undefined;
|
|
2869
3061
|
}
|
|
2870
|
-
|
|
2871
|
-
|
|
3062
|
+
/*
|
|
3063
|
+
* Collect all child nodes to correct their relative positions when top/left changes
|
|
3064
|
+
* Determine largest minimal extent the parent node is allowed to resize to
|
|
3065
|
+
*/
|
|
2872
3066
|
childNodes = [];
|
|
2873
3067
|
childExtent = undefined;
|
|
2874
3068
|
for (const [childId, child] of nodeLookup) {
|
|
@@ -2922,8 +3116,10 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
|
|
|
2922
3116
|
change.y = isYPosChange ? y : prevValues.y;
|
|
2923
3117
|
prevValues.x = change.x;
|
|
2924
3118
|
prevValues.y = change.y;
|
|
2925
|
-
|
|
2926
|
-
|
|
3119
|
+
/*
|
|
3120
|
+
* when top/left changes, correct the relative positions of child nodes
|
|
3121
|
+
* so that they stay in the same position
|
|
3122
|
+
*/
|
|
2927
3123
|
if (childNodes.length > 0) {
|
|
2928
3124
|
const xChange = x - prevX;
|
|
2929
3125
|
const yChange = y - prevY;
|