@html-graph/html-graph 8.17.0 → 8.18.1

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.
@@ -619,7 +619,7 @@ const canvasErrorText = Object.freeze({
619
619
  removeNonexistentPort: (portId) => `Failed to remove port with ID ${JSON.stringify(portId)} because it does not exist`,
620
620
  accessNonexistentEdge: (edgeId) => `Failed to access edge with ID ${JSON.stringify(edgeId)} because it does not exist`,
621
621
  addEdgeWithExistingId: (edgeId) => `Failed to add edge with ID ${JSON.stringify(edgeId)} because an edge with this ID already exists`,
622
- addEdgeWithElementInUse: (edgeId, useEdgeId) => `Failed to add edge with ID ${JSON.stringify(edgeId)} because its SVG element is already attached to edge with ID ${JSON.stringify(useEdgeId)}`,
622
+ addEdgeWithElementInUse: (edgeId, useEdgeId) => `Failed to add edge with ID ${JSON.stringify(edgeId)} because its element is already attached to edge with ID ${JSON.stringify(useEdgeId)}`,
623
623
  addEdgeFromNonexistentPort: (edgeId, portId) => `Failed to add edge with ID ${JSON.stringify(edgeId)} from port with ID ${JSON.stringify(portId)} because the port does not exist`,
624
624
  addEdgeToNonexistentPort: (edgeId, portId) => `Failed to add edge with ID ${JSON.stringify(edgeId)} to port with ID ${JSON.stringify(portId)} because the port does not exist`,
625
625
  updateNonexistentEdge: (edgeId) => `Failed to update edge with ID ${JSON.stringify(edgeId)} because it does not exist`,
@@ -1471,48 +1471,52 @@ const createRoundedPath = (path, roundness) => {
1471
1471
  return parts.join(" ");
1472
1472
  };
1473
1473
  const createLine$1 = (from, to) => {
1474
- const horizontalLineDir = to.x - from.x >= 0;
1474
+ const fromLine = from.linePoint;
1475
+ const toLine = to.linePoint;
1476
+ const horizontalLineDir = toLine.x - fromLine.x >= 0;
1475
1477
  const fromPortDir = from.dirX >= 0;
1476
1478
  const toPortDir = to.dirX >= 0;
1477
1479
  const isSameDirPorts = fromPortDir === toPortDir;
1478
1480
  if (isSameDirPorts) {
1479
1481
  const isSameDirLine = fromPortDir === horizontalLineDir;
1480
- const centerX = (from.x + to.x) / 2;
1481
- const centerY2 = (from.y + to.y) / 2;
1482
+ const centerX = (fromLine.x + toLine.x) / 2;
1483
+ const centerY2 = (fromLine.y + toLine.y) / 2;
1482
1484
  const midpoint = { x: centerX, y: centerY2 };
1483
1485
  if (isSameDirLine) {
1484
1486
  return {
1485
1487
  points: [
1486
- { x: from.x, y: from.y },
1487
- { x: midpoint.x, y: from.y },
1488
- { x: midpoint.x, y: to.y },
1489
- { x: to.x, y: to.y }
1488
+ from.arrowPoint,
1489
+ { x: midpoint.x, y: fromLine.y },
1490
+ { x: midpoint.x, y: toLine.y },
1491
+ to.arrowPoint
1490
1492
  ],
1491
1493
  midpoint
1492
1494
  };
1493
1495
  }
1494
1496
  return {
1495
1497
  points: [
1496
- { x: from.x, y: from.y },
1497
- { x: from.x, y: midpoint.y },
1498
- { x: to.x, y: midpoint.y },
1499
- { x: to.x, y: to.y }
1498
+ from.arrowPoint,
1499
+ fromLine,
1500
+ { x: fromLine.x, y: midpoint.y },
1501
+ { x: toLine.x, y: midpoint.y },
1502
+ toLine,
1503
+ to.arrowPoint
1500
1504
  ],
1501
1505
  midpoint
1502
1506
  };
1503
1507
  }
1504
1508
  const isSameSourceDir = fromPortDir === horizontalLineDir;
1505
- const centerY = (from.y + to.y) / 2;
1509
+ const centerY = (fromLine.y + toLine.y) / 2;
1506
1510
  if (isSameSourceDir) {
1507
- const joint2 = { x: to.x, y: from.y };
1511
+ const joint2 = { x: toLine.x, y: fromLine.y };
1508
1512
  return {
1509
- points: [{ x: from.x, y: from.y }, joint2, { x: to.x, y: to.y }],
1513
+ points: [from.arrowPoint, joint2, toLine, to.arrowPoint],
1510
1514
  midpoint: { x: joint2.x, y: centerY }
1511
1515
  };
1512
1516
  }
1513
- const joint = { x: from.x, y: to.y };
1517
+ const joint = { x: fromLine.x, y: toLine.y };
1514
1518
  return {
1515
- points: [{ x: from.x, y: from.y }, joint, { x: to.x, y: to.y }],
1519
+ points: [from.arrowPoint, fromLine, joint, to.arrowPoint],
1516
1520
  midpoint: { x: joint.x, y: centerY }
1517
1521
  };
1518
1522
  };
@@ -1536,14 +1540,7 @@ class HorizontalEdgePath {
1536
1540
  fromDir,
1537
1541
  from
1538
1542
  ) : from;
1539
- const endArrow = hasTargetArrow ? createRotatedPoint(
1540
- {
1541
- x: to.x - arrowLength,
1542
- y: to.y
1543
- },
1544
- toDir,
1545
- to
1546
- ) : to;
1543
+ const endArrow = hasTargetArrow ? createRotatedPoint({ x: to.x - arrowLength, y: to.y }, toDir, to) : to;
1547
1544
  const gap = arrowLength + arrowOffset;
1548
1545
  const beginLine = createRotatedPoint(
1549
1546
  { x: from.x + gap, y: from.y },
@@ -1552,21 +1549,10 @@ class HorizontalEdgePath {
1552
1549
  );
1553
1550
  const endLine = createRotatedPoint({ x: to.x - gap, y: to.y }, toDir, to);
1554
1551
  const line = createLine$1(
1555
- {
1556
- x: beginLine.x,
1557
- y: beginLine.y,
1558
- dirX: fromDir.x
1559
- },
1560
- {
1561
- x: endLine.x,
1562
- y: endLine.y,
1563
- dirX: toDir.x
1564
- }
1565
- );
1566
- this.path = createRoundedPath(
1567
- [beginArrow, ...line.points, endArrow],
1568
- roundness
1552
+ { arrowPoint: beginArrow, linePoint: beginLine, dirX: fromDir.x },
1553
+ { arrowPoint: endArrow, linePoint: endLine, dirX: toDir.x }
1569
1554
  );
1555
+ this.path = createRoundedPath(line.points, roundness);
1570
1556
  this.midpoint = line.midpoint;
1571
1557
  }
1572
1558
  }
@@ -1683,48 +1669,52 @@ class StraightEdgePath {
1683
1669
  }
1684
1670
  }
