@xyflow/system 0.0.21 → 0.0.23
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/constants.d.ts +0 -1
- package/dist/esm/constants.d.ts.map +1 -1
- package/dist/esm/index.js +307 -191
- package/dist/esm/index.mjs +307 -191
- package/dist/esm/types/general.d.ts +3 -3
- package/dist/esm/types/general.d.ts.map +1 -1
- package/dist/esm/types/index.d.ts +1 -0
- package/dist/esm/types/index.d.ts.map +1 -1
- package/dist/esm/types/nodes.d.ts +22 -16
- package/dist/esm/types/nodes.d.ts.map +1 -1
- package/dist/esm/utils/edges/general.d.ts +5 -6
- package/dist/esm/utils/edges/general.d.ts.map +1 -1
- package/dist/esm/utils/edges/positions.d.ts +3 -3
- package/dist/esm/utils/edges/positions.d.ts.map +1 -1
- package/dist/esm/utils/general.d.ts +3 -3
- package/dist/esm/utils/general.d.ts.map +1 -1
- package/dist/esm/utils/graph.d.ts +16 -5
- package/dist/esm/utils/graph.d.ts.map +1 -1
- package/dist/esm/utils/store.d.ts +9 -5
- package/dist/esm/utils/store.d.ts.map +1 -1
- package/dist/esm/xydrag/XYDrag.d.ts +2 -2
- package/dist/esm/xydrag/XYDrag.d.ts.map +1 -1
- package/dist/esm/xydrag/utils.d.ts +3 -3
- package/dist/esm/xydrag/utils.d.ts.map +1 -1
- package/dist/esm/xyhandle/XYHandle.d.ts +2 -2
- package/dist/esm/xyhandle/XYHandle.d.ts.map +1 -1
- package/dist/esm/xyhandle/utils.d.ts +4 -4
- 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/xypanzoom/filter.d.ts.map +1 -1
- package/dist/umd/constants.d.ts +0 -1
- package/dist/umd/constants.d.ts.map +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/types/changes.d.ts +50 -0
- package/dist/umd/types/changes.d.ts.map +1 -0
- package/dist/umd/types/general.d.ts +3 -3
- package/dist/umd/types/general.d.ts.map +1 -1
- package/dist/umd/types/index.d.ts +1 -0
- package/dist/umd/types/index.d.ts.map +1 -1
- package/dist/umd/types/nodes.d.ts +22 -16
- package/dist/umd/types/nodes.d.ts.map +1 -1
- package/dist/umd/utils/edges/general.d.ts +5 -6
- package/dist/umd/utils/edges/general.d.ts.map +1 -1
- package/dist/umd/utils/edges/positions.d.ts +3 -3
- package/dist/umd/utils/edges/positions.d.ts.map +1 -1
- package/dist/umd/utils/general.d.ts +3 -3
- package/dist/umd/utils/general.d.ts.map +1 -1
- package/dist/umd/utils/graph.d.ts +16 -5
- package/dist/umd/utils/graph.d.ts.map +1 -1
- package/dist/umd/utils/store.d.ts +9 -5
- package/dist/umd/utils/store.d.ts.map +1 -1
- package/dist/umd/xydrag/XYDrag.d.ts +2 -2
- package/dist/umd/xydrag/XYDrag.d.ts.map +1 -1
- package/dist/umd/xydrag/utils.d.ts +3 -3
- package/dist/umd/xydrag/utils.d.ts.map +1 -1
- package/dist/umd/xyhandle/XYHandle.d.ts +2 -2
- package/dist/umd/xyhandle/XYHandle.d.ts.map +1 -1
- package/dist/umd/xyhandle/utils.d.ts +4 -4
- 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/xypanzoom/filter.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/esm/index.mjs
CHANGED
|
@@ -17,7 +17,6 @@ const errorMessages = {
|
|
|
17
17
|
error011: (edgeType) => `Edge type "${edgeType}" not found. Using fallback type "default".`,
|
|
18
18
|
error012: (id) => `Node with id "${id}" does not exist, it may have been removed. This can happen when a node is deleted before the "onNodeClick" handler is called.`,
|
|
19
19
|
};
|
|
20
|
-
const internalsSymbol = Symbol.for('internals');
|
|
21
20
|
const infiniteExtent = [
|
|
22
21
|
[Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
|
|
23
22
|
[Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
|
|
@@ -120,6 +119,7 @@ const isEdgeBase = (element) => 'id' in element && 'source' in element && 'targe
|
|
|
120
119
|
* @returns A boolean indicating whether the element is an Node
|
|
121
120
|
*/
|
|
122
121
|
const isNodeBase = (element) => 'id' in element && 'position' in element && !('source' in element) && !('target' in element);
|
|
122
|
+
const isInternalNodeBase = (element) => 'id' in element && 'internals' in element && !('source' in element) && !('target' in element);
|
|
123
123
|
/**
|
|
124
124
|
* Pass in a node, and get connected nodes where edge.source === node.id
|
|
125
125
|
* @public
|
|
@@ -182,10 +182,10 @@ const getNodePositionWithOrigin = (node, nodeOrigin = [0, 0]) => {
|
|
|
182
182
|
};
|
|
183
183
|
return {
|
|
184
184
|
position,
|
|
185
|
-
positionAbsolute: node
|
|
185
|
+
positionAbsolute: 'internals' in node
|
|
186
186
|
? {
|
|
187
|
-
x: node.
|
|
188
|
-
y: node.
|
|
187
|
+
x: node.internals.positionAbsolute.x - offsetX,
|
|
188
|
+
y: node.internals.positionAbsolute.y - offsetY,
|
|
189
189
|
}
|
|
190
190
|
: position,
|
|
191
191
|
};
|
|
@@ -199,6 +199,7 @@ const getNodePositionWithOrigin = (node, nodeOrigin = [0, 0]) => {
|
|
|
199
199
|
* @param params.useRelativePosition - Whether to use the relative or absolute node positions
|
|
200
200
|
* @returns Bounding box enclosing all nodes
|
|
201
201
|
*/
|
|
202
|
+
// @todo how to handle this if users do not have absolute positions?
|
|
202
203
|
const getNodesBounds = (nodes, params = { nodeOrigin: [0, 0], useRelativePosition: false }) => {
|
|
203
204
|
if (nodes.length === 0) {
|
|
204
205
|
return { x: 0, y: 0, width: 0, height: 0 };
|
|
@@ -212,7 +213,30 @@ const getNodesBounds = (nodes, params = { nodeOrigin: [0, 0], useRelativePositio
|
|
|
212
213
|
}, { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity });
|
|
213
214
|
return boxToRect(box);
|
|
214
215
|
};
|
|
215
|
-
|
|
216
|
+
/**
|
|
217
|
+
* Determines a bounding box that contains all given nodes in an array
|
|
218
|
+
* @internal
|
|
219
|
+
*/
|
|
220
|
+
const getInternalNodesBounds = (nodeLookup, params = {
|
|
221
|
+
nodeOrigin: [0, 0],
|
|
222
|
+
useRelativePosition: false,
|
|
223
|
+
}) => {
|
|
224
|
+
if (nodeLookup.size === 0) {
|
|
225
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
226
|
+
}
|
|
227
|
+
let box = { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity };
|
|
228
|
+
nodeLookup.forEach((node) => {
|
|
229
|
+
if (params.filter == undefined || params.filter(node)) {
|
|
230
|
+
const nodePos = getNodePositionWithOrigin(node, node.origin || params.nodeOrigin);
|
|
231
|
+
box = getBoundsOfBoxes(box, rectToBox({
|
|
232
|
+
...nodePos[params.useRelativePosition ? 'position' : 'positionAbsolute'],
|
|
233
|
+
...getNodeDimensions(node),
|
|
234
|
+
}));
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
return boxToRect(box);
|
|
238
|
+
};
|
|
239
|
+
const getNodesInside = (nodeLookup, rect, [tx, ty, tScale] = [0, 0, 1], partially = false,
|
|
216
240
|
// set excludeNonSelectableNodes if you want to pay attention to the nodes "selectable" attribute
|
|
217
241
|
excludeNonSelectableNodes = false, nodeOrigin = [0, 0]) => {
|
|
218
242
|
const paneRect = {
|
|
@@ -220,12 +244,13 @@ excludeNonSelectableNodes = false, nodeOrigin = [0, 0]) => {
|
|
|
220
244
|
width: rect.width / tScale,
|
|
221
245
|
height: rect.height / tScale,
|
|
222
246
|
};
|
|
223
|
-
const visibleNodes =
|
|
224
|
-
|
|
225
|
-
const
|
|
226
|
-
const
|
|
247
|
+
const visibleNodes = [];
|
|
248
|
+
for (const [, node] of nodeLookup) {
|
|
249
|
+
const { measured, selectable = true, hidden = false } = node;
|
|
250
|
+
const width = measured.width ?? node.width ?? node.initialWidth ?? null;
|
|
251
|
+
const height = measured.height ?? node.height ?? node.initialHeight ?? null;
|
|
227
252
|
if ((excludeNonSelectableNodes && !selectable) || hidden) {
|
|
228
|
-
|
|
253
|
+
continue;
|
|
229
254
|
}
|
|
230
255
|
const overlappingArea = getOverlappingArea(paneRect, nodeToRect(node, nodeOrigin));
|
|
231
256
|
const notInitialized = width === null || height === null;
|
|
@@ -233,10 +258,9 @@ excludeNonSelectableNodes = false, nodeOrigin = [0, 0]) => {
|
|
|
233
258
|
const area = (width ?? 0) * (height ?? 0);
|
|
234
259
|
const isVisible = notInitialized || partiallyVisible || overlappingArea >= area;
|
|
235
260
|
if (isVisible || node.dragging) {
|
|
236
|
-
|
|
261
|
+
visibleNodes.push(node);
|
|
237
262
|
}
|
|
238
|
-
|
|
239
|
-
}, []);
|
|
263
|
+
}
|
|
240
264
|
return visibleNodes;
|
|
241
265
|
};
|
|
242
266
|
/**
|
|
@@ -252,13 +276,15 @@ const getConnectedEdges = (nodes, edges) => {
|
|
|
252
276
|
});
|
|
253
277
|
return edges.filter((edge) => nodeIds.has(edge.source) || nodeIds.has(edge.target));
|
|
254
278
|
};
|
|
255
|
-
function fitView({
|
|
256
|
-
const filteredNodes =
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
279
|
+
function fitView({ nodeLookup, width, height, panZoom, minZoom, maxZoom, nodeOrigin = [0, 0] }, options) {
|
|
280
|
+
const filteredNodes = [];
|
|
281
|
+
nodeLookup.forEach((n) => {
|
|
282
|
+
const isVisible = n.measured.width && n.measured.height && (options?.includeHiddenNodes || !n.hidden);
|
|
283
|
+
// TODO: this remove options.nodes.some with a Set
|
|
284
|
+
if (isVisible &&
|
|
285
|
+
(!options?.nodes || (options?.nodes.length && options?.nodes.some((optionNode) => optionNode.id === n.id)))) {
|
|
286
|
+
filteredNodes.push(n);
|
|
260
287
|
}
|
|
261
|
-
return isVisible;
|
|
262
288
|
});
|
|
263
289
|
if (filteredNodes.length > 0) {
|
|
264
290
|
const bounds = getNodesBounds(filteredNodes, { nodeOrigin });
|
|
@@ -280,7 +306,7 @@ function clampNodeExtent(node, extent) {
|
|
|
280
306
|
if (!extent || extent === 'parent') {
|
|
281
307
|
return extent;
|
|
282
308
|
}
|
|
283
|
-
return [extent[0], [extent[1][0] - (node.
|
|
309
|
+
return [extent[0], [extent[1][0] - (node.measured?.width ?? 0), extent[1][1] - (node.measured?.height ?? 0)]];
|
|
284
310
|
}
|
|
285
311
|
/**
|
|
286
312
|
* This function calculates the next position of a node, taking into account the node's extent, parent node, and origin.
|
|
@@ -290,7 +316,7 @@ function clampNodeExtent(node, extent) {
|
|
|
290
316
|
*/
|
|
291
317
|
function calculateNodePosition({ nodeId, nextPosition, nodeLookup, nodeOrigin = [0, 0], nodeExtent, onError, }) {
|
|
292
318
|
const node = nodeLookup.get(nodeId);
|
|
293
|
-
const parentNode = node.
|
|
319
|
+
const parentNode = node.parentId ? nodeLookup.get(node.parentId) : undefined;
|
|
294
320
|
const { x: parentX, y: parentY } = parentNode
|
|
295
321
|
? getNodePositionWithOrigin(parentNode, parentNode.origin || nodeOrigin).positionAbsolute
|
|
296
322
|
: { x: 0, y: 0 };
|
|
@@ -300,10 +326,10 @@ function calculateNodePosition({ nodeId, nextPosition, nodeLookup, nodeOrigin =
|
|
|
300
326
|
onError?.('005', errorMessages['error005']());
|
|
301
327
|
}
|
|
302
328
|
else {
|
|
303
|
-
const nodeWidth = node.
|
|
304
|
-
const nodeHeight = node.
|
|
305
|
-
const parentWidth = parentNode
|
|
306
|
-
const parentHeight = parentNode
|
|
329
|
+
const nodeWidth = node.measured.width;
|
|
330
|
+
const nodeHeight = node.measured.height;
|
|
331
|
+
const parentWidth = parentNode.measured.width;
|
|
332
|
+
const parentHeight = parentNode.measured.height;
|
|
307
333
|
if (nodeWidth && nodeHeight && parentWidth && parentHeight) {
|
|
308
334
|
const currNodeOrigin = node.origin || nodeOrigin;
|
|
309
335
|
const extentX = parentX + nodeWidth * currNodeOrigin[0];
|
|
@@ -350,7 +376,7 @@ async function getElementsToRemove({ nodesToRemove = [], edgesToRemove = [], nod
|
|
|
350
376
|
continue;
|
|
351
377
|
}
|
|
352
378
|
const isIncluded = nodeIds.includes(node.id);
|
|
353
|
-
const parentHit = !isIncluded && node.
|
|
379
|
+
const parentHit = !isIncluded && node.parentId && matchingNodes.find((n) => n.id === node.parentId);
|
|
354
380
|
if (isIncluded || parentHit) {
|
|
355
381
|
matchingNodes.push(node);
|
|
356
382
|
}
|
|
@@ -430,16 +456,16 @@ const nodeToRect = (node, nodeOrigin = [0, 0]) => {
|
|
|
430
456
|
const { positionAbsolute } = getNodePositionWithOrigin(node, node.origin || nodeOrigin);
|
|
431
457
|
return {
|
|
432
458
|
...positionAbsolute,
|
|
433
|
-
width: node.
|
|
434
|
-
height: node.
|
|
459
|
+
width: node.measured?.width ?? node.width ?? 0,
|
|
460
|
+
height: node.measured?.height ?? node.height ?? 0,
|
|
435
461
|
};
|
|
436
462
|
};
|
|
437
463
|
const nodeToBox = (node, nodeOrigin = [0, 0]) => {
|
|
438
464
|
const { positionAbsolute } = getNodePositionWithOrigin(node, node.origin || nodeOrigin);
|
|
439
465
|
return {
|
|
440
466
|
...positionAbsolute,
|
|
441
|
-
x2: positionAbsolute.x + (node.
|
|
442
|
-
y2: positionAbsolute.y + (node.
|
|
467
|
+
x2: positionAbsolute.x + (node.measured?.width ?? node.width ?? 0),
|
|
468
|
+
y2: positionAbsolute.y + (node.measured?.height ?? node.height ?? 0),
|
|
443
469
|
};
|
|
444
470
|
};
|
|
445
471
|
const getBoundsOfRects = (rect1, rect2) => boxToRect(getBoundsOfBoxes(rectToBox(rect1), rectToBox(rect2)));
|
|
@@ -519,13 +545,13 @@ function isCoordinateExtent(extent) {
|
|
|
519
545
|
}
|
|
520
546
|
function getNodeDimensions(node) {
|
|
521
547
|
return {
|
|
522
|
-
width: node.
|
|
523
|
-
height: node.
|
|
548
|
+
width: node.measured?.width ?? node.width ?? node.initialWidth ?? 0,
|
|
549
|
+
height: node.measured?.height ?? node.height ?? node.initialHeight ?? 0,
|
|
524
550
|
};
|
|
525
551
|
}
|
|
526
552
|
function nodeHasDimensions(node) {
|
|
527
|
-
return ((node.
|
|
528
|
-
(node.
|
|
553
|
+
return ((node.measured?.width ?? node.width ?? node.initialWidth) !== undefined &&
|
|
554
|
+
(node.measured?.height ?? node.height ?? node.initialHeight) !== undefined);
|
|
529
555
|
}
|
|
530
556
|
|
|
531
557
|
function getPointerPosition(event, { snapGrid = [0, 0], snapToGrid = false, transform }) {
|
|
@@ -688,7 +714,7 @@ function getElevatedEdgeZIndex({ sourceNode, targetNode, selected = false, zInde
|
|
|
688
714
|
return zIndex;
|
|
689
715
|
}
|
|
690
716
|
const edgeOrConnectedNodeSelected = selected || targetNode.selected || sourceNode.selected;
|
|
691
|
-
const selectedZIndex = Math.max(sourceNode
|
|
717
|
+
const selectedZIndex = Math.max(sourceNode.internals.z || 0, targetNode.internals.z || 0, 1000);
|
|
692
718
|
return zIndex + (edgeOrConnectedNodeSelected ? selectedZIndex : 0);
|
|
693
719
|
}
|
|
694
720
|
function isEdgeVisible({ sourceNode, targetNode, width, height, transform }) {
|
|
@@ -993,16 +1019,17 @@ function getSmoothStepPath({ sourceX, sourceY, sourcePosition = Position.Bottom,
|
|
|
993
1019
|
}
|
|
994
1020
|
|
|
995
1021
|
function isNodeInitialized(node) {
|
|
996
|
-
return (
|
|
997
|
-
!!(node
|
|
1022
|
+
return (node &&
|
|
1023
|
+
!!(node.internals.handleBounds || node.handles?.length) &&
|
|
1024
|
+
!!(node.measured.width || node.width || node.initialWidth));
|
|
998
1025
|
}
|
|
999
1026
|
function getEdgePosition(params) {
|
|
1000
1027
|
const { sourceNode, targetNode } = params;
|
|
1001
1028
|
if (!isNodeInitialized(sourceNode) || !isNodeInitialized(targetNode)) {
|
|
1002
1029
|
return null;
|
|
1003
1030
|
}
|
|
1004
|
-
const sourceHandleBounds = sourceNode
|
|
1005
|
-
const targetHandleBounds = targetNode
|
|
1031
|
+
const sourceHandleBounds = sourceNode.internals.handleBounds || toHandleBounds(sourceNode.handles);
|
|
1032
|
+
const targetHandleBounds = targetNode.internals.handleBounds || toHandleBounds(targetNode.handles);
|
|
1006
1033
|
const sourceHandle = getHandle(sourceHandleBounds?.source ?? [], params.sourceHandle);
|
|
1007
1034
|
const targetHandle = getHandle(
|
|
1008
1035
|
// when connection type is loose we can define all handles as sources and connect source -> source
|
|
@@ -1052,8 +1079,8 @@ function toHandleBounds(handles) {
|
|
|
1052
1079
|
};
|
|
1053
1080
|
}
|
|
1054
1081
|
function getHandlePosition(position, node, handle = null) {
|
|
1055
|
-
const x = (handle?.x ?? 0) +
|
|
1056
|
-
const y = (handle?.y ?? 0) +
|
|
1082
|
+
const x = (handle?.x ?? 0) + node.internals.positionAbsolute.x;
|
|
1083
|
+
const y = (handle?.y ?? 0) + node.internals.positionAbsolute.y;
|
|
1057
1084
|
const { width, height } = handle ?? getNodeDimensions(node);
|
|
1058
1085
|
switch (position) {
|
|
1059
1086
|
case Position.Top:
|
|
@@ -1144,111 +1171,177 @@ function getNodeToolbarTransform(nodeRect, viewport, position, offset, align) {
|
|
|
1144
1171
|
return `translate(${pos[0]}px, ${pos[1]}px) translate(${shift[0]}%, ${shift[1]}%)`;
|
|
1145
1172
|
}
|
|
1146
1173
|
|
|
1147
|
-
function updateAbsolutePositions(
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1174
|
+
function updateAbsolutePositions(nodeLookup, options = {
|
|
1175
|
+
nodeOrigin: [0, 0],
|
|
1176
|
+
elevateNodesOnSelect: true,
|
|
1177
|
+
defaults: {},
|
|
1178
|
+
}, parentNodeIds) {
|
|
1179
|
+
const selectedNodeZ = options?.elevateNodesOnSelect ? 1000 : 0;
|
|
1180
|
+
for (const [id, node] of nodeLookup) {
|
|
1181
|
+
const parentId = node.parentId;
|
|
1182
|
+
if (parentId && !nodeLookup.has(parentId)) {
|
|
1183
|
+
throw new Error(`Parent node ${parentId} not found`);
|
|
1184
|
+
}
|
|
1185
|
+
if (parentId || node.internals.isParent || parentNodeIds?.has(id)) {
|
|
1186
|
+
const parentNode = parentId ? nodeLookup.get(parentId) : null;
|
|
1187
|
+
const { x, y, z } = calculateXYZPosition(node, nodeLookup, {
|
|
1155
1188
|
...node.position,
|
|
1156
|
-
z: node
|
|
1157
|
-
}, parentNode?.origin || nodeOrigin);
|
|
1158
|
-
const
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
: node.computed?.positionAbsolute;
|
|
1165
|
-
node[internalsSymbol].z = z;
|
|
1166
|
-
if (parentNodes?.[node.id]) {
|
|
1167
|
-
node[internalsSymbol].isParent = true;
|
|
1189
|
+
z: (isNumeric(node.zIndex) ? node.zIndex : 0) + (node.selected ? selectedNodeZ : 0),
|
|
1190
|
+
}, parentNode?.origin || options.nodeOrigin);
|
|
1191
|
+
const currPosition = node.internals.positionAbsolute;
|
|
1192
|
+
const positionChanged = x !== currPosition.x || y !== currPosition.y;
|
|
1193
|
+
node.internals.positionAbsolute = positionChanged ? { x, y } : currPosition;
|
|
1194
|
+
node.internals.z = z;
|
|
1195
|
+
if (parentNodeIds !== undefined) {
|
|
1196
|
+
node.internals.isParent = !!parentNodeIds?.has(id);
|
|
1168
1197
|
}
|
|
1198
|
+
nodeLookup.set(id, node);
|
|
1169
1199
|
}
|
|
1170
|
-
|
|
1171
|
-
});
|
|
1200
|
+
}
|
|
1172
1201
|
}
|
|
1173
|
-
function
|
|
1202
|
+
function adoptUserNodes(nodes, nodeLookup, options = {
|
|
1174
1203
|
nodeOrigin: [0, 0],
|
|
1175
1204
|
elevateNodesOnSelect: true,
|
|
1176
1205
|
defaults: {},
|
|
1206
|
+
checkEquality: true,
|
|
1177
1207
|
}) {
|
|
1178
1208
|
const tmpLookup = new Map(nodeLookup);
|
|
1179
1209
|
nodeLookup.clear();
|
|
1180
|
-
const parentNodes = {};
|
|
1181
1210
|
const selectedNodeZ = options?.elevateNodesOnSelect ? 1000 : 0;
|
|
1182
|
-
const
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
},
|
|
1209
|
-
});
|
|
1210
|
-
nodeLookup.set(node.id, node);
|
|
1211
|
-
return node;
|
|
1211
|
+
const parentNodeIds = new Set();
|
|
1212
|
+
nodes.forEach((userNode) => {
|
|
1213
|
+
const currentStoreNode = tmpLookup.get(userNode.id);
|
|
1214
|
+
if (userNode.parentId) {
|
|
1215
|
+
parentNodeIds.add(userNode.parentId);
|
|
1216
|
+
}
|
|
1217
|
+
if (options.checkEquality && userNode === currentStoreNode?.internals.userNode) {
|
|
1218
|
+
nodeLookup.set(userNode.id, currentStoreNode);
|
|
1219
|
+
}
|
|
1220
|
+
else {
|
|
1221
|
+
nodeLookup.set(userNode.id, {
|
|
1222
|
+
...options.defaults,
|
|
1223
|
+
...userNode,
|
|
1224
|
+
measured: {
|
|
1225
|
+
width: userNode.measured?.width,
|
|
1226
|
+
height: userNode.measured?.height,
|
|
1227
|
+
},
|
|
1228
|
+
internals: {
|
|
1229
|
+
positionAbsolute: userNode.position,
|
|
1230
|
+
handleBounds: currentStoreNode?.internals.handleBounds,
|
|
1231
|
+
z: (isNumeric(userNode.zIndex) ? userNode.zIndex : 0) + (userNode.selected ? selectedNodeZ : 0),
|
|
1232
|
+
userNode,
|
|
1233
|
+
isParent: false,
|
|
1234
|
+
},
|
|
1235
|
+
});
|
|
1236
|
+
}
|
|
1212
1237
|
});
|
|
1213
|
-
|
|
1214
|
-
|
|
1238
|
+
if (parentNodeIds.size > 0) {
|
|
1239
|
+
updateAbsolutePositions(nodeLookup, options, parentNodeIds);
|
|
1240
|
+
}
|
|
1215
1241
|
}
|
|
1216
|
-
function calculateXYZPosition(node,
|
|
1217
|
-
if (!node.
|
|
1242
|
+
function calculateXYZPosition(node, nodeLookup, result, nodeOrigin = [0, 0]) {
|
|
1243
|
+
if (!node.parentId) {
|
|
1218
1244
|
return result;
|
|
1219
1245
|
}
|
|
1220
|
-
const parentNode = nodeLookup.get(node.
|
|
1246
|
+
const parentNode = nodeLookup.get(node.parentId);
|
|
1221
1247
|
const { position: parentNodePosition } = getNodePositionWithOrigin(parentNode, parentNode?.origin || nodeOrigin);
|
|
1222
|
-
return calculateXYZPosition(parentNode,
|
|
1248
|
+
return calculateXYZPosition(parentNode, nodeLookup, {
|
|
1223
1249
|
x: (result.x ?? 0) + parentNodePosition.x,
|
|
1224
1250
|
y: (result.y ?? 0) + parentNodePosition.y,
|
|
1225
|
-
z: (parentNode
|
|
1251
|
+
z: (parentNode.internals.z ?? 0) > (result.z ?? 0) ? parentNode.internals.z ?? 0 : result.z ?? 0,
|
|
1226
1252
|
}, parentNode.origin || nodeOrigin);
|
|
1227
1253
|
}
|
|
1228
|
-
function
|
|
1254
|
+
function handleParentExpand(nodes, nodeLookup) {
|
|
1255
|
+
const changes = [];
|
|
1256
|
+
const chilNodeRects = new Map();
|
|
1257
|
+
nodes.forEach((node) => {
|
|
1258
|
+
const parentId = node.parentId;
|
|
1259
|
+
if (node.expandParent && parentId) {
|
|
1260
|
+
const parentNode = nodeLookup.get(parentId);
|
|
1261
|
+
if (parentNode) {
|
|
1262
|
+
const parentRect = chilNodeRects.get(parentId) || nodeToRect(parentNode, node.origin);
|
|
1263
|
+
const expandedRect = getBoundsOfRects(parentRect, nodeToRect(node, node.origin));
|
|
1264
|
+
chilNodeRects.set(parentId, expandedRect);
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
});
|
|
1268
|
+
if (chilNodeRects.size > 0) {
|
|
1269
|
+
chilNodeRects.forEach((rect, id) => {
|
|
1270
|
+
const origParent = nodeLookup.get(id);
|
|
1271
|
+
const { position } = getNodePositionWithOrigin(origParent, origParent.origin);
|
|
1272
|
+
const dimensions = getNodeDimensions(origParent);
|
|
1273
|
+
if (rect.x < position.x || rect.y < position.y) {
|
|
1274
|
+
const xChange = Math.round(Math.abs(position.x - rect.x));
|
|
1275
|
+
const yChange = Math.round(Math.abs(position.y - rect.y));
|
|
1276
|
+
changes.push({
|
|
1277
|
+
id,
|
|
1278
|
+
type: 'position',
|
|
1279
|
+
position: {
|
|
1280
|
+
x: position.x - xChange,
|
|
1281
|
+
y: position.y - yChange,
|
|
1282
|
+
},
|
|
1283
|
+
});
|
|
1284
|
+
changes.push({
|
|
1285
|
+
id,
|
|
1286
|
+
type: 'dimensions',
|
|
1287
|
+
resizing: true,
|
|
1288
|
+
dimensions: {
|
|
1289
|
+
width: dimensions.width + xChange,
|
|
1290
|
+
height: dimensions.height + yChange,
|
|
1291
|
+
},
|
|
1292
|
+
});
|
|
1293
|
+
// @todo we need to reset child node positions if < 0
|
|
1294
|
+
}
|
|
1295
|
+
else if (dimensions.width < rect.width || dimensions.height < rect.height) {
|
|
1296
|
+
changes.push({
|
|
1297
|
+
id,
|
|
1298
|
+
type: 'dimensions',
|
|
1299
|
+
resizing: true,
|
|
1300
|
+
dimensions: {
|
|
1301
|
+
width: Math.max(dimensions.width, rect.width),
|
|
1302
|
+
height: Math.max(dimensions.height, rect.height),
|
|
1303
|
+
},
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
return changes;
|
|
1309
|
+
}
|
|
1310
|
+
function updateNodeInternals(updates, nodeLookup, domNode, nodeOrigin) {
|
|
1229
1311
|
const viewportNode = domNode?.querySelector('.xyflow__viewport');
|
|
1312
|
+
let updatedInternals = false;
|
|
1230
1313
|
if (!viewportNode) {
|
|
1231
|
-
return
|
|
1314
|
+
return { changes: [], updatedInternals };
|
|
1232
1315
|
}
|
|
1316
|
+
const changes = [];
|
|
1233
1317
|
const style = window.getComputedStyle(viewportNode);
|
|
1234
1318
|
const { m22: zoom } = new window.DOMMatrixReadOnly(style.transform);
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1319
|
+
// in this array we collect nodes, that might trigger changes (like expanding parent)
|
|
1320
|
+
const triggerChangeNodes = [];
|
|
1321
|
+
updates.forEach((update) => {
|
|
1322
|
+
const node = nodeLookup.get(update.id);
|
|
1323
|
+
if (node?.hidden) {
|
|
1324
|
+
nodeLookup.set(node.id, {
|
|
1325
|
+
...node,
|
|
1326
|
+
internals: {
|
|
1327
|
+
...node.internals,
|
|
1328
|
+
handleBounds: undefined,
|
|
1329
|
+
},
|
|
1330
|
+
});
|
|
1331
|
+
updatedInternals = true;
|
|
1332
|
+
}
|
|
1333
|
+
else if (node) {
|
|
1238
1334
|
const dimensions = getDimensions(update.nodeElement);
|
|
1335
|
+
const dimensionChanged = node.measured.width !== dimensions.width || node.measured.height !== dimensions.height;
|
|
1239
1336
|
const doUpdate = !!(dimensions.width &&
|
|
1240
1337
|
dimensions.height &&
|
|
1241
|
-
(
|
|
1338
|
+
(dimensionChanged || !node.internals.handleBounds || update.force));
|
|
1242
1339
|
if (doUpdate) {
|
|
1243
|
-
onUpdate?.(node.id, dimensions);
|
|
1244
1340
|
const newNode = {
|
|
1245
1341
|
...node,
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
...
|
|
1249
|
-
},
|
|
1250
|
-
[internalsSymbol]: {
|
|
1251
|
-
...node[internalsSymbol],
|
|
1342
|
+
measured: dimensions,
|
|
1343
|
+
internals: {
|
|
1344
|
+
...node.internals,
|
|
1252
1345
|
handleBounds: {
|
|
1253
1346
|
source: getHandleBounds('.source', update.nodeElement, zoom, node.origin || nodeOrigin),
|
|
1254
1347
|
target: getHandleBounds('.target', update.nodeElement, zoom, node.origin || nodeOrigin),
|
|
@@ -1256,12 +1349,25 @@ function updateNodeDimensions(updates, nodes, nodeLookup, domNode, nodeOrigin, o
|
|
|
1256
1349
|
},
|
|
1257
1350
|
};
|
|
1258
1351
|
nodeLookup.set(node.id, newNode);
|
|
1259
|
-
|
|
1352
|
+
updatedInternals = true;
|
|
1353
|
+
if (dimensionChanged) {
|
|
1354
|
+
changes.push({
|
|
1355
|
+
id: newNode.id,
|
|
1356
|
+
type: 'dimensions',
|
|
1357
|
+
dimensions,
|
|
1358
|
+
});
|
|
1359
|
+
if (newNode.expandParent) {
|
|
1360
|
+
triggerChangeNodes.push(newNode);
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1260
1363
|
}
|
|
1261
1364
|
}
|
|
1262
|
-
return node;
|
|
1263
1365
|
});
|
|
1264
|
-
|
|
1366
|
+
if (triggerChangeNodes.length > 0) {
|
|
1367
|
+
const parentExpandChanges = handleParentExpand(triggerChangeNodes, nodeLookup);
|
|
1368
|
+
changes.push(...parentExpandChanges);
|
|
1369
|
+
}
|
|
1370
|
+
return { changes, updatedInternals };
|
|
1265
1371
|
}
|
|
1266
1372
|
function panBy({ delta, panZoom, transform, translateExtent, width, height, }) {
|
|
1267
1373
|
if (!panZoom || (!delta.x && !delta.y)) {
|
|
@@ -1315,18 +1421,18 @@ function shallowNodeData(a, b) {
|
|
|
1315
1421
|
function wrapSelectionDragFunc(selectionFunc) {
|
|
1316
1422
|
return (event, _, nodes) => selectionFunc?.(event, nodes);
|
|
1317
1423
|
}
|
|
1318
|
-
function isParentSelected(node,
|
|
1319
|
-
if (!node.
|
|
1424
|
+
function isParentSelected(node, nodeLookup) {
|
|
1425
|
+
if (!node.parentId) {
|
|
1320
1426
|
return false;
|
|
1321
1427
|
}
|
|
1322
|
-
const parentNode =
|
|
1428
|
+
const parentNode = nodeLookup.get(node.parentId);
|
|
1323
1429
|
if (!parentNode) {
|
|
1324
1430
|
return false;
|
|
1325
1431
|
}
|
|
1326
1432
|
if (parentNode.selected) {
|
|
1327
1433
|
return true;
|
|
1328
1434
|
}
|
|
1329
|
-
return isParentSelected(parentNode,
|
|
1435
|
+
return isParentSelected(parentNode, nodeLookup);
|
|
1330
1436
|
}
|
|
1331
1437
|
function hasSelector(target, selector, domNode) {
|
|
1332
1438
|
let current = target;
|
|
@@ -1340,32 +1446,35 @@ function hasSelector(target, selector, domNode) {
|
|
|
1340
1446
|
return false;
|
|
1341
1447
|
}
|
|
1342
1448
|
// looks for all selected nodes and created a NodeDragItem for each of them
|
|
1343
|
-
function getDragItems(
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
(
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1449
|
+
function getDragItems(nodeLookup, nodesDraggable, mousePos, nodeId) {
|
|
1450
|
+
const dragItems = [];
|
|
1451
|
+
for (const [id, node] of nodeLookup) {
|
|
1452
|
+
if ((node.selected || node.id === nodeId) &&
|
|
1453
|
+
(!node.parentId || !isParentSelected(node, nodeLookup)) &&
|
|
1454
|
+
(node.draggable || (nodesDraggable && typeof node.draggable === 'undefined'))) {
|
|
1455
|
+
const internalNode = nodeLookup.get(id);
|
|
1456
|
+
dragItems.push({
|
|
1457
|
+
id: internalNode.id,
|
|
1458
|
+
position: internalNode.position || { x: 0, y: 0 },
|
|
1459
|
+
distance: {
|
|
1460
|
+
x: mousePos.x - internalNode.internals.positionAbsolute.x,
|
|
1461
|
+
y: mousePos.y - internalNode.internals.positionAbsolute.y,
|
|
1462
|
+
},
|
|
1463
|
+
extent: internalNode.extent,
|
|
1464
|
+
parentId: internalNode.parentId,
|
|
1465
|
+
origin: internalNode.origin,
|
|
1466
|
+
expandParent: internalNode.expandParent,
|
|
1467
|
+
internals: {
|
|
1468
|
+
positionAbsolute: internalNode.internals.positionAbsolute || { x: 0, y: 0 },
|
|
1469
|
+
},
|
|
1470
|
+
measured: {
|
|
1471
|
+
width: internalNode.measured.width || 0,
|
|
1472
|
+
height: internalNode.measured.height || 0,
|
|
1473
|
+
},
|
|
1474
|
+
});
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
return dragItems;
|
|
1369
1478
|
}
|
|
1370
1479
|
// returns two params:
|
|
1371
1480
|
// 1. the dragged node (or the first of the list, if we are dragging a node selection)
|
|
@@ -1376,9 +1485,8 @@ function getEventHandlerParams({ nodeId, dragItems, nodeLookup, }) {
|
|
|
1376
1485
|
return {
|
|
1377
1486
|
...node,
|
|
1378
1487
|
position: n.position,
|
|
1379
|
-
|
|
1380
|
-
...n.
|
|
1381
|
-
positionAbsolute: n.computed.positionAbsolute,
|
|
1488
|
+
measured: {
|
|
1489
|
+
...n.measured,
|
|
1382
1490
|
},
|
|
1383
1491
|
};
|
|
1384
1492
|
});
|
|
@@ -1414,17 +1522,20 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
|
|
|
1414
1522
|
}
|
|
1415
1523
|
// if there is selection with multiple nodes and a node extent is set, we need to adjust the node extent for each node
|
|
1416
1524
|
// based on its position so that the node stays at it's position relative to the selection.
|
|
1417
|
-
|
|
1525
|
+
let adjustedNodeExtent = [
|
|
1418
1526
|
[nodeExtent[0][0], nodeExtent[0][1]],
|
|
1419
1527
|
[nodeExtent[1][0], nodeExtent[1][1]],
|
|
1420
1528
|
];
|
|
1421
1529
|
if (dragItems.length > 1 && nodeExtent && !n.extent) {
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1530
|
+
const { positionAbsolute } = n.internals;
|
|
1531
|
+
const x1 = positionAbsolute.x - nodesBox.x + nodeExtent[0][0];
|
|
1532
|
+
const x2 = positionAbsolute.x + (n.measured?.width ?? 0) - nodesBox.x2 + nodeExtent[1][0];
|
|
1533
|
+
const y1 = positionAbsolute.y - nodesBox.y + nodeExtent[0][1];
|
|
1534
|
+
const y2 = positionAbsolute.y + (n.measured?.height ?? 0) - nodesBox.y2 + nodeExtent[1][1];
|
|
1535
|
+
adjustedNodeExtent = [
|
|
1536
|
+
[x1, y1],
|
|
1537
|
+
[x2, y2],
|
|
1538
|
+
];
|
|
1428
1539
|
}
|
|
1429
1540
|
const { position, positionAbsolute } = calculateNodePosition({
|
|
1430
1541
|
nodeId: n.id,
|
|
@@ -1437,7 +1548,7 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
|
|
|
1437
1548
|
// we want to make sure that we only fire a change event when there is a change
|
|
1438
1549
|
hasChange = hasChange || n.position.x !== position.x || n.position.y !== position.y;
|
|
1439
1550
|
n.position = position;
|
|
1440
|
-
n.
|
|
1551
|
+
n.internals.positionAbsolute = positionAbsolute;
|
|
1441
1552
|
return n;
|
|
1442
1553
|
});
|
|
1443
1554
|
if (!hasChange) {
|
|
@@ -1474,7 +1585,7 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
|
|
|
1474
1585
|
autoPanId = requestAnimationFrame(autoPan);
|
|
1475
1586
|
}
|
|
1476
1587
|
function startDrag(event) {
|
|
1477
|
-
const {
|
|
1588
|
+
const { nodeLookup, multiSelectionActive, nodesDraggable, transform, snapGrid, snapToGrid, selectNodesOnDrag, onNodeDragStart, onSelectionDragStart, unselectNodesAndEdges, } = getStoreItems();
|
|
1478
1589
|
dragStarted = true;
|
|
1479
1590
|
if ((!selectNodesOnDrag || !isSelectable) && !multiSelectionActive && nodeId) {
|
|
1480
1591
|
if (!nodeLookup.get(nodeId)?.selected) {
|
|
@@ -1487,7 +1598,7 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
|
|
|
1487
1598
|
}
|
|
1488
1599
|
const pointerPos = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
|
|
1489
1600
|
lastPos = pointerPos;
|
|
1490
|
-
dragItems = getDragItems(
|
|
1601
|
+
dragItems = getDragItems(nodeLookup, nodesDraggable, pointerPos, nodeId);
|
|
1491
1602
|
if (dragItems.length > 0 && (onDragStart || onNodeDragStart || (!nodeId && onSelectionDragStart))) {
|
|
1492
1603
|
const [currentNode, currentNodes] = getEventHandlerParams({
|
|
1493
1604
|
nodeId,
|
|
@@ -1587,8 +1698,8 @@ function getHandles(node, handleBounds, type, currentHandle) {
|
|
|
1587
1698
|
id: h.id || null,
|
|
1588
1699
|
type,
|
|
1589
1700
|
nodeId: node.id,
|
|
1590
|
-
x:
|
|
1591
|
-
y:
|
|
1701
|
+
x: node.internals.positionAbsolute.x + h.x + h.width / 2,
|
|
1702
|
+
y: node.internals.positionAbsolute.y + h.y + h.height / 2,
|
|
1592
1703
|
});
|
|
1593
1704
|
}
|
|
1594
1705
|
return res;
|
|
@@ -1618,20 +1729,17 @@ function getClosestHandle(pos, connectionRadius, handles) {
|
|
|
1618
1729
|
: // if multiple handles are layouted on top of each other we take the one with type = target because it's more likely that the user wants to connect to this one
|
|
1619
1730
|
closestHandles.find((handle) => handle.type === 'target') || closestHandles[0];
|
|
1620
1731
|
}
|
|
1621
|
-
function getHandleLookup({
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
targetHandles = getHandles(node, handleBounds, 'target', `${nodeId}-${handleId}-${handleType}`);
|
|
1630
|
-
}
|
|
1631
|
-
res.push(...sourceHandles, ...targetHandles);
|
|
1732
|
+
function getHandleLookup({ nodeLookup, nodeId, handleId, handleType, }) {
|
|
1733
|
+
const connectionHandles = [];
|
|
1734
|
+
for (const [, node] of nodeLookup) {
|
|
1735
|
+
if (node.internals.handleBounds) {
|
|
1736
|
+
const id = `${nodeId}-${handleId}-${handleType}`;
|
|
1737
|
+
const sourceHandles = getHandles(node, node.internals.handleBounds, 'source', id);
|
|
1738
|
+
const targetHandles = getHandles(node, node.internals.handleBounds, 'target', id);
|
|
1739
|
+
connectionHandles.push(...sourceHandles, ...targetHandles);
|
|
1632
1740
|
}
|
|
1633
|
-
|
|
1634
|
-
|
|
1741
|
+
}
|
|
1742
|
+
return connectionHandles;
|
|
1635
1743
|
}
|
|
1636
1744
|
function getHandleType(edgeUpdaterType, handleDomNode) {
|
|
1637
1745
|
if (edgeUpdaterType) {
|
|
@@ -1658,7 +1766,7 @@ function getConnectionStatus(isInsideConnectionRadius, isHandleValid) {
|
|
|
1658
1766
|
|
|
1659
1767
|
const alwaysValid = () => true;
|
|
1660
1768
|
let connectionStartHandle = null;
|
|
1661
|
-
function onPointerDown(event, { connectionMode, connectionRadius, handleId, nodeId, edgeUpdaterType, isTarget, domNode,
|
|
1769
|
+
function onPointerDown(event, { connectionMode, connectionRadius, handleId, nodeId, edgeUpdaterType, isTarget, domNode, nodeLookup, lib, autoPanOnConnect, flowId, panBy, cancelConnection, onConnectStart, onConnect, onConnectEnd, isValidConnection = alwaysValid, onEdgeUpdateEnd, updateConnection, getTransform, getConnectionStartHandle, }) {
|
|
1662
1770
|
// when xyflow is used inside a shadow root we can't use document
|
|
1663
1771
|
const doc = getHostForElement(event.target);
|
|
1664
1772
|
let autoPanId = 0;
|
|
@@ -1676,7 +1784,7 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
|
|
|
1676
1784
|
let isValid = false;
|
|
1677
1785
|
let handleDomNode = null;
|
|
1678
1786
|
const handleLookup = getHandleLookup({
|
|
1679
|
-
|
|
1787
|
+
nodeLookup,
|
|
1680
1788
|
nodeId,
|
|
1681
1789
|
handleId,
|
|
1682
1790
|
handleType,
|
|
@@ -1940,7 +2048,9 @@ function createPanOnScrollHandler({ zoomPanValues, noWheelClassName, d3Selection
|
|
|
1940
2048
|
}
|
|
1941
2049
|
function createZoomOnScrollHandler({ noWheelClassName, preventScrolling, d3ZoomHandler }) {
|
|
1942
2050
|
return function (event, d) {
|
|
1943
|
-
if
|
|
2051
|
+
// we still want to enable pinch zooming even if preventScrolling is set to false
|
|
2052
|
+
const preventZoom = !preventScrolling && event.type === 'wheel' && !event.ctrlKey;
|
|
2053
|
+
if (preventZoom || isWrappedWithClass(event, noWheelClassName)) {
|
|
1944
2054
|
return null;
|
|
1945
2055
|
}
|
|
1946
2056
|
event.preventDefault();
|
|
@@ -2021,10 +2131,6 @@ function createFilter({ zoomActivationKeyPressed, zoomOnScroll, zoomOnPinch, pan
|
|
|
2021
2131
|
if (userSelectionActive) {
|
|
2022
2132
|
return false;
|
|
2023
2133
|
}
|
|
2024
|
-
// if zoom on double click is disabled, we prevent the double click event
|
|
2025
|
-
if (!zoomOnDoubleClick && event.type === 'dblclick') {
|
|
2026
|
-
return false;
|
|
2027
|
-
}
|
|
2028
2134
|
// if the target element is inside an element with the nowheel class, we prevent zooming
|
|
2029
2135
|
if (isWrappedWithClass(event, noWheelClassName) && event.type === 'wheel') {
|
|
2030
2136
|
return false;
|
|
@@ -2080,6 +2186,7 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
|
|
|
2080
2186
|
[bbox.width, bbox.height],
|
|
2081
2187
|
], translateExtent);
|
|
2082
2188
|
const d3ZoomHandler = d3Selection.on('wheel.zoom');
|
|
2189
|
+
const d3DblClickZoomHandler = d3Selection.on('dblclick.zoom');
|
|
2083
2190
|
d3ZoomInstance.wheelDelta(wheelDelta);
|
|
2084
2191
|
function setTransform(transform, options) {
|
|
2085
2192
|
if (d3Selection) {
|
|
@@ -2152,6 +2259,15 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
|
|
|
2152
2259
|
lib,
|
|
2153
2260
|
});
|
|
2154
2261
|
d3ZoomInstance.filter(filter);
|
|
2262
|
+
// We cannot add zoomOnDoubleClick to the filter above because
|
|
2263
|
+
// double tapping on touch screens circumvents the filter and
|
|
2264
|
+
// dblclick.zoom is fired on the selection directly
|
|
2265
|
+
if (zoomOnDoubleClick) {
|
|
2266
|
+
d3Selection.on('dblclick.zoom', d3DblClickZoomHandler);
|
|
2267
|
+
}
|
|
2268
|
+
else {
|
|
2269
|
+
d3Selection.on('dblclick.zoom', null);
|
|
2270
|
+
}
|
|
2155
2271
|
}
|
|
2156
2272
|
function destroy() {
|
|
2157
2273
|
d3ZoomInstance.on('zoom', null);
|
|
@@ -2462,14 +2578,14 @@ const initChange = {
|
|
|
2462
2578
|
function nodeToParentExtent(node) {
|
|
2463
2579
|
return [
|
|
2464
2580
|
[0, 0],
|
|
2465
|
-
[node.
|
|
2581
|
+
[node.measured.width, node.measured.height],
|
|
2466
2582
|
];
|
|
2467
2583
|
}
|
|
2468
2584
|
function nodeToChildExtent(child, parent, nodeOrigin) {
|
|
2469
2585
|
const x = parent.position.x + child.position.x;
|
|
2470
2586
|
const y = parent.position.y + child.position.y;
|
|
2471
|
-
const width = child.
|
|
2472
|
-
const height = child.
|
|
2587
|
+
const width = child.measured.width ?? 0;
|
|
2588
|
+
const height = child.measured.height ?? 0;
|
|
2473
2589
|
const originOffsetX = nodeOrigin[0] * width;
|
|
2474
2590
|
const originOffsetY = nodeOrigin[1] * height;
|
|
2475
2591
|
return [
|
|
@@ -2495,8 +2611,8 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange }) {
|
|
|
2495
2611
|
if (node) {
|
|
2496
2612
|
const { xSnapped, ySnapped } = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
|
|
2497
2613
|
prevValues = {
|
|
2498
|
-
width: node.
|
|
2499
|
-
height: node.
|
|
2614
|
+
width: node.measured?.width ?? 0,
|
|
2615
|
+
height: node.measured?.height ?? 0,
|
|
2500
2616
|
x: node.position.x ?? 0,
|
|
2501
2617
|
y: node.position.y ?? 0,
|
|
2502
2618
|
};
|
|
@@ -2508,7 +2624,7 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange }) {
|
|
|
2508
2624
|
};
|
|
2509
2625
|
parentNode = undefined;
|
|
2510
2626
|
if (node.extent === 'parent' || node.expandParent) {
|
|
2511
|
-
parentNode = nodeLookup.get(node.
|
|
2627
|
+
parentNode = nodeLookup.get(node.parentId);
|
|
2512
2628
|
if (parentNode && node.extent === 'parent') {
|
|
2513
2629
|
parentExtent = nodeToParentExtent(parentNode);
|
|
2514
2630
|
}
|
|
@@ -2518,7 +2634,7 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange }) {
|
|
|
2518
2634
|
childNodes = [];
|
|
2519
2635
|
childExtent = undefined;
|
|
2520
2636
|
for (const [childId, child] of nodeLookup) {
|
|
2521
|
-
if (child.
|
|
2637
|
+
if (child.parentId === nodeId) {
|
|
2522
2638
|
childNodes.push({
|
|
2523
2639
|
id: childId,
|
|
2524
2640
|
position: { ...child.position },
|
|
@@ -2626,4 +2742,4 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange }) {
|
|
|
2626
2742
|
};
|
|
2627
2743
|
}
|
|
2628
2744
|
|
|
2629
|
-
export { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, ResizeControlVariant, SelectionMode, XYDrag, XYHandle, XYMinimap, XYPanZoom, XYResizer, XY_RESIZER_HANDLE_POSITIONS, XY_RESIZER_LINE_POSITIONS, addEdge,
|
|
2745
|
+
export { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, ResizeControlVariant, SelectionMode, XYDrag, XYHandle, XYMinimap, XYPanZoom, XYResizer, XY_RESIZER_HANDLE_POSITIONS, XY_RESIZER_LINE_POSITIONS, addEdge, adoptUserNodes, areConnectionMapsEqual, boxToRect, calcAutoPan, calculateNodePosition, clamp, clampPosition, createMarkerIds, devWarn, elementSelectionKeys, errorMessages, fitView, getBezierEdgeCenter, getBezierPath, getBoundsOfBoxes, getBoundsOfRects, getConnectedEdges, getDimensions, getEdgeCenter, getEdgePosition, getElementsToRemove, getElevatedEdgeZIndex, getEventPosition, getHandleBounds, getHostForElement, getIncomers, getInternalNodesBounds, getMarkerId, getNodeDimensions, getNodePositionWithOrigin, getNodeToolbarTransform, getNodesBounds, getNodesInside, getOutgoers, getOverlappingArea, getPointerPosition, getPositionWithOrigin, getSmoothStepPath, getStraightPath, getViewportForBounds, handleConnectionChange, handleParentExpand, infiniteExtent, isCoordinateExtent, isEdgeBase, isEdgeVisible, isInputDOMNode, isInternalNodeBase, isMacOs, isMouseEvent, isNodeBase, isNumeric, isRectObject, nodeHasDimensions, nodeToBox, nodeToRect, panBy, pointToRendererPoint, rectToBox, rendererPointToPoint, shallowNodeData, snapPosition, updateAbsolutePositions, updateConnectionLookup, updateEdge, updateNodeInternals };
|