diff --git a/src/Blazor.Diagrams.Core/Models/NodeModel.cs b/src/Blazor.Diagrams.Core/Models/NodeModel.cs
index 610a5aac..102a9fed 100644
--- a/src/Blazor.Diagrams.Core/Models/NodeModel.cs
+++ b/src/Blazor.Diagrams.Core/Models/NodeModel.cs
@@ -107,7 +107,13 @@ public void SetSize(double width, double height)
if (newSize.Equals(_size) == true)
return;
+ Size? oldSize = Size != null ? new Size(Size.Width, Size.Height) : null;
+
Size = newSize;
+ if (oldSize != null)
+ {
+ UpdatePortPositions(oldSize, newSize);
+ }
Refresh();
RefreshLinks();
SizeChanging?.Invoke(this);
@@ -156,6 +162,9 @@ public virtual void UpdatePositionSilently(double deltaX, double deltaY)
public virtual bool CanAttachTo(ILinkable other) => other is not PortModel && other is not BaseLinkModel;
+ ///
+ /// Updates port positions when node position changes.
+ ///
private void UpdatePortPositions(double deltaX, double deltaY)
{
// Save some JS calls and update ports directly here
@@ -166,6 +175,21 @@ private void UpdatePortPositions(double deltaX, double deltaY)
}
}
+ ///
+ /// Updates port positions when node size changes.
+ ///
+ private void UpdatePortPositions(Size oldSize, Size newSize)
+ {
+ var deltaWidth = newSize.Width - oldSize.Width;
+ var deltaHeight = newSize.Height - oldSize.Height;
+
+ foreach (var port in _ports)
+ {
+ port.SetPortPositionOnNodeSizeChanged(deltaWidth, deltaHeight);
+ port.RefreshLinks();
+ }
+ }
+
protected void TriggerMoving()
{
Moving?.Invoke(this);
diff --git a/src/Blazor.Diagrams.Core/Models/PortModel.cs b/src/Blazor.Diagrams.Core/Models/PortModel.cs
index a0c85081..ef206856 100644
--- a/src/Blazor.Diagrams.Core/Models/PortModel.cs
+++ b/src/Blazor.Diagrams.Core/Models/PortModel.cs
@@ -67,4 +67,38 @@ public virtual bool CanAttachTo(ILinkable other)
void ILinkable.AddLink(BaseLinkModel link) => _links.Add(link);
void ILinkable.RemoveLink(BaseLinkModel link) => _links.Remove(link);
+
+ public virtual void SetPortPositionOnNodeSizeChanged(double deltaWidth, double deltaHeight)
+ {
+ switch (Alignment)
+ {
+ case PortAlignment.Top:
+ Position = new Point(Position.X + deltaWidth / 2, Position.Y);
+ break;
+ case PortAlignment.TopRight:
+ Position = new Point(Position.X + deltaWidth, Position.Y);
+ break;
+ case PortAlignment.TopLeft:
+ Position = new Point(Position.X, Position.Y);
+ break;
+ case PortAlignment.Right:
+ Position = new Point(Position.X + deltaWidth, Position.Y + deltaHeight / 2);
+ break;
+ case PortAlignment.Left:
+ Position = new Point(Position.X, Position.Y + deltaHeight / 2);
+ break;
+ case PortAlignment.Bottom:
+ Position = new Point(Position.X + deltaWidth / 2, Position.Y + deltaHeight);
+ break;
+ case PortAlignment.BottomRight:
+ Position = new Point(Position.X + deltaWidth, Position.Y + deltaHeight);
+ break;
+ case PortAlignment.BottomLeft:
+ Position = new Point(Position.X, Position.Y + deltaHeight);
+ break;
+ default:
+ Position = new Point(Position.X, Position.Y);
+ break;
+ }
+ }
}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Blazor.Diagrams.Core.Tests.csproj b/tests/Blazor.Diagrams.Core.Tests/Blazor.Diagrams.Core.Tests.csproj
index 11c8ea2c..ee63923f 100644
--- a/tests/Blazor.Diagrams.Core.Tests/Blazor.Diagrams.Core.Tests.csproj
+++ b/tests/Blazor.Diagrams.Core.Tests/Blazor.Diagrams.Core.Tests.csproj
@@ -1,4 +1,4 @@
-
+
net6.0
diff --git a/tests/Blazor.Diagrams.Core.Tests/Models/NodeModelTest.cs b/tests/Blazor.Diagrams.Core.Tests/Models/NodeModelTest.cs
new file mode 100644
index 00000000..b27edc99
--- /dev/null
+++ b/tests/Blazor.Diagrams.Core.Tests/Models/NodeModelTest.cs
@@ -0,0 +1,53 @@
+using Blazor.Diagrams.Core.Geometry;
+using Blazor.Diagrams.Core.Models;
+using Moq;
+using Xunit;
+
+namespace Blazor.Diagrams.Core.Tests.Models
+{
+ public class NodeModelTest
+ {
+ [Fact]
+ public void UpdatePortOnSetPosition()
+ {
+ var node = new NodeModel(position: new Point(100, 100));
+ node.Size = new Size(100, 100);
+
+ var port = new PortModel(node, PortAlignment.BottomLeft, new Point(50, 50));
+ node.AddPort(port);
+
+ var newX = 200;
+ var newY = 300;
+
+ //Act
+ node.SetPosition(newX, newY);
+
+ //Assert
+ Assert.Equal(150, port.Position.X);
+ Assert.Equal(250, port.Position.Y);
+ }
+
+ [Fact]
+ public void SetPortPositionOnNodeSizeChangedIsCalledOnSetSize()
+ {
+ // Arrange
+ var oldWidth = 100.0;
+ var oldHeight = 100.0;
+ var newWidth = 500.0;
+ var newHeight = 700.0;
+ var deltaX = newWidth - oldWidth;
+ var deltaY = newHeight - oldHeight;
+
+ var node = new NodeModel(new Point(100, 100)) { Size = new Size(oldWidth, oldHeight) };
+ var portMock = new Mock(node, PortAlignment.BottomLeft, null, null);
+
+ node.AddPort(portMock.Object);
+
+ // Act
+ node.SetSize(newWidth, newHeight);
+
+ // Assert
+ portMock.Verify(m => m.SetPortPositionOnNodeSizeChanged(deltaX, deltaY), Times.Once);
+ }
+ }
+}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Models/PortModelTest.cs b/tests/Blazor.Diagrams.Core.Tests/Models/PortModelTest.cs
new file mode 100644
index 00000000..d4dc57bf
--- /dev/null
+++ b/tests/Blazor.Diagrams.Core.Tests/Models/PortModelTest.cs
@@ -0,0 +1,33 @@
+using Blazor.Diagrams.Core.Geometry;
+using Blazor.Diagrams.Core.Models;
+using Xunit;
+
+namespace Blazor.Diagrams.Core.Tests.Models
+{
+ public class PortModelTest
+ {
+ [Theory]
+ [InlineData(PortAlignment.Top, 50, 0)]
+ [InlineData(PortAlignment.TopLeft, 0, 0)]
+ [InlineData(PortAlignment.TopRight, 100, 0)]
+ [InlineData(PortAlignment.Bottom, 50, 100)]
+ [InlineData(PortAlignment.BottomLeft, 0, 100)]
+ [InlineData(PortAlignment.BottomRight, 100, 100)]
+ [InlineData(PortAlignment.Left, 0, 50)]
+ [InlineData(PortAlignment.Right, 100, 50)]
+ public void SetPortPositionOnNodeSizeChangedCalculatesCorrectPosition(PortAlignment alignment, double expectedXPosition, double expectedYPosition)
+ {
+ // Arrange
+ var node = new NodeModel();
+ var port = new PortModel(node, alignment, new Point(0, 0));
+ node.Size = new Size(100, 100);
+
+ // Act
+ port.SetPortPositionOnNodeSizeChanged(100, 100);
+
+ // Assert
+ Assert.Equal(expectedXPosition, port.Position.X);
+ Assert.Equal(expectedYPosition, port.Position.Y);
+ }
+ }
+}