1685
1671
  const createLine = (from, to) => {
1686
- const verticalLineDir = to.y - from.y >= 0;
1672
+ const fromLine = from.linePoint;
1673
+ const toLine = to.linePoint;
1674
+ const verticalLineDir = toLine.y - fromLine.y >= 0;
1687
1675
  const fromPortDir = from.dirY >= 0;
1688
1676
  const toPortDir = to.dirY >= 0;
1689
1677
  const isSameDirPorts = fromPortDir === toPortDir;
1690
1678
  if (isSameDirPorts) {
1691
1679
  const isSameDirLine = fromPortDir === verticalLineDir;
1692
- const centerX2 = (from.x + to.x) / 2;
1693
- const centerY = (from.y + to.y) / 2;
1680
+ const centerX2 = (fromLine.x + toLine.x) / 2;
1681
+ const centerY = (fromLine.y + toLine.y) / 2;
1694
1682
  const midpoint = { x: centerX2, y: centerY };
1695
1683
  if (isSameDirLine) {
1696
1684
  return {
1697
1685
  points: [
1698
- { x: from.x, y: from.y },
1699
- { x: from.x, y: midpoint.y },
1700
- { x: to.x, y: midpoint.y },
1701
- { x: to.x, y: to.y }
1686
+ from.arrowPoint,
1687
+ { x: fromLine.x, y: midpoint.y },
1688
+ { x: toLine.x, y: midpoint.y },
1689
+ to.arrowPoint
1702
1690
  ],
1703
1691
  midpoint
1704
1692
  };
1705
1693
  }
1706
1694
  return {
1707
1695
  points: [
1708
- { x: from.x, y: from.y },
1709
- { x: midpoint.x, y: from.y },
1710
- { x: midpoint.x, y: to.y },
1711
- { x: to.x, y: to.y }
1696
+ from.arrowPoint,
1697
+ fromLine,
1698
+ { x: midpoint.x, y: fromLine.y },
1699
+ { x: midpoint.x, y: toLine.y },
1700
+ toLine,
1701
+ to.arrowPoint
1712
1702
  ],
1713
1703
  midpoint
1714
1704
  };
1715
1705
  }
1716
1706
  const isSameSourceDir = fromPortDir === verticalLineDir;
1717
- const centerX = (from.x + to.x) / 2;
1707
+ const centerX = (fromLine.x + toLine.x) / 2;
1718
1708
  if (isSameSourceDir) {
1719
- const joint2 = { x: from.x, y: to.y };
1709
+ const joint2 = { x: fromLine.x, y: toLine.y };
1720
1710
  return {
1721
- points: [{ x: from.x, y: from.y }, joint2, { x: to.x, y: to.y }],
1711
+ points: [from.arrowPoint, joint2, toLine, to.arrowPoint],
1722
1712
  midpoint: { x: centerX, y: joint2.y }
1723
1713
  };
1724
1714
  }
1725
- const joint = { x: to.x, y: from.y };
1715
+ const joint = { x: toLine.x, y: fromLine.y };
1726
1716
  return {
1727
- points: [{ x: from.x, y: from.y }, joint, { x: to.x, y: to.y }],
1717
+ points: [from.arrowPoint, fromLine, joint, to.arrowPoint],
1728
1718
  midpoint: { x: centerX, y: joint.y }
1729
1719
  };
1730
1720
  };
@@ -1748,14 +1738,7 @@ class VerticalEdgePath {
1748
1738
  fromDir,
1749
1739
  from
1750
1740
  ) : from;
1751
- const endArrow = hasTargetArrow ? createRotatedPoint(
1752
- {
1753
- x: to.x - arrowLength,
1754
- y: to.y
1755
- },
1756
- toDir,
1757
- to
1758
- ) : to;
1741
+ const endArrow = hasTargetArrow ? createRotatedPoint({ x: to.x - arrowLength, y: to.y }, toDir, to) : to;
1759
1742
  const gap = arrowLength + arrowOffset;
