From a4d0828b34ea8db03f819d93badeb008e3157979 Mon Sep 17 00:00:00 2001 From: Heather <30523814+Heathermcx@users.noreply.github.com> Date: Tue, 12 Dec 2023 10:37:27 +1100 Subject: [PATCH 1/7] Use Controls to implement node resizing (#10) --- .../Documentation/Controls/Overview.razor | 35 ++++++++ .../Controls/Default/ResizeControl.cs | 38 ++++++++ src/Blazor.Diagrams.Core/Models/GroupModel.cs | 26 ++---- src/Blazor.Diagrams.Core/Models/NodeModel.cs | 23 ++++- .../Resizing/BottomLeftResizerProvider.cs | 75 ++++++++++++++++ .../Resizing/BottomRightResizerProvider.cs | 66 ++++++++++++++ .../Positions/Resizing/IResizerProvider.cs | 14 +++ .../Resizing/TopLeftResizerProvider.cs | 75 ++++++++++++++++ .../Resizing/TopRightResizerProvider.cs | 74 ++++++++++++++++ src/Blazor.Diagrams/BlazorDiagram.cs | 3 +- .../Controls/ResizeControlWidget.razor | 10 +++ .../Components/NodeWidget.razor | 10 ++- .../wwwroot/default.styles.css | 24 +++++ .../wwwroot/default.styles.min.css | 2 +- .../wwwroot/default.styles.min.css.gz | Bin 683 -> 735 bytes .../Controls/ResizeControlTests.cs | 75 ++++++++++++++++ .../BottomLeftResizerProviderTests.cs | 82 ++++++++++++++++++ .../BottomRightResizerProviderTests.cs | 80 +++++++++++++++++ .../Resizing/TopLeftResizerProviderTests.cs | 82 ++++++++++++++++++ .../Resizing/TopRightResizerProviderTests.cs | 82 ++++++++++++++++++ .../Controls/ResizeControlWidgetTests.cs | 25 ++++++ 21 files changed, 876 insertions(+), 25 deletions(-) create mode 100644 src/Blazor.Diagrams.Core/Controls/Default/ResizeControl.cs create mode 100644 src/Blazor.Diagrams.Core/Positions/Resizing/BottomLeftResizerProvider.cs create mode 100644 src/Blazor.Diagrams.Core/Positions/Resizing/BottomRightResizerProvider.cs create mode 100644 src/Blazor.Diagrams.Core/Positions/Resizing/IResizerProvider.cs create mode 100644 src/Blazor.Diagrams.Core/Positions/Resizing/TopLeftResizerProvider.cs create mode 100644 src/Blazor.Diagrams.Core/Positions/Resizing/TopRightResizerProvider.cs create mode 100644 src/Blazor.Diagrams/Components/Controls/ResizeControlWidget.razor create mode 100644 tests/Blazor.Diagrams.Core.Tests/Controls/ResizeControlTests.cs create mode 100644 tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomLeftResizerProviderTests.cs create mode 100644 tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomRightResizerProviderTests.cs create mode 100644 tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopLeftResizerProviderTests.cs create mode 100644 tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopRightResizerProviderTests.cs create mode 100644 tests/Blazor.Diagrams.Tests/Components/Controls/ResizeControlWidgetTests.cs diff --git a/site/Site/Pages/Documentation/Controls/Overview.razor b/site/Site/Pages/Documentation/Controls/Overview.razor index bd87fa9a1..335838ae5 100644 --- a/site/Site/Pages/Documentation/Controls/Overview.razor +++ b/site/Site/Pages/Documentation/Controls/Overview.razor @@ -3,6 +3,7 @@ @using Blazor.Diagrams.Core.Controls; @using Blazor.Diagrams.Core.PathGenerators; @using Blazor.Diagrams.Core.Positions; +@using Blazor.Diagrams.Core.Positions.Resizing; @using Blazor.Diagrams.Core.Routers; @layout DocumentationLayout @inherits DocumentationPage @@ -135,6 +136,26 @@ Diagram.Controls.AddFor(SomeModel) +

Resize Control

+ +

+ The ResizeControl adds a resizer which is a box that when dragged, can resize the node. The resizer position and movement of the node is controlled using a Resizer Provider.
+ There are four ResizerProviders, one for each corner. Custom resizing behavior can be created by implementing IResizerProvider. +

+ +

+Diagram.Controls.AddFor(SomeModel).Add(new ResizeControl(new BottomRightResizerProvider()));
+Diagram.Controls.AddFor(SomeModel).Add(new ResizeControl(new BottomLeftResizerProvider()));
+Diagram.Controls.AddFor(SomeModel).Add(new ResizeControl(new TopRightResizerProvider()));
+Diagram.Controls.AddFor(SomeModel).Add(new ResizeControl(new TopLeftResizerProvider()));
+
+ +
+ + + +
+ @@ -143,6 +164,7 @@ Diagram.Controls.AddFor(SomeModel) private BlazorDiagram _rDiagram = new(); private BlazorDiagram _ahDiagram = new(); private BlazorDiagram _dnlDiagram = new(); + private BlazorDiagram _resizerDiagram = new(); protected override void OnInitialized() { @@ -198,5 +220,18 @@ Diagram.Controls.AddFor(SomeModel) _dnlDiagram.Controls.AddFor(dnlNode2).Add(new DragNewLinkControl(0, 0.5, offsetX: -20)); _dnlDiagram.SelectModel(dnlNode1, false); _dnlDiagram.SelectModel(dnlNode2, false); + + // Resize Control + var resizeNode1 = _resizerDiagram.Nodes.Add(new NodeModel(new Point(100, 100))); + var resizeNode2 = _resizerDiagram.Nodes.Add(new NodeModel(new Point(500, 150))); + resizeNode1.Title = "Title"; + resizeNode2.Title = "Title"; + _resizerDiagram.Controls.AddFor(resizeNode1, ControlsType.OnSelection).Add(new ResizeControl(new BottomRightResizerProvider())); + _resizerDiagram.Controls.AddFor(resizeNode1, ControlsType.OnSelection).Add(new ResizeControl(new BottomLeftResizerProvider())); + _resizerDiagram.Controls.AddFor(resizeNode1, ControlsType.OnSelection).Add(new ResizeControl(new TopRightResizerProvider())); + _resizerDiagram.Controls.AddFor(resizeNode1, ControlsType.OnSelection).Add(new ResizeControl(new TopLeftResizerProvider())); + _resizerDiagram.Controls.AddFor(resizeNode2, ControlsType.OnSelection).Add(new ResizeControl(new BottomRightResizerProvider())); + _resizerDiagram.SelectModel(resizeNode1, false); + _resizerDiagram.SelectModel(resizeNode2, false); } } \ No newline at end of file diff --git a/src/Blazor.Diagrams.Core/Controls/Default/ResizeControl.cs b/src/Blazor.Diagrams.Core/Controls/Default/ResizeControl.cs new file mode 100644 index 000000000..4517f673d --- /dev/null +++ b/src/Blazor.Diagrams.Core/Controls/Default/ResizeControl.cs @@ -0,0 +1,38 @@ +using Blazor.Diagrams.Core.Events; +using Blazor.Diagrams.Core.Geometry; +using Blazor.Diagrams.Core.Models.Base; +using Blazor.Diagrams.Core.Positions.Resizing; +using System.Threading.Tasks; + +namespace Blazor.Diagrams.Core.Controls.Default +{ + public class ResizeControl : ExecutableControl + { + private readonly IResizerProvider _resizeProvider; + + public ResizeControl(IResizerProvider resizeProvider) + { + _resizeProvider = resizeProvider; + } + + public override Point? GetPosition(Model model) => _resizeProvider.GetPosition(model); + + public string? Class => _resizeProvider.Class; + + public override ValueTask OnPointerDown(Diagram diagram, Model model, PointerEventArgs e) + { + _resizeProvider.OnResizeStart(diagram, model, e); + diagram.PointerMove += _resizeProvider.OnPointerMove; + diagram.PointerUp += _resizeProvider.OnResizeEnd; + diagram.PointerUp += (_, _) => OnResizeEnd(diagram); + + return ValueTask.CompletedTask; + } + + void OnResizeEnd(Diagram diagram) + { + diagram.PointerMove -= _resizeProvider.OnPointerMove; + diagram.PointerUp -= _resizeProvider.OnResizeEnd; + } + } +} diff --git a/src/Blazor.Diagrams.Core/Models/GroupModel.cs b/src/Blazor.Diagrams.Core/Models/GroupModel.cs index 041d872ec..4a450be1b 100644 --- a/src/Blazor.Diagrams.Core/Models/GroupModel.cs +++ b/src/Blazor.Diagrams.Core/Models/GroupModel.cs @@ -27,13 +27,10 @@ public void AddChild(NodeModel child) { _children.Add(child); child.Group = this; - child.SizeChanged += OnNodeChanged; + child.SizeChanging += OnNodeChanged; child.Moving += OnNodeChanged; - if (UpdateDimensions()) - { - Refresh(); - } + UpdateDimensions(); } public void RemoveChild(NodeModel child) @@ -42,14 +39,10 @@ public void RemoveChild(NodeModel child) return; child.Group = null; - child.SizeChanged -= OnNodeChanged; + child.SizeChanging -= OnNodeChanged; child.Moving -= OnNodeChanged; - if (UpdateDimensions()) - { - Refresh(); - RefreshLinks(); - } + UpdateDimensions(); } public override void SetPosition(double x, double y) @@ -83,7 +76,7 @@ public void Ungroup() foreach (var child in Children) { child.Group = null; - child.SizeChanged -= OnNodeChanged; + child.SizeChanging -= OnNodeChanged; child.Moving -= OnNodeChanged; } @@ -96,7 +89,7 @@ private void Initialize(IEnumerable children) { _children.Add(child); child.Group = this; - child.SizeChanged += OnNodeChanged; + child.SizeChanging += OnNodeChanged; child.Moving += OnNodeChanged; } @@ -105,10 +98,7 @@ private void Initialize(IEnumerable children) private void OnNodeChanged(NodeModel node) { - if (UpdateDimensions()) - { - Refresh(); - } + UpdateDimensions(); } private bool UpdateDimensions() @@ -128,7 +118,7 @@ private bool UpdateDimensions() TriggerMoving(); } - Size = new Size(bounds.Width + Padding * 2, bounds.Height + Padding * 2); + SetSize(bounds.Width + Padding * 2, bounds.Height + Padding * 2); return true; } } diff --git a/src/Blazor.Diagrams.Core/Models/NodeModel.cs b/src/Blazor.Diagrams.Core/Models/NodeModel.cs index 053c5b3d8..610a5aac3 100644 --- a/src/Blazor.Diagrams.Core/Models/NodeModel.cs +++ b/src/Blazor.Diagrams.Core/Models/NodeModel.cs @@ -11,7 +11,9 @@ public class NodeModel : MovableModel, IHasBounds, IHasShape, ILinkable private readonly List _ports = new(); private readonly List _links = new(); private Size? _size; + public Size MinimumDimensions { get; set; } = new Size(0, 0); + public event Action? SizeChanging; public event Action? SizeChanged; public event Action? Moving; @@ -28,11 +30,7 @@ public Size? Size get => _size; set { - if (value?.Equals(_size) == true) - return; - _size = value; - SizeChanged?.Invoke(this); } } public bool ControlledSize { get; init; } @@ -103,6 +101,23 @@ public override void SetPosition(double x, double y) Moving?.Invoke(this); } + public void SetSize(double width, double height) + { + var newSize = new Size(width, height); + if (newSize.Equals(_size) == true) + return; + + Size = newSize; + Refresh(); + RefreshLinks(); + SizeChanging?.Invoke(this); + } + + public void TriggerSizeChanged() + { + SizeChanged?.Invoke(this); + } + public virtual void UpdatePositionSilently(double deltaX, double deltaY) { base.SetPosition(Position.X + deltaX, Position.Y + deltaY); diff --git a/src/Blazor.Diagrams.Core/Positions/Resizing/BottomLeftResizerProvider.cs b/src/Blazor.Diagrams.Core/Positions/Resizing/BottomLeftResizerProvider.cs new file mode 100644 index 000000000..c4e576c92 --- /dev/null +++ b/src/Blazor.Diagrams.Core/Positions/Resizing/BottomLeftResizerProvider.cs @@ -0,0 +1,75 @@ +using Blazor.Diagrams.Core.Events; +using Blazor.Diagrams.Core.Geometry; +using Blazor.Diagrams.Core.Models; +using Blazor.Diagrams.Core.Models.Base; + +namespace Blazor.Diagrams.Core.Positions.Resizing +{ + public class BottomLeftResizerProvider : IResizerProvider + { + public string? Class => "bottomleft"; + + private Size _originalSize = null!; + private Point _originalPosition = null!; + private Point _originalMousePosition = null!; + private NodeModel _nodeModel = null!; + + public Point? GetPosition(Model model) + { + if (model is NodeModel nodeModel && nodeModel.Size is not null) + { + return new Point(nodeModel.Position.X - 5, nodeModel.Position.Y + nodeModel.Size.Height + 5); + } + return null; + } + + public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventArgs) + { + if (model is NodeModel nodeModel) + { + _originalPosition = new Point(nodeModel.Position.X, nodeModel.Position.Y); + _originalMousePosition = new Point(eventArgs.ClientX, eventArgs.ClientY); + _originalSize = nodeModel.Size!; + _nodeModel = nodeModel; + } + } + + public void OnPointerMove(Model? model, PointerEventArgs args) + { + if (_nodeModel is null) + { + return; + } + + var height = _originalSize.Height + (args.ClientY - _originalMousePosition.Y); + var width = _originalSize.Width - (args.ClientX - _originalMousePosition.X); + + var positionX = _originalPosition.X + (args.ClientX - _originalMousePosition.X); + var positionY = _originalPosition.Y; + + if (width < _nodeModel.MinimumDimensions.Width) + { + width = _nodeModel.MinimumDimensions.Width; + positionX = _nodeModel.Position.X; + } + if (height < _nodeModel.MinimumDimensions.Height) + { + height = _nodeModel.MinimumDimensions.Height; + positionY = _nodeModel.Position.Y; + } + + _nodeModel.SetPosition(positionX, positionY); + _nodeModel.SetSize(width, height); + } + + public void OnResizeEnd(Model? model, PointerEventArgs args) + { + _nodeModel?.TriggerSizeChanged(); + _originalSize = null!; + _originalPosition = null!; + _originalMousePosition = null!; + _nodeModel = null!; + } + + } +} diff --git a/src/Blazor.Diagrams.Core/Positions/Resizing/BottomRightResizerProvider.cs b/src/Blazor.Diagrams.Core/Positions/Resizing/BottomRightResizerProvider.cs new file mode 100644 index 000000000..f55e26d71 --- /dev/null +++ b/src/Blazor.Diagrams.Core/Positions/Resizing/BottomRightResizerProvider.cs @@ -0,0 +1,66 @@ +using Blazor.Diagrams.Core.Events; +using Blazor.Diagrams.Core.Geometry; +using Blazor.Diagrams.Core.Models; +using Blazor.Diagrams.Core.Models.Base; + +namespace Blazor.Diagrams.Core.Positions.Resizing +{ + public class BottomRightResizerProvider : IResizerProvider + { + public string? Class => "bottomright"; + + private Size _originalSize = null!; + private Point _originalMousePosition = null!; + private NodeModel _nodeModel = null!; + + public Point? GetPosition(Model model) + { + if (model is NodeModel nodeModel && nodeModel.Size is not null) + { + return new Point(nodeModel.Position.X + nodeModel.Size.Width + 5, nodeModel.Position.Y + nodeModel.Size.Height + 5); + } + return null; + } + + public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventArgs) + { + if (model is NodeModel nodeModel) + { + _originalMousePosition = new Point(eventArgs.ClientX, eventArgs.ClientY); + _originalSize = nodeModel.Size!; + _nodeModel = nodeModel; + } + } + + public void OnPointerMove(Model? model, PointerEventArgs args) + { + if (_nodeModel is null) + { + return; + } + + var height = _originalSize.Height + (args.ClientY - _originalMousePosition.Y); + var width = _originalSize.Width + (args.ClientX - _originalMousePosition.X); + + if (width < _nodeModel.MinimumDimensions.Width) + { + width = _nodeModel.MinimumDimensions.Width; + } + if (height < _nodeModel.MinimumDimensions.Height) + { + height = _nodeModel.MinimumDimensions.Height; + } + + _nodeModel.SetSize(width, height); + } + + public void OnResizeEnd(Model? model, PointerEventArgs args) + { + _nodeModel?.TriggerSizeChanged(); + _originalSize = null!; + _originalMousePosition = null!; + _nodeModel = null!; + } + + } +} diff --git a/src/Blazor.Diagrams.Core/Positions/Resizing/IResizerProvider.cs b/src/Blazor.Diagrams.Core/Positions/Resizing/IResizerProvider.cs new file mode 100644 index 000000000..65a2ecdde --- /dev/null +++ b/src/Blazor.Diagrams.Core/Positions/Resizing/IResizerProvider.cs @@ -0,0 +1,14 @@ +using Blazor.Diagrams.Core.Events; +using Blazor.Diagrams.Core.Models; +using Blazor.Diagrams.Core.Models.Base; + +namespace Blazor.Diagrams.Core.Positions.Resizing +{ + public interface IResizerProvider : IPositionProvider + { + public string? Class { get; } + public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventArgs); + public void OnPointerMove(Model? model, PointerEventArgs args); + public void OnResizeEnd(Model? model, PointerEventArgs args); + } +} diff --git a/src/Blazor.Diagrams.Core/Positions/Resizing/TopLeftResizerProvider.cs b/src/Blazor.Diagrams.Core/Positions/Resizing/TopLeftResizerProvider.cs new file mode 100644 index 000000000..7c3afe5ce --- /dev/null +++ b/src/Blazor.Diagrams.Core/Positions/Resizing/TopLeftResizerProvider.cs @@ -0,0 +1,75 @@ +using Blazor.Diagrams.Core.Events; +using Blazor.Diagrams.Core.Geometry; +using Blazor.Diagrams.Core.Models; +using Blazor.Diagrams.Core.Models.Base; + +namespace Blazor.Diagrams.Core.Positions.Resizing +{ + public class TopLeftResizerProvider : IResizerProvider + { + public string? Class => "topleft"; + + private Size _originalSize = null!; + private Point _originalPosition = null!; + private Point _originalMousePosition = null!; + private NodeModel _nodeModel = null!; + + public Point? GetPosition(Model model) + { + if (model is NodeModel nodeModel && nodeModel.Size is not null) + { + return new Point(nodeModel.Position.X - 5, nodeModel.Position.Y - 5); + } + return null; + } + + public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventArgs) + { + if (model is NodeModel nodeModel) + { + _originalPosition = new Point(nodeModel.Position.X, nodeModel.Position.Y); + _originalMousePosition = new Point(eventArgs.ClientX, eventArgs.ClientY); + _originalSize = nodeModel.Size!; + _nodeModel = nodeModel; + } + } + + public void OnPointerMove(Model? model, PointerEventArgs args) + { + if (_nodeModel is null) + { + return; + } + + var height = _originalSize.Height - (args.ClientY - _originalMousePosition.Y); + var width = _originalSize.Width - (args.ClientX - _originalMousePosition.X); + + var positionX = _originalPosition.X + (args.ClientX - _originalMousePosition.X); + var positionY = _originalPosition.Y + (args.ClientY - _originalMousePosition.Y); + + if (width < _nodeModel.MinimumDimensions.Width) + { + width = _nodeModel.MinimumDimensions.Width; + positionX = _nodeModel.Position.X; + } + if (height < _nodeModel.MinimumDimensions.Height) + { + height = _nodeModel.MinimumDimensions.Height; + positionY = _nodeModel.Position.Y; + } + + _nodeModel.SetPosition(positionX, positionY); + _nodeModel.SetSize(width, height); + } + + public void OnResizeEnd(Model? model, PointerEventArgs args) + { + _nodeModel?.TriggerSizeChanged(); + _originalSize = null!; + _originalPosition = null!; + _originalMousePosition = null!; + _nodeModel = null!; + } + + } +} diff --git a/src/Blazor.Diagrams.Core/Positions/Resizing/TopRightResizerProvider.cs b/src/Blazor.Diagrams.Core/Positions/Resizing/TopRightResizerProvider.cs new file mode 100644 index 000000000..e9ea4e14a --- /dev/null +++ b/src/Blazor.Diagrams.Core/Positions/Resizing/TopRightResizerProvider.cs @@ -0,0 +1,74 @@ +using Blazor.Diagrams.Core.Events; +using Blazor.Diagrams.Core.Geometry; +using Blazor.Diagrams.Core.Models; +using Blazor.Diagrams.Core.Models.Base; + +namespace Blazor.Diagrams.Core.Positions.Resizing +{ + public class TopRightResizerProvider : IResizerProvider + { + public string? Class => "topright"; + + private Size _originalSize = null!; + private Point _originalPosition = null!; + private Point _originalMousePosition = null!; + private NodeModel _nodeModel = null!; + + public Point? GetPosition(Model model) + { + if (model is NodeModel nodeModel && nodeModel.Size is not null) + { + return new Point(nodeModel.Position.X + nodeModel.Size.Width + 5, nodeModel.Position.Y - 5); + } + return null; + } + + public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventArgs) + { + if (model is NodeModel nodeModel) + { + _originalPosition = new Point(nodeModel.Position.X, nodeModel.Position.Y); + _originalMousePosition = new Point(eventArgs.ClientX, eventArgs.ClientY); + _originalSize = nodeModel.Size!; + _nodeModel = nodeModel; + } + } + + public void OnPointerMove(Model? model, PointerEventArgs args) + { + if (_nodeModel is null) + { + return; + } + var height = _originalSize.Height - (args.ClientY - _originalMousePosition.Y); + var width = _originalSize.Width + (args.ClientX - _originalMousePosition.X); + + var positionX = _originalPosition.X; + var positionY = _originalPosition.Y + (args.ClientY - _originalMousePosition.Y); + + if (width < _nodeModel.MinimumDimensions.Width) + { + width = _nodeModel.MinimumDimensions.Width; + positionX = _nodeModel.Position.X; + } + if (height < _nodeModel.MinimumDimensions.Height) + { + height = _nodeModel.MinimumDimensions.Height; + positionY = _nodeModel.Position.Y; + } + + _nodeModel.SetPosition(positionX, positionY); + _nodeModel.SetSize(width, height); + } + + public void OnResizeEnd(Model? model, PointerEventArgs args) + { + _nodeModel?.TriggerSizeChanged(); + _originalSize = null!; + _originalPosition = null!; + _originalMousePosition = null!; + _nodeModel = null!; + } + + } +} diff --git a/src/Blazor.Diagrams/BlazorDiagram.cs b/src/Blazor.Diagrams/BlazorDiagram.cs index ab61d98a8..b18eab9dc 100644 --- a/src/Blazor.Diagrams/BlazorDiagram.cs +++ b/src/Blazor.Diagrams/BlazorDiagram.cs @@ -19,7 +19,8 @@ public BlazorDiagram(BlazorDiagramOptions? options = null) [typeof(RemoveControl)] = typeof(RemoveControlWidget), [typeof(BoundaryControl)] = typeof(BoundaryControlWidget), [typeof(DragNewLinkControl)] = typeof(DragNewLinkControlWidget), - [typeof(ArrowHeadControl)] = typeof(ArrowHeadControlWidget) + [typeof(ArrowHeadControl)] = typeof(ArrowHeadControlWidget), + [typeof(ResizeControl)] = typeof(ResizeControlWidget) }; Options = options ?? new BlazorDiagramOptions(); diff --git a/src/Blazor.Diagrams/Components/Controls/ResizeControlWidget.razor b/src/Blazor.Diagrams/Components/Controls/ResizeControlWidget.razor new file mode 100644 index 000000000..cfd15bd7b --- /dev/null +++ b/src/Blazor.Diagrams/Components/Controls/ResizeControlWidget.razor @@ -0,0 +1,10 @@ +
+ +@code +{ + [Parameter] + public ResizeControl Control { get; set; } = null!; + + [Parameter] + public Model Model { get; set; } = null!; +} diff --git a/src/Blazor.Diagrams/Components/NodeWidget.razor b/src/Blazor.Diagrams/Components/NodeWidget.razor index 37ff3da8d..726e51d2c 100644 --- a/src/Blazor.Diagrams/Components/NodeWidget.razor +++ b/src/Blazor.Diagrams/Components/NodeWidget.razor @@ -1,4 +1,4 @@ -
+
@(Node.Title ?? "Title") @foreach (var port in Node.Ports) { @@ -11,4 +11,12 @@ [Parameter] public NodeModel Node { get; set; } = null!; + private string GenerateStyle() + { + if (Node.Size is not null) + { + return $"width: {Node.Size.Width}px; height: {Node.Size.Height}px"; + } + return string.Empty; + } } \ No newline at end of file diff --git a/src/Blazor.Diagrams/wwwroot/default.styles.css b/src/Blazor.Diagrams/wwwroot/default.styles.css index b095bbe4e..2b355029a 100644 --- a/src/Blazor.Diagrams/wwwroot/default.styles.css +++ b/src/Blazor.Diagrams/wwwroot/default.styles.css @@ -127,4 +127,28 @@ g.diagram-group.default.selected > rect { transform: translate(-50%, -50%); } +.default-node-resizer { + width: 5px; + height: 5px; + background-color: #f5f5f5; + border: 1px solid #6e9fd4; + position: absolute; +} + +.default-node-resizer.bottomright { + cursor: nwse-resize; +} + +.default-node-resizer.topright { + cursor: nesw-resize; +} + +.default-node-resizer.bottomleft { + cursor: nesw-resize; +} + +.default-node-resizer.topleft { + cursor: nwse-resize; +} + /*# sourceMappingURL=wwwroot\default.styles.css.map */ diff --git a/src/Blazor.Diagrams/wwwroot/default.styles.min.css b/src/Blazor.Diagrams/wwwroot/default.styles.min.css index c44adedc3..e794e823e 100644 --- a/src/Blazor.Diagrams/wwwroot/default.styles.min.css +++ b/src/Blazor.Diagrams/wwwroot/default.styles.min.css @@ -1 +1 @@ -.default-node{width:100px;height:80px;border-radius:10px;background-color:#f5f5f5;border:1px solid #e8e8e8;-webkit-box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12);box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12);position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;}.default-node.selected{border:1px solid #6e9fd4;}.default-node.selected .diagram-port{border:1px solid #6e9fd4;}.default-node .diagram-port,.default.diagram-group .diagram-port{width:20px;height:20px;margin:-10px;border-radius:50%;background-color:#f5f5f5;border:1px solid #d4d4d4;cursor:pointer;position:absolute;}.default-node .diagram-port:hover,.default-node .diagram-port.has-links,.default.diagram-group .diagram-port.has-links{background-color:#000;}.default-node .diagram-port.bottom,.default.diagram-group .diagram-port.bottom{bottom:0;left:50%;}.default-node .diagram-port.bottomleft,.default.diagram-group .diagram-port.bottomleft{bottom:0;left:0;}.default-node .diagram-port.bottomright,.default.diagram-group .diagram-port.bottomright{bottom:0;right:0;}.default-node .diagram-port.top,.default.diagram-group .diagram-port.top{top:0;left:50%;}.default-node .diagram-port.topleft,.default.diagram-group .diagram-port.topleft{top:0;left:0;}.default-node .diagram-port.topright,.default.diagram-group .diagram-port.topright{top:0;right:0;}.default-node .diagram-port.left,.default.diagram-group .diagram-port.left{left:0;top:50%;}.default-node .diagram-port.right,.default.diagram-group .diagram-port.right{right:0;top:50%;}.diagram-navigator.default{position:absolute;bottom:10px;right:10px;border:3px solid #9ba8b0;border-radius:15px;padding:20px;background-color:#fff;}div.diagram-group.default{outline:2px solid #000;background:#c6c6c6;}div.diagram-group.default.selected{outline:2px solid #6e9fd4;}g.diagram-group.default rect{outline:2px solid #000;fill:#c6c632;}g.diagram-group.default.selected>rect{outline:2px solid #008000;}.diagram-link div.default-link-label{display:inline-block;color:#fff;background-color:#6e9fd4;border-radius:.25rem;padding:.25rem;text-align:center;font-size:.875rem;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;min-width:3rem;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%);} \ No newline at end of file +.default-node{width:100px;height:80px;border-radius:10px;background-color:#f5f5f5;border:1px solid #e8e8e8;-webkit-box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12);box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12);position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;}.default-node.selected{border:1px solid #6e9fd4;}.default-node.selected .diagram-port{border:1px solid #6e9fd4;}.default-node .diagram-port,.default.diagram-group .diagram-port{width:20px;height:20px;margin:-10px;border-radius:50%;background-color:#f5f5f5;border:1px solid #d4d4d4;cursor:pointer;position:absolute;}.default-node .diagram-port:hover,.default-node .diagram-port.has-links,.default.diagram-group .diagram-port.has-links{background-color:#000;}.default-node .diagram-port.bottom,.default.diagram-group .diagram-port.bottom{bottom:0;left:50%;}.default-node .diagram-port.bottomleft,.default.diagram-group .diagram-port.bottomleft{bottom:0;left:0;}.default-node .diagram-port.bottomright,.default.diagram-group .diagram-port.bottomright{bottom:0;right:0;}.default-node .diagram-port.top,.default.diagram-group .diagram-port.top{top:0;left:50%;}.default-node .diagram-port.topleft,.default.diagram-group .diagram-port.topleft{top:0;left:0;}.default-node .diagram-port.topright,.default.diagram-group .diagram-port.topright{top:0;right:0;}.default-node .diagram-port.left,.default.diagram-group .diagram-port.left{left:0;top:50%;}.default-node .diagram-port.right,.default.diagram-group .diagram-port.right{right:0;top:50%;}.diagram-navigator.default{position:absolute;bottom:10px;right:10px;border:3px solid #9ba8b0;border-radius:15px;padding:20px;background-color:#fff;}div.diagram-group.default{outline:2px solid #000;background:#c6c6c6;}div.diagram-group.default.selected{outline:2px solid #6e9fd4;}g.diagram-group.default rect{outline:2px solid #000;fill:#c6c632;}g.diagram-group.default.selected>rect{outline:2px solid #008000;}.diagram-link div.default-link-label{display:inline-block;color:#fff;background-color:#6e9fd4;border-radius:.25rem;padding:.25rem;text-align:center;font-size:.875rem;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;min-width:3rem;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%);}.default-node-resizer{width:5px;height:5px;background-color:#f5f5f5;border:1px solid #6e9fd4;position:absolute;}.default-node-resizer.bottomright{cursor:nwse-resize;}.default-node-resizer.topright{cursor:nesw-resize;}.default-node-resizer.bottomleft{cursor:nesw-resize;}.default-node-resizer.topleft{cursor:nwse-resize;} \ No newline at end of file diff --git a/src/Blazor.Diagrams/wwwroot/default.styles.min.css.gz b/src/Blazor.Diagrams/wwwroot/default.styles.min.css.gz index 905f20cd3084e4807fd8feb323b3f30ca017d835..3c43a8a10a61907cb9619cdbdc3efc83f8d13ceb 100644 GIT binary patch literal 735 zcmV<50wDb#iwFP!000003bj^kj@mE~y$aH*(yoM~5SEs8q~68Bli=dmk?jDxXiwH3 zJyNewJ8`}?K*Ep80^;$Tc{Ah541a(B2`HqbzCFD6=x)nq(%dk3epKx%rdTq|u>AFgzUXfPM zIZ+uC7_G(?y9vKNQn2*Zt$0@|ZE=NURifHkCyB+C2JVJ}_wop8c?S{fiAJ1>gPs+3 z2fvI%3B&NNH$ftek@-BL8f$OR{opX>keVumGZ-B95f+F4!Za%qwzn9R)sp4V(+*oWuC}kq6yU>+3lcw<}WyfJCtxK{r z_N@jSbyV(c?(E>F-FLU{80ot96>Cl3&93V%l-0cDManp@`Pb1+3oZN4+ora@LwSAI z#}-vMz7U)MagqSPG&7P3X9gu)?hbJ;m*Wik2!~e_L>mQpdpUk<;B1CtHMQdqY4!m) z*#4+6%~UP5wN}T5g%n`Ns{FVn)nnmEkTZem!L{yl7)69mrOI*jWdBaUGqP2@bYCx( z?Fq=l@$g+k3S6kl&(KXbLfzv7BhsgQY9=;(gC^|fsyON9{FYYRni>_*rwNtbSedWX RwAgE&{R6yf)WanU007NuYeE13 literal 683 zcmV;c0#yAUiwFP!000003bj^iZlf>|zDlHOrACSoAx)baY42k2K)f+FvQ3gU>dE%U z9%-+zwt)a85AtJWCBfrw=9?Ge{QdnWppcP@8zdx!(}7X5#mg`(kMR~*zBPE`o)f7k zD5MBwmA2$aA=GD~RTc(4V+ZI5=9qv}ddFSv0pE{AYqvYG#-eSOF)7?IEU2mz;dy zUW}cr&?w_@?91GKkPyOIE^rFMfQnmGf?O=uxFvP1sNIW3x8GGu~E#^u?_>t(3O7QZk>YbJa;=ag~9aq2R6DgIe4`1Y4pJXJV%(h26nV z<50pdyy;DlNMmF%ji|=j3c4R0#vC%^Q#gUaVIN^}_-{;;B2ljHj}Uo&KDQ5jiI zqp-k}{Y=i4#ZFID1MU;t_xpkTwCILlQf8)m?_F=4b_92G^ML2I+pWVr>kUYdJdgW0F5LN-bG{VH5rY)L3(BCn^=g)x(5@fT(LVJK&pWM%AI z4LItk+}qsQ!B6R{TQ`h!Q~QFocJAhvb!Wa00|h0{qn8kxV!V1EF1|6CQyBGt@<2B5ur1w3hbZk-wAj|wu=|;Ywm5| Rf!sO%`Ul{II$Grk008_RO;G>< diff --git a/tests/Blazor.Diagrams.Core.Tests/Controls/ResizeControlTests.cs b/tests/Blazor.Diagrams.Core.Tests/Controls/ResizeControlTests.cs new file mode 100644 index 000000000..dcd9bab14 --- /dev/null +++ b/tests/Blazor.Diagrams.Core.Tests/Controls/ResizeControlTests.cs @@ -0,0 +1,75 @@ +using Blazor.Diagrams.Core.Controls.Default; +using Blazor.Diagrams.Core.Events; +using Blazor.Diagrams.Core.Models.Base; +using Blazor.Diagrams.Core.Positions.Resizing; +using Moq; +using Xunit; + +namespace Blazor.Diagrams.Core.Tests.Controls +{ + public class ResizeControlTests + { + [Fact] + public void GetPosition_ShouldUseResizeProviderGetPosition() + { + var resizeProvider = new Mock(); + var control = new ResizeControl(resizeProvider.Object); + var model = new Mock(); + + control.GetPosition(model.Object); + + resizeProvider.Verify(m => m.GetPosition(model.Object), Times.Once); + } + + [Fact] + public void OnPointerDown_ShouldInvokeResizeStart() + { + var resizeProvider = new Mock(); + var control = new ResizeControl(resizeProvider.Object); + var diagram = Mock.Of(); + var model = Mock.Of(); + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true); + + control.OnPointerDown(diagram, model, eventArgs); + + resizeProvider.Verify(m => m.OnResizeStart(diagram, model, eventArgs), Times.Once); + } + + [Fact] + public void OnPointerDown_ShouldAddEventHandlers() + { + var resizeProvider = new Mock(); + var control = new ResizeControl(resizeProvider.Object); + var diagram = new TestDiagram(); + var model = Mock.Of(); + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true); + + control.OnPointerDown(diagram, model, eventArgs); + + diagram.TriggerPointerMove(model, eventArgs); + resizeProvider.Verify(m => m.OnPointerMove(model, eventArgs), Times.Once); + + diagram.TriggerPointerUp(model, eventArgs); + resizeProvider.Verify(m => m.OnResizeEnd(model, eventArgs), Times.Once); + } + + [Fact] + public void OnPointerUp_ShouldRemoveEventHandlers() + { + var resizeProvider = new Mock(); + var control = new ResizeControl(resizeProvider.Object); + var diagram = new TestDiagram(); + var model = Mock.Of(); + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true); + + control.OnPointerDown(diagram, model, eventArgs); + diagram.TriggerPointerUp(model, eventArgs); + + diagram.TriggerPointerMove(model, eventArgs); + resizeProvider.Verify(m => m.OnPointerMove(model, eventArgs), Times.Never); + + diagram.TriggerPointerUp(model, eventArgs); + resizeProvider.Verify(m => m.OnResizeEnd(model, eventArgs), Times.Once); + } + } +} diff --git a/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomLeftResizerProviderTests.cs b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomLeftResizerProviderTests.cs new file mode 100644 index 000000000..79ef6c17b --- /dev/null +++ b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomLeftResizerProviderTests.cs @@ -0,0 +1,82 @@ +using Blazor.Diagrams.Core.Controls.Default; +using Blazor.Diagrams.Core.Events; +using Blazor.Diagrams.Core.Geometry; +using Blazor.Diagrams.Core.Models; +using Blazor.Diagrams.Core.Positions.Resizing; +using FluentAssertions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Blazor.Diagrams.Core.Tests.Positions.Resizing +{ + public class BottomLeftResizerProviderTests + { + [Fact] + public void DragResizer_ShouldResizeNode() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new BottomLeftResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(10); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(90); + node.Size.Height.Should().Be(215); + } + + [Fact] + public void DragResizer_SmallerThanMinSize_SetsNodeToMinSize() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new BottomLeftResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(99, -199, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + eventArgs = new PointerEventArgs(300, -300, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(99); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(0); + node.Size.Height.Should().Be(0); + } + } +} diff --git a/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomRightResizerProviderTests.cs b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomRightResizerProviderTests.cs new file mode 100644 index 000000000..20ab27770 --- /dev/null +++ b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomRightResizerProviderTests.cs @@ -0,0 +1,80 @@ +using Blazor.Diagrams.Core.Controls.Default; +using Blazor.Diagrams.Core.Events; +using Blazor.Diagrams.Core.Geometry; +using Blazor.Diagrams.Core.Models; +using Blazor.Diagrams.Core.Positions.Resizing; +using FluentAssertions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Blazor.Diagrams.Core.Tests.Positions.Resizing +{ + public class BottomRightResizerProviderTests + { + [Fact] + public void DragResizer_ShouldResizeNode() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new BottomRightResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(110); + node.Size.Height.Should().Be(215); + } + + [Fact] + public void DragResizer_SmallerThanMinSize_SetsNodeToMinSize() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new BottomRightResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(-300, -300, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(0); + node.Size.Height.Should().Be(0); + } + } +} diff --git a/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopLeftResizerProviderTests.cs b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopLeftResizerProviderTests.cs new file mode 100644 index 000000000..1cc715d59 --- /dev/null +++ b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopLeftResizerProviderTests.cs @@ -0,0 +1,82 @@ +using Blazor.Diagrams.Core.Controls.Default; +using Blazor.Diagrams.Core.Events; +using Blazor.Diagrams.Core.Geometry; +using Blazor.Diagrams.Core.Models; +using Blazor.Diagrams.Core.Positions.Resizing; +using FluentAssertions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Blazor.Diagrams.Core.Tests.Positions.Resizing +{ + public class TopLeftResizerProviderTests + { + [Fact] + public void DragResizer_ShouldResizeNode() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new TopLeftResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(10); + node.Position.Y.Should().Be(15); + node.Size.Width.Should().Be(90); + node.Size.Height.Should().Be(185); + } + + [Fact] + public void DragResizer_SmallerThanMinSize_SetsNodeToMinSize() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new TopLeftResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(99, 199, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + eventArgs = new PointerEventArgs(300, 300, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(99); + node.Position.Y.Should().Be(199); + node.Size.Width.Should().Be(0); + node.Size.Height.Should().Be(0); + } + } +} diff --git a/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopRightResizerProviderTests.cs b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopRightResizerProviderTests.cs new file mode 100644 index 000000000..a138d524f --- /dev/null +++ b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopRightResizerProviderTests.cs @@ -0,0 +1,82 @@ +using Blazor.Diagrams.Core.Controls.Default; +using Blazor.Diagrams.Core.Events; +using Blazor.Diagrams.Core.Geometry; +using Blazor.Diagrams.Core.Models; +using Blazor.Diagrams.Core.Positions.Resizing; +using FluentAssertions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Blazor.Diagrams.Core.Tests.Positions.Resizing +{ + public class TopRightResizerProviderTests + { + [Fact] + public void DragResizer_ShouldResizeNode() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new TopRightResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(15); + node.Size.Width.Should().Be(110); + node.Size.Height.Should().Be(185); + } + + [Fact] + public void DragResizer_SmallerThanMinSize_SetsNodeToMinSize() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new TopRightResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(-99, 199, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + eventArgs = new PointerEventArgs(-300, 300, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(199); + node.Size.Width.Should().Be(0); + node.Size.Height.Should().Be(0); + } + } +} diff --git a/tests/Blazor.Diagrams.Tests/Components/Controls/ResizeControlWidgetTests.cs b/tests/Blazor.Diagrams.Tests/Components/Controls/ResizeControlWidgetTests.cs new file mode 100644 index 000000000..bf51e541c --- /dev/null +++ b/tests/Blazor.Diagrams.Tests/Components/Controls/ResizeControlWidgetTests.cs @@ -0,0 +1,25 @@ +using Blazor.Diagrams.Components.Controls; +using Blazor.Diagrams.Core.Controls.Default; +using Blazor.Diagrams.Core.Positions.Resizing; +using Bunit; +using Moq; +using Xunit; + +namespace Blazor.Diagrams.Tests.Components.Controls +{ + public class ResizeControlWidgetTests + { + [Fact] + public void ShouldRenderDiv() + { + using var ctx = new TestContext(); + var providerMock = Mock.Of(); + + var cut = ctx.RenderComponent(parameters => + parameters.Add(w => w.Control, new ResizeControl(providerMock)) + ); + + cut.MarkupMatches("
"); + } + } +} From 920dc36dfb3c547e7b5b007d29b389cce6fe2b15 Mon Sep 17 00:00:00 2001 From: Heather <30523814+Heathermcx@users.noreply.github.com> Date: Tue, 9 Jan 2024 17:10:13 +1100 Subject: [PATCH 2/7] Account for diagram zoom when dragging resizers (#16) * add test * add fix * enable zoom for testing * finish writing tests * add fix for remaining resizers * Revert "enable zoom for testing" This reverts commit 69fa0aa301bedf49ddbfbb91e31c21d2f4016902. * fix formatting * make fields nullable * fix nullables * use file scoped namespaces --- .../Resizing/BottomLeftResizerProvider.cs | 32 +-- .../Resizing/BottomRightResizerProvider.cs | 25 ++- .../Resizing/TopLeftResizerProvider.cs | 33 +-- .../Resizing/TopRightResizerProvider.cs | 34 +-- .../Controls/ResizeControlTests.cs | 103 +++++----- .../BottomLeftResizerProviderTests.cs | 193 ++++++++++++------ .../BottomRightResizerProviderTests.cs | 189 +++++++++++------ .../Resizing/TopLeftResizerProviderTests.cs | 193 ++++++++++++------ .../Resizing/TopRightResizerProviderTests.cs | 193 ++++++++++++------ .../Controls/ResizeControlWidgetTests.cs | 25 ++- 10 files changed, 642 insertions(+), 378 deletions(-) diff --git a/src/Blazor.Diagrams.Core/Positions/Resizing/BottomLeftResizerProvider.cs b/src/Blazor.Diagrams.Core/Positions/Resizing/BottomLeftResizerProvider.cs index c4e576c92..f3e8b10d4 100644 --- a/src/Blazor.Diagrams.Core/Positions/Resizing/BottomLeftResizerProvider.cs +++ b/src/Blazor.Diagrams.Core/Positions/Resizing/BottomLeftResizerProvider.cs @@ -7,12 +7,14 @@ namespace Blazor.Diagrams.Core.Positions.Resizing { public class BottomLeftResizerProvider : IResizerProvider { - public string? Class => "bottomleft"; + public string? Class => "bottomleft"; + + private Size? _originalSize; + private Point? _originalPosition; + private Point? _originalMousePosition; + private NodeModel? _nodeModel; + private Diagram? _diagram; - private Size _originalSize = null!; - private Point _originalPosition = null!; - private Point _originalMousePosition = null!; - private NodeModel _nodeModel = null!; public Point? GetPosition(Model model) { @@ -29,22 +31,23 @@ public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventAr { _originalPosition = new Point(nodeModel.Position.X, nodeModel.Position.Y); _originalMousePosition = new Point(eventArgs.ClientX, eventArgs.ClientY); - _originalSize = nodeModel.Size!; + _originalSize = nodeModel.Size; _nodeModel = nodeModel; + _diagram = diagram; } } public void OnPointerMove(Model? model, PointerEventArgs args) { - if (_nodeModel is null) + if (_originalSize is null || _originalPosition is null || _originalMousePosition is null || _nodeModel is null || _diagram is null) { return; } - var height = _originalSize.Height + (args.ClientY - _originalMousePosition.Y); - var width = _originalSize.Width - (args.ClientX - _originalMousePosition.X); + var height = _originalSize.Height + (args.ClientY - _originalMousePosition.Y) / _diagram.Zoom; + var width = _originalSize.Width - (args.ClientX - _originalMousePosition.X) / _diagram.Zoom; - var positionX = _originalPosition.X + (args.ClientX - _originalMousePosition.X); + var positionX = _originalPosition.X + (args.ClientX - _originalMousePosition.X) / _diagram.Zoom; var positionY = _originalPosition.Y; if (width < _nodeModel.MinimumDimensions.Width) @@ -65,10 +68,11 @@ public void OnPointerMove(Model? model, PointerEventArgs args) public void OnResizeEnd(Model? model, PointerEventArgs args) { _nodeModel?.TriggerSizeChanged(); - _originalSize = null!; - _originalPosition = null!; - _originalMousePosition = null!; - _nodeModel = null!; + _originalSize = null; + _originalPosition = null; + _originalMousePosition = null; + _nodeModel = null; + _diagram = null; } } diff --git a/src/Blazor.Diagrams.Core/Positions/Resizing/BottomRightResizerProvider.cs b/src/Blazor.Diagrams.Core/Positions/Resizing/BottomRightResizerProvider.cs index f55e26d71..d5cad9e89 100644 --- a/src/Blazor.Diagrams.Core/Positions/Resizing/BottomRightResizerProvider.cs +++ b/src/Blazor.Diagrams.Core/Positions/Resizing/BottomRightResizerProvider.cs @@ -9,11 +9,12 @@ public class BottomRightResizerProvider : IResizerProvider { public string? Class => "bottomright"; - private Size _originalSize = null!; - private Point _originalMousePosition = null!; - private NodeModel _nodeModel = null!; + private Size? _originalSize; + private Point? _originalMousePosition; + private NodeModel? _nodeModel; + private Diagram? _diagram; - public Point? GetPosition(Model model) + public Point? GetPosition(Model model) { if (model is NodeModel nodeModel && nodeModel.Size is not null) { @@ -27,20 +28,21 @@ public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventAr if (model is NodeModel nodeModel) { _originalMousePosition = new Point(eventArgs.ClientX, eventArgs.ClientY); - _originalSize = nodeModel.Size!; + _originalSize = nodeModel.Size; _nodeModel = nodeModel; + _diagram = diagram; } } public void OnPointerMove(Model? model, PointerEventArgs args) { - if (_nodeModel is null) + if (_originalSize is null || _originalMousePosition is null || _nodeModel is null || _diagram is null) { return; } - var height = _originalSize.Height + (args.ClientY - _originalMousePosition.Y); - var width = _originalSize.Width + (args.ClientX - _originalMousePosition.X); + var height = _originalSize.Height + (args.ClientY - _originalMousePosition.Y) / _diagram.Zoom; + var width = _originalSize.Width + (args.ClientX - _originalMousePosition.X) / _diagram.Zoom; if (width < _nodeModel.MinimumDimensions.Width) { @@ -57,9 +59,10 @@ public void OnPointerMove(Model? model, PointerEventArgs args) public void OnResizeEnd(Model? model, PointerEventArgs args) { _nodeModel?.TriggerSizeChanged(); - _originalSize = null!; - _originalMousePosition = null!; - _nodeModel = null!; + _originalSize = null; + _originalMousePosition = null; + _nodeModel = null; + _diagram = null; } } diff --git a/src/Blazor.Diagrams.Core/Positions/Resizing/TopLeftResizerProvider.cs b/src/Blazor.Diagrams.Core/Positions/Resizing/TopLeftResizerProvider.cs index 7c3afe5ce..c9d7fbe6b 100644 --- a/src/Blazor.Diagrams.Core/Positions/Resizing/TopLeftResizerProvider.cs +++ b/src/Blazor.Diagrams.Core/Positions/Resizing/TopLeftResizerProvider.cs @@ -7,12 +7,13 @@ namespace Blazor.Diagrams.Core.Positions.Resizing { public class TopLeftResizerProvider : IResizerProvider { - public string? Class => "topleft"; + public string? Class => "topleft"; - private Size _originalSize = null!; - private Point _originalPosition = null!; - private Point _originalMousePosition = null!; - private NodeModel _nodeModel = null!; + private Size? _originalSize; + private Point? _originalPosition; + private Point? _originalMousePosition; + private NodeModel? _nodeModel; + private Diagram? _diagram; public Point? GetPosition(Model model) { @@ -29,23 +30,24 @@ public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventAr { _originalPosition = new Point(nodeModel.Position.X, nodeModel.Position.Y); _originalMousePosition = new Point(eventArgs.ClientX, eventArgs.ClientY); - _originalSize = nodeModel.Size!; + _originalSize = nodeModel.Size; _nodeModel = nodeModel; + _diagram = diagram; } } public void OnPointerMove(Model? model, PointerEventArgs args) { - if (_nodeModel is null) + if (_originalSize is null || _originalPosition is null || _originalMousePosition is null || _nodeModel is null || _diagram is null) { return; } - var height = _originalSize.Height - (args.ClientY - _originalMousePosition.Y); - var width = _originalSize.Width - (args.ClientX - _originalMousePosition.X); + var height = _originalSize.Height - (args.ClientY - _originalMousePosition.Y) / _diagram.Zoom; + var width = _originalSize.Width - (args.ClientX - _originalMousePosition.X) / _diagram.Zoom; - var positionX = _originalPosition.X + (args.ClientX - _originalMousePosition.X); - var positionY = _originalPosition.Y + (args.ClientY - _originalMousePosition.Y); + var positionX = _originalPosition.X + (args.ClientX - _originalMousePosition.X) / _diagram.Zoom; + var positionY = _originalPosition.Y + (args.ClientY - _originalMousePosition.Y) / _diagram.Zoom; if (width < _nodeModel.MinimumDimensions.Width) { @@ -65,10 +67,11 @@ public void OnPointerMove(Model? model, PointerEventArgs args) public void OnResizeEnd(Model? model, PointerEventArgs args) { _nodeModel?.TriggerSizeChanged(); - _originalSize = null!; - _originalPosition = null!; - _originalMousePosition = null!; - _nodeModel = null!; + _originalSize = null; + _originalPosition = null; + _originalMousePosition = null; + _nodeModel = null; + _diagram = null; } } diff --git a/src/Blazor.Diagrams.Core/Positions/Resizing/TopRightResizerProvider.cs b/src/Blazor.Diagrams.Core/Positions/Resizing/TopRightResizerProvider.cs index e9ea4e14a..8f19bc727 100644 --- a/src/Blazor.Diagrams.Core/Positions/Resizing/TopRightResizerProvider.cs +++ b/src/Blazor.Diagrams.Core/Positions/Resizing/TopRightResizerProvider.cs @@ -7,12 +7,13 @@ namespace Blazor.Diagrams.Core.Positions.Resizing { public class TopRightResizerProvider : IResizerProvider { - public string? Class => "topright"; + public string? Class => "topright"; - private Size _originalSize = null!; - private Point _originalPosition = null!; - private Point _originalMousePosition = null!; - private NodeModel _nodeModel = null!; + private Size? _originalSize; + private Point? _originalPosition; + private Point? _originalMousePosition; + private NodeModel? _nodeModel; + private Diagram? _diagram; public Point? GetPosition(Model model) { @@ -29,22 +30,24 @@ public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventAr { _originalPosition = new Point(nodeModel.Position.X, nodeModel.Position.Y); _originalMousePosition = new Point(eventArgs.ClientX, eventArgs.ClientY); - _originalSize = nodeModel.Size!; + _originalSize = nodeModel.Size; _nodeModel = nodeModel; + _diagram = diagram; } } public void OnPointerMove(Model? model, PointerEventArgs args) { - if (_nodeModel is null) + if (_originalSize is null || _originalPosition is null || _originalMousePosition is null || _nodeModel is null || _diagram is null) { return; } - var height = _originalSize.Height - (args.ClientY - _originalMousePosition.Y); - var width = _originalSize.Width + (args.ClientX - _originalMousePosition.X); + + var height = _originalSize.Height - (args.ClientY - _originalMousePosition.Y) / _diagram.Zoom; + var width = _originalSize.Width + (args.ClientX - _originalMousePosition.X) / _diagram.Zoom; var positionX = _originalPosition.X; - var positionY = _originalPosition.Y + (args.ClientY - _originalMousePosition.Y); + var positionY = _originalPosition.Y + (args.ClientY - _originalMousePosition.Y) / _diagram.Zoom; if (width < _nodeModel.MinimumDimensions.Width) { @@ -64,11 +67,12 @@ public void OnPointerMove(Model? model, PointerEventArgs args) public void OnResizeEnd(Model? model, PointerEventArgs args) { _nodeModel?.TriggerSizeChanged(); - _originalSize = null!; - _originalPosition = null!; - _originalMousePosition = null!; - _nodeModel = null!; + _originalSize = null; + _originalPosition = null; + _originalMousePosition = null; + _nodeModel = null; + _diagram = null; } } -} +} \ No newline at end of file diff --git a/tests/Blazor.Diagrams.Core.Tests/Controls/ResizeControlTests.cs b/tests/Blazor.Diagrams.Core.Tests/Controls/ResizeControlTests.cs index dcd9bab14..5192be721 100644 --- a/tests/Blazor.Diagrams.Core.Tests/Controls/ResizeControlTests.cs +++ b/tests/Blazor.Diagrams.Core.Tests/Controls/ResizeControlTests.cs @@ -5,71 +5,70 @@ using Moq; using Xunit; -namespace Blazor.Diagrams.Core.Tests.Controls +namespace Blazor.Diagrams.Core.Tests.Controls; + +public class ResizeControlTests { - public class ResizeControlTests + [Fact] + public void GetPosition_ShouldUseResizeProviderGetPosition() { - [Fact] - public void GetPosition_ShouldUseResizeProviderGetPosition() - { - var resizeProvider = new Mock(); - var control = new ResizeControl(resizeProvider.Object); - var model = new Mock(); + var resizeProvider = new Mock(); + var control = new ResizeControl(resizeProvider.Object); + var model = new Mock(); - control.GetPosition(model.Object); + control.GetPosition(model.Object); - resizeProvider.Verify(m => m.GetPosition(model.Object), Times.Once); - } + resizeProvider.Verify(m => m.GetPosition(model.Object), Times.Once); + } - [Fact] - public void OnPointerDown_ShouldInvokeResizeStart() - { - var resizeProvider = new Mock(); - var control = new ResizeControl(resizeProvider.Object); - var diagram = Mock.Of(); - var model = Mock.Of(); - var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true); + [Fact] + public void OnPointerDown_ShouldInvokeResizeStart() + { + var resizeProvider = new Mock(); + var control = new ResizeControl(resizeProvider.Object); + var diagram = Mock.Of(); + var model = Mock.Of(); + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true); - control.OnPointerDown(diagram, model, eventArgs); + control.OnPointerDown(diagram, model, eventArgs); - resizeProvider.Verify(m => m.OnResizeStart(diagram, model, eventArgs), Times.Once); - } + resizeProvider.Verify(m => m.OnResizeStart(diagram, model, eventArgs), Times.Once); + } - [Fact] - public void OnPointerDown_ShouldAddEventHandlers() - { - var resizeProvider = new Mock(); - var control = new ResizeControl(resizeProvider.Object); - var diagram = new TestDiagram(); - var model = Mock.Of(); - var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true); + [Fact] + public void OnPointerDown_ShouldAddEventHandlers() + { + var resizeProvider = new Mock(); + var control = new ResizeControl(resizeProvider.Object); + var diagram = new TestDiagram(); + var model = Mock.Of(); + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true); - control.OnPointerDown(diagram, model, eventArgs); - - diagram.TriggerPointerMove(model, eventArgs); - resizeProvider.Verify(m => m.OnPointerMove(model, eventArgs), Times.Once); + control.OnPointerDown(diagram, model, eventArgs); + + diagram.TriggerPointerMove(model, eventArgs); + resizeProvider.Verify(m => m.OnPointerMove(model, eventArgs), Times.Once); - diagram.TriggerPointerUp(model, eventArgs); - resizeProvider.Verify(m => m.OnResizeEnd(model, eventArgs), Times.Once); - } + diagram.TriggerPointerUp(model, eventArgs); + resizeProvider.Verify(m => m.OnResizeEnd(model, eventArgs), Times.Once); + } - [Fact] - public void OnPointerUp_ShouldRemoveEventHandlers() - { - var resizeProvider = new Mock(); - var control = new ResizeControl(resizeProvider.Object); - var diagram = new TestDiagram(); - var model = Mock.Of(); - var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true); + [Fact] + public void OnPointerUp_ShouldRemoveEventHandlers() + { + var resizeProvider = new Mock(); + var control = new ResizeControl(resizeProvider.Object); + var diagram = new TestDiagram(); + var model = Mock.Of(); + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true); - control.OnPointerDown(diagram, model, eventArgs); - diagram.TriggerPointerUp(model, eventArgs); + control.OnPointerDown(diagram, model, eventArgs); + diagram.TriggerPointerUp(model, eventArgs); - diagram.TriggerPointerMove(model, eventArgs); - resizeProvider.Verify(m => m.OnPointerMove(model, eventArgs), Times.Never); + diagram.TriggerPointerMove(model, eventArgs); + resizeProvider.Verify(m => m.OnPointerMove(model, eventArgs), Times.Never); - diagram.TriggerPointerUp(model, eventArgs); - resizeProvider.Verify(m => m.OnResizeEnd(model, eventArgs), Times.Once); - } + diagram.TriggerPointerUp(model, eventArgs); + resizeProvider.Verify(m => m.OnResizeEnd(model, eventArgs), Times.Once); } } diff --git a/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomLeftResizerProviderTests.cs b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomLeftResizerProviderTests.cs index 79ef6c17b..1605cb14f 100644 --- a/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomLeftResizerProviderTests.cs +++ b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomLeftResizerProviderTests.cs @@ -11,72 +11,135 @@ using System.Threading.Tasks; using Xunit; -namespace Blazor.Diagrams.Core.Tests.Positions.Resizing +namespace Blazor.Diagrams.Core.Tests.Positions.Resizing; + +public class BottomLeftResizerProviderTests { - public class BottomLeftResizerProviderTests + [Fact] + public void DragResizer_ShouldResizeNode() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new BottomLeftResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(10); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(90); + node.Size.Height.Should().Be(215); + } + + [Fact] + public void DragResizer_SmallerThanMinSize_SetsNodeToMinSize() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new BottomLeftResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(99, -199, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + eventArgs = new PointerEventArgs(300, -300, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(99); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(0); + node.Size.Height.Should().Be(0); + } + + [Fact] + public void DragResizer_ShouldResizeNode_WhenDiagramZoomedOut() { - [Fact] - public void DragResizer_ShouldResizeNode() - { - // setup - var diagram = new TestDiagram(); - diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); - var node = new NodeModel(position: new Point(0, 0)); - node.Size = new Size(100, 200); - var control = new ResizeControl(new BottomLeftResizerProvider()); - diagram.Controls.AddFor(node).Add(control); - diagram.SelectModel(node, false); - - // before resize - node.Position.X.Should().Be(0); - node.Position.Y.Should().Be(0); - node.Size.Width.Should().Be(100); - node.Size.Height.Should().Be(200); - - // resize - var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - control.OnPointerDown(diagram, node, eventArgs); - eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - diagram.TriggerPointerMove(null, eventArgs); - - // after resize - node.Position.X.Should().Be(10); - node.Position.Y.Should().Be(0); - node.Size.Width.Should().Be(90); - node.Size.Height.Should().Be(215); - } - - [Fact] - public void DragResizer_SmallerThanMinSize_SetsNodeToMinSize() - { - // setup - var diagram = new TestDiagram(); - diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); - var node = new NodeModel(position: new Point(0, 0)); - node.Size = new Size(100, 200); - var control = new ResizeControl(new BottomLeftResizerProvider()); - diagram.Controls.AddFor(node).Add(control); - diagram.SelectModel(node, false); - - // before resize - node.Position.X.Should().Be(0); - node.Position.Y.Should().Be(0); - node.Size.Width.Should().Be(100); - node.Size.Height.Should().Be(200); - - // resize - var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - control.OnPointerDown(diagram, node, eventArgs); - eventArgs = new PointerEventArgs(99, -199, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - diagram.TriggerPointerMove(null, eventArgs); - eventArgs = new PointerEventArgs(300, -300, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - diagram.TriggerPointerMove(null, eventArgs); - - // after resize - node.Position.X.Should().Be(99); - node.Position.Y.Should().Be(0); - node.Size.Width.Should().Be(0); - node.Size.Height.Should().Be(0); - } + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new BottomLeftResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + diagram.SetZoom(0.5); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(20); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(80); + node.Size.Height.Should().Be(230); + } + + [Fact] + public void DragResizer_ShouldResizeNode_WhenDiagramZoomedIn() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new BottomLeftResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + diagram.SetZoom(2); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(5); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(95); + node.Size.Height.Should().Be(207.5); } } diff --git a/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomRightResizerProviderTests.cs b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomRightResizerProviderTests.cs index 20ab27770..959724e6d 100644 --- a/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomRightResizerProviderTests.cs +++ b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomRightResizerProviderTests.cs @@ -11,70 +11,133 @@ using System.Threading.Tasks; using Xunit; -namespace Blazor.Diagrams.Core.Tests.Positions.Resizing +namespace Blazor.Diagrams.Core.Tests.Positions.Resizing; + +public class BottomRightResizerProviderTests { - public class BottomRightResizerProviderTests + [Fact] + public void DragResizer_ShouldResizeNode() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new BottomRightResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(110); + node.Size.Height.Should().Be(215); + } + + [Fact] + public void DragResizer_SmallerThanMinSize_SetsNodeToMinSize() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new BottomRightResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(-300, -300, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(0); + node.Size.Height.Should().Be(0); + } + + [Fact] + public void DragResizer_ShouldResizeNode_WhenDiagramZoomedOut() { - [Fact] - public void DragResizer_ShouldResizeNode() - { - // setup - var diagram = new TestDiagram(); - diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); - var node = new NodeModel(position: new Point(0, 0)); - node.Size = new Size(100, 200); - var control = new ResizeControl(new BottomRightResizerProvider()); - diagram.Controls.AddFor(node).Add(control); - diagram.SelectModel(node, false); - - // before resize - node.Position.X.Should().Be(0); - node.Position.Y.Should().Be(0); - node.Size.Width.Should().Be(100); - node.Size.Height.Should().Be(200); - - // resize - var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - control.OnPointerDown(diagram, node, eventArgs); - eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - diagram.TriggerPointerMove(null, eventArgs); - - // after resize - node.Position.X.Should().Be(0); - node.Position.Y.Should().Be(0); - node.Size.Width.Should().Be(110); - node.Size.Height.Should().Be(215); - } - - [Fact] - public void DragResizer_SmallerThanMinSize_SetsNodeToMinSize() - { - // setup - var diagram = new TestDiagram(); - diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); - var node = new NodeModel(position: new Point(0, 0)); - node.Size = new Size(100, 200); - var control = new ResizeControl(new BottomRightResizerProvider()); - diagram.Controls.AddFor(node).Add(control); - diagram.SelectModel(node, false); - - // before resize - node.Position.X.Should().Be(0); - node.Position.Y.Should().Be(0); - node.Size.Width.Should().Be(100); - node.Size.Height.Should().Be(200); - - // resize - var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - control.OnPointerDown(diagram, node, eventArgs); - eventArgs = new PointerEventArgs(-300, -300, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - diagram.TriggerPointerMove(null, eventArgs); - - // after resize - node.Position.X.Should().Be(0); - node.Position.Y.Should().Be(0); - node.Size.Width.Should().Be(0); - node.Size.Height.Should().Be(0); - } + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new BottomRightResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + diagram.SetZoom(0.5); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(120); + node.Size.Height.Should().Be(230); + } + + [Fact] + public void DragResizer_ShouldResizeNode_WhenDiagramZoomedIn() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new BottomRightResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + diagram.SetZoom(2); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(105); + node.Size.Height.Should().Be(207.5); } } diff --git a/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopLeftResizerProviderTests.cs b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopLeftResizerProviderTests.cs index 1cc715d59..13d241d08 100644 --- a/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopLeftResizerProviderTests.cs +++ b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopLeftResizerProviderTests.cs @@ -11,72 +11,135 @@ using System.Threading.Tasks; using Xunit; -namespace Blazor.Diagrams.Core.Tests.Positions.Resizing +namespace Blazor.Diagrams.Core.Tests.Positions.Resizing; + +public class TopLeftResizerProviderTests { - public class TopLeftResizerProviderTests + [Fact] + public void DragResizer_ShouldResizeNode() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new TopLeftResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(10); + node.Position.Y.Should().Be(15); + node.Size.Width.Should().Be(90); + node.Size.Height.Should().Be(185); + } + + [Fact] + public void DragResizer_SmallerThanMinSize_SetsNodeToMinSize() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new TopLeftResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(99, 199, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + eventArgs = new PointerEventArgs(300, 300, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(99); + node.Position.Y.Should().Be(199); + node.Size.Width.Should().Be(0); + node.Size.Height.Should().Be(0); + } + + [Fact] + public void DragResizer_ShouldResizeNode_WhenDiagramZoomedOut() { - [Fact] - public void DragResizer_ShouldResizeNode() - { - // setup - var diagram = new TestDiagram(); - diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); - var node = new NodeModel(position: new Point(0, 0)); - node.Size = new Size(100, 200); - var control = new ResizeControl(new TopLeftResizerProvider()); - diagram.Controls.AddFor(node).Add(control); - diagram.SelectModel(node, false); - - // before resize - node.Position.X.Should().Be(0); - node.Position.Y.Should().Be(0); - node.Size.Width.Should().Be(100); - node.Size.Height.Should().Be(200); - - // resize - var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - control.OnPointerDown(diagram, node, eventArgs); - eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - diagram.TriggerPointerMove(null, eventArgs); - - // after resize - node.Position.X.Should().Be(10); - node.Position.Y.Should().Be(15); - node.Size.Width.Should().Be(90); - node.Size.Height.Should().Be(185); - } - - [Fact] - public void DragResizer_SmallerThanMinSize_SetsNodeToMinSize() - { - // setup - var diagram = new TestDiagram(); - diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); - var node = new NodeModel(position: new Point(0, 0)); - node.Size = new Size(100, 200); - var control = new ResizeControl(new TopLeftResizerProvider()); - diagram.Controls.AddFor(node).Add(control); - diagram.SelectModel(node, false); - - // before resize - node.Position.X.Should().Be(0); - node.Position.Y.Should().Be(0); - node.Size.Width.Should().Be(100); - node.Size.Height.Should().Be(200); - - // resize - var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - control.OnPointerDown(diagram, node, eventArgs); - eventArgs = new PointerEventArgs(99, 199, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - diagram.TriggerPointerMove(null, eventArgs); - eventArgs = new PointerEventArgs(300, 300, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - diagram.TriggerPointerMove(null, eventArgs); - - // after resize - node.Position.X.Should().Be(99); - node.Position.Y.Should().Be(199); - node.Size.Width.Should().Be(0); - node.Size.Height.Should().Be(0); - } + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new TopLeftResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + diagram.SetZoom(0.5); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(20); + node.Position.Y.Should().Be(30); + node.Size.Width.Should().Be(80); + node.Size.Height.Should().Be(170); + } + + [Fact] + public void DragResizer_ShouldResizeNode_WhenDiagramZoomedIn() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new TopLeftResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + diagram.SetZoom(2); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(5); + node.Position.Y.Should().Be(7.5); + node.Size.Width.Should().Be(95); + node.Size.Height.Should().Be(192.5); } } diff --git a/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopRightResizerProviderTests.cs b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopRightResizerProviderTests.cs index a138d524f..5fcd3b821 100644 --- a/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopRightResizerProviderTests.cs +++ b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopRightResizerProviderTests.cs @@ -11,72 +11,135 @@ using System.Threading.Tasks; using Xunit; -namespace Blazor.Diagrams.Core.Tests.Positions.Resizing +namespace Blazor.Diagrams.Core.Tests.Positions.Resizing; + +public class TopRightResizerProviderTests { - public class TopRightResizerProviderTests + [Fact] + public void DragResizer_ShouldResizeNode() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new TopRightResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(15); + node.Size.Width.Should().Be(110); + node.Size.Height.Should().Be(185); + } + + [Fact] + public void DragResizer_SmallerThanMinSize_SetsNodeToMinSize() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new TopRightResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(-99, 199, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + eventArgs = new PointerEventArgs(-300, 300, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(199); + node.Size.Width.Should().Be(0); + node.Size.Height.Should().Be(0); + } + + [Fact] + public void DragResizer_ShouldResizeNode_WhenDiagramZoomedOut() { - [Fact] - public void DragResizer_ShouldResizeNode() - { - // setup - var diagram = new TestDiagram(); - diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); - var node = new NodeModel(position: new Point(0, 0)); - node.Size = new Size(100, 200); - var control = new ResizeControl(new TopRightResizerProvider()); - diagram.Controls.AddFor(node).Add(control); - diagram.SelectModel(node, false); - - // before resize - node.Position.X.Should().Be(0); - node.Position.Y.Should().Be(0); - node.Size.Width.Should().Be(100); - node.Size.Height.Should().Be(200); - - // resize - var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - control.OnPointerDown(diagram, node, eventArgs); - eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - diagram.TriggerPointerMove(null, eventArgs); - - // after resize - node.Position.X.Should().Be(0); - node.Position.Y.Should().Be(15); - node.Size.Width.Should().Be(110); - node.Size.Height.Should().Be(185); - } - - [Fact] - public void DragResizer_SmallerThanMinSize_SetsNodeToMinSize() - { - // setup - var diagram = new TestDiagram(); - diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); - var node = new NodeModel(position: new Point(0, 0)); - node.Size = new Size(100, 200); - var control = new ResizeControl(new TopRightResizerProvider()); - diagram.Controls.AddFor(node).Add(control); - diagram.SelectModel(node, false); - - // before resize - node.Position.X.Should().Be(0); - node.Position.Y.Should().Be(0); - node.Size.Width.Should().Be(100); - node.Size.Height.Should().Be(200); - - // resize - var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - control.OnPointerDown(diagram, node, eventArgs); - eventArgs = new PointerEventArgs(-99, 199, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - diagram.TriggerPointerMove(null, eventArgs); - eventArgs = new PointerEventArgs(-300, 300, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); - diagram.TriggerPointerMove(null, eventArgs); - - // after resize - node.Position.X.Should().Be(0); - node.Position.Y.Should().Be(199); - node.Size.Width.Should().Be(0); - node.Size.Height.Should().Be(0); - } + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new TopRightResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + diagram.SetZoom(0.5); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(30); + node.Size.Width.Should().Be(120); + node.Size.Height.Should().Be(170); + } + + [Fact] + public void DragResizer_ShouldResizeNode_WhenDiagramZoomedIn() + { + // setup + var diagram = new TestDiagram(); + diagram.SetContainer(new Rectangle(0, 0, 1000, 400)); + var node = new NodeModel(position: new Point(0, 0)); + node.Size = new Size(100, 200); + var control = new ResizeControl(new TopRightResizerProvider()); + diagram.Controls.AddFor(node).Add(control); + diagram.SelectModel(node, false); + diagram.SetZoom(2); + + // before resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(0); + node.Size.Width.Should().Be(100); + node.Size.Height.Should().Be(200); + + // resize + var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + control.OnPointerDown(diagram, node, eventArgs); + eventArgs = new PointerEventArgs(10, 15, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true); + diagram.TriggerPointerMove(null, eventArgs); + + // after resize + node.Position.X.Should().Be(0); + node.Position.Y.Should().Be(7.5); + node.Size.Width.Should().Be(105); + node.Size.Height.Should().Be(192.5); } } diff --git a/tests/Blazor.Diagrams.Tests/Components/Controls/ResizeControlWidgetTests.cs b/tests/Blazor.Diagrams.Tests/Components/Controls/ResizeControlWidgetTests.cs index bf51e541c..ebc758c47 100644 --- a/tests/Blazor.Diagrams.Tests/Components/Controls/ResizeControlWidgetTests.cs +++ b/tests/Blazor.Diagrams.Tests/Components/Controls/ResizeControlWidgetTests.cs @@ -5,21 +5,20 @@ using Moq; using Xunit; -namespace Blazor.Diagrams.Tests.Components.Controls -{ +namespace Blazor.Diagrams.Tests.Components.Controls; + public class ResizeControlWidgetTests +{ + [Fact] + public void ShouldRenderDiv() { - [Fact] - public void ShouldRenderDiv() - { - using var ctx = new TestContext(); - var providerMock = Mock.Of(); - - var cut = ctx.RenderComponent(parameters => - parameters.Add(w => w.Control, new ResizeControl(providerMock)) - ); + using var ctx = new TestContext(); + var providerMock = Mock.Of(); + + var cut = ctx.RenderComponent(parameters => + parameters.Add(w => w.Control, new ResizeControl(providerMock)) + ); - cut.MarkupMatches("
"); - } + cut.MarkupMatches("
"); } } From 522ddb17b9617c736738a92c58e977bf24281720 Mon Sep 17 00:00:00 2001 From: Renan Alvarenga Date: Thu, 29 Feb 2024 12:49:56 +1100 Subject: [PATCH 3/7] update ports when node resized --- src/Blazor.Diagrams.Core/Models/NodeModel.cs | 24 +++++++++ src/Blazor.Diagrams.Core/Models/PortModel.cs | 34 ++++++++++++ .../Models/NodeModelTest.cs | 53 +++++++++++++++++++ .../Models/PortModelTest.cs | 33 ++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 tests/Blazor.Diagrams.Core.Tests/Models/NodeModelTest.cs create mode 100644 tests/Blazor.Diagrams.Core.Tests/Models/PortModelTest.cs diff --git a/src/Blazor.Diagrams.Core/Models/NodeModel.cs b/src/Blazor.Diagrams.Core/Models/NodeModel.cs index 610a5aac3..102a9fed6 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 a0c850816..ef2068567 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/Models/NodeModelTest.cs b/tests/Blazor.Diagrams.Core.Tests/Models/NodeModelTest.cs new file mode 100644 index 000000000..b27edc990 --- /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 000000000..d4dc57bf5 --- /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); + } + } +} From 05ba5e1e8fa4b1fa7c7a76400c727ec676fb274d Mon Sep 17 00:00:00 2001 From: Suraj Date: Tue, 30 Jan 2024 10:30:06 +0530 Subject: [PATCH 4/7] fix css for resizers --- src/Blazor.Diagrams/wwwroot/default.styles.css | 1 + src/Blazor.Diagrams/wwwroot/default.styles.min.css | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Blazor.Diagrams/wwwroot/default.styles.css b/src/Blazor.Diagrams/wwwroot/default.styles.css index 2b355029a..0e37330c2 100644 --- a/src/Blazor.Diagrams/wwwroot/default.styles.css +++ b/src/Blazor.Diagrams/wwwroot/default.styles.css @@ -133,6 +133,7 @@ g.diagram-group.default.selected > rect { background-color: #f5f5f5; border: 1px solid #6e9fd4; position: absolute; + transform: translate(-2.5px, -2.5px); } .default-node-resizer.bottomright { diff --git a/src/Blazor.Diagrams/wwwroot/default.styles.min.css b/src/Blazor.Diagrams/wwwroot/default.styles.min.css index e794e823e..781fb0aed 100644 --- a/src/Blazor.Diagrams/wwwroot/default.styles.min.css +++ b/src/Blazor.Diagrams/wwwroot/default.styles.min.css @@ -1 +1 @@ -.default-node{width:100px;height:80px;border-radius:10px;background-color:#f5f5f5;border:1px solid #e8e8e8;-webkit-box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12);box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12);position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;}.default-node.selected{border:1px solid #6e9fd4;}.default-node.selected .diagram-port{border:1px solid #6e9fd4;}.default-node .diagram-port,.default.diagram-group .diagram-port{width:20px;height:20px;margin:-10px;border-radius:50%;background-color:#f5f5f5;border:1px solid #d4d4d4;cursor:pointer;position:absolute;}.default-node .diagram-port:hover,.default-node .diagram-port.has-links,.default.diagram-group .diagram-port.has-links{background-color:#000;}.default-node .diagram-port.bottom,.default.diagram-group .diagram-port.bottom{bottom:0;left:50%;}.default-node .diagram-port.bottomleft,.default.diagram-group .diagram-port.bottomleft{bottom:0;left:0;}.default-node .diagram-port.bottomright,.default.diagram-group .diagram-port.bottomright{bottom:0;right:0;}.default-node .diagram-port.top,.default.diagram-group .diagram-port.top{top:0;left:50%;}.default-node .diagram-port.topleft,.default.diagram-group .diagram-port.topleft{top:0;left:0;}.default-node .diagram-port.topright,.default.diagram-group .diagram-port.topright{top:0;right:0;}.default-node .diagram-port.left,.default.diagram-group .diagram-port.left{left:0;top:50%;}.default-node .diagram-port.right,.default.diagram-group .diagram-port.right{right:0;top:50%;}.diagram-navigator.default{position:absolute;bottom:10px;right:10px;border:3px solid #9ba8b0;border-radius:15px;padding:20px;background-color:#fff;}div.diagram-group.default{outline:2px solid #000;background:#c6c6c6;}div.diagram-group.default.selected{outline:2px solid #6e9fd4;}g.diagram-group.default rect{outline:2px solid #000;fill:#c6c632;}g.diagram-group.default.selected>rect{outline:2px solid #008000;}.diagram-link div.default-link-label{display:inline-block;color:#fff;background-color:#6e9fd4;border-radius:.25rem;padding:.25rem;text-align:center;font-size:.875rem;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;min-width:3rem;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%);}.default-node-resizer{width:5px;height:5px;background-color:#f5f5f5;border:1px solid #6e9fd4;position:absolute;}.default-node-resizer.bottomright{cursor:nwse-resize;}.default-node-resizer.topright{cursor:nesw-resize;}.default-node-resizer.bottomleft{cursor:nesw-resize;}.default-node-resizer.topleft{cursor:nwse-resize;} \ No newline at end of file +.default-node{width:100px;height:80px;border-radius:10px;background-color:#f5f5f5;border:1px solid #e8e8e8;-webkit-box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12);box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12);position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;}.default-node.selected{border:1px solid #6e9fd4;}.default-node.selected .diagram-port{border:1px solid #6e9fd4;}.default-node .diagram-port,.default.diagram-group .diagram-port{width:20px;height:20px;margin:-10px;border-radius:50%;background-color:#f5f5f5;border:1px solid #d4d4d4;cursor:pointer;position:absolute;}.default-node .diagram-port:hover,.default-node .diagram-port.has-links,.default.diagram-group .diagram-port.has-links{background-color:#000;}.default-node .diagram-port.bottom,.default.diagram-group .diagram-port.bottom{bottom:0;left:50%;}.default-node .diagram-port.bottomleft,.default.diagram-group .diagram-port.bottomleft{bottom:0;left:0;}.default-node .diagram-port.bottomright,.default.diagram-group .diagram-port.bottomright{bottom:0;right:0;}.default-node .diagram-port.top,.default.diagram-group .diagram-port.top{top:0;left:50%;}.default-node .diagram-port.topleft,.default.diagram-group .diagram-port.topleft{top:0;left:0;}.default-node .diagram-port.topright,.default.diagram-group .diagram-port.topright{top:0;right:0;}.default-node .diagram-port.left,.default.diagram-group .diagram-port.left{left:0;top:50%;}.default-node .diagram-port.right,.default.diagram-group .diagram-port.right{right:0;top:50%;}.diagram-navigator.default{position:absolute;bottom:10px;right:10px;border:3px solid #9ba8b0;border-radius:15px;padding:20px;background-color:#fff;}div.diagram-group.default{outline:2px solid #000;background:#c6c6c6;}div.diagram-group.default.selected{outline:2px solid #6e9fd4;}g.diagram-group.default rect{outline:2px solid #000;fill:#c6c632;}g.diagram-group.default.selected>rect{outline:2px solid #008000;}.diagram-link div.default-link-label{display:inline-block;color:#fff;background-color:#6e9fd4;border-radius:.25rem;padding:.25rem;text-align:center;font-size:.875rem;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;min-width:3rem;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%);}.default-node-resizer{width:5px;height:5px;background-color:#f5f5f5;border:1px solid #6e9fd4;position:absolute;transform:translate(-2.5px,-2.5px);}.default-node-resizer.bottomright{cursor:nwse-resize;}.default-node-resizer.topright{cursor:nesw-resize;}.default-node-resizer.bottomleft{cursor:nesw-resize;}.default-node-resizer.topleft{cursor:nwse-resize;} \ No newline at end of file From a7ce3eb0f6dcf3b09aed1995e612f02eebfd9eb0 Mon Sep 17 00:00:00 2001 From: Heather Cox Date: Wed, 3 Jul 2024 09:46:26 +1000 Subject: [PATCH 5/7] refactor ResizerProvider interface to abstract class --- .../Controls/Default/ResizeControl.cs | 4 +- .../Resizing/BottomLeftResizerProvider.cs | 70 ++---------- .../Resizing/BottomRightResizerProvider.cs | 60 ++-------- .../Positions/Resizing/IResizerProvider.cs | 14 --- .../Positions/Resizing/ResizerProvider.cs | 104 ++++++++++++++++++ .../Resizing/TopLeftResizerProvider.cs | 69 ++---------- .../Resizing/TopRightResizerProvider.cs | 69 ++---------- .../Controls/ResizeControlTests.cs | 12 +- .../Controls/ResizeControlWidgetTests.cs | 4 +- 9 files changed, 146 insertions(+), 260 deletions(-) delete mode 100644 src/Blazor.Diagrams.Core/Positions/Resizing/IResizerProvider.cs create mode 100644 src/Blazor.Diagrams.Core/Positions/Resizing/ResizerProvider.cs diff --git a/src/Blazor.Diagrams.Core/Controls/Default/ResizeControl.cs b/src/Blazor.Diagrams.Core/Controls/Default/ResizeControl.cs index 4517f673d..04d0e02a5 100644 --- a/src/Blazor.Diagrams.Core/Controls/Default/ResizeControl.cs +++ b/src/Blazor.Diagrams.Core/Controls/Default/ResizeControl.cs @@ -8,9 +8,9 @@ namespace Blazor.Diagrams.Core.Controls.Default { public class ResizeControl : ExecutableControl { - private readonly IResizerProvider _resizeProvider; + private readonly ResizerProvider _resizeProvider; - public ResizeControl(IResizerProvider resizeProvider) + public ResizeControl(ResizerProvider resizeProvider) { _resizeProvider = resizeProvider; } diff --git a/src/Blazor.Diagrams.Core/Positions/Resizing/BottomLeftResizerProvider.cs b/src/Blazor.Diagrams.Core/Positions/Resizing/BottomLeftResizerProvider.cs index f3e8b10d4..6b6cc3dc5 100644 --- a/src/Blazor.Diagrams.Core/Positions/Resizing/BottomLeftResizerProvider.cs +++ b/src/Blazor.Diagrams.Core/Positions/Resizing/BottomLeftResizerProvider.cs @@ -1,22 +1,18 @@ -using Blazor.Diagrams.Core.Events; -using Blazor.Diagrams.Core.Geometry; +using Blazor.Diagrams.Core.Geometry; using Blazor.Diagrams.Core.Models; using Blazor.Diagrams.Core.Models.Base; namespace Blazor.Diagrams.Core.Positions.Resizing { - public class BottomLeftResizerProvider : IResizerProvider + public class BottomLeftResizerProvider : ResizerProvider { - public string? Class => "bottomleft"; + override public string? Class => "bottomleft"; + override public bool ShouldChangeXPositionOnResize => true; + override public bool ShouldChangeYPositionOnResize => false; + override public bool ShouldAddTotalMovedX => false; + override public bool ShouldAddTotalMovedY => true; - private Size? _originalSize; - private Point? _originalPosition; - private Point? _originalMousePosition; - private NodeModel? _nodeModel; - private Diagram? _diagram; - - - public Point? GetPosition(Model model) + public override Point? GetPosition(Model model) { if (model is NodeModel nodeModel && nodeModel.Size is not null) { @@ -25,55 +21,5 @@ public class BottomLeftResizerProvider : IResizerProvider return null; } - public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventArgs) - { - if (model is NodeModel nodeModel) - { - _originalPosition = new Point(nodeModel.Position.X, nodeModel.Position.Y); - _originalMousePosition = new Point(eventArgs.ClientX, eventArgs.ClientY); - _originalSize = nodeModel.Size; - _nodeModel = nodeModel; - _diagram = diagram; - } - } - - public void OnPointerMove(Model? model, PointerEventArgs args) - { - if (_originalSize is null || _originalPosition is null || _originalMousePosition is null || _nodeModel is null || _diagram is null) - { - return; - } - - var height = _originalSize.Height + (args.ClientY - _originalMousePosition.Y) / _diagram.Zoom; - var width = _originalSize.Width - (args.ClientX - _originalMousePosition.X) / _diagram.Zoom; - - var positionX = _originalPosition.X + (args.ClientX - _originalMousePosition.X) / _diagram.Zoom; - var positionY = _originalPosition.Y; - - if (width < _nodeModel.MinimumDimensions.Width) - { - width = _nodeModel.MinimumDimensions.Width; - positionX = _nodeModel.Position.X; - } - if (height < _nodeModel.MinimumDimensions.Height) - { - height = _nodeModel.MinimumDimensions.Height; - positionY = _nodeModel.Position.Y; - } - - _nodeModel.SetPosition(positionX, positionY); - _nodeModel.SetSize(width, height); - } - - public void OnResizeEnd(Model? model, PointerEventArgs args) - { - _nodeModel?.TriggerSizeChanged(); - _originalSize = null; - _originalPosition = null; - _originalMousePosition = null; - _nodeModel = null; - _diagram = null; - } - } } diff --git a/src/Blazor.Diagrams.Core/Positions/Resizing/BottomRightResizerProvider.cs b/src/Blazor.Diagrams.Core/Positions/Resizing/BottomRightResizerProvider.cs index d5cad9e89..394b882bb 100644 --- a/src/Blazor.Diagrams.Core/Positions/Resizing/BottomRightResizerProvider.cs +++ b/src/Blazor.Diagrams.Core/Positions/Resizing/BottomRightResizerProvider.cs @@ -1,20 +1,18 @@ -using Blazor.Diagrams.Core.Events; -using Blazor.Diagrams.Core.Geometry; +using Blazor.Diagrams.Core.Geometry; using Blazor.Diagrams.Core.Models; using Blazor.Diagrams.Core.Models.Base; namespace Blazor.Diagrams.Core.Positions.Resizing { - public class BottomRightResizerProvider : IResizerProvider + public class BottomRightResizerProvider : ResizerProvider { - public string? Class => "bottomright"; + override public string? Class => "bottomright"; + override public bool ShouldChangeXPositionOnResize => false; + override public bool ShouldChangeYPositionOnResize => false; + override public bool ShouldAddTotalMovedX => true; + override public bool ShouldAddTotalMovedY => true; - private Size? _originalSize; - private Point? _originalMousePosition; - private NodeModel? _nodeModel; - private Diagram? _diagram; - - public Point? GetPosition(Model model) + public override Point? GetPosition(Model model) { if (model is NodeModel nodeModel && nodeModel.Size is not null) { @@ -23,47 +21,5 @@ public class BottomRightResizerProvider : IResizerProvider return null; } - public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventArgs) - { - if (model is NodeModel nodeModel) - { - _originalMousePosition = new Point(eventArgs.ClientX, eventArgs.ClientY); - _originalSize = nodeModel.Size; - _nodeModel = nodeModel; - _diagram = diagram; - } - } - - public void OnPointerMove(Model? model, PointerEventArgs args) - { - if (_originalSize is null || _originalMousePosition is null || _nodeModel is null || _diagram is null) - { - return; - } - - var height = _originalSize.Height + (args.ClientY - _originalMousePosition.Y) / _diagram.Zoom; - var width = _originalSize.Width + (args.ClientX - _originalMousePosition.X) / _diagram.Zoom; - - if (width < _nodeModel.MinimumDimensions.Width) - { - width = _nodeModel.MinimumDimensions.Width; - } - if (height < _nodeModel.MinimumDimensions.Height) - { - height = _nodeModel.MinimumDimensions.Height; - } - - _nodeModel.SetSize(width, height); - } - - public void OnResizeEnd(Model? model, PointerEventArgs args) - { - _nodeModel?.TriggerSizeChanged(); - _originalSize = null; - _originalMousePosition = null; - _nodeModel = null; - _diagram = null; - } - } } diff --git a/src/Blazor.Diagrams.Core/Positions/Resizing/IResizerProvider.cs b/src/Blazor.Diagrams.Core/Positions/Resizing/IResizerProvider.cs deleted file mode 100644 index 65a2ecdde..000000000 --- a/src/Blazor.Diagrams.Core/Positions/Resizing/IResizerProvider.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Blazor.Diagrams.Core.Events; -using Blazor.Diagrams.Core.Models; -using Blazor.Diagrams.Core.Models.Base; - -namespace Blazor.Diagrams.Core.Positions.Resizing -{ - public interface IResizerProvider : IPositionProvider - { - public string? Class { get; } - public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventArgs); - public void OnPointerMove(Model? model, PointerEventArgs args); - public void OnResizeEnd(Model? model, PointerEventArgs args); - } -} diff --git a/src/Blazor.Diagrams.Core/Positions/Resizing/ResizerProvider.cs b/src/Blazor.Diagrams.Core/Positions/Resizing/ResizerProvider.cs new file mode 100644 index 000000000..f44626c19 --- /dev/null +++ b/src/Blazor.Diagrams.Core/Positions/Resizing/ResizerProvider.cs @@ -0,0 +1,104 @@ +using Blazor.Diagrams.Core.Events; +using Blazor.Diagrams.Core.Geometry; +using Blazor.Diagrams.Core.Models; +using Blazor.Diagrams.Core.Models.Base; + +namespace Blazor.Diagrams.Core.Positions.Resizing +{ + public abstract class ResizerProvider : IPositionProvider + { + abstract public string? Class { get; } + + protected Size? OriginalSize { get; set; } + protected Point? OriginalPosition { get; set; } + protected double? LastClientX { get; set; } + protected double? LastClientY { get; set; } + protected NodeModel? NodeModel { get; set; } + protected Diagram? Diagram { get; set; } + private double _totalMovedX = 0; + private double _totalMovedY = 0; + + abstract public bool ShouldChangeXPositionOnResize { get; } + abstract public bool ShouldChangeYPositionOnResize { get; } + /// Controls whether the totalMovedX should be added or subtracted + abstract public bool ShouldAddTotalMovedX { get; } + /// Controls whether the totalMovedY should be added or subtracted + abstract public bool ShouldAddTotalMovedY { get; } + + abstract public Point? GetPosition(Model model); + + virtual public (Size size, Point position) CalculateNewSizeAndPosition(double deltaX, double deltaY) + { + _totalMovedX += deltaX; + _totalMovedY += deltaY; + + var width = OriginalSize!.Width + (ShouldAddTotalMovedX ? _totalMovedX : -_totalMovedX) / Diagram!.Zoom; + var height = OriginalSize.Height + (ShouldAddTotalMovedY ? _totalMovedY : -_totalMovedY) / Diagram!.Zoom; + + var positionX = OriginalPosition!.X + (ShouldChangeXPositionOnResize ? _totalMovedX : 0) / Diagram!.Zoom; + var positionY = OriginalPosition.Y + (ShouldChangeYPositionOnResize ? _totalMovedY : 0) / Diagram!.Zoom; + + if (width < NodeModel!.MinimumDimensions.Width) + { + width = NodeModel.MinimumDimensions.Width; + positionX = NodeModel.Position.X; + } + if (height < NodeModel.MinimumDimensions.Height) + { + height = NodeModel.MinimumDimensions.Height; + positionY = NodeModel.Position.Y; + } + + return (new Size(width, height), new Point(positionX, positionY)); + } + + virtual public void SetSizeAndPosition(Size size, Point position) + { + NodeModel!.SetPosition(position.X, position.Y); + NodeModel.SetSize(size.Width, size.Height); + } + + virtual public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs e) + { + if (model is NodeModel nodeModel) + { + LastClientX = e.ClientX; + LastClientY = e.ClientY; + OriginalPosition = new Point(nodeModel.Position.X, nodeModel.Position.Y); + OriginalSize = nodeModel.Size; + this.NodeModel = nodeModel; + Diagram = diagram; + } + } + + virtual public void OnPointerMove(Model? model, PointerEventArgs e) + { + if (OriginalSize is null || OriginalPosition is null || NodeModel is null || Diagram is null) + { + return; + } + + var deltaX = (e.ClientX - LastClientX!.Value); + var deltaY = (e.ClientY - LastClientY!.Value); + + LastClientX = e.ClientX; + LastClientY = e.ClientY; + + var result = CalculateNewSizeAndPosition(deltaX, deltaY); + SetSizeAndPosition(result.size, result.position); + } + + virtual public void OnResizeEnd(Model? model, PointerEventArgs args) + { + NodeModel?.TriggerSizeChanged(); + OriginalSize = null; + OriginalPosition = null; + NodeModel = null; + _totalMovedX = 0; + _totalMovedY = 0; + LastClientX = null; + LastClientY = null; + Diagram = null; + } + } +} diff --git a/src/Blazor.Diagrams.Core/Positions/Resizing/TopLeftResizerProvider.cs b/src/Blazor.Diagrams.Core/Positions/Resizing/TopLeftResizerProvider.cs index c9d7fbe6b..24ccaa132 100644 --- a/src/Blazor.Diagrams.Core/Positions/Resizing/TopLeftResizerProvider.cs +++ b/src/Blazor.Diagrams.Core/Positions/Resizing/TopLeftResizerProvider.cs @@ -1,21 +1,18 @@ -using Blazor.Diagrams.Core.Events; -using Blazor.Diagrams.Core.Geometry; +using Blazor.Diagrams.Core.Geometry; using Blazor.Diagrams.Core.Models; using Blazor.Diagrams.Core.Models.Base; namespace Blazor.Diagrams.Core.Positions.Resizing { - public class TopLeftResizerProvider : IResizerProvider + public class TopLeftResizerProvider : ResizerProvider { - public string? Class => "topleft"; + override public string? Class => "topleft"; + override public bool ShouldChangeXPositionOnResize => true; + override public bool ShouldChangeYPositionOnResize => true; + override public bool ShouldAddTotalMovedX => false; + override public bool ShouldAddTotalMovedY => false; - private Size? _originalSize; - private Point? _originalPosition; - private Point? _originalMousePosition; - private NodeModel? _nodeModel; - private Diagram? _diagram; - - public Point? GetPosition(Model model) + public override Point? GetPosition(Model model) { if (model is NodeModel nodeModel && nodeModel.Size is not null) { @@ -24,55 +21,5 @@ public class TopLeftResizerProvider : IResizerProvider return null; } - public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventArgs) - { - if (model is NodeModel nodeModel) - { - _originalPosition = new Point(nodeModel.Position.X, nodeModel.Position.Y); - _originalMousePosition = new Point(eventArgs.ClientX, eventArgs.ClientY); - _originalSize = nodeModel.Size; - _nodeModel = nodeModel; - _diagram = diagram; - } - } - - public void OnPointerMove(Model? model, PointerEventArgs args) - { - if (_originalSize is null || _originalPosition is null || _originalMousePosition is null || _nodeModel is null || _diagram is null) - { - return; - } - - var height = _originalSize.Height - (args.ClientY - _originalMousePosition.Y) / _diagram.Zoom; - var width = _originalSize.Width - (args.ClientX - _originalMousePosition.X) / _diagram.Zoom; - - var positionX = _originalPosition.X + (args.ClientX - _originalMousePosition.X) / _diagram.Zoom; - var positionY = _originalPosition.Y + (args.ClientY - _originalMousePosition.Y) / _diagram.Zoom; - - if (width < _nodeModel.MinimumDimensions.Width) - { - width = _nodeModel.MinimumDimensions.Width; - positionX = _nodeModel.Position.X; - } - if (height < _nodeModel.MinimumDimensions.Height) - { - height = _nodeModel.MinimumDimensions.Height; - positionY = _nodeModel.Position.Y; - } - - _nodeModel.SetPosition(positionX, positionY); - _nodeModel.SetSize(width, height); - } - - public void OnResizeEnd(Model? model, PointerEventArgs args) - { - _nodeModel?.TriggerSizeChanged(); - _originalSize = null; - _originalPosition = null; - _originalMousePosition = null; - _nodeModel = null; - _diagram = null; - } - } } diff --git a/src/Blazor.Diagrams.Core/Positions/Resizing/TopRightResizerProvider.cs b/src/Blazor.Diagrams.Core/Positions/Resizing/TopRightResizerProvider.cs index 8f19bc727..72fd2a525 100644 --- a/src/Blazor.Diagrams.Core/Positions/Resizing/TopRightResizerProvider.cs +++ b/src/Blazor.Diagrams.Core/Positions/Resizing/TopRightResizerProvider.cs @@ -1,21 +1,18 @@ -using Blazor.Diagrams.Core.Events; -using Blazor.Diagrams.Core.Geometry; +using Blazor.Diagrams.Core.Geometry; using Blazor.Diagrams.Core.Models; using Blazor.Diagrams.Core.Models.Base; namespace Blazor.Diagrams.Core.Positions.Resizing { - public class TopRightResizerProvider : IResizerProvider + public class TopRightResizerProvider : ResizerProvider { - public string? Class => "topright"; + override public string? Class => "topright"; + override public bool ShouldChangeXPositionOnResize => false; + override public bool ShouldChangeYPositionOnResize => true; + override public bool ShouldAddTotalMovedX => true; + override public bool ShouldAddTotalMovedY => false; - private Size? _originalSize; - private Point? _originalPosition; - private Point? _originalMousePosition; - private NodeModel? _nodeModel; - private Diagram? _diagram; - - public Point? GetPosition(Model model) + public override Point? GetPosition(Model model) { if (model is NodeModel nodeModel && nodeModel.Size is not null) { @@ -24,55 +21,5 @@ public class TopRightResizerProvider : IResizerProvider return null; } - public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventArgs) - { - if (model is NodeModel nodeModel) - { - _originalPosition = new Point(nodeModel.Position.X, nodeModel.Position.Y); - _originalMousePosition = new Point(eventArgs.ClientX, eventArgs.ClientY); - _originalSize = nodeModel.Size; - _nodeModel = nodeModel; - _diagram = diagram; - } - } - - public void OnPointerMove(Model? model, PointerEventArgs args) - { - if (_originalSize is null || _originalPosition is null || _originalMousePosition is null || _nodeModel is null || _diagram is null) - { - return; - } - - var height = _originalSize.Height - (args.ClientY - _originalMousePosition.Y) / _diagram.Zoom; - var width = _originalSize.Width + (args.ClientX - _originalMousePosition.X) / _diagram.Zoom; - - var positionX = _originalPosition.X; - var positionY = _originalPosition.Y + (args.ClientY - _originalMousePosition.Y) / _diagram.Zoom; - - if (width < _nodeModel.MinimumDimensions.Width) - { - width = _nodeModel.MinimumDimensions.Width; - positionX = _nodeModel.Position.X; - } - if (height < _nodeModel.MinimumDimensions.Height) - { - height = _nodeModel.MinimumDimensions.Height; - positionY = _nodeModel.Position.Y; - } - - _nodeModel.SetPosition(positionX, positionY); - _nodeModel.SetSize(width, height); - } - - public void OnResizeEnd(Model? model, PointerEventArgs args) - { - _nodeModel?.TriggerSizeChanged(); - _originalSize = null; - _originalPosition = null; - _originalMousePosition = null; - _nodeModel = null; - _diagram = null; - } - } } \ No newline at end of file diff --git a/tests/Blazor.Diagrams.Core.Tests/Controls/ResizeControlTests.cs b/tests/Blazor.Diagrams.Core.Tests/Controls/ResizeControlTests.cs index 5192be721..543ecb6f0 100644 --- a/tests/Blazor.Diagrams.Core.Tests/Controls/ResizeControlTests.cs +++ b/tests/Blazor.Diagrams.Core.Tests/Controls/ResizeControlTests.cs @@ -12,7 +12,7 @@ public class ResizeControlTests [Fact] public void GetPosition_ShouldUseResizeProviderGetPosition() { - var resizeProvider = new Mock(); + var resizeProvider = new Mock(); var control = new ResizeControl(resizeProvider.Object); var model = new Mock(); @@ -24,7 +24,7 @@ public void GetPosition_ShouldUseResizeProviderGetPosition() [Fact] public void OnPointerDown_ShouldInvokeResizeStart() { - var resizeProvider = new Mock(); + var resizeProvider = new Mock(); var control = new ResizeControl(resizeProvider.Object); var diagram = Mock.Of(); var model = Mock.Of(); @@ -38,14 +38,14 @@ public void OnPointerDown_ShouldInvokeResizeStart() [Fact] public void OnPointerDown_ShouldAddEventHandlers() { - var resizeProvider = new Mock(); + var resizeProvider = new Mock(); var control = new ResizeControl(resizeProvider.Object); var diagram = new TestDiagram(); var model = Mock.Of(); var eventArgs = new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true); control.OnPointerDown(diagram, model, eventArgs); - + diagram.TriggerPointerMove(model, eventArgs); resizeProvider.Verify(m => m.OnPointerMove(model, eventArgs), Times.Once); @@ -56,7 +56,7 @@ public void OnPointerDown_ShouldAddEventHandlers() [Fact] public void OnPointerUp_ShouldRemoveEventHandlers() { - var resizeProvider = new Mock(); + var resizeProvider = new Mock(); var control = new ResizeControl(resizeProvider.Object); var diagram = new TestDiagram(); var model = Mock.Of(); @@ -71,4 +71,4 @@ public void OnPointerUp_ShouldRemoveEventHandlers() diagram.TriggerPointerUp(model, eventArgs); resizeProvider.Verify(m => m.OnResizeEnd(model, eventArgs), Times.Once); } -} +} \ No newline at end of file diff --git a/tests/Blazor.Diagrams.Tests/Components/Controls/ResizeControlWidgetTests.cs b/tests/Blazor.Diagrams.Tests/Components/Controls/ResizeControlWidgetTests.cs index ebc758c47..ee4aa80a1 100644 --- a/tests/Blazor.Diagrams.Tests/Components/Controls/ResizeControlWidgetTests.cs +++ b/tests/Blazor.Diagrams.Tests/Components/Controls/ResizeControlWidgetTests.cs @@ -7,13 +7,13 @@ namespace Blazor.Diagrams.Tests.Components.Controls; - public class ResizeControlWidgetTests +public class ResizeControlWidgetTests { [Fact] public void ShouldRenderDiv() { using var ctx = new TestContext(); - var providerMock = Mock.Of(); + var providerMock = Mock.Of(); var cut = ctx.RenderComponent(parameters => parameters.Add(w => w.Control, new ResizeControl(providerMock)) From 2dfae4b23d4667ea908411e92a305275a7e8d982 Mon Sep 17 00:00:00 2001 From: Heather Cox Date: Wed, 3 Jul 2024 09:47:39 +1000 Subject: [PATCH 6/7] update documentation --- site/Site/Pages/Documentation/Controls/Overview.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/Site/Pages/Documentation/Controls/Overview.razor b/site/Site/Pages/Documentation/Controls/Overview.razor index 335838ae5..96ad07b25 100644 --- a/site/Site/Pages/Documentation/Controls/Overview.razor +++ b/site/Site/Pages/Documentation/Controls/Overview.razor @@ -140,7 +140,7 @@ Diagram.Controls.AddFor(SomeModel)

The ResizeControl adds a resizer which is a box that when dragged, can resize the node. The resizer position and movement of the node is controlled using a Resizer Provider.
- There are four ResizerProviders, one for each corner. Custom resizing behavior can be created by implementing IResizerProvider. + There are four ResizerProviders, one for each corner. Custom resizing behavior can be created by inheriting and overriding ResizerProvider.



From 6ef826023ecfe3288834f23df1327c074b4b1ac8 Mon Sep 17 00:00:00 2001
From: Heather Cox 
Date: Wed, 3 Jul 2024 09:57:27 +1000
Subject: [PATCH 7/7] add link between nodes in docs example

---
 site/Site/Pages/Documentation/Controls/Overview.razor | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/site/Site/Pages/Documentation/Controls/Overview.razor b/site/Site/Pages/Documentation/Controls/Overview.razor
index 96ad07b25..e732cfd2c 100644
--- a/site/Site/Pages/Documentation/Controls/Overview.razor
+++ b/site/Site/Pages/Documentation/Controls/Overview.razor
@@ -224,6 +224,9 @@ Diagram.Controls.AddFor(SomeModel).Add(new ResizeControl(new TopLeftResizerProvi
 		// Resize Control
 		var resizeNode1 = _resizerDiagram.Nodes.Add(new NodeModel(new Point(100, 100)));
 		var resizeNode2 = _resizerDiagram.Nodes.Add(new NodeModel(new Point(500, 150)));
+		var resizeNode1Port = resizeNode1.AddPort(PortAlignment.Right);
+		var resizeNode2Port = resizeNode2.AddPort(PortAlignment.Left);
+		_resizerDiagram.Links.Add(new LinkModel(resizeNode1Port, resizeNode2Port));
 		resizeNode1.Title = "Title";
 		resizeNode2.Title = "Title";
 		_resizerDiagram.Controls.AddFor(resizeNode1, ControlsType.OnSelection).Add(new ResizeControl(new BottomRightResizerProvider()));