@xyflow/system 0.0.23 → 0.0.25
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 +346 -315
- package/dist/esm/index.mjs +346 -315
- package/dist/esm/types/changes.d.ts +1 -0
- package/dist/esm/types/changes.d.ts.map +1 -1
- package/dist/esm/types/general.d.ts +4 -4
- package/dist/esm/types/general.d.ts.map +1 -1
- package/dist/esm/types/nodes.d.ts +3 -3
- package/dist/esm/types/nodes.d.ts.map +1 -1
- package/dist/esm/utils/general.d.ts +22 -2
- package/dist/esm/utils/general.d.ts.map +1 -1
- package/dist/esm/utils/graph.d.ts +6 -8
- package/dist/esm/utils/graph.d.ts.map +1 -1
- package/dist/esm/utils/store.d.ts +6 -5
- package/dist/esm/utils/store.d.ts.map +1 -1
- package/dist/esm/utils/types.d.ts +6 -0
- package/dist/esm/utils/types.d.ts.map +1 -1
- package/dist/esm/xydrag/XYDrag.d.ts +1 -1
- package/dist/esm/xydrag/XYDrag.d.ts.map +1 -1
- package/dist/esm/xydrag/utils.d.ts +4 -5
- package/dist/esm/xydrag/utils.d.ts.map +1 -1
- package/dist/esm/xyminimap/index.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/esm/xypanzoom/utils.d.ts.map +1 -1
- package/dist/esm/xyresizer/XYResizer.d.ts +6 -11
- package/dist/esm/xyresizer/XYResizer.d.ts.map +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/types/changes.d.ts +1 -0
- package/dist/umd/types/changes.d.ts.map +1 -1
- package/dist/umd/types/general.d.ts +4 -4
- package/dist/umd/types/general.d.ts.map +1 -1
- package/dist/umd/types/nodes.d.ts +3 -3
- package/dist/umd/types/nodes.d.ts.map +1 -1
- package/dist/umd/utils/general.d.ts +22 -2
- package/dist/umd/utils/general.d.ts.map +1 -1
- package/dist/umd/utils/graph.d.ts +6 -8
- package/dist/umd/utils/graph.d.ts.map +1 -1
- package/dist/umd/utils/store.d.ts +6 -5
- package/dist/umd/utils/store.d.ts.map +1 -1
- package/dist/umd/utils/types.d.ts +6 -0
- package/dist/umd/utils/types.d.ts.map +1 -1
- package/dist/umd/xydrag/XYDrag.d.ts +1 -1
- package/dist/umd/xydrag/XYDrag.d.ts.map +1 -1
- package/dist/umd/xydrag/utils.d.ts +4 -5
- package/dist/umd/xydrag/utils.d.ts.map +1 -1
- package/dist/umd/xyminimap/index.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/dist/umd/xypanzoom/utils.d.ts.map +1 -1
- package/dist/umd/xyresizer/XYResizer.d.ts +6 -11
- package/dist/umd/xyresizer/XYResizer.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/esm/index.js
CHANGED
|
@@ -161,33 +161,20 @@ const getIncomers = (node, nodes, edges) => {
|
|
|
161
161
|
return nodes.filter((n) => incomersIds.has(n.id));
|
|
162
162
|
};
|
|
163
163
|
const getNodePositionWithOrigin = (node, nodeOrigin = [0, 0]) => {
|
|
164
|
-
if (!node) {
|
|
165
|
-
return {
|
|
166
|
-
position: {
|
|
167
|
-
x: 0,
|
|
168
|
-
y: 0,
|
|
169
|
-
},
|
|
170
|
-
positionAbsolute: {
|
|
171
|
-
x: 0,
|
|
172
|
-
y: 0,
|
|
173
|
-
},
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
164
|
const { width, height } = getNodeDimensions(node);
|
|
177
|
-
const
|
|
178
|
-
const
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
y: node.position.y - offsetY,
|
|
182
|
-
};
|
|
165
|
+
const positionAbsolute = 'internals' in node ? node.internals.positionAbsolute : node.position;
|
|
166
|
+
const origin = node.origin || nodeOrigin;
|
|
167
|
+
const offsetX = width * origin[0];
|
|
168
|
+
const offsetY = height * origin[1];
|
|
183
169
|
return {
|
|
184
|
-
position
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
:
|
|
170
|
+
position: {
|
|
171
|
+
x: node.position.x - offsetX,
|
|
172
|
+
y: node.position.y - offsetY,
|
|
173
|
+
},
|
|
174
|
+
positionAbsolute: {
|
|
175
|
+
x: positionAbsolute.x - offsetX,
|
|
176
|
+
y: positionAbsolute.y - offsetY,
|
|
177
|
+
},
|
|
191
178
|
};
|
|
192
179
|
};
|
|
193
180
|
/**
|
|
@@ -196,20 +183,15 @@ const getNodePositionWithOrigin = (node, nodeOrigin = [0, 0]) => {
|
|
|
196
183
|
* @remarks Useful when combined with {@link getViewportForBounds} to calculate the correct transform to fit the given nodes in a viewport.
|
|
197
184
|
* @param nodes - Nodes to calculate the bounds for
|
|
198
185
|
* @param params.nodeOrigin - Origin of the nodes: [0, 0] - top left, [0.5, 0.5] - center
|
|
199
|
-
* @param params.useRelativePosition - Whether to use the relative or absolute node positions
|
|
200
186
|
* @returns Bounding box enclosing all nodes
|
|
201
187
|
*/
|
|
202
|
-
|
|
203
|
-
const getNodesBounds = (nodes, params = { nodeOrigin: [0, 0], useRelativePosition: false }) => {
|
|
188
|
+
const getNodesBounds = (nodes, params = { nodeOrigin: [0, 0] }) => {
|
|
204
189
|
if (nodes.length === 0) {
|
|
205
190
|
return { x: 0, y: 0, width: 0, height: 0 };
|
|
206
191
|
}
|
|
207
192
|
const box = nodes.reduce((currBox, node) => {
|
|
208
|
-
const
|
|
209
|
-
return getBoundsOfBoxes(currBox,
|
|
210
|
-
...nodePos[params.useRelativePosition ? 'position' : 'positionAbsolute'],
|
|
211
|
-
...getNodeDimensions(node),
|
|
212
|
-
}));
|
|
193
|
+
const nodeBox = nodeToBox(node, params.nodeOrigin);
|
|
194
|
+
return getBoundsOfBoxes(currBox, nodeBox);
|
|
213
195
|
}, { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity });
|
|
214
196
|
return boxToRect(box);
|
|
215
197
|
};
|
|
@@ -219,7 +201,6 @@ const getNodesBounds = (nodes, params = { nodeOrigin: [0, 0], useRelativePositio
|
|
|
219
201
|
*/
|
|
220
202
|
const getInternalNodesBounds = (nodeLookup, params = {
|
|
221
203
|
nodeOrigin: [0, 0],
|
|
222
|
-
useRelativePosition: false,
|
|
223
204
|
}) => {
|
|
224
205
|
if (nodeLookup.size === 0) {
|
|
225
206
|
return { x: 0, y: 0, width: 0, height: 0 };
|
|
@@ -227,16 +208,13 @@ const getInternalNodesBounds = (nodeLookup, params = {
|
|
|
227
208
|
let box = { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity };
|
|
228
209
|
nodeLookup.forEach((node) => {
|
|
229
210
|
if (params.filter == undefined || params.filter(node)) {
|
|
230
|
-
const
|
|
231
|
-
box = getBoundsOfBoxes(box,
|
|
232
|
-
...nodePos[params.useRelativePosition ? 'position' : 'positionAbsolute'],
|
|
233
|
-
...getNodeDimensions(node),
|
|
234
|
-
}));
|
|
211
|
+
const nodeBox = nodeToBox(node, params.nodeOrigin);
|
|
212
|
+
box = getBoundsOfBoxes(box, nodeBox);
|
|
235
213
|
}
|
|
236
214
|
});
|
|
237
215
|
return boxToRect(box);
|
|
238
216
|
};
|
|
239
|
-
const getNodesInside = (
|
|
217
|
+
const getNodesInside = (nodes, rect, [tx, ty, tScale] = [0, 0, 1], partially = false,
|
|
240
218
|
// set excludeNonSelectableNodes if you want to pay attention to the nodes "selectable" attribute
|
|
241
219
|
excludeNonSelectableNodes = false, nodeOrigin = [0, 0]) => {
|
|
242
220
|
const paneRect = {
|
|
@@ -245,7 +223,7 @@ excludeNonSelectableNodes = false, nodeOrigin = [0, 0]) => {
|
|
|
245
223
|
height: rect.height / tScale,
|
|
246
224
|
};
|
|
247
225
|
const visibleNodes = [];
|
|
248
|
-
for (const [, node] of
|
|
226
|
+
for (const [, node] of nodes) {
|
|
249
227
|
const { measured, selectable = true, hidden = false } = node;
|
|
250
228
|
const width = measured.width ?? node.width ?? node.initialWidth ?? null;
|
|
251
229
|
const height = measured.height ?? node.height ?? node.initialHeight ?? null;
|
|
@@ -278,11 +256,10 @@ const getConnectedEdges = (nodes, edges) => {
|
|
|
278
256
|
};
|
|
279
257
|
function fitView({ nodeLookup, width, height, panZoom, minZoom, maxZoom, nodeOrigin = [0, 0] }, options) {
|
|
280
258
|
const filteredNodes = [];
|
|
259
|
+
const optionNodeIds = options?.nodes ? new Set(options.nodes.map((node) => node.id)) : null;
|
|
281
260
|
nodeLookup.forEach((n) => {
|
|
282
261
|
const isVisible = n.measured.width && n.measured.height && (options?.includeHiddenNodes || !n.hidden);
|
|
283
|
-
|
|
284
|
-
if (isVisible &&
|
|
285
|
-
(!options?.nodes || (options?.nodes.length && options?.nodes.some((optionNode) => optionNode.id === n.id)))) {
|
|
262
|
+
if (isVisible && (!optionNodeIds || optionNodeIds.has(n.id))) {
|
|
286
263
|
filteredNodes.push(n);
|
|
287
264
|
}
|
|
288
265
|
});
|
|
@@ -369,24 +346,24 @@ function calculateNodePosition({ nodeId, nextPosition, nodeLookup, nodeOrigin =
|
|
|
369
346
|
* @returns nodes: nodes that can be deleted, edges: edges that can be deleted
|
|
370
347
|
*/
|
|
371
348
|
async function getElementsToRemove({ nodesToRemove = [], edgesToRemove = [], nodes, edges, onBeforeDelete, }) {
|
|
372
|
-
const nodeIds = nodesToRemove.map((node) => node.id);
|
|
349
|
+
const nodeIds = new Set(nodesToRemove.map((node) => node.id));
|
|
373
350
|
const matchingNodes = [];
|
|
374
351
|
for (const node of nodes) {
|
|
375
352
|
if (node.deletable === false) {
|
|
376
353
|
continue;
|
|
377
354
|
}
|
|
378
|
-
const isIncluded = nodeIds.
|
|
355
|
+
const isIncluded = nodeIds.has(node.id);
|
|
379
356
|
const parentHit = !isIncluded && node.parentId && matchingNodes.find((n) => n.id === node.parentId);
|
|
380
357
|
if (isIncluded || parentHit) {
|
|
381
358
|
matchingNodes.push(node);
|
|
382
359
|
}
|
|
383
360
|
}
|
|
384
|
-
const edgeIds = edgesToRemove.map((edge) => edge.id);
|
|
361
|
+
const edgeIds = new Set(edgesToRemove.map((edge) => edge.id));
|
|
385
362
|
const deletableEdges = edges.filter((edge) => edge.deletable !== false);
|
|
386
363
|
const connectedEdges = getConnectedEdges(matchingNodes, deletableEdges);
|
|
387
364
|
const matchingEdges = connectedEdges;
|
|
388
365
|
for (const edge of deletableEdges) {
|
|
389
|
-
const isIncluded = edgeIds.
|
|
366
|
+
const isIncluded = edgeIds.has(edge.id);
|
|
390
367
|
if (isIncluded && !matchingEdges.find((e) => e.id === edge.id)) {
|
|
391
368
|
matchingEdges.push(edge);
|
|
392
369
|
}
|
|
@@ -453,19 +430,21 @@ const boxToRect = ({ x, y, x2, y2 }) => ({
|
|
|
453
430
|
height: y2 - y,
|
|
454
431
|
});
|
|
455
432
|
const nodeToRect = (node, nodeOrigin = [0, 0]) => {
|
|
456
|
-
const {
|
|
433
|
+
const { x, y } = getNodePositionWithOrigin(node, nodeOrigin).positionAbsolute;
|
|
457
434
|
return {
|
|
458
|
-
|
|
435
|
+
x,
|
|
436
|
+
y,
|
|
459
437
|
width: node.measured?.width ?? node.width ?? 0,
|
|
460
438
|
height: node.measured?.height ?? node.height ?? 0,
|
|
461
439
|
};
|
|
462
440
|
};
|
|
463
441
|
const nodeToBox = (node, nodeOrigin = [0, 0]) => {
|
|
464
|
-
const {
|
|
442
|
+
const { x, y } = getNodePositionWithOrigin(node, nodeOrigin).positionAbsolute;
|
|
465
443
|
return {
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
444
|
+
x,
|
|
445
|
+
y,
|
|
446
|
+
x2: x + (node.measured?.width ?? node.width ?? 0),
|
|
447
|
+
y2: y + (node.measured?.height ?? node.height ?? 0),
|
|
469
448
|
};
|
|
470
449
|
};
|
|
471
450
|
const getBoundsOfRects = (rect1, rect2) => boxToRect(getBoundsOfBoxes(rectToBox(rect1), rectToBox(rect2)));
|
|
@@ -553,6 +532,32 @@ function nodeHasDimensions(node) {
|
|
|
553
532
|
return ((node.measured?.width ?? node.width ?? node.initialWidth) !== undefined &&
|
|
554
533
|
(node.measured?.height ?? node.height ?? node.initialHeight) !== undefined);
|
|
555
534
|
}
|
|
535
|
+
/**
|
|
536
|
+
* Convert child position to aboslute position
|
|
537
|
+
*
|
|
538
|
+
* @internal
|
|
539
|
+
* @param position
|
|
540
|
+
* @param parentId
|
|
541
|
+
* @param nodeLookup
|
|
542
|
+
* @param nodeOrigin
|
|
543
|
+
* @returns an internal node with an absolute position
|
|
544
|
+
*/
|
|
545
|
+
function evaluateAbsolutePosition(position, parentId, nodeLookup, nodeOrigin = [0, 0]) {
|
|
546
|
+
let nextParentId = parentId;
|
|
547
|
+
const positionAbsolute = { ...position };
|
|
548
|
+
while (nextParentId) {
|
|
549
|
+
const parent = nodeLookup.get(parentId);
|
|
550
|
+
nextParentId = parent?.parentId;
|
|
551
|
+
if (parent) {
|
|
552
|
+
const origin = parent.origin || nodeOrigin;
|
|
553
|
+
const xOffset = (parent.measured.width ?? 0) * origin[0];
|
|
554
|
+
const yOffset = (parent.measured.height ?? 0) * origin[1];
|
|
555
|
+
positionAbsolute.x += parent.position.x - xOffset;
|
|
556
|
+
positionAbsolute.y += parent.position.y - yOffset;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return positionAbsolute;
|
|
560
|
+
}
|
|
556
561
|
|
|
557
562
|
function getPointerPosition(event, { snapGrid = [0, 0], snapToGrid = false, transform }) {
|
|
558
563
|
const { x, y } = getEventPosition(event);
|
|
@@ -1175,31 +1180,33 @@ function updateAbsolutePositions(nodeLookup, options = {
|
|
|
1175
1180
|
nodeOrigin: [0, 0],
|
|
1176
1181
|
elevateNodesOnSelect: true,
|
|
1177
1182
|
defaults: {},
|
|
1178
|
-
}
|
|
1183
|
+
}) {
|
|
1179
1184
|
const selectedNodeZ = options?.elevateNodesOnSelect ? 1000 : 0;
|
|
1180
|
-
for (const [
|
|
1185
|
+
for (const [, node] of nodeLookup) {
|
|
1181
1186
|
const parentId = node.parentId;
|
|
1182
|
-
if (
|
|
1187
|
+
if (!parentId) {
|
|
1188
|
+
continue;
|
|
1189
|
+
}
|
|
1190
|
+
if (!nodeLookup.has(parentId)) {
|
|
1183
1191
|
throw new Error(`Parent node ${parentId} not found`);
|
|
1184
1192
|
}
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
node.internals
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
}
|
|
1198
|
-
nodeLookup.set(id, node);
|
|
1193
|
+
const parentNode = nodeLookup.get(parentId);
|
|
1194
|
+
const { x, y, z } = calculateXYZPosition(node, nodeLookup, {
|
|
1195
|
+
...node.position,
|
|
1196
|
+
z: (isNumeric(node.zIndex) ? node.zIndex : 0) + (node.selected ? selectedNodeZ : 0),
|
|
1197
|
+
}, parentNode?.origin ?? options.nodeOrigin);
|
|
1198
|
+
const currPosition = node.internals.positionAbsolute;
|
|
1199
|
+
const positionChanged = x !== currPosition.x || y !== currPosition.y;
|
|
1200
|
+
if (positionChanged || z !== node.internals.z) {
|
|
1201
|
+
node.internals = {
|
|
1202
|
+
...node.internals,
|
|
1203
|
+
positionAbsolute: positionChanged ? { x, y } : currPosition,
|
|
1204
|
+
z,
|
|
1205
|
+
};
|
|
1199
1206
|
}
|
|
1200
1207
|
}
|
|
1201
1208
|
}
|
|
1202
|
-
function adoptUserNodes(nodes, nodeLookup, options = {
|
|
1209
|
+
function adoptUserNodes(nodes, nodeLookup, parentLookup, options = {
|
|
1203
1210
|
nodeOrigin: [0, 0],
|
|
1204
1211
|
elevateNodesOnSelect: true,
|
|
1205
1212
|
defaults: {},
|
|
@@ -1207,18 +1214,15 @@ function adoptUserNodes(nodes, nodeLookup, options = {
|
|
|
1207
1214
|
}) {
|
|
1208
1215
|
const tmpLookup = new Map(nodeLookup);
|
|
1209
1216
|
nodeLookup.clear();
|
|
1217
|
+
parentLookup.clear();
|
|
1210
1218
|
const selectedNodeZ = options?.elevateNodesOnSelect ? 1000 : 0;
|
|
1211
|
-
const parentNodeIds = new Set();
|
|
1212
1219
|
nodes.forEach((userNode) => {
|
|
1213
|
-
|
|
1214
|
-
if (userNode.
|
|
1215
|
-
|
|
1216
|
-
}
|
|
1217
|
-
if (options.checkEquality && userNode === currentStoreNode?.internals.userNode) {
|
|
1218
|
-
nodeLookup.set(userNode.id, currentStoreNode);
|
|
1220
|
+
let internalNode = tmpLookup.get(userNode.id);
|
|
1221
|
+
if (options.checkEquality && userNode === internalNode?.internals.userNode) {
|
|
1222
|
+
nodeLookup.set(userNode.id, internalNode);
|
|
1219
1223
|
}
|
|
1220
1224
|
else {
|
|
1221
|
-
|
|
1225
|
+
internalNode = {
|
|
1222
1226
|
...options.defaults,
|
|
1223
1227
|
...userNode,
|
|
1224
1228
|
measured: {
|
|
@@ -1227,79 +1231,93 @@ function adoptUserNodes(nodes, nodeLookup, options = {
|
|
|
1227
1231
|
},
|
|
1228
1232
|
internals: {
|
|
1229
1233
|
positionAbsolute: userNode.position,
|
|
1230
|
-
handleBounds:
|
|
1234
|
+
handleBounds: internalNode?.internals.handleBounds,
|
|
1231
1235
|
z: (isNumeric(userNode.zIndex) ? userNode.zIndex : 0) + (userNode.selected ? selectedNodeZ : 0),
|
|
1232
1236
|
userNode,
|
|
1233
|
-
isParent: false,
|
|
1234
1237
|
},
|
|
1235
|
-
}
|
|
1238
|
+
};
|
|
1239
|
+
nodeLookup.set(userNode.id, internalNode);
|
|
1240
|
+
}
|
|
1241
|
+
if (userNode.parentId) {
|
|
1242
|
+
const childNodes = parentLookup.get(userNode.parentId);
|
|
1243
|
+
if (childNodes) {
|
|
1244
|
+
childNodes.push(internalNode);
|
|
1245
|
+
}
|
|
1246
|
+
else {
|
|
1247
|
+
parentLookup.set(userNode.parentId, [internalNode]);
|
|
1248
|
+
}
|
|
1236
1249
|
}
|
|
1237
1250
|
});
|
|
1238
|
-
if (
|
|
1239
|
-
updateAbsolutePositions(nodeLookup, options
|
|
1251
|
+
if (parentLookup.size > 0) {
|
|
1252
|
+
updateAbsolutePositions(nodeLookup, options);
|
|
1240
1253
|
}
|
|
1241
1254
|
}
|
|
1242
1255
|
function calculateXYZPosition(node, nodeLookup, result, nodeOrigin = [0, 0]) {
|
|
1243
1256
|
if (!node.parentId) {
|
|
1244
1257
|
return result;
|
|
1245
1258
|
}
|
|
1246
|
-
const
|
|
1247
|
-
const
|
|
1248
|
-
return calculateXYZPosition(
|
|
1249
|
-
x: (result.x ?? 0) +
|
|
1250
|
-
y: (result.y ?? 0) +
|
|
1251
|
-
z: (
|
|
1252
|
-
},
|
|
1253
|
-
}
|
|
1254
|
-
function
|
|
1259
|
+
const parent = nodeLookup.get(node.parentId);
|
|
1260
|
+
const parentPosition = getNodePositionWithOrigin(parent, nodeOrigin).position;
|
|
1261
|
+
return calculateXYZPosition(parent, nodeLookup, {
|
|
1262
|
+
x: (result.x ?? 0) + parentPosition.x,
|
|
1263
|
+
y: (result.y ?? 0) + parentPosition.y,
|
|
1264
|
+
z: (parent.internals.z ?? 0) > (result.z ?? 0) ? parent.internals.z ?? 0 : result.z ?? 0,
|
|
1265
|
+
}, parent.origin || nodeOrigin);
|
|
1266
|
+
}
|
|
1267
|
+
function handleExpandParent(children, nodeLookup, parentLookup, nodeOrigin) {
|
|
1255
1268
|
const changes = [];
|
|
1256
|
-
const
|
|
1257
|
-
nodes
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
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
|
-
}
|
|
1269
|
+
const parentExpansions = new Map();
|
|
1270
|
+
// determine the expanded rectangle the child nodes would take for each parent
|
|
1271
|
+
for (const child of children) {
|
|
1272
|
+
const parent = nodeLookup.get(child.parentId);
|
|
1273
|
+
if (!parent) {
|
|
1274
|
+
continue;
|
|
1266
1275
|
}
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
+
const parentRect = parentExpansions.get(child.parentId)?.expandedRect ?? nodeToRect(parent, parent.origin ?? nodeOrigin);
|
|
1277
|
+
const expandedRect = getBoundsOfRects(parentRect, child.rect);
|
|
1278
|
+
parentExpansions.set(child.parentId, { expandedRect, parent });
|
|
1279
|
+
}
|
|
1280
|
+
if (parentExpansions.size > 0) {
|
|
1281
|
+
parentExpansions.forEach(({ expandedRect, parent }, parentId) => {
|
|
1282
|
+
// determine the position & dimensions of the parent
|
|
1283
|
+
const { position } = getNodePositionWithOrigin(parent, parent.origin);
|
|
1284
|
+
const dimensions = getNodeDimensions(parent);
|
|
1285
|
+
// determine how much the parent expands by moving the position
|
|
1286
|
+
const xChange = expandedRect.x < position.x ? Math.round(Math.abs(position.x - expandedRect.x)) : 0;
|
|
1287
|
+
const yChange = expandedRect.y < position.y ? Math.round(Math.abs(position.y - expandedRect.y)) : 0;
|
|
1288
|
+
if (xChange > 0 || yChange > 0) {
|
|
1276
1289
|
changes.push({
|
|
1277
|
-
id,
|
|
1290
|
+
id: parentId,
|
|
1278
1291
|
type: 'position',
|
|
1279
1292
|
position: {
|
|
1280
1293
|
x: position.x - xChange,
|
|
1281
1294
|
y: position.y - yChange,
|
|
1282
1295
|
},
|
|
1283
1296
|
});
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1297
|
+
// We move all child nodes in the oppsite direction
|
|
1298
|
+
// so the x,y changes of the parent do not move the children
|
|
1299
|
+
const childNodes = parentLookup.get(parentId);
|
|
1300
|
+
childNodes?.forEach((childNode) => {
|
|
1301
|
+
if (!children.some((child) => child.id === childNode.id)) {
|
|
1302
|
+
changes.push({
|
|
1303
|
+
id: childNode.id,
|
|
1304
|
+
type: 'position',
|
|
1305
|
+
position: {
|
|
1306
|
+
x: childNode.position.x + xChange,
|
|
1307
|
+
y: childNode.position.y + yChange,
|
|
1308
|
+
},
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1292
1311
|
});
|
|
1293
|
-
// @todo we need to reset child node positions if < 0
|
|
1294
1312
|
}
|
|
1295
|
-
|
|
1313
|
+
if (dimensions.width < expandedRect.width || dimensions.height < expandedRect.height) {
|
|
1296
1314
|
changes.push({
|
|
1297
|
-
id,
|
|
1315
|
+
id: parentId,
|
|
1298
1316
|
type: 'dimensions',
|
|
1299
|
-
|
|
1317
|
+
setAttributes: true,
|
|
1300
1318
|
dimensions: {
|
|
1301
|
-
width: Math.max(dimensions.width,
|
|
1302
|
-
height: Math.max(dimensions.height,
|
|
1319
|
+
width: Math.max(dimensions.width, Math.round(expandedRect.width)),
|
|
1320
|
+
height: Math.max(dimensions.height, Math.round(expandedRect.height)),
|
|
1303
1321
|
},
|
|
1304
1322
|
});
|
|
1305
1323
|
}
|
|
@@ -1307,7 +1325,7 @@ function handleParentExpand(nodes, nodeLookup) {
|
|
|
1307
1325
|
}
|
|
1308
1326
|
return changes;
|
|
1309
1327
|
}
|
|
1310
|
-
function updateNodeInternals(updates, nodeLookup, domNode, nodeOrigin) {
|
|
1328
|
+
function updateNodeInternals(updates, nodeLookup, parentLookup, domNode, nodeOrigin) {
|
|
1311
1329
|
const viewportNode = domNode?.querySelector('.xyflow__viewport');
|
|
1312
1330
|
let updatedInternals = false;
|
|
1313
1331
|
if (!viewportNode) {
|
|
@@ -1317,7 +1335,7 @@ function updateNodeInternals(updates, nodeLookup, domNode, nodeOrigin) {
|
|
|
1317
1335
|
const style = window.getComputedStyle(viewportNode);
|
|
1318
1336
|
const { m22: zoom } = new window.DOMMatrixReadOnly(style.transform);
|
|
1319
1337
|
// in this array we collect nodes, that might trigger changes (like expanding parent)
|
|
1320
|
-
const
|
|
1338
|
+
const parentExpandChildren = [];
|
|
1321
1339
|
updates.forEach((update) => {
|
|
1322
1340
|
const node = nodeLookup.get(update.id);
|
|
1323
1341
|
if (node?.hidden) {
|
|
@@ -1356,15 +1374,19 @@ function updateNodeInternals(updates, nodeLookup, domNode, nodeOrigin) {
|
|
|
1356
1374
|
type: 'dimensions',
|
|
1357
1375
|
dimensions,
|
|
1358
1376
|
});
|
|
1359
|
-
if (newNode.expandParent) {
|
|
1360
|
-
|
|
1377
|
+
if (newNode.expandParent && newNode.parentId) {
|
|
1378
|
+
parentExpandChildren.push({
|
|
1379
|
+
id: newNode.id,
|
|
1380
|
+
parentId: newNode.parentId,
|
|
1381
|
+
rect: nodeToRect(newNode, newNode.origin || nodeOrigin),
|
|
1382
|
+
});
|
|
1361
1383
|
}
|
|
1362
1384
|
}
|
|
1363
1385
|
}
|
|
1364
1386
|
}
|
|
1365
1387
|
});
|
|
1366
|
-
if (
|
|
1367
|
-
const parentExpandChanges =
|
|
1388
|
+
if (parentExpandChildren.length > 0) {
|
|
1389
|
+
const parentExpandChanges = handleExpandParent(parentExpandChildren, nodeLookup, parentLookup, nodeOrigin);
|
|
1368
1390
|
changes.push(...parentExpandChanges);
|
|
1369
1391
|
}
|
|
1370
1392
|
return { changes, updatedInternals };
|
|
@@ -1418,9 +1440,6 @@ function shallowNodeData(a, b) {
|
|
|
1418
1440
|
return true;
|
|
1419
1441
|
}
|
|
1420
1442
|
|
|
1421
|
-
function wrapSelectionDragFunc(selectionFunc) {
|
|
1422
|
-
return (event, _, nodes) => selectionFunc?.(event, nodes);
|
|
1423
|
-
}
|
|
1424
1443
|
function isParentSelected(node, nodeLookup) {
|
|
1425
1444
|
if (!node.parentId) {
|
|
1426
1445
|
return false;
|
|
@@ -1447,31 +1466,33 @@ function hasSelector(target, selector, domNode) {
|
|
|
1447
1466
|
}
|
|
1448
1467
|
// looks for all selected nodes and created a NodeDragItem for each of them
|
|
1449
1468
|
function getDragItems(nodeLookup, nodesDraggable, mousePos, nodeId) {
|
|
1450
|
-
const dragItems =
|
|
1469
|
+
const dragItems = new Map();
|
|
1451
1470
|
for (const [id, node] of nodeLookup) {
|
|
1452
1471
|
if ((node.selected || node.id === nodeId) &&
|
|
1453
1472
|
(!node.parentId || !isParentSelected(node, nodeLookup)) &&
|
|
1454
1473
|
(node.draggable || (nodesDraggable && typeof node.draggable === 'undefined'))) {
|
|
1455
1474
|
const internalNode = nodeLookup.get(id);
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
+
if (internalNode) {
|
|
1476
|
+
dragItems.set(id, {
|
|
1477
|
+
id,
|
|
1478
|
+
position: internalNode.position || { x: 0, y: 0 },
|
|
1479
|
+
distance: {
|
|
1480
|
+
x: mousePos.x - internalNode.internals.positionAbsolute.x,
|
|
1481
|
+
y: mousePos.y - internalNode.internals.positionAbsolute.y,
|
|
1482
|
+
},
|
|
1483
|
+
extent: internalNode.extent,
|
|
1484
|
+
parentId: internalNode.parentId,
|
|
1485
|
+
origin: internalNode.origin,
|
|
1486
|
+
expandParent: internalNode.expandParent,
|
|
1487
|
+
internals: {
|
|
1488
|
+
positionAbsolute: internalNode.internals.positionAbsolute || { x: 0, y: 0 },
|
|
1489
|
+
},
|
|
1490
|
+
measured: {
|
|
1491
|
+
width: internalNode.measured.width ?? 0,
|
|
1492
|
+
height: internalNode.measured.height ?? 0,
|
|
1493
|
+
},
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1475
1496
|
}
|
|
1476
1497
|
}
|
|
1477
1498
|
return dragItems;
|
|
@@ -1480,24 +1501,34 @@ function getDragItems(nodeLookup, nodesDraggable, mousePos, nodeId) {
|
|
|
1480
1501
|
// 1. the dragged node (or the first of the list, if we are dragging a node selection)
|
|
1481
1502
|
// 2. array of selected nodes (for multi selections)
|
|
1482
1503
|
function getEventHandlerParams({ nodeId, dragItems, nodeLookup, }) {
|
|
1483
|
-
const nodesFromDragItems =
|
|
1484
|
-
|
|
1485
|
-
|
|
1504
|
+
const nodesFromDragItems = [];
|
|
1505
|
+
for (const [id, dragItem] of dragItems) {
|
|
1506
|
+
const node = nodeLookup.get(id)?.internals.userNode;
|
|
1507
|
+
if (node) {
|
|
1508
|
+
nodesFromDragItems.push({
|
|
1509
|
+
...node,
|
|
1510
|
+
position: dragItem.position,
|
|
1511
|
+
});
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
if (!nodeId) {
|
|
1515
|
+
return [nodesFromDragItems[0], nodesFromDragItems];
|
|
1516
|
+
}
|
|
1517
|
+
const node = nodeLookup.get(nodeId).internals.userNode;
|
|
1518
|
+
return [
|
|
1519
|
+
{
|
|
1486
1520
|
...node,
|
|
1487
|
-
position:
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
};
|
|
1492
|
-
});
|
|
1493
|
-
return [nodeId ? nodesFromDragItems.find((n) => n.id === nodeId) : nodesFromDragItems[0], nodesFromDragItems];
|
|
1521
|
+
position: dragItems.get(nodeId)?.position || node.position,
|
|
1522
|
+
},
|
|
1523
|
+
nodesFromDragItems,
|
|
1524
|
+
];
|
|
1494
1525
|
}
|
|
1495
1526
|
|
|
1496
1527
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1497
1528
|
function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragStop, }) {
|
|
1498
1529
|
let lastPos = { x: null, y: null };
|
|
1499
1530
|
let autoPanId = 0;
|
|
1500
|
-
let dragItems =
|
|
1531
|
+
let dragItems = new Map();
|
|
1501
1532
|
let autoPanStarted = false;
|
|
1502
1533
|
let mousePosition = { x: 0, y: 0 };
|
|
1503
1534
|
let containerBounds = null;
|
|
@@ -1511,12 +1542,12 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
|
|
|
1511
1542
|
lastPos = { x, y };
|
|
1512
1543
|
let hasChange = false;
|
|
1513
1544
|
let nodesBox = { x: 0, y: 0, x2: 0, y2: 0 };
|
|
1514
|
-
if (dragItems.
|
|
1515
|
-
const rect =
|
|
1545
|
+
if (dragItems.size > 1 && nodeExtent) {
|
|
1546
|
+
const rect = getInternalNodesBounds(dragItems, { nodeOrigin });
|
|
1516
1547
|
nodesBox = rectToBox(rect);
|
|
1517
1548
|
}
|
|
1518
|
-
|
|
1519
|
-
let nextPosition = { x: x -
|
|
1549
|
+
for (const [id, dragItem] of dragItems) {
|
|
1550
|
+
let nextPosition = { x: x - dragItem.distance.x, y: y - dragItem.distance.y };
|
|
1520
1551
|
if (snapToGrid) {
|
|
1521
1552
|
nextPosition = snapPosition(nextPosition, snapGrid);
|
|
1522
1553
|
}
|
|
@@ -1526,19 +1557,19 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
|
|
|
1526
1557
|
[nodeExtent[0][0], nodeExtent[0][1]],
|
|
1527
1558
|
[nodeExtent[1][0], nodeExtent[1][1]],
|
|
1528
1559
|
];
|
|
1529
|
-
if (dragItems.
|
|
1530
|
-
const { positionAbsolute } =
|
|
1560
|
+
if (dragItems.size > 1 && nodeExtent && !dragItem.extent) {
|
|
1561
|
+
const { positionAbsolute } = dragItem.internals;
|
|
1531
1562
|
const x1 = positionAbsolute.x - nodesBox.x + nodeExtent[0][0];
|
|
1532
|
-
const x2 = positionAbsolute.x +
|
|
1563
|
+
const x2 = positionAbsolute.x + dragItem.measured.width - nodesBox.x2 + nodeExtent[1][0];
|
|
1533
1564
|
const y1 = positionAbsolute.y - nodesBox.y + nodeExtent[0][1];
|
|
1534
|
-
const y2 = positionAbsolute.y +
|
|
1565
|
+
const y2 = positionAbsolute.y + dragItem.measured.height - nodesBox.y2 + nodeExtent[1][1];
|
|
1535
1566
|
adjustedNodeExtent = [
|
|
1536
1567
|
[x1, y1],
|
|
1537
1568
|
[x2, y2],
|
|
1538
1569
|
];
|
|
1539
1570
|
}
|
|
1540
1571
|
const { position, positionAbsolute } = calculateNodePosition({
|
|
1541
|
-
nodeId:
|
|
1572
|
+
nodeId: id,
|
|
1542
1573
|
nextPosition,
|
|
1543
1574
|
nodeLookup,
|
|
1544
1575
|
nodeExtent: adjustedNodeExtent,
|
|
@@ -1546,11 +1577,10 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
|
|
|
1546
1577
|
onError,
|
|
1547
1578
|
});
|
|
1548
1579
|
// we want to make sure that we only fire a change event when there is a change
|
|
1549
|
-
hasChange = hasChange ||
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
});
|
|
1580
|
+
hasChange = hasChange || dragItem.position.x !== position.x || dragItem.position.y !== position.y;
|
|
1581
|
+
dragItem.position = position;
|
|
1582
|
+
dragItem.internals.positionAbsolute = positionAbsolute;
|
|
1583
|
+
}
|
|
1554
1584
|
if (!hasChange) {
|
|
1555
1585
|
return;
|
|
1556
1586
|
}
|
|
@@ -1564,8 +1594,7 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
|
|
|
1564
1594
|
onDrag?.(dragEvent, dragItems, currentNode, currentNodes);
|
|
1565
1595
|
onNodeDrag?.(dragEvent, currentNode, currentNodes);
|
|
1566
1596
|
if (!nodeId) {
|
|
1567
|
-
|
|
1568
|
-
_onSelectionDrag(dragEvent, currentNode, currentNodes);
|
|
1597
|
+
onSelectionDrag?.(dragEvent, currentNodes);
|
|
1569
1598
|
}
|
|
1570
1599
|
}
|
|
1571
1600
|
}
|
|
@@ -1599,7 +1628,7 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
|
|
|
1599
1628
|
const pointerPos = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
|
|
1600
1629
|
lastPos = pointerPos;
|
|
1601
1630
|
dragItems = getDragItems(nodeLookup, nodesDraggable, pointerPos, nodeId);
|
|
1602
|
-
if (dragItems.
|
|
1631
|
+
if (dragItems.size > 0 && (onDragStart || onNodeDragStart || (!nodeId && onSelectionDragStart))) {
|
|
1603
1632
|
const [currentNode, currentNodes] = getEventHandlerParams({
|
|
1604
1633
|
nodeId,
|
|
1605
1634
|
dragItems,
|
|
@@ -1608,8 +1637,7 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
|
|
|
1608
1637
|
onDragStart?.(event.sourceEvent, dragItems, currentNode, currentNodes);
|
|
1609
1638
|
onNodeDragStart?.(event.sourceEvent, currentNode, currentNodes);
|
|
1610
1639
|
if (!nodeId) {
|
|
1611
|
-
|
|
1612
|
-
_onSelectionDragStart(event.sourceEvent, currentNode, currentNodes);
|
|
1640
|
+
onSelectionDragStart?.(event.sourceEvent, currentNodes);
|
|
1613
1641
|
}
|
|
1614
1642
|
}
|
|
1615
1643
|
}
|
|
@@ -1653,7 +1681,7 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
|
|
|
1653
1681
|
autoPanStarted = false;
|
|
1654
1682
|
dragStarted = false;
|
|
1655
1683
|
cancelAnimationFrame(autoPanId);
|
|
1656
|
-
if (dragItems.
|
|
1684
|
+
if (dragItems.size > 0) {
|
|
1657
1685
|
const { nodeLookup, updateNodePositions, onNodeDragStop, onSelectionDragStop } = getStoreItems();
|
|
1658
1686
|
updateNodePositions(dragItems, false);
|
|
1659
1687
|
if (onDragStop || onNodeDragStop || (!nodeId && onSelectionDragStop)) {
|
|
@@ -1665,8 +1693,7 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
|
|
|
1665
1693
|
onDragStop?.(event.sourceEvent, dragItems, currentNode, currentNodes);
|
|
1666
1694
|
onNodeDragStop?.(event.sourceEvent, currentNode, currentNodes);
|
|
1667
1695
|
if (!nodeId) {
|
|
1668
|
-
|
|
1669
|
-
_onSelectionDragStop(event.sourceEvent, currentNode, currentNodes);
|
|
1696
|
+
onSelectionDragStop?.(event.sourceEvent, currentNodes);
|
|
1670
1697
|
}
|
|
1671
1698
|
}
|
|
1672
1699
|
}
|
|
@@ -1945,15 +1972,30 @@ function XYMinimap({ domNode, panZoom, getTransform, getViewScale }) {
|
|
|
1945
1972
|
const nextZoom = transform[2] * Math.pow(2, pinchDelta);
|
|
1946
1973
|
panZoom.scaleTo(nextZoom);
|
|
1947
1974
|
};
|
|
1975
|
+
let panStart = [0, 0];
|
|
1976
|
+
const panStartHandler = (event) => {
|
|
1977
|
+
if (event.sourceEvent.type === 'mousedown' || event.sourceEvent.type === 'touchstart') {
|
|
1978
|
+
panStart = [
|
|
1979
|
+
event.sourceEvent.clientX ?? event.sourceEvent.touches[0].clientX,
|
|
1980
|
+
event.sourceEvent.clientY ?? event.sourceEvent.touches[0].clientY,
|
|
1981
|
+
];
|
|
1982
|
+
}
|
|
1983
|
+
};
|
|
1948
1984
|
const panHandler = (event) => {
|
|
1949
1985
|
const transform = getTransform();
|
|
1950
|
-
if (event.sourceEvent.type !== 'mousemove' || !panZoom) {
|
|
1986
|
+
if ((event.sourceEvent.type !== 'mousemove' && event.sourceEvent.type !== 'touchmove') || !panZoom) {
|
|
1951
1987
|
return;
|
|
1952
1988
|
}
|
|
1989
|
+
const panCurrent = [
|
|
1990
|
+
event.sourceEvent.clientX ?? event.sourceEvent.touches[0].clientX,
|
|
1991
|
+
event.sourceEvent.clientY ?? event.sourceEvent.touches[0].clientY,
|
|
1992
|
+
];
|
|
1993
|
+
const panDelta = [panCurrent[0] - panStart[0], panCurrent[1] - panStart[1]];
|
|
1994
|
+
panStart = panCurrent;
|
|
1953
1995
|
const moveScale = getViewScale() * Math.max(transform[2], Math.log(transform[2])) * (inversePan ? -1 : 1);
|
|
1954
1996
|
const position = {
|
|
1955
|
-
x: transform[0] -
|
|
1956
|
-
y: transform[1] -
|
|
1997
|
+
x: transform[0] - panDelta[0] * moveScale,
|
|
1998
|
+
y: transform[1] - panDelta[1] * moveScale,
|
|
1957
1999
|
};
|
|
1958
2000
|
const extent = [
|
|
1959
2001
|
[0, 0],
|
|
@@ -1966,6 +2008,7 @@ function XYMinimap({ domNode, panZoom, getTransform, getViewScale }) {
|
|
|
1966
2008
|
}, extent, translateExtent);
|
|
1967
2009
|
};
|
|
1968
2010
|
const zoomAndPanHandler = zoom()
|
|
2011
|
+
.on('start', panStartHandler)
|
|
1969
2012
|
// @ts-ignore
|
|
1970
2013
|
.on('zoom', pannable ? panHandler : null)
|
|
1971
2014
|
// @ts-ignore
|
|
@@ -1982,6 +2025,7 @@ function XYMinimap({ domNode, panZoom, getTransform, getViewScale }) {
|
|
|
1982
2025
|
};
|
|
1983
2026
|
}
|
|
1984
2027
|
|
|
2028
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1985
2029
|
const viewChanged = (prevViewport, eventViewport) => prevViewport.x !== eventViewport.x || prevViewport.y !== eventViewport.y || prevViewport.zoom !== eventViewport.k;
|
|
1986
2030
|
const transformToViewport = (transform) => ({
|
|
1987
2031
|
x: transform.x,
|
|
@@ -2005,9 +2049,8 @@ function createPanOnScrollHandler({ zoomPanValues, noWheelClassName, d3Selection
|
|
|
2005
2049
|
event.preventDefault();
|
|
2006
2050
|
event.stopImmediatePropagation();
|
|
2007
2051
|
const currentZoom = d3Selection.property('__zoom').k || 1;
|
|
2008
|
-
const _isMacOs = isMacOs();
|
|
2009
2052
|
// macos sets ctrlKey=true for pinch gesture on a trackpad
|
|
2010
|
-
if (event.ctrlKey && zoomOnPinch
|
|
2053
|
+
if (event.ctrlKey && zoomOnPinch) {
|
|
2011
2054
|
const point = pointer(event);
|
|
2012
2055
|
const pinchDelta = wheelDelta(event);
|
|
2013
2056
|
const zoom = currentZoom * Math.pow(2, pinchDelta);
|
|
@@ -2021,7 +2064,7 @@ function createPanOnScrollHandler({ zoomPanValues, noWheelClassName, d3Selection
|
|
|
2021
2064
|
let deltaX = panOnScrollMode === PanOnScrollMode.Vertical ? 0 : event.deltaX * deltaNormalize;
|
|
2022
2065
|
let deltaY = panOnScrollMode === PanOnScrollMode.Horizontal ? 0 : event.deltaY * deltaNormalize;
|
|
2023
2066
|
// this enables vertical scrolling with shift + scroll on windows
|
|
2024
|
-
if (!
|
|
2067
|
+
if (!isMacOs() && event.shiftKey && panOnScrollMode !== PanOnScrollMode.Vertical) {
|
|
2025
2068
|
deltaX = event.deltaY * deltaNormalize;
|
|
2026
2069
|
deltaY = 0;
|
|
2027
2070
|
}
|
|
@@ -2152,9 +2195,7 @@ function createFilter({ zoomActivationKeyPressed, zoomOnScroll, zoomOnPinch, pan
|
|
|
2152
2195
|
return false;
|
|
2153
2196
|
}
|
|
2154
2197
|
// if the pane is only movable using allowed clicks
|
|
2155
|
-
if (Array.isArray(panOnDrag) &&
|
|
2156
|
-
!panOnDrag.includes(event.button) &&
|
|
2157
|
-
(event.type === 'mousedown' || event.type === 'touchstart')) {
|
|
2198
|
+
if (Array.isArray(panOnDrag) && !panOnDrag.includes(event.button) && event.type === 'mousedown') {
|
|
2158
2199
|
return false;
|
|
2159
2200
|
}
|
|
2160
2201
|
// We only allow right clicks if pan on drag is set to right click
|
|
@@ -2292,6 +2333,7 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
|
|
|
2292
2333
|
if (currentTransform.k !== viewport.zoom ||
|
|
2293
2334
|
currentTransform.x !== viewport.x ||
|
|
2294
2335
|
currentTransform.y !== viewport.y) {
|
|
2336
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2295
2337
|
// @ts-ignore
|
|
2296
2338
|
d3ZoomInstance?.transform(d3Selection, nextTransform, null, { sync: true });
|
|
2297
2339
|
}
|
|
@@ -2565,16 +2607,6 @@ const initStartValues = {
|
|
|
2565
2607
|
pointerY: 0,
|
|
2566
2608
|
aspectRatio: 1,
|
|
2567
2609
|
};
|
|
2568
|
-
const initChange = {
|
|
2569
|
-
x: 0,
|
|
2570
|
-
y: 0,
|
|
2571
|
-
width: 0,
|
|
2572
|
-
height: 0,
|
|
2573
|
-
isXPosChange: false,
|
|
2574
|
-
isYPosChange: false,
|
|
2575
|
-
isWidthChange: false,
|
|
2576
|
-
isHeightChange: false,
|
|
2577
|
-
};
|
|
2578
2610
|
function nodeToParentExtent(node) {
|
|
2579
2611
|
return [
|
|
2580
2612
|
[0, 0],
|
|
@@ -2593,7 +2625,7 @@ function nodeToChildExtent(child, parent, nodeOrigin) {
|
|
|
2593
2625
|
[x + width - originOffsetX, y + height - originOffsetY],
|
|
2594
2626
|
];
|
|
2595
2627
|
}
|
|
2596
|
-
function XYResizer({ domNode, nodeId, getStoreItems, onChange }) {
|
|
2628
|
+
function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
|
|
2597
2629
|
const selection = select(domNode);
|
|
2598
2630
|
function update({ controlPosition, boundaries, keepAspectRatio, onResizeStart, onResize, onResizeEnd, shouldResize, }) {
|
|
2599
2631
|
let prevValues = { ...initPrevValues };
|
|
@@ -2608,128 +2640,127 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange }) {
|
|
|
2608
2640
|
.on('start', (event) => {
|
|
2609
2641
|
const { nodeLookup, transform, snapGrid, snapToGrid, nodeOrigin } = getStoreItems();
|
|
2610
2642
|
node = nodeLookup.get(nodeId);
|
|
2611
|
-
if (node) {
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2643
|
+
if (!node) {
|
|
2644
|
+
return;
|
|
2645
|
+
}
|
|
2646
|
+
const { xSnapped, ySnapped } = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
|
|
2647
|
+
prevValues = {
|
|
2648
|
+
width: node.measured?.width ?? 0,
|
|
2649
|
+
height: node.measured?.height ?? 0,
|
|
2650
|
+
x: node.position.x ?? 0,
|
|
2651
|
+
y: node.position.y ?? 0,
|
|
2652
|
+
};
|
|
2653
|
+
startValues = {
|
|
2654
|
+
...prevValues,
|
|
2655
|
+
pointerX: xSnapped,
|
|
2656
|
+
pointerY: ySnapped,
|
|
2657
|
+
aspectRatio: prevValues.width / prevValues.height,
|
|
2658
|
+
};
|
|
2659
|
+
parentNode = undefined;
|
|
2660
|
+
if (node.extent === 'parent' || node.expandParent) {
|
|
2661
|
+
parentNode = nodeLookup.get(node.parentId);
|
|
2662
|
+
if (parentNode && node.extent === 'parent') {
|
|
2663
|
+
parentExtent = nodeToParentExtent(parentNode);
|
|
2631
2664
|
}
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
]
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2665
|
+
}
|
|
2666
|
+
// Collect all child nodes to correct their relative positions when top/left changes
|
|
2667
|
+
// Determine largest minimal extent the parent node is allowed to resize to
|
|
2668
|
+
childNodes = [];
|
|
2669
|
+
childExtent = undefined;
|
|
2670
|
+
for (const [childId, child] of nodeLookup) {
|
|
2671
|
+
if (child.parentId === nodeId) {
|
|
2672
|
+
childNodes.push({
|
|
2673
|
+
id: childId,
|
|
2674
|
+
position: { ...child.position },
|
|
2675
|
+
extent: child.extent,
|
|
2676
|
+
});
|
|
2677
|
+
if (child.extent === 'parent' || child.expandParent) {
|
|
2678
|
+
const extent = nodeToChildExtent(child, node, child.origin ?? nodeOrigin);
|
|
2679
|
+
if (childExtent) {
|
|
2680
|
+
childExtent = [
|
|
2681
|
+
[Math.min(extent[0][0], childExtent[0][0]), Math.min(extent[0][1], childExtent[0][1])],
|
|
2682
|
+
[Math.max(extent[1][0], childExtent[1][0]), Math.max(extent[1][1], childExtent[1][1])],
|
|
2683
|
+
];
|
|
2684
|
+
}
|
|
2685
|
+
else {
|
|
2686
|
+
childExtent = extent;
|
|
2654
2687
|
}
|
|
2655
2688
|
}
|
|
2656
2689
|
}
|
|
2657
|
-
onResizeStart?.(event, { ...prevValues });
|
|
2658
2690
|
}
|
|
2691
|
+
onResizeStart?.(event, { ...prevValues });
|
|
2659
2692
|
})
|
|
2660
2693
|
.on('drag', (event) => {
|
|
2661
2694
|
const { transform, snapGrid, snapToGrid, nodeOrigin: storeNodeOrigin } = getStoreItems();
|
|
2662
2695
|
const pointerPosition = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
|
|
2663
2696
|
const childChanges = [];
|
|
2664
|
-
if (node) {
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
startValues.y = startValues.y - change.y;
|
|
2689
|
-
}
|
|
2697
|
+
if (!node) {
|
|
2698
|
+
return;
|
|
2699
|
+
}
|
|
2700
|
+
const { x: prevX, y: prevY, width: prevWidth, height: prevHeight } = prevValues;
|
|
2701
|
+
const change = {};
|
|
2702
|
+
const nodeOrigin = node.origin ?? storeNodeOrigin;
|
|
2703
|
+
const { width, height, x, y } = getDimensionsAfterResize(startValues, controlDirection, pointerPosition, boundaries, keepAspectRatio, nodeOrigin, parentExtent, childExtent);
|
|
2704
|
+
const isWidthChange = width !== prevWidth;
|
|
2705
|
+
const isHeightChange = height !== prevHeight;
|
|
2706
|
+
const isXPosChange = x !== prevX && isWidthChange;
|
|
2707
|
+
const isYPosChange = y !== prevY && isHeightChange;
|
|
2708
|
+
if (!isXPosChange && !isYPosChange && !isWidthChange && !isHeightChange) {
|
|
2709
|
+
return;
|
|
2710
|
+
}
|
|
2711
|
+
if (isXPosChange || isYPosChange || nodeOrigin[0] === 1 || nodeOrigin[1] == 1) {
|
|
2712
|
+
change.x = isXPosChange ? x : prevValues.x;
|
|
2713
|
+
change.y = isYPosChange ? y : prevValues.y;
|
|
2714
|
+
prevValues.x = change.x;
|
|
2715
|
+
prevValues.y = change.y;
|
|
2716
|
+
// Fix expandParent when resizing from top/left
|
|
2717
|
+
if (parentNode && node.expandParent) {
|
|
2718
|
+
if (change.x && change.x < 0) {
|
|
2719
|
+
prevValues.x = 0;
|
|
2720
|
+
startValues.x = startValues.x - change.x;
|
|
2690
2721
|
}
|
|
2691
|
-
if (
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
for (const childNode of childNodes) {
|
|
2695
|
-
childNode.position = {
|
|
2696
|
-
x: childNode.position.x - xChange + nodeOrigin[0] * (width - prevWidth),
|
|
2697
|
-
y: childNode.position.y - yChange + nodeOrigin[1] * (height - prevHeight),
|
|
2698
|
-
};
|
|
2699
|
-
childChanges.push(childNode);
|
|
2700
|
-
}
|
|
2722
|
+
if (change.y && change.y < 0) {
|
|
2723
|
+
prevValues.y = 0;
|
|
2724
|
+
startValues.y = startValues.y - change.y;
|
|
2701
2725
|
}
|
|
2702
2726
|
}
|
|
2703
|
-
if (
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
}
|
|
2714
|
-
const direction = getResizeDirection({
|
|
2715
|
-
width: prevValues.width,
|
|
2716
|
-
prevWidth,
|
|
2717
|
-
height: prevValues.height,
|
|
2718
|
-
prevHeight,
|
|
2719
|
-
affectsX: controlDirection.affectsX,
|
|
2720
|
-
affectsY: controlDirection.affectsY,
|
|
2721
|
-
});
|
|
2722
|
-
const nextValues = { ...prevValues, direction };
|
|
2723
|
-
const callResize = shouldResize?.(event, nextValues);
|
|
2724
|
-
if (callResize === false) {
|
|
2725
|
-
return;
|
|
2727
|
+
if (childNodes.length > 0) {
|
|
2728
|
+
const xChange = x - prevX;
|
|
2729
|
+
const yChange = y - prevY;
|
|
2730
|
+
for (const childNode of childNodes) {
|
|
2731
|
+
childNode.position = {
|
|
2732
|
+
x: childNode.position.x - xChange + nodeOrigin[0] * (width - prevWidth),
|
|
2733
|
+
y: childNode.position.y - yChange + nodeOrigin[1] * (height - prevHeight),
|
|
2734
|
+
};
|
|
2735
|
+
childChanges.push(childNode);
|
|
2736
|
+
}
|
|
2726
2737
|
}
|
|
2727
|
-
onResize?.(event, nextValues);
|
|
2728
|
-
onChange(change, childChanges);
|
|
2729
2738
|
}
|
|
2739
|
+
if (isWidthChange || isHeightChange) {
|
|
2740
|
+
change.width = isWidthChange ? width : prevValues.width;
|
|
2741
|
+
change.height = isHeightChange ? height : prevValues.height;
|
|
2742
|
+
prevValues.width = change.width;
|
|
2743
|
+
prevValues.height = change.height;
|
|
2744
|
+
}
|
|
2745
|
+
const direction = getResizeDirection({
|
|
2746
|
+
width: prevValues.width,
|
|
2747
|
+
prevWidth,
|
|
2748
|
+
height: prevValues.height,
|
|
2749
|
+
prevHeight,
|
|
2750
|
+
affectsX: controlDirection.affectsX,
|
|
2751
|
+
affectsY: controlDirection.affectsY,
|
|
2752
|
+
});
|
|
2753
|
+
const nextValues = { ...prevValues, direction };
|
|
2754
|
+
const callResize = shouldResize?.(event, nextValues);
|
|
2755
|
+
if (callResize === false) {
|
|
2756
|
+
return;
|
|
2757
|
+
}
|
|
2758
|
+
onResize?.(event, nextValues);
|
|
2759
|
+
onChange(change, childChanges);
|
|
2730
2760
|
})
|
|
2731
2761
|
.on('end', (event) => {
|
|
2732
2762
|
onResizeEnd?.(event, { ...prevValues });
|
|
2763
|
+
onEnd?.();
|
|
2733
2764
|
});
|
|
2734
2765
|
selection.call(dragHandler);
|
|
2735
2766
|
}
|
|
@@ -2742,4 +2773,4 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange }) {
|
|
|
2742
2773
|
};
|
|
2743
2774
|
}
|
|
2744
2775
|
|
|
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,
|
|
2776
|
+
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, evaluateAbsolutePosition, 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, handleExpandParent, infiniteExtent, isCoordinateExtent, isEdgeBase, isEdgeVisible, isInputDOMNode, isInternalNodeBase, isMacOs, isMouseEvent, isNodeBase, isNumeric, isRectObject, nodeHasDimensions, nodeToBox, nodeToRect, panBy, pointToRendererPoint, rectToBox, rendererPointToPoint, shallowNodeData, snapPosition, updateAbsolutePositions, updateConnectionLookup, updateEdge, updateNodeInternals };
|