1760
1743
  const beginLine = createRotatedPoint(
1761
1744
  { x: from.x + gap, y: from.y },
@@ -1764,21 +1747,10 @@ class VerticalEdgePath {
1764
1747
  );
1765
1748
  const endLine = createRotatedPoint({ x: to.x - gap, y: to.y }, toDir, to);
1766
1749
  const line = createLine(
1767
- {
1768
- x: beginLine.x,
1769
- y: beginLine.y,
1770
- dirY: fromDir.y
1771
- },
1772
- {
1773
- x: endLine.x,
1774
- y: endLine.y,
1775
- dirY: toDir.y
1776
- }
1777
- );
1778
- this.path = createRoundedPath(
1779
- [beginArrow, ...line.points, endArrow],
1780
- roundness
1750
+ { arrowPoint: beginArrow, linePoint: beginLine, dirY: fromDir.y },
1751
+ { arrowPoint: endArrow, linePoint: endLine, dirY: toDir.y }
1781
1752
  );
1753
+ this.path = createRoundedPath(line.points, roundness);
1782
1754
  this.midpoint = line.midpoint;
1783
1755
  }
1784
1756
  }
@@ -2293,6 +2265,9 @@ class BezierEdgeShape {
2293
2265
  this.pathShape.render(params);
2294
2266
  }
2295
2267
  }
2268
+ const horizontalizeDirection = (direction) => {
2269
+ return Math.cos(direction) > 0 ? 0 : Math.PI;
2270
+ };
2296
2271
  class HorizontalEdgeShape {
2297
2272
  constructor(params) {
2298
2273
  __publicField(this, "svg");
@@ -2373,7 +2348,18 @@ class HorizontalEdgeShape {
2373
2348
  this.onAfterRender = this.pathShape.onAfterRender;
2374
2349
  }
2375
2350
  render(params) {
2376
- this.pathShape.render(params);
2351
+ const { from, to, category } = params;
2352
+ this.pathShape.render({
2353
+ category,
2354
+ from: {
2355
+ ...from,
2356
+ direction: horizontalizeDirection(from.direction)
2357
+ },
2358
+ to: {
2359
+ ...to,
2360
+ direction: horizontalizeDirection(to.direction)
2361
+ }
2362
+ });
2377
2363
  }
2378
2364
  }
2379
2365
  class StraightEdgeShape {
@@ -2462,6 +2448,10 @@ class StraightEdgeShape {
2462
2448
  this.pathShape.render(params);
2463
2449
  }
2464
2450
  }
2451
+ const pi2 = Math.PI / 2;
2452
+ const verticalizeDirection = (direction) => {
2453
+ return Math.sin(direction) > 0 ? pi2 : -pi2;
2454
+ };
2465
2455
  class VerticalEdgeShape {
2466
2456
  constructor(params) {
2467
2457
  __publicField(this, "svg");
@@ -2542,7 +2532,18 @@ class VerticalEdgeShape {
2542
2532
  this.onAfterRender = this.pathShape.onAfterRender;
2543
2533
  }
2544
2534
  render(params) {
2545
- this.pathShape.render(params);
2535
+ const { from, to, category } = params;
2536
+ this.pathShape.render({
2537
+ category,
2538
+ from: {
2539
+ ...from,
2540
+ direction: verticalizeDirection(from.direction)
2541
+ },
2542
+ to: {
2543
+ ...to,
2544
+ direction: verticalizeDirection(to.direction)
2545
+ }
2546
+ });
2546
2547
  }
2547
2548
  }
2548
2549
  class DirectEdgeShape {
@@ -3229,13 +3230,11 @@ class ViewportController {
3229
3230
  start = timestamp;
3230
3231
  }
3231
3232
  const progress = Math.min((timestamp - start) / duration, 1);
3232
- if (progress <= 1) {
3233
- this.viewportStore.patchViewportMatrix({
3234
- scale: previousViewportMatrix.scale + progress * deltaMatrix.scale,
3235
- x: previousViewportMatrix.x + progress * deltaMatrix.x,
3236
- y: previousViewportMatrix.y + progress * deltaMatrix.y
3237
- });
3238
- }
3233
+ this.viewportStore.patchViewportMatrix({
3234
+ scale: previousViewportMatrix.scale + progress * deltaMatrix.scale,
3235
+ x: previousViewportMatrix.x + progress * deltaMatrix.x,
3236
+ y: previousViewportMatrix.y + progress * deltaMatrix.y
3237
+ });
3239
3238
  if (progress < 1) {
3240
3239
  this.win.requestAnimationFrame(step);
3241
3240
  }
@@ -3305,7 +3304,7 @@ class DraggablePortsConfigurator {
3305
3304
  }
3306
3305
  const target = event.currentTarget;
3307
3306
  const portId = this.canvas.graph.findPortIdsByElement(target)[0];
3308
- const dragAllowed = this.params.portDragAllowedVerifier(portId, {
3307
+ const dragAllowed = this.params.onPointerDownVerifier(portId, {
3309
3308
  x: mouseEvent.clientX,
3310
3309
  y: mouseEvent.clientY
3311
3310
  });
@@ -3347,7 +3346,7 @@ class DraggablePortsConfigurator {
3347
3346
  const touch = touchEvent.touches[0];
3348
3347
  const target = event.currentTarget;
3349
3348
  const portId = this.canvas.graph.findPortIdsByElement(target)[0];
3350
- const dragAllowed = this.params.portDragAllowedVerifier(portId, {
3349
+ const dragAllowed = this.params.onPointerDownVerifier(portId, {
3351
3350
  x: touch.clientX,
3352
3351
  y: touch.clientY
3353
3352
  });
@@ -3585,6 +3584,52 @@ class UserSelectableElementsConfigurator {
3585
3584
  }
3586
3585
  }
3587
3586
  }
3587
+ const resolveCreateEdgeRequest = (params, targetPortId) => {
3588
+ return {
3589
+ from: params.isDirect ? params.staticPortId : targetPortId,
3590
+ to: params.isDirect ? targetPortId : params.staticPortId
3591
+ };
3592
+ };
3593
+ class ClosestConnectablePortDraggingPortDirectionResolver {
3594
+ constructor(graph, connectionAllowedVerifier) {
3595
+ this.graph = graph;
3596
+ this.connectionAllowedVerifier = connectionAllowedVerifier;
3597
+ }
3598
+ resolve(params) {
3599
+ let closestDirection = void 0;
3600
+ let closestDistance = Infinity;
3601
+ const { cursor } = params;
3602
+ this.graph.getAllPortIds().forEach((portId) => {
3603
+ const { element, direction, nodeId } = this.graph.getPort(portId);
3604
+ const { x, y } = this.graph.getNode(nodeId);
3605
+ if (x === null || y === null) {
3606
+ return;
3607
+ }
3608
+ const request = resolveCreateEdgeRequest(params, portId);
3609
+ if (!this.connectionAllowedVerifier(request)) {
3610
+ return;
3611
+ }
3612
+ const { top, left, width, height } = element.getBoundingClientRect();
3613
+ const center = { x: left + width / 2, y: top + height / 2 };
3614
+ const dx = cursor.x - center.x;
3615
+ const dy = cursor.y - center.y;
3616
+ const distance = Math.sqrt(dx * dx + dy * dy);
3617
+ if (distance < closestDistance) {
3618
+ closestDistance = distance;
3619
+ closestDirection = direction;
3620
+ }
3621
+ });
3622
+ return closestDirection;
3623
+ }
3624
+ }
3625
+ class ConstantDraggingPortDirectionResolver {
3626
+ constructor(direction) {
3627
+ this.direction = direction;
3628
+ }
3629
+ resolve() {
3630
+ return this.direction;
3631
+ }
3632
+ }
3588
3633
  class UserDraggableNodesConfigurator {
3589
3634
  constructor(canvas, element, window2, pointInsideVerifier, params) {
3590
3635
  __publicField(this, "grabbedNode", null);
@@ -4306,8 +4351,7 @@ class BackgroundConfigurator {
4306
4351
  class UserConnectablePortsConfigurator {
4307
4352
  constructor(canvas, overlayLayer, viewportStore, window2, pointInsideVerifier, params) {
4308
4353
  __publicField(this, "overlayCanvas");
4309
- __publicField(this, "staticPortId", null);
4310
- __publicField(this, "isTargetDragging", true);
4354
+ __publicField(this, "edgeInProgress", null);
4311
4355
  __publicField(this, "onEdgeCreated", (edgeId) => {
4312
4356
  this.params.onAfterEdgeCreated(edgeId);
4313
4357
  });
@@ -4325,7 +4369,7 @@ class UserConnectablePortsConfigurator {
4325
4369
  const draggablePortsParams = {
4326
4370
  mouseDownEventVerifier: this.params.mouseDownEventVerifier,
4327
4371
  mouseUpEventVerifier: this.params.mouseUpEventVerifier,
4328
- portDragAllowedVerifier: (portId, cursor) => {
4372
+ onPointerDownVerifier: (portId, cursor) => {
4329
4373
  const connectionType = this.params.connectionTypeResolver(portId);
4330
4374
  if (connectionType === null) {
4331
4375
  return false;
@@ -4341,13 +4385,9 @@ class UserConnectablePortsConfigurator {
4341
4385
  this.resetDragState();
4342
4386
  },
4343
4387
  onPointerOutside: () => {
4344
- const staticPortId = this.staticPortId;
4345
- const isTargetDragging = this.isTargetDragging;
4388
+ const params2 = this.edgeInProgress;
4346
4389
  this.resetDragState();
4347
- this.params.onEdgeCreationInterrupted({
4348
- staticPortId,
4349
- isDirect: isTargetDragging
4350
- });
4390
+ this.params.onEdgeCreationInterrupted(params2);
4351
4391
  }
4352
4392
  };
4353
4393
  DraggablePortsConfigurator.configure(
@@ -4367,9 +4407,8 @@ class UserConnectablePortsConfigurator {
4367
4407
  params
4368
4408
  );
4369
4409
  }
4370
- grabPort(portId, cursor, connectionType) {
4371
- const port = this.canvas.graph.getPort(portId);
4372
- this.staticPortId = portId;
4410
+ grabPort(staticPortId, cursor, connectionType) {
4411
+ const port = this.canvas.graph.getPort(staticPortId);
4373
4412
  const portRect = port.element.getBoundingClientRect();
4374
4413
  const portX = portRect.x + portRect.width / 2;
4375
4414
  const portY = portRect.y + portRect.height / 2;
@@ -4387,13 +4426,23 @@ class UserConnectablePortsConfigurator {
4387
4426
  portCoords: portPoint,
4388
4427
  portDirection: port.direction
4389
4428
  };
4429
+ const isDirect = connectionType === "direct";
4430
+ this.edgeInProgress = {
4431
+ staticPortId,
4432
+ isDirect
4433
+ };
4434
+ const resolvedDirection = this.params.draggingPortDirectionResolver.resolve(
4435
+ {
4436
+ cursor,
4437
+ ...this.edgeInProgress
4438
+ }
4439
+ );
4390
4440
  const draggingParams = {
4391
4441
  overlayNodeId: OverlayId.DraggingNodeId,
4392
4442
  portCoords: cursorPoint,
4393
- portDirection: this.params.dragPortDirection
4443
+ portDirection: resolvedDirection ?? port.direction
4394
4444
  };
4395
- this.isTargetDragging = connectionType === "direct";
4396
- const [sourceParams, targetParams] = this.isTargetDragging ? [staticParams, draggingParams] : [draggingParams, staticParams];
4445
+ const [sourceParams, targetParams] = isDirect ? [staticParams, draggingParams] : [draggingParams, staticParams];
4397
4446
  this.overlayCanvas.addNode(createAddNodeOverlayRequest(sourceParams));
4398
4447
  this.overlayCanvas.addNode(createAddNodeOverlayRequest(targetParams));
4399
4448
  this.overlayCanvas.addEdge({
@@ -4403,25 +4452,24 @@ class UserConnectablePortsConfigurator {
4403
4452
  });
4404
4453
  }
4405
4454
  resetDragState() {
4406
- this.staticPortId = null;
4407
- this.isTargetDragging = true;
4455
+ this.edgeInProgress = null;
4408
4456
  this.overlayCanvas.clear();
4409
4457
  }
4410
4458
  tryCreateConnection(cursor) {
4411
- const draggingPortId = findPortAtPoint(this.canvas.graph, cursor);
4412
- if (draggingPortId === null) {
4413
- this.params.onEdgeCreationInterrupted({
4414
- staticPortId: this.staticPortId,
4415
- isDirect: this.isTargetDragging
4416
- });
4459
+ const targetPortId = findPortAtPoint(this.canvas.graph, cursor);
4460
+ if (targetPortId === null) {
4461
+ this.params.onEdgeCreationInterrupted(this.edgeInProgress);
4417
4462
  return;
4418
4463
  }
4419
- const staticPortId = this.staticPortId;
4420
- const sourceId = this.isTargetDragging ? staticPortId : draggingPortId;
4421
- const targetId = this.isTargetDragging ? draggingPortId : staticPortId;
4422
- const request = { from: sourceId, to: targetId };
4464
+ const request = resolveCreateEdgeRequest(
4465
+ this.edgeInProgress,
4466
+ targetPortId
4467
+ );
4423
4468
  const connectionAllowed = this.params.connectionAllowedVerifier(request);
4424
- const processedRequest = this.params.connectionPreprocessor(request);
4469
+ const processedRequest = this.params.connectionPreprocessor({
4470
+ from: request.from,
4471
+ to: request.to
4472
+ });
4425
4473
  if (connectionAllowed && processedRequest !== null) {
4426
4474
  this.canvas.graph.onAfterEdgeAdded.subscribe(this.onEdgeCreated);
4427
4475
  this.canvas.addEdge(processedRequest);
@@ -4430,23 +4478,26 @@ class UserConnectablePortsConfigurator {
4430
4478
  this.params.onEdgeCreationPrevented(request);
4431
4479
  }
4432
4480
  }
4433
- moveDraggingPort(dragPoint) {
4481
+ moveDraggingPort(cursor) {
4434
4482
  const canvasRect = this.overlayLayer.getBoundingClientRect();
4435
4483
  const nodeContentCoords = this.canvas.viewport.createContentCoords({
4436
- x: dragPoint.x - canvasRect.x,
4437
- y: dragPoint.y - canvasRect.y
4484
+ x: cursor.x - canvasRect.x,
4485
+ y: cursor.y - canvasRect.y
4486
+ });
4487
+ const direction = this.params.draggingPortDirectionResolver.resolve({
4488
+ cursor,
4489
+ ...this.edgeInProgress
4438
4490
  });
4439
4491
  this.overlayCanvas.updateNode(OverlayId.DraggingNodeId, {
4440
4492
  x: nodeContentCoords.x,
4441
4493
  y: nodeContentCoords.y
4442
- });
4494
+ }).updatePort(OverlayId.DraggingNodeId, { direction });
4443
4495
  }
4444
4496
  }
4445
4497
  class UserDraggableEdgesConfigurator {
4446
4498
  constructor(canvas, overlayLayer, viewportStore, window2, pointInsideVerifier, params) {
4447
4499
  __publicField(this, "overlayCanvas");
4448
- __publicField(this, "staticPortId", null);
4449
- __publicField(this, "isTargetDragging", true);
4500
+ __publicField(this, "edgeInProgress", null);
4450
4501
  __publicField(this, "draggingEdgePayload", null);
4451
4502
  __publicField(this, "onEdgeReattached", (edgeId) => {
4452
4503
  this.params.onAfterEdgeReattached(edgeId);
@@ -4465,7 +4516,7 @@ class UserDraggableEdgesConfigurator {
4465
4516
  const draggablePortsParams = {
4466
4517
  mouseDownEventVerifier: this.params.mouseDownEventVerifier,
4467
4518
  mouseUpEventVerifier: this.params.mouseUpEventVerifier,
4468
- portDragAllowedVerifier: (portId, cursor) => {
4519
+ onPointerDownVerifier: (portId, cursor) => {
4469
4520
  return this.tryStartEdgeDragging(portId, cursor);
4470
4521
  },
4471
4522
  onPointerMove: (cursor) => {
@@ -4511,10 +4562,9 @@ class UserDraggableEdgesConfigurator {
4511
4562
  }
4512
4563
  const edge = this.canvas.graph.getEdge(edgeId);
4513
4564
  const isSourceDragging = portId === edge.from;
4514
- const isTargetDragging = portId === edge.to;
4565
+ const isDirect = portId === edge.to;
4515
4566
  const staticPortId = isSourceDragging ? edge.to : edge.from;
4516
- this.staticPortId = staticPortId;
4517
- this.isTargetDragging = isTargetDragging;
4567
+ this.edgeInProgress = { staticPortId, isDirect };
4518
4568
  const draggingPort = this.canvas.graph.getPort(portId);
4519
4569
  const staticPort = this.canvas.graph.getPort(staticPortId);
4520
4570
  const staticRect = staticPort.element.getBoundingClientRect();
@@ -4544,12 +4594,18 @@ class UserDraggableEdgesConfigurator {
4544
4594
  portCoords: staticPoint,
4545
4595
  portDirection: staticPort.direction
4546
4596
  };
4597
+ const resolvedDirection = this.params.draggingPortDirectionResolver.resolve(
4598
+ {
4599
+ cursor,
4600
+ ...this.edgeInProgress
4601
+ }
4602
+ );
4547
4603
  const draggingParams = {
4548
4604
  overlayNodeId: OverlayId.DraggingNodeId,
4549
4605
  portCoords: draggingPoint,
4550
- portDirection: draggingPort.direction
4606
+ portDirection: resolvedDirection ?? draggingPort.direction
4551
4607
  };
4552
- const [sourceParams, targetParams] = this.isTargetDragging ? [staticParams, draggingParams] : [draggingParams, staticParams];
4608
+ const [sourceParams, targetParams] = isDirect ? [staticParams, draggingParams] : [draggingParams, staticParams];
4553
4609
  this.overlayCanvas.addNode(createAddNodeOverlayRequest(sourceParams));
4554
4610
  this.overlayCanvas.addNode(createAddNodeOverlayRequest(targetParams));
4555
4611
  const overlayEdgeShape = this.params.draggingEdgeShapeFactory !== null ? this.params.draggingEdgeShapeFactory(OverlayId.EdgeId) : edge.shape;
@@ -4563,30 +4619,43 @@ class UserDraggableEdgesConfigurator {
4563
4619
  }
4564
4620
  resetDragState() {
4565
4621
  this.draggingEdgePayload = null;
4566
- this.staticPortId = null;
4567
- this.isTargetDragging = true;
4622
+ this.edgeInProgress = null;
4568
4623
  this.overlayCanvas.clear();
4569
4624
  }
4570
- moveDraggingPort(dragPoint) {
4625
+ moveDraggingPort(cursor) {
4571
4626
  const canvasRect = this.overlayLayer.getBoundingClientRect();
4572
4627
  const nodeViewCoords = {
4573
- x: dragPoint.x - canvasRect.x,
4574
- y: dragPoint.y - canvasRect.y
4628
+ x: cursor.x - canvasRect.x,
4629
+ y: cursor.y - canvasRect.y
4575
4630
  };
4576
4631
  const nodeContentCoords = this.canvas.viewport.createContentCoords(nodeViewCoords);
4632
+ const direction = this.params.draggingPortDirectionResolver.resolve({
4633
+ cursor,
4634
+ ...this.edgeInProgress
4635
+ });
4577
4636
  this.overlayCanvas.updateNode(OverlayId.DraggingNodeId, {
4578
4637
  x: nodeContentCoords.x,
4579
4638
  y: nodeContentCoords.y
4580
- });
4639
+ }).updatePort(OverlayId.DraggingNodeId, { direction });
4581
4640
  }
4582
4641
  tryCreateConnection(cursor) {
4583
4642
  const draggingPortId = findPortAtPoint(this.canvas.graph, cursor);
4584
4643
  this.overlayCanvas.removeEdge(OverlayId.EdgeId);
4585
4644
  if (draggingPortId === null) {
4586
- this.handleEdgeReattachInterrupted();
4645
+ const edge2 = this.draggingEdgePayload;
4646
+ this.params.onEdgeReattachInterrupted({
4647
+ id: edge2.id,
4648
+ from: edge2.from,
4649
+ to: edge2.to,
4650
+ shape: edge2.shape,
4651
+ priority: edge2.priority
4652
+ });
4587
4653
  return;
4588
4654
  }
4589
- const [from, to] = this.isTargetDragging ? [this.staticPortId, draggingPortId] : [draggingPortId, this.staticPortId];
4655
+ const { from, to } = resolveCreateEdgeRequest(
4656
+ this.edgeInProgress,
4657
+ draggingPortId
4658
+ );
4590
4659
  const edge = this.draggingEdgePayload;
4591
4660
  const request = {
4592
4661
  id: edge.id,
@@ -4615,16 +4684,6 @@ class UserDraggableEdgesConfigurator {
4615
4684
  });
4616
4685
  }
4617
4686
  }
4618
- handleEdgeReattachInterrupted() {
4619
- const edge = this.draggingEdgePayload;
4620
- this.params.onEdgeReattachInterrupted({
4621
- id: edge.id,
4622
- from: edge.from,
4623
- to: edge.to,
4624
- shape: edge.shape,
4625
- priority: edge.priority
4626
- });
4627
- }
4628
4687
  }
4629
4688
  class ManualLayoutApplicationStrategyConfigurator {
4630
4689
  constructor(applier, trigger) {
@@ -4989,6 +5048,87 @@ const selectionDefaults = Object.freeze({
4989
5048
  });
4990
5049
  const noopFn = () => {
4991
5050
  };
5051
+ const resolveDraggingPortDirectionResolver = (config, graph, connectionAllowedVerifier) => {
5052
+ if (config === "closest-connectable-port") {
5053
+ return new ClosestConnectablePortDraggingPortDirectionResolver(
5054
+ graph,
5055
+ connectionAllowedVerifier
5056
+ );
5057
+ }
5058
+ return new ConstantDraggingPortDirectionResolver(config);
5059
+ };
5060
+ const resolveEdgeShapeFactory = (config) => {
5061
+ if (typeof config === "function") {
5062
+ return config;
5063
+ }
5064
+ switch (config.type) {
5065
+ case "straight":
5066
+ return () => new StraightEdgeShape({
5067
+ color: config.color,
5068
+ width: config.width,
5069
+ arrowLength: config.arrowLength,
5070
+ arrowOffset: config.arrowOffset,
5071
+ arrowRenderer: config.arrowRenderer,
5072
+ hasSourceArrow: config.hasSourceArrow,
5073
+ hasTargetArrow: config.hasTargetArrow,
5074
+ cycleSquareSide: config.cycleSquareSide,
5075
+ roundness: config.roundness,
5076
+ detourDistance: config.detourDistance,
5077
+ detourDirection: config.detourDirection
5078
+ });
5079
+ case "horizontal":
5080
+ return () => new HorizontalEdgeShape({
5081
+ color: config.color,
5082
+ width: config.width,
5083
+ arrowLength: config.arrowLength,
5084
+ arrowOffset: config.arrowOffset,
5085
+ arrowRenderer: config.arrowRenderer,
5086
+ hasSourceArrow: config.hasSourceArrow,
5087
+ hasTargetArrow: config.hasTargetArrow,
5088
+ cycleSquareSide: config.cycleSquareSide,
5089
+ roundness: config.roundness,
5090
+ detourDistance: config.detourDistance
5091
+ });
5092
+ case "vertical":
5093
+ return () => new VerticalEdgeShape({
5094
+ color: config.color,
5095
+ width: config.width,
5096
+ arrowLength: config.arrowLength,
5097
+ arrowOffset: config.arrowOffset,
5098
+ arrowRenderer: config.arrowRenderer,
5099
+ hasSourceArrow: config.hasSourceArrow,
5100
+ hasTargetArrow: config.hasTargetArrow,
5101
+ cycleSquareSide: config.cycleSquareSide,
5102
+ roundness: config.roundness,
5103
+ detourDistance: config.detourDistance
5104
+ });
5105
+ case "direct":
5106
+ return () => new DirectEdgeShape({
5107
+ color: config.color,
5108
+ width: config.width,
5109
+ arrowLength: config.arrowLength,
5110
+ arrowRenderer: config.arrowRenderer,
5111
+ hasSourceArrow: config.hasSourceArrow,
5112
+ hasTargetArrow: config.hasTargetArrow,
5113
+ sourceOffset: config.sourceOffset,
5114
+ targetOffset: config.targetOffset
5115
+ });
5116
+ default:
5117
+ return () => new BezierEdgeShape({
5118
+ color: config.color,
5119
+ width: config.width,
5120
+ arrowLength: config.arrowLength,
5121
+ arrowRenderer: config.arrowRenderer,
5122
+ hasSourceArrow: config.hasSourceArrow,
5123
+ hasTargetArrow: config.hasTargetArrow,
5124
+ cycleRadius: config.cycleRadius,
5125
+ smallCycleRadius: config.smallCycleRadius,
5126
+ curvature: config.curvature,
5127
+ detourDistance: config.detourDistance,
5128
+ detourDirection: config.detourDirection
5129
+ });
5130
+ }
5131
+ };
4992
5132
  const createDraggableNodesParams = (config) => {
4993
5133
  var _a, _b, _c, _d, _e, _f;
4994
5134
  const nodeDragVerifier = config.nodeDragVerifier ?? (() => true);
@@ -5183,102 +5323,36 @@ const createBackgroundParams = (backgroundConfig) => {
5183
5323
  maxViewportScale: backgroundConfig.maxViewportScale ?? 10
5184
5324
  };
5185
5325
  };
5186
- const resolveEdgeShapeFactory = (config) => {
5187
- if (typeof config === "function") {
5188
- return config;
5189
- }
5190
- switch (config.type) {
5191
- case "straight":
5192
- return () => new StraightEdgeShape({
5193
- color: config.color,
5194
- width: config.width,
5195
- arrowLength: config.arrowLength,
5196
- arrowOffset: config.arrowOffset,
5197
- arrowRenderer: config.arrowRenderer,
5198
- hasSourceArrow: config.hasSourceArrow,
5199
- hasTargetArrow: config.hasTargetArrow,
5200
- cycleSquareSide: config.cycleSquareSide,
5201
- roundness: config.roundness,
5202
- detourDistance: config.detourDistance,
5203
- detourDirection: config.detourDirection
5204
- });
5205
- case "horizontal":
5206
- return () => new HorizontalEdgeShape({
5207
- color: config.color,
5208
- width: config.width,
5209
- arrowLength: config.arrowLength,
5210
- arrowOffset: config.arrowOffset,
5211
- arrowRenderer: config.arrowRenderer,
5212
- hasSourceArrow: config.hasSourceArrow,
5213
- hasTargetArrow: config.hasTargetArrow,
5214
- cycleSquareSide: config.cycleSquareSide,
5215
- roundness: config.roundness,
5216
- detourDistance: config.detourDistance
5217
- });
5218
- case "vertical":
5219
- return () => new VerticalEdgeShape({
5220
- color: config.color,
5221
- width: config.width,
5222
- arrowLength: config.arrowLength,
5223
- arrowOffset: config.arrowOffset,
5224
- arrowRenderer: config.arrowRenderer,
5225
- hasSourceArrow: config.hasSourceArrow,
5226
- hasTargetArrow: config.hasTargetArrow,
5227
- cycleSquareSide: config.cycleSquareSide,
5228
- roundness: config.roundness,
5229
- detourDistance: config.detourDistance
5230
- });
5231
- case "direct":
5232
- return () => new DirectEdgeShape({
5233
- color: config.color,
5234
- width: config.width,
5235
- arrowLength: config.arrowLength,
5236
- arrowRenderer: config.arrowRenderer,
5237
- hasSourceArrow: config.hasSourceArrow,
5238
- hasTargetArrow: config.hasTargetArrow,
5239
- sourceOffset: config.sourceOffset,
5240
- targetOffset: config.targetOffset
5241
- });
5242
- default:
5243
- return () => new BezierEdgeShape({
5244
- color: config.color,
5245
- width: config.width,
5246
- arrowLength: config.arrowLength,
5247
- arrowRenderer: config.arrowRenderer,
5248
- hasSourceArrow: config.hasSourceArrow,
5249
- hasTargetArrow: config.hasTargetArrow,
5250
- cycleRadius: config.cycleRadius,
5251
- smallCycleRadius: config.smallCycleRadius,
5252
- curvature: config.curvature,
5253
- detourDistance: config.detourDistance,
5254
- detourDirection: config.detourDirection
5255
- });
5256
- }
5257
- };
5258
5326
  const defaults$3 = Object.freeze({
5259
5327
  connectionTypeResolver: () => "direct",
5260
5328
  connectionPreprocessor: (request) => request,
5261
5329
  connectionAllowedVerifier: () => true,
5262
5330
  mouseEventVerifier: (event) => event.button === 0
5263
5331
  });
5264
- const createConnectablePortsParams = (config, defaultEdgeShapeFactory, defaultDragPortDirection) => {
5332
+ const createConnectablePortsParams = (config, defaultEdgeShapeFactory, graph) => {
5265
5333
  var _a, _b, _c;
5334
+ const connectionAllowedVerifier = config.connectionAllowedVerifier ?? defaults$3.connectionAllowedVerifier;
5266
5335
  return {
5267
5336
  connectionTypeResolver: config.connectionTypeResolver ?? defaults$3.connectionTypeResolver,
5337
+ connectionAllowedVerifier,
5338
+ draggingPortDirectionResolver: resolveDraggingPortDirectionResolver(
5339
+ config.dragPortDirection,
5340
+ graph,
5341
+ connectionAllowedVerifier
5342
+ ),
5343
+ edgeShapeFactory: config.edgeShape !== void 0 ? resolveEdgeShapeFactory(config.edgeShape) : defaultEdgeShapeFactory,
5268
5344
  connectionPreprocessor: config.connectionPreprocessor ?? defaults$3.connectionPreprocessor,
5269
- connectionAllowedVerifier: config.connectionAllowedVerifier ?? defaults$3.connectionAllowedVerifier,
5270
5345
  mouseDownEventVerifier: config.mouseDownEventVerifier ?? defaults$3.mouseEventVerifier,
5271
5346
  mouseUpEventVerifier: config.mouseUpEventVerifier ?? defaults$3.mouseEventVerifier,
5272
5347
  onAfterEdgeCreated: ((_a = config.events) == null ? void 0 : _a.onAfterEdgeCreated) ?? noopFn,
5273
5348
  onEdgeCreationInterrupted: ((_b = config.events) == null ? void 0 : _b.onEdgeCreationInterrupted) ?? noopFn,
5274
- onEdgeCreationPrevented: ((_c = config.events) == null ? void 0 : _c.onEdgeCreationPrevented) ?? noopFn,
5275
- dragPortDirection: config.dragPortDirection ?? defaultDragPortDirection,
5276
- edgeShapeFactory: config.edgeShape !== void 0 ? resolveEdgeShapeFactory(config.edgeShape) : defaultEdgeShapeFactory
5349
+ onEdgeCreationPrevented: ((_c = config.events) == null ? void 0 : _c.onEdgeCreationPrevented) ?? noopFn
5277
5350
  };
5278
5351
  };
5279
5352
  const defaults$2 = Object.freeze({
5280
5353
  connectionAllowedVerifier: () => true,
5281
5354
  connectionPreprocessor: (request) => request,
5355
+ // TODO: remove ctrl key
5282
5356
  mouseDownEventVerifier: (event) => event.button === 0 && event.ctrlKey,
5283
5357
  mouseUpEventVerifier: (event) => event.button === 0
5284
5358
  });
@@ -5292,16 +5366,22 @@ const createDraggableEdgeParams = (config, graph) => {
5292
5366
  return null;
5293
5367
  }
5294
5368
  };
5369
+ const connectionAllowedVerifier = config.connectionAllowedVerifier ?? defaults$2.connectionAllowedVerifier;
5295
5370
  return {
5296
5371
  connectionPreprocessor: config.connectionPreprocessor ?? defaults$2.connectionPreprocessor,
5297
- connectionAllowedVerifier: config.connectionAllowedVerifier ?? defaults$2.connectionAllowedVerifier,
5372
+ connectionAllowedVerifier,
5298
5373
  mouseDownEventVerifier: config.mouseDownEventVerifier ?? defaults$2.mouseDownEventVerifier,
5299
5374
  mouseUpEventVerifier: config.mouseUpEventVerifier ?? defaults$2.mouseUpEventVerifier,
5300
5375
  draggingEdgeResolver: config.draggingEdgeResolver ?? defaultDraggingEdgeResolver,
5301
5376
  draggingEdgeShapeFactory: config.draggingEdgeShape !== void 0 ? resolveEdgeShapeFactory(config.draggingEdgeShape) : null,
5302
5377
  onAfterEdgeReattached: ((_a = config.events) == null ? void 0 : _a.onAfterEdgeReattached) ?? noopFn,
5303
5378
  onEdgeReattachInterrupted: ((_b = config.events) == null ? void 0 : _b.onEdgeReattachInterrupted) ?? noopFn,
5304
- onEdgeReattachPrevented: ((_c = config.events) == null ? void 0 : _c.onEdgeReattachPrevented) ?? noopFn
5379
+ onEdgeReattachPrevented: ((_c = config.events) == null ? void 0 : _c.onEdgeReattachPrevented) ?? noopFn,
5380
+ draggingPortDirectionResolver: resolveDraggingPortDirectionResolver(
5381
+ config.dragPortDirection,
5382
+ graph,
5383
+ connectionAllowedVerifier
5384
+ )
5305
5385
  };
5306
5386
  };
5307
5387
  const createVirtualScrollParams = (config) => {
@@ -6923,7 +7003,7 @@ class CanvasBuilder {
6923
7003
  const params = createConnectablePortsParams(
6924
7004
  this.connectablePortsConfig,
6925
7005
  graphControllerParams.edges.shapeFactory,
6926
- graphControllerParams.ports.direction
7006
+ canvas.graph
6927
7007
  );
6928
7008
  UserConnectablePortsConfigurator.configure(
6929
7009
  canvas,