@(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/Components/Renderers/PortRenderer.cs b/src/Blazor.Diagrams/Components/Renderers/PortRenderer.cs
index bbd4786f1..275d4108b 100644
--- a/src/Blazor.Diagrams/Components/Renderers/PortRenderer.cs
+++ b/src/Blazor.Diagrams/Components/Renderers/PortRenderer.cs
@@ -124,10 +124,17 @@ private async Task UpdateDimensions()
var zoom = BlazorDiagram.Zoom;
var pan = BlazorDiagram.Pan;
var rect = await JSRuntime.GetBoundingClientRect(_element);
+
+ if (rect is not null)
+ {
+ Port.Size = new Size(rect.Width / zoom, rect.Height / zoom);
- Port.Size = new Size(rect.Width / zoom, rect.Height / zoom);
- Port.Position = new Point((rect.Left - BlazorDiagram.Container.Left - pan.X) / zoom,
- (rect.Top - BlazorDiagram.Container.Top - pan.Y) / zoom);
+ if (BlazorDiagram.Container is not null)
+ {
+ Port.Position = new Point((rect.Left - BlazorDiagram.Container.Left - pan.X) / zoom,
+ (rect.Top - BlazorDiagram.Container.Top - pan.Y) / zoom);
+ }
+ }
Port.Initialized = true;
_updatingDimensions = false;
diff --git a/src/Blazor.Diagrams/Components/Widgets/GridWidget.razor.cs b/src/Blazor.Diagrams/Components/Widgets/GridWidget.razor.cs
index 596f985ff..ba3ac9547 100644
--- a/src/Blazor.Diagrams/Components/Widgets/GridWidget.razor.cs
+++ b/src/Blazor.Diagrams/Components/Widgets/GridWidget.razor.cs
@@ -1,7 +1,7 @@
-using System;
-using System.Text;
using Blazor.Diagrams.Core.Extensions;
using Microsoft.AspNetCore.Components;
+using System;
+using System.Text;
namespace Blazor.Diagrams.Components.Widgets;
@@ -11,7 +11,7 @@ public partial class GridWidget : IDisposable
private double _scaledSize;
private double _posX;
private double _posY;
-
+
[CascadingParameter] public BlazorDiagram BlazorDiagram { get; set; } = null!;
[Parameter] public double Size { get; set; } = 20;
[Parameter] public double ZoomThreshold { get; set; } = 0;
@@ -38,6 +38,11 @@ protected override void OnParametersSet()
_visible = BlazorDiagram.Zoom > ZoomThreshold;
}
+ private void RefreshPosition(double deltaX, double deltaY)
+ {
+ RefreshPosition();
+ }
+
private void RefreshPosition()
{
_posX = BlazorDiagram.Pan.X;
@@ -67,7 +72,7 @@ private string GenerateStyle()
default:
throw new ArgumentOutOfRangeException();
}
-
+
return sb.ToString();
}
}
diff --git a/src/Blazor.Diagrams/Components/Widgets/SelectionBoxWidget.razor b/src/Blazor.Diagrams/Components/Widgets/SelectionBoxWidget.razor
index 4ad4e761e..5cfa9417e 100644
--- a/src/Blazor.Diagrams/Components/Widgets/SelectionBoxWidget.razor
+++ b/src/Blazor.Diagrams/Components/Widgets/SelectionBoxWidget.razor
@@ -1,4 +1,4 @@
-@if (_selectionBoxTopLeft != null && _selectionBoxSize != null)
+@if (_selectionBounds is not null)
{
}
\ No newline at end of file
diff --git a/src/Blazor.Diagrams/Components/Widgets/SelectionBoxWidget.razor.cs b/src/Blazor.Diagrams/Components/Widgets/SelectionBoxWidget.razor.cs
index 738fabf1a..988166755 100644
--- a/src/Blazor.Diagrams/Components/Widgets/SelectionBoxWidget.razor.cs
+++ b/src/Blazor.Diagrams/Components/Widgets/SelectionBoxWidget.razor.cs
@@ -1,4 +1,5 @@
using System;
+using Blazor.Diagrams.Core.Behaviors;
using Blazor.Diagrams.Core.Events;
using Blazor.Diagrams.Core.Geometry;
using Blazor.Diagrams.Core.Models.Base;
@@ -8,9 +9,8 @@ namespace Blazor.Diagrams.Components.Widgets;
public partial class SelectionBoxWidget : IDisposable
{
- private Point? _initialClientPoint;
- private Size? _selectionBoxSize; // Todo: remove unneeded instantiations
- private Point? _selectionBoxTopLeft; // Todo: remove unneeded instantiations
+ private Rectangle? _selectionBounds;
+ private SelectionBoxBehavior? _selectionBoxBehavior;
[CascadingParameter] public BlazorDiagram BlazorDiagram { get; set; } = null!;
@@ -18,74 +18,30 @@ public partial class SelectionBoxWidget : IDisposable
public void Dispose()
{
- BlazorDiagram.PointerDown -= OnPointerDown;
- BlazorDiagram.PointerMove -= OnPointerMove;
- BlazorDiagram.PointerUp -= OnPointerUp;
+ if (_selectionBoxBehavior is not null)
+ {
+ _selectionBoxBehavior.SelectionBoundsChanged -= SelectionBoundsChanged;
+ }
}
protected override void OnInitialized()
{
- BlazorDiagram.PointerDown += OnPointerDown;
- BlazorDiagram.PointerMove += OnPointerMove;
- BlazorDiagram.PointerUp += OnPointerUp;
- }
-
- private string GenerateStyle()
- {
- return FormattableString.Invariant(
- $"position: absolute; background: {Background}; top: {_selectionBoxTopLeft!.Y}px; left: {_selectionBoxTopLeft.X}px; width: {_selectionBoxSize!.Width}px; height: {_selectionBoxSize.Height}px;");
- }
-
- private void OnPointerDown(Model? model, MouseEventArgs e)
- {
- if (model != null || !e.ShiftKey)
- return;
-
- _initialClientPoint = new Point(e.ClientX, e.ClientY);
- }
-
- private void OnPointerMove(Model? model, MouseEventArgs e)
- {
- if (_initialClientPoint == null)
- return;
-
- SetSelectionBoxInformation(e);
-
- var start = BlazorDiagram.GetRelativeMousePoint(_initialClientPoint.X, _initialClientPoint.Y);
- var end = BlazorDiagram.GetRelativeMousePoint(e.ClientX, e.ClientY);
- var (sX, sY) = (Math.Min(start.X, end.X), Math.Min(start.Y, end.Y));
- var (eX, eY) = (Math.Max(start.X, end.X), Math.Max(start.Y, end.Y));
- var bounds = new Rectangle(sX, sY, eX, eY);
-
- foreach (var node in BlazorDiagram.Nodes)
+ _selectionBoxBehavior = BlazorDiagram.GetBehavior
();
+ if (_selectionBoxBehavior is not null)
{
- var nodeBounds = node.GetBounds();
- if (nodeBounds == null)
- continue;
-
- if (bounds.Overlap(nodeBounds))
- BlazorDiagram.SelectModel(node, false);
- else if (node.Selected) BlazorDiagram.UnselectModel(node);
+ _selectionBoxBehavior.SelectionBoundsChanged += SelectionBoundsChanged;
}
-
- InvokeAsync(StateHasChanged);
}
- private void SetSelectionBoxInformation(MouseEventArgs e)
+ void SelectionBoundsChanged(object? sender, Rectangle? bounds)
{
- var start = BlazorDiagram.GetRelativePoint(_initialClientPoint!.X, _initialClientPoint.Y);
- var end = BlazorDiagram.GetRelativePoint(e.ClientX, e.ClientY);
- var (sX, sY) = (Math.Min(start.X, end.X), Math.Min(start.Y, end.Y));
- var (eX, eY) = (Math.Max(start.X, end.X), Math.Max(start.Y, end.Y));
- _selectionBoxTopLeft = new Point(sX, sY);
- _selectionBoxSize = new Size(eX - sX, eY - sY);
+ _selectionBounds = bounds;
+ InvokeAsync(StateHasChanged);
}
- private void OnPointerUp(Model? model, MouseEventArgs e)
+ private string GenerateStyle()
{
- _initialClientPoint = null;
- _selectionBoxTopLeft = null;
- _selectionBoxSize = null;
- InvokeAsync(StateHasChanged);
+ return FormattableString.Invariant(
+ $"position: absolute; background: {Background}; top: {_selectionBounds!.Top}px; left: {_selectionBounds.Left}px; width: {_selectionBounds.Width}px; height: {_selectionBounds.Height}px;");
}
}
\ No newline at end of file
diff --git a/src/Blazor.Diagrams/Extensions/JSRuntimeExtensions.cs b/src/Blazor.Diagrams/Extensions/JSRuntimeExtensions.cs
index 459456863..3e32f8e1b 100644
--- a/src/Blazor.Diagrams/Extensions/JSRuntimeExtensions.cs
+++ b/src/Blazor.Diagrams/Extensions/JSRuntimeExtensions.cs
@@ -1,6 +1,4 @@
-using System;
-using System.Threading.Tasks;
-using Blazor.Diagrams.Core.Geometry;
+using Blazor.Diagrams.Core.Geometry;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
@@ -28,6 +26,18 @@ public static async Task ObserveResizes(this IJSRuntime jsRuntime, ElementRef
public static async Task UnobserveResizes(this IJSRuntime jsRuntime, ElementReference element)
{
- await jsRuntime.InvokeVoidAsync("ZBlazorDiagrams.unobserve", element, element.Id);
+ try
+ {
+ await jsRuntime.InvokeVoidAsync("ZBlazorDiagrams.unobserve", element, element.Id);
+ }
+ catch (JSDisconnectedException)
+ {
+ // Ignore, JSRuntime was already disconnected
+ }
+ }
+
+ public static async Task AddDefaultPreventingForWheelHandler(this IJSRuntime jsRuntime, ElementReference element)
+ {
+ await jsRuntime.InvokeVoidAsync("ZBlazorDiagrams.addDefaultPreventingHandler", element, "wheel");
}
}
\ No newline at end of file
diff --git a/src/Blazor.Diagrams/sgKey.snk b/src/Blazor.Diagrams/sgKey.snk
new file mode 100644
index 000000000..4ff3c2f7a
Binary files /dev/null and b/src/Blazor.Diagrams/sgKey.snk differ
diff --git a/src/Blazor.Diagrams/wwwroot/default.styles.css b/src/Blazor.Diagrams/wwwroot/default.styles.css
index b095bbe4e..0e37330c2 100644
--- a/src/Blazor.Diagrams/wwwroot/default.styles.css
+++ b/src/Blazor.Diagrams/wwwroot/default.styles.css
@@ -127,4 +127,29 @@ 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;
+ 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;
+}
+
/*# 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..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%);}
\ 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
diff --git a/src/Blazor.Diagrams/wwwroot/default.styles.min.css.gz b/src/Blazor.Diagrams/wwwroot/default.styles.min.css.gz
index 905f20cd3..3c43a8a10 100644
Binary files a/src/Blazor.Diagrams/wwwroot/default.styles.min.css.gz and b/src/Blazor.Diagrams/wwwroot/default.styles.min.css.gz differ
diff --git a/src/Blazor.Diagrams/wwwroot/script.js b/src/Blazor.Diagrams/wwwroot/script.js
index 293b8768d..3f25c16f8 100644
--- a/src/Blazor.Diagrams/wwwroot/script.js
+++ b/src/Blazor.Diagrams/wwwroot/script.js
@@ -40,10 +40,14 @@ var s = {
}
},
unobserve: (element, id) => {
- if (!element) return;
- s.ro.unobserve(element);
+ if (element) {
+ s.ro.unobserve(element);
+ }
delete s.tracked[id];
delete s.canvases[id];
+ },
+ addDefaultPreventingHandler: (element, eventName) => {
+ element.addEventListener(eventName, e => e.preventDefault(), { passive: false });
}
};
window.ZBlazorDiagrams = s;
diff --git a/src/Blazor.Diagrams/wwwroot/script.min.js b/src/Blazor.Diagrams/wwwroot/script.min.js
index f295e538c..a900d0005 100644
--- a/src/Blazor.Diagrams/wwwroot/script.min.js
+++ b/src/Blazor.Diagrams/wwwroot/script.min.js
@@ -1 +1 @@
-var s={canvases:{},tracked:{},getBoundingClientRect:n=>n.getBoundingClientRect(),mo:new MutationObserver(()=>{for(id in s.canvases){const t=s.canvases[id],i=t.lastBounds,n=t.elem.getBoundingClientRect();(i.left!==n.left||i.top!==n.top||i.width!==n.width||i.height!==n.height)&&(t.lastBounds=n,t.ref.invokeMethodAsync("OnResize",n))}}),ro:new ResizeObserver(n=>{for(const t of n){let i=Array.from(t.target.attributes).find(n=>n.name.startsWith("_bl")).name.substring(4),n=s.tracked[i];n&&n.ref.invokeMethodAsync("OnResize",t.target.getBoundingClientRect())}}),observe:(n,t,i)=>{n&&(s.ro.observe(n),s.tracked[i]={ref:t},n.classList.contains("diagram-canvas")&&(s.canvases[i]={elem:n,ref:t,lastBounds:n.getBoundingClientRect()}))},unobserve:(n,t)=>{n&&(s.ro.unobserve(n),delete s.tracked[t],delete s.canvases[t])}};window.ZBlazorDiagrams=s;window.addEventListener("scroll",()=>{for(id in s.canvases){const n=s.canvases[id];n.lastBounds=n.elem.getBoundingClientRect();n.ref.invokeMethodAsync("OnResize",n.lastBounds)}});s.mo.observe(document.body,{childList:!0,subtree:!0});
\ No newline at end of file
+var s = { canvases: {}, tracked: {}, getBoundingClientRect: e => e.getBoundingClientRect(), mo: new MutationObserver((() => { for (id in s.canvases) { const e = s.canvases[id], t = e.lastBounds, n = e.elem.getBoundingClientRect(); t.left === n.left && t.top === n.top && t.width === n.width && t.height === n.height || (e.lastBounds = n, e.ref.invokeMethodAsync("OnResize", n)) } })), ro: new ResizeObserver((e => { for (const t of e) { let e = Array.from(t.target.attributes).find((e => e.name.startsWith("_bl"))).name.substring(4), n = s.tracked[e]; n && n.ref.invokeMethodAsync("OnResize", t.target.getBoundingClientRect()) } })), observe: (e, t, n) => { e && (s.ro.observe(e), s.tracked[n] = { ref: t }, e.classList.contains("diagram-canvas") && (s.canvases[n] = { elem: e, ref: t, lastBounds: e.getBoundingClientRect() })) }, unobserve: (e, t) => { e && s.ro.unobserve(e), delete s.tracked[t], delete s.canvases[t] }, addDefaultPreventingHandler: (e, s) => { e.addEventListener(s, (e => e.preventDefault()), { passive: !1 }) } }; window.ZBlazorDiagrams = s, window.addEventListener("scroll", (() => { for (id in s.canvases) { const e = s.canvases[id]; e.lastBounds = e.elem.getBoundingClientRect(), e.ref.invokeMethodAsync("OnResize", e.lastBounds) } })), s.mo.observe(document.body, { childList: !0, subtree: !0 });
\ No newline at end of file
diff --git a/src/Blazor.Diagrams/wwwroot/script.min.js.gz b/src/Blazor.Diagrams/wwwroot/script.min.js.gz
index e444f12bd..a4db96478 100644
Binary files a/src/Blazor.Diagrams/wwwroot/script.min.js.gz and b/src/Blazor.Diagrams/wwwroot/script.min.js.gz differ
diff --git a/src/Blazor.Diagrams/wwwroot/style.css b/src/Blazor.Diagrams/wwwroot/style.css
index 35c0aaa30..b2d6a1355 100644
--- a/src/Blazor.Diagrams/wwwroot/style.css
+++ b/src/Blazor.Diagrams/wwwroot/style.css
@@ -4,8 +4,6 @@
position: relative;
outline: none;
overflow: hidden;
- cursor: -webkit-grab;
- cursor: grab;
touch-action: none;
}
@@ -82,6 +80,8 @@
.diagram-link foreignObject.diagram-link-label {
overflow: visible;
pointer-events: none;
+ width: 1px;
+ height: 1px;
}
div.diagram-control {
diff --git a/src/Blazor.Diagrams/wwwroot/style.min.css b/src/Blazor.Diagrams/wwwroot/style.min.css
index 4abcd9d42..8982e6caf 100644
--- a/src/Blazor.Diagrams/wwwroot/style.min.css
+++ b/src/Blazor.Diagrams/wwwroot/style.min.css
@@ -1 +1 @@
-.diagram-canvas{width:100%;height:100%;position:relative;outline:none;overflow:hidden;cursor:-webkit-grab;cursor:grab;touch-action:none;}.diagram-svg-layer,.diagram-html-layer{top:0;left:0;right:0;bottom:0;position:absolute;pointer-events:none;-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;width:100%;height:100%;overflow:visible;}.html-layer,.svg-layer{position:absolute;pointer-events:none;-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;width:100%;height:100%;overflow:visible;}.diagram-node{position:absolute;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:move;pointer-events:all;}.diagram-node.locked{cursor:pointer;}.diagram-link{pointer-events:visiblePainted;cursor:pointer;}.diagram-navigator{z-index:10;}.diagram-navigator .current-view{position:absolute;border:2px solid #000;}.diagram-group{position:absolute;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:move;pointer-events:all;}.diagram-group .children{position:absolute;overflow:visible;pointer-events:none;}.diagram-link foreignObject.diagram-link-label{overflow:visible;pointer-events:none;}div.diagram-control{position:absolute;}.executable.diagram-control{pointer-events:all;cursor:pointer;}
\ No newline at end of file
+.diagram-canvas{width:100%;height:100%;position:relative;outline:0;overflow:hidden;cursor:-webkit-grab;cursor:grab;touch-action:none;}.diagram-svg-layer,.diagram-html-layer{top:0;left:0;right:0;bottom:0;position:absolute;pointer-events:none;-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;width:100%;height:100%;overflow:visible;}.html-layer,.svg-layer{position:absolute;pointer-events:none;-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;width:100%;height:100%;overflow:visible;}.diagram-node{position:absolute;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:move;pointer-events:all;}.diagram-node.locked{cursor:pointer;}.diagram-link{pointer-events:visiblePainted;cursor:pointer;}.diagram-navigator{z-index:10;}.diagram-navigator .current-view{position:absolute;border:2px solid #000;}.diagram-group{position:absolute;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:move;pointer-events:all;}.diagram-group .children{position:absolute;overflow:visible;pointer-events:none;}.diagram-link foreignObject.diagram-link-label{overflow:visible;pointer-events:none;width:1px;height:1px;}div.diagram-control{position:absolute;}.executable.diagram-control{pointer-events:all;cursor:pointer;}
\ No newline at end of file
diff --git a/src/Blazor.Diagrams/wwwroot/style.min.css.gz b/src/Blazor.Diagrams/wwwroot/style.min.css.gz
index e72cb7d8a..16ae04074 100644
Binary files a/src/Blazor.Diagrams/wwwroot/style.min.css.gz and b/src/Blazor.Diagrams/wwwroot/style.min.css.gz differ
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
new file mode 100644
index 000000000..888d6a9b7
--- /dev/null
+++ b/src/Directory.Build.props
@@ -0,0 +1,10 @@
+
+
+ net8.0;net6.0
+ enable
+ enable
+ true
+
+
+
+
\ No newline at end of file
diff --git a/tests/Blazor.Diagrams.Core.Tests/Anchors/DynamicAnchorTests.cs b/tests/Blazor.Diagrams.Core.Tests/Anchors/DynamicAnchorTests.cs
index 97a7460b4..0f8bfde0a 100644
--- a/tests/Blazor.Diagrams.Core.Tests/Anchors/DynamicAnchorTests.cs
+++ b/tests/Blazor.Diagrams.Core.Tests/Anchors/DynamicAnchorTests.cs
@@ -2,7 +2,6 @@
using Blazor.Diagrams.Core.Geometry;
using Blazor.Diagrams.Core.Models;
using Blazor.Diagrams.Core.Positions;
-using FluentAssertions;
using Xunit;
namespace Blazor.Diagrams.Core.Tests.Anchors;
@@ -37,7 +36,7 @@ public void GetPosition_ShouldReturnNull_WhenNodesSizeIsNull()
var position = anchor1.GetPosition(link);
// Assert
- position.Should().BeNull();
+ Assert.Null(position);
}
[Fact]
@@ -72,9 +71,9 @@ public void GetPosition_ShouldReturnClosestPositionToOtherNodesCenter_WhenRouteI
var position = anchor1.GetPosition(link);
// Assert
- position.Should().NotBeNull();
- position!.X.Should().Be(220);
- position.Y.Should().Be(95);
+ Assert.NotNull(position);
+ Assert.Equal(220,position!.X);
+ Assert.Equal(95, position.Y);
}
[Fact]
@@ -109,9 +108,9 @@ public void GetPosition_ShouldReturnClosestPositionToOtherNodesCenterWithOffset_
var position = anchor1.GetPosition(link);
// Assert
- position.Should().NotBeNull();
- position!.X.Should().Be(230);
- position.Y.Should().Be(85);
+ Assert.NotNull(position);
+ Assert.Equal(230, position!.X);
+ Assert.Equal(85, position.Y);
}
[Fact]
@@ -149,9 +148,9 @@ public void GetPosition_ShouldReturnClosestPositionToFirstVertex_WhenRouteIsNotE
});
// Assert
- position.Should().NotBeNull();
- position!.X.Should().Be(220);
- position.Y.Should().Be(125);
+ Assert.NotNull(position);
+ Assert.Equal(220, position!.X);
+ Assert.Equal(125, position.Y);
}
[Fact]
@@ -189,8 +188,8 @@ public void GetPosition_ShouldReturnClosestPositionToLastVertex_WhenRouteIsNotEm
});
// Assert
- position.Should().NotBeNull();
- position!.X.Should().Be(300);
- position.Y.Should().Be(120);
+ Assert.NotNull(position);
+ Assert.Equal(300, position!.X);
+ Assert.Equal(120, position.Y);
}
}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Anchors/ShapeIntersectionAnchorTests.cs b/tests/Blazor.Diagrams.Core.Tests/Anchors/ShapeIntersectionAnchorTests.cs
index 71726a926..70cfe7844 100644
--- a/tests/Blazor.Diagrams.Core.Tests/Anchors/ShapeIntersectionAnchorTests.cs
+++ b/tests/Blazor.Diagrams.Core.Tests/Anchors/ShapeIntersectionAnchorTests.cs
@@ -3,7 +3,6 @@
using Blazor.Diagrams.Core.Anchors;
using Blazor.Diagrams.Core.Geometry;
using Blazor.Diagrams.Core.Models;
-using FluentAssertions;
using Moq;
using Xunit;
@@ -27,8 +26,8 @@ public void GetPlainPosition_ShouldReturnNodeCenter()
// Assert
var center = node.GetBounds()!.Center;
- position.X.Should().Be(center.X);
- position.Y.Should().Be(center.Y);
+ Assert.Equal(center.X, position.X);
+ Assert.Equal(center.Y, position.Y);
}
[Fact]
@@ -43,7 +42,7 @@ public void GetPosition_ShouldReturnNull_WhenNodeSizeIsNull()
var position = anchor.GetPosition(link);
// Assert
- position.Should().BeNull();
+ Assert.Null(position);
}
[Fact]
@@ -67,8 +66,8 @@ public void GetPosition_ShouldUseRouteToFindOtherPositionForIntersection_WhenSou
// Assert
var line = args.Single();
- line.Start.Should().BeEquivalentTo(route[0]);
- line.End.Should().BeEquivalentTo(node.GetBounds()!.Center);
+ Assert.Equal(route[0],line.Start);
+ Assert.Equal(node.GetBounds()!.Center, line.End);
}
[Fact]
@@ -93,8 +92,8 @@ public void GetPosition_ShouldUseRouteToFindOtherPositionForIntersection_WhenTar
// Assert
var line = args.Single();
- line.Start.Should().BeEquivalentTo(route[^1]);
- line.End.Should().BeEquivalentTo(node.GetBounds()!.Center);
+ Assert.Equal(route[^1],line.Start);
+ Assert.Equal(node.GetBounds()!.Center,line.End);
}
[Fact]
@@ -120,8 +119,8 @@ public void GetPosition_ShouldCallOtherGetPlainPosition_WhenNoRoute()
// Assert
var line = args.Single();
- line.Start.Should().BeEquivalentTo(pt);
- line.End.Should().BeEquivalentTo(node.GetBounds()!.Center);
+ Assert.Equal(pt,line.Start);
+ Assert.Equal(node.GetBounds()!.Center, line.End);
}
[Fact]
@@ -145,7 +144,7 @@ public void GetPosition_ShouldReturnNull_WhenOtherPositionIsNull()
var position = source.GetPosition(link);
// Assert
- position.Should().BeNull();
+ Assert.Null(position);
}
private class CustomNodeModel : NodeModel
diff --git a/tests/Blazor.Diagrams.Core.Tests/Anchors/SinglePortAnchorTests.cs b/tests/Blazor.Diagrams.Core.Tests/Anchors/SinglePortAnchorTests.cs
index e01d746f7..4d64d1a9f 100644
--- a/tests/Blazor.Diagrams.Core.Tests/Anchors/SinglePortAnchorTests.cs
+++ b/tests/Blazor.Diagrams.Core.Tests/Anchors/SinglePortAnchorTests.cs
@@ -1,7 +1,6 @@
using Blazor.Diagrams.Core.Anchors;
using Blazor.Diagrams.Core.Geometry;
using Blazor.Diagrams.Core.Models;
-using FluentAssertions;
using Moq;
using Xunit;
@@ -26,8 +25,8 @@ public void GetPlainPosition_ShouldReturnMiddlePosition()
// Assert
var mp = port.MiddlePosition;
- position.X.Should().Be(mp.X);
- position.Y.Should().Be(mp.Y);
+ Assert.Equal(mp.X, position.X);
+ Assert.Equal(mp.Y, position.Y);
}
[Fact]
@@ -47,7 +46,7 @@ public void GetPosition_ShouldReturnNull_WhenPortNotInitialized()
var position = anchor.GetPosition(link);
// Assert
- position.Should().BeNull();
+ Assert.Null(position);
}
[Fact]
@@ -72,8 +71,8 @@ public void GetPosition_ShouldReturnMiddlePosition_WhenMiddleIfNoMarker()
// Assert
var mp = port.MiddlePosition;
- position.X.Should().Be(mp.X);
- position.Y.Should().Be(mp.Y);
+ Assert.Equal(mp.X, position.X);
+ Assert.Equal(mp.Y, position.Y);
}
[Theory]
@@ -106,8 +105,8 @@ public void GetPosition_ShouldReturnAlignmentBasedPosition_WhenUseShapeAndAlignm
var position = anchor.GetPosition(link)!;
// Assert
- position.X.Should().Be(x);
- position.Y.Should().Be(y);
+ Assert.Equal(x, position.X);
+ Assert.Equal(y, position.Y);
}
[Theory]
@@ -139,7 +138,7 @@ public void GetPosition_ShouldUsePointAtAngle_WhenUseShapeAndAlignmentIsTrue(Por
// Act
var position = anchor.GetPosition(link)!;
-
+
// Assert
shapeMock.Verify(s => s.GetPointAtAngle(angle), Times.Once);
}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Behaviors/DragMovablesBehaviorTests.cs b/tests/Blazor.Diagrams.Core.Tests/Behaviors/DragMovablesBehaviorTests.cs
index ba73788b3..457ba46fb 100644
--- a/tests/Blazor.Diagrams.Core.Tests/Behaviors/DragMovablesBehaviorTests.cs
+++ b/tests/Blazor.Diagrams.Core.Tests/Behaviors/DragMovablesBehaviorTests.cs
@@ -1,8 +1,8 @@
+using Blazor.Diagrams.Core.Behaviors;
using Blazor.Diagrams.Core.Events;
using Blazor.Diagrams.Core.Geometry;
using Blazor.Diagrams.Core.Models;
using Blazor.Diagrams.Core.Options;
-using FluentAssertions;
using Moq;
using Xunit;
@@ -78,7 +78,7 @@ public void Behavior_ShouldTriggerMoved()
new PointerEventArgs(150, 150, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
// Assert
- movedTrigger.Should().BeTrue();
+ Assert.True(movedTrigger);
}
[Fact]
@@ -98,7 +98,7 @@ public void Behavior_ShouldNotTriggerMoved_WhenMovableDidntMove()
new PointerEventArgs(150, 150, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
// Assert
- movedTrigger.Should().BeFalse();
+ Assert.False(movedTrigger);
}
[Fact]
@@ -140,4 +140,24 @@ public void Behavior_ShouldCallSetPosition_WhenGroupHasAutoSize()
// Assert
nodeMock.Verify(n => n.SetPosition(50, 50), Times.Once);
}
+
+ [Fact]
+ public void Behavior_ShouldCallSetPosition_WhenPanChanges()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ var nodeMock = new Mock(Point.Zero);
+ var node = diagram.Nodes.Add(nodeMock.Object);
+ diagram.SelectModel(node, false);
+ diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior();
+ diagram.SetContainer(new Rectangle(0, 0, 100, 100));
+
+ // Act
+ diagram.TriggerPointerDown(node,
+ new PointerEventArgs(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+ diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, false, false, 100, 100, 0, 0));
+
+ // Assert
+ nodeMock.Verify(n => n.SetPosition(100, 100), Times.Once);
+ }
}
\ No newline at end of file
diff --git a/tests/Blazor.Diagrams.Core.Tests/Behaviors/DragNewLinkBehaviorTests.cs b/tests/Blazor.Diagrams.Core.Tests/Behaviors/DragNewLinkBehaviorTests.cs
index 18f466eec..753335cdf 100644
--- a/tests/Blazor.Diagrams.Core.Tests/Behaviors/DragNewLinkBehaviorTests.cs
+++ b/tests/Blazor.Diagrams.Core.Tests/Behaviors/DragNewLinkBehaviorTests.cs
@@ -1,9 +1,8 @@
using Blazor.Diagrams.Core.Anchors;
+using Blazor.Diagrams.Core.Behaviors;
using Blazor.Diagrams.Core.Events;
using Blazor.Diagrams.Core.Geometry;
using Blazor.Diagrams.Core.Models;
-using FluentAssertions;
-using System.Linq;
using Xunit;
namespace Blazor.Diagrams.Core.Tests.Behaviors;
@@ -31,11 +30,11 @@ public void Behavior_ShouldCreateLinkWithSinglePortAnchorSource_WhenMouseDownOnP
// Assert
var link = diagram.Links.Single();
var source = link.Source as SinglePortAnchor;
- source.Should().NotBeNull();
- source!.Port.Should().BeSameAs(port);
+ Assert.NotNull(source);
+ Assert.Same(port, source!.Port);
var ongoingPosition = (link.Target as PositionAnchor)!.GetPlainPosition()!;
- ongoingPosition.X.Should().Be(100);
- ongoingPosition.Y.Should().Be(100);
+ Assert.Equal(100, ongoingPosition.X);
+ Assert.Equal(100, ongoingPosition.Y);
}
[Fact]
@@ -63,14 +62,14 @@ public void Behavior_ShouldCreateLinkUsingFactory_WhenMouseDownOnPort()
new PointerEventArgs(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
// Assert
- factoryCalled.Should().BeTrue();
+ Assert.True(factoryCalled);
var link = diagram.Links.Single();
var source = link.Source as SinglePortAnchor;
- source.Should().NotBeNull();
- source!.Port.Should().BeSameAs(port);
+ Assert.NotNull(source);
+ Assert.Same(port, source!.Port);
var ongoingPosition = (link.Target as PositionAnchor)!.GetPlainPosition()!;
- ongoingPosition.X.Should().Be(100);
- ongoingPosition.Y.Should().Be(100);
+ Assert.Equal(100, ongoingPosition.X);
+ Assert.Equal(100, ongoingPosition.Y);
}
[Fact]
@@ -99,9 +98,9 @@ public void Behavior_ShouldUpdateOngoingPosition_WhenMouseMoveIsTriggered()
// Assert
var source = link.Source as SinglePortAnchor;
var ongoingPosition = (link.Target as PositionAnchor)!.GetPlainPosition()!;
- ongoingPosition.X.Should().BeGreaterThan(145);
- ongoingPosition.Y.Should().BeGreaterThan(145);
- linkRefreshed.Should().BeTrue();
+ Assert.True(ongoingPosition.X > 145);
+ Assert.True(ongoingPosition.Y > 145);
+ Assert.True(linkRefreshed);
}
[Fact]
@@ -131,9 +130,9 @@ public void Behavior_ShouldUpdateOngoingPosition_WhenMouseMoveIsTriggeredAndZoom
// Assert
var source = link.Source as SinglePortAnchor;
var ongoingPosition = (link.Target as PositionAnchor)!.GetPlainPosition()!;
- ongoingPosition.X.Should().BeApproximately(107.7, 0.1);
- ongoingPosition.Y.Should().BeApproximately(101.7, 0.1);
- linkRefreshed.Should().BeTrue();
+ Assert.InRange(ongoingPosition.X, 107.6, 107.8);
+ Assert.InRange(ongoingPosition.Y, 101.6, 101.8);
+ Assert.True(linkRefreshed);
}
[Fact]
@@ -171,9 +170,9 @@ public void Behavior_ShouldSnapToClosestPortAndRefreshPort_WhenSnappingIsEnabled
// Assert
var link = diagram.Links.Single();
var target = link.Target as SinglePortAnchor;
- target.Should().NotBeNull();
- target!.Port.Should().BeSameAs(port2);
- port2Refreshed.Should().BeTrue();
+ Assert.NotNull(target);
+ Assert.Same(port2, target!.Port);
+ Assert.True(port2Refreshed);
}
[Fact]
@@ -208,7 +207,7 @@ public void Behavior_ShouldNotSnapToPort_WhenSnappingIsEnabledAndPortIsNotInRadi
// Assert
var link = diagram.Links.Single();
- link.Target.Should().BeOfType();
+ Assert.IsType(link.Target);
}
[Fact]
@@ -250,8 +249,8 @@ public void Behavior_ShouldUnSnapAndRefreshPort_WhenSnappingIsEnabledAndPortIsNo
// Assert
var link = diagram.Links.Single();
var target = link.Target as SinglePortAnchor;
- target.Should().BeNull();
- port2Refreshes.Should().Be(2);
+ Assert.Null(target);
+ Assert.Equal(2, port2Refreshes);
}
[Fact]
@@ -275,7 +274,7 @@ public void Behavior_ShouldRemoveLink_WhenMouseUpOnCanvasAndRequireTargetIsTrue(
new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
// Assert
- diagram.Links.Should().BeEmpty();
+ Assert.Empty(diagram.Links);
}
[Fact]
@@ -299,7 +298,7 @@ public void Behavior_ShouldRemoveLink_WhenMouseUpOnSamePort()
new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
// Assert
- diagram.Links.Should().BeEmpty();
+ Assert.Empty(diagram.Links);
}
[Fact]
@@ -335,9 +334,9 @@ public void Behavior_ShouldSetTarget_WhenMouseUp()
// Assert
var link = diagram.Links.Single();
var target = link.Target as SinglePortAnchor;
- target.Should().NotBeNull();
- target!.Port.Should().BeSameAs(port2);
- port2Refreshes.Should().Be(1);
+ Assert.NotNull(target);
+ Assert.Same(port2, target!.Port);
+ Assert.Equal(1, port2Refreshes);
}
[Fact]
@@ -362,7 +361,7 @@ public void Behavior_ShouldNotCreateOngoingLink_WhenFactoryReturnsNull()
new PointerEventArgs(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
// Assert
- diagram.Links.Should().HaveCount(0);
+ Assert.Empty(diagram.Links);
}
[Fact]
@@ -398,7 +397,7 @@ public void Behavior_ShouldTriggerLinkTargetAttached_WhenMouseUpOnOtherPort()
new PointerEventArgs(105, 105, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
// Assert
- targetAttachedTriggers.Should().Be(1);
+ Assert.Equal(1, targetAttachedTriggers);
}
[Fact]
@@ -439,6 +438,62 @@ public void Behavior_ShouldTriggerLinkTargetAttached_WhenLinkSnappedToPortAndMou
new PointerEventArgs(140, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
// Assert
- targetAttachedTriggers.Should().Be(1);
+ Assert.Equal(1, targetAttachedTriggers);
+ }
+
+ [Fact]
+ public void Behavior_ShouldNotCreateLinkWithSinglePortAnchorSource_WhenMouseDownOnPort()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ diagram.SetContainer(new Rectangle(0, 0, 1000, 400));
+ var node = new NodeModel(position: new Point(100, 50));
+ var port = node.AddPort(new PortModel(node)
+ {
+ Initialized = true,
+ Position = new Point(110, 60),
+ Size = new Size(10, 20),
+ Enabled = false
+ });
+
+ // Act
+ diagram.TriggerPointerDown(port,
+ new PointerEventArgs(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+
+ // Assert
+ Assert.Empty(diagram.Links);
+ }
+
+ [Fact]
+ public void Behavior_ShouldUpdateOngoingPosition_WhenPanChanges()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ diagram.SetContainer(new Rectangle(0, 0, 1000, 400));
+ var node = new NodeModel(position: new Point(100, 50));
+ var linkRefreshed = false;
+ var port = node.AddPort(new PortModel(node)
+ {
+ Initialized = true,
+ Position = new Point(100, 50),
+ Size = new Size(10, 20)
+ });
+ diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior();
+
+ // Act
+ diagram.TriggerPointerDown(port,
+ new PointerEventArgs(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+ var link = diagram.Links.Single();
+ link.Changed += _ => linkRefreshed = true;
+ diagram.TriggerPointerMove(null,
+ new PointerEventArgs(150, 150, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+ diagram.TriggerWheel(new WheelEventArgs(150, 150, 0, 0, false, false, false, 100, 100, 0, 0));
+
+ // Assert
+ var source = link.Source as SinglePortAnchor;
+ var ongoingPosition = (link.Target as PositionAnchor)!.GetPlainPosition()!;
+ Assert.InRange(ongoingPosition.X, 245, 247);
+ Assert.InRange(ongoingPosition.Y, 245, 247);
+ Assert.True(linkRefreshed);
}
}
\ No newline at end of file
diff --git a/tests/Blazor.Diagrams.Core.Tests/Behaviors/EventsBehaviorTests.cs b/tests/Blazor.Diagrams.Core.Tests/Behaviors/EventsBehaviorTests.cs
index 5df0724d8..b514549aa 100644
--- a/tests/Blazor.Diagrams.Core.Tests/Behaviors/EventsBehaviorTests.cs
+++ b/tests/Blazor.Diagrams.Core.Tests/Behaviors/EventsBehaviorTests.cs
@@ -1,6 +1,5 @@
using Blazor.Diagrams.Core.Behaviors;
using Blazor.Diagrams.Core.Events;
-using FluentAssertions;
using System.Threading.Tasks;
using Xunit;
@@ -22,7 +21,7 @@ public void Behavior_ShouldNotTriggerMouseClick_WhenItsRemoved()
diagram.TriggerPointerUp(null, new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
// Assert
- eventTriggered.Should().BeFalse();
+ Assert.False(eventTriggered);
}
[Fact]
@@ -38,7 +37,7 @@ public void Behavior_ShouldTriggerMouseClick_WhenMouseDownThenUpWithoutMove()
diagram.TriggerPointerUp(null, new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
// Assert
- eventTriggered.Should().BeTrue();
+ Assert.True(eventTriggered);
}
[Fact]
@@ -55,7 +54,7 @@ public void Behavior_ShouldNotTriggerMouseClick_WhenMouseMoves()
diagram.TriggerPointerUp(null, new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
// Assert
- eventTriggered.Should().BeFalse();
+ Assert.False(eventTriggered);
}
[Fact]
@@ -71,7 +70,7 @@ public void Behavior_ShouldTriggerMouseDoubleClick_WhenTwoMouseClicksHappenWithi
diagram.TriggerPointerClick(null, new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
// Assert
- eventTriggered.Should().BeTrue();
+ Assert.True(eventTriggered);
}
[Fact]
@@ -88,7 +87,7 @@ public async Task Behavior_ShouldNotTriggerMouseDoubleClick_WhenTimeExceeds500()
diagram.TriggerPointerClick(null, new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
// Assert
- eventTriggered.Should().BeFalse();
+ Assert.False(eventTriggered);
}
[Fact]
@@ -103,6 +102,6 @@ public void Behavior_ShouldTriggerMouseClick_OnlyWhenMouseDownWasAlsoTriggered_I
diagram.TriggerPointerUp(null, new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
// Assert
- eventTriggered.Should().BeFalse();
+ Assert.False(eventTriggered);
}
}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Behaviors/KeyboardShortcutsBehaviorTests.cs b/tests/Blazor.Diagrams.Core.Tests/Behaviors/KeyboardShortcutsBehaviorTests.cs
index 42fe887b7..baa7c30ad 100644
--- a/tests/Blazor.Diagrams.Core.Tests/Behaviors/KeyboardShortcutsBehaviorTests.cs
+++ b/tests/Blazor.Diagrams.Core.Tests/Behaviors/KeyboardShortcutsBehaviorTests.cs
@@ -1,6 +1,5 @@
using Blazor.Diagrams.Core.Behaviors;
using Blazor.Diagrams.Core.Events;
-using FluentAssertions;
using System.Threading.Tasks;
using Xunit;
@@ -33,7 +32,7 @@ public void Behavior_ShouldExecuteAction_WhenCombinationIsPressed(string key, bo
diagram.TriggerKeyDown(new KeyboardEventArgs(key, key, 0, ctrl, shift, alt));
// Assert
- executed.Should().BeTrue();
+ Assert.True(executed);
}
[Fact]
@@ -55,7 +54,7 @@ public void Behavior_ShouldDoNothing_WhenRemoved()
diagram.TriggerKeyDown(new KeyboardEventArgs("A", "A", 0, false, false, false));
// Assert
- executed.Should().BeFalse();
+ Assert.False(executed);
}
[Fact]
@@ -83,7 +82,7 @@ public void SetShortcut_ShouldOverride()
diagram.TriggerKeyDown(new KeyboardEventArgs("A", "A", 0, false, false, false));
// Assert
- executed1.Should().BeFalse();
- executed2.Should().BeTrue();
+ Assert.False(executed1);
+ Assert.True(executed2);
}
}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Behaviors/KeyboardShortcutsDefaultsTests.cs b/tests/Blazor.Diagrams.Core.Tests/Behaviors/KeyboardShortcutsDefaultsTests.cs
index 3a30fc040..9d2b500de 100644
--- a/tests/Blazor.Diagrams.Core.Tests/Behaviors/KeyboardShortcutsDefaultsTests.cs
+++ b/tests/Blazor.Diagrams.Core.Tests/Behaviors/KeyboardShortcutsDefaultsTests.cs
@@ -1,8 +1,5 @@
using Blazor.Diagrams.Core.Behaviors;
using Blazor.Diagrams.Core.Models;
-using FluentAssertions;
-using System;
-using System.Threading.Tasks;
using Xunit;
namespace Blazor.Diagrams.Core.Tests.Behaviors;
@@ -24,7 +21,7 @@ public async Task DeleteSelection_ShouldNotDeleteModel_WhenItsLocked()
await KeyboardShortcutsDefaults.DeleteSelection(diagram);
// Assert
- diagram.Nodes.Count.Should().Be(1);
+ Assert.Single(diagram.Nodes);
}
[Fact]
@@ -47,8 +44,8 @@ public async Task DeleteSelection_ShouldTakeIntoAccountGroupConstraint()
await KeyboardShortcutsDefaults.DeleteSelection(diagram);
// Assert
- funcCalled.Should().BeTrue();
- diagram.Groups.Count.Should().Be(1);
+ Assert.True(funcCalled);
+ Assert.Single(diagram.Groups);
}
[Fact]
@@ -71,8 +68,8 @@ public async Task DeleteSelection_ShouldTakeIntoAccountNodeConstraint()
await KeyboardShortcutsDefaults.DeleteSelection(diagram);
// Assert
- funcCalled.Should().BeTrue();
- diagram.Nodes.Count.Should().Be(1);
+ Assert.True(funcCalled);
+ Assert.Single(diagram.Nodes);
}
[Fact]
@@ -100,8 +97,8 @@ public async Task DeleteSelection_ShouldTakeIntoAccountLinkConstraint()
await KeyboardShortcutsDefaults.DeleteSelection(diagram);
// Assert
- funcCalled.Should().BeTrue();
- diagram.Links.Count.Should().Be(1);
+ Assert.True(funcCalled);
+ Assert.Single(diagram.Links);
}
[Fact]
@@ -126,8 +123,8 @@ public async Task DeleteSelection_ShouldResultInSingleRefresh()
await KeyboardShortcutsDefaults.DeleteSelection(diagram);
// Assert
- diagram.Nodes.Count.Should().Be(0);
- diagram.Links.Count.Should().Be(0);
- refreshes.Should().Be(1);
+ Assert.Empty(diagram.Nodes);
+ Assert.Empty(diagram.Links);
+ Assert.Equal(1, refreshes);
}
}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Behaviors/PanBehaviorTests.cs b/tests/Blazor.Diagrams.Core.Tests/Behaviors/PanBehaviorTests.cs
new file mode 100644
index 000000000..3feee5090
--- /dev/null
+++ b/tests/Blazor.Diagrams.Core.Tests/Behaviors/PanBehaviorTests.cs
@@ -0,0 +1,54 @@
+using Blazor.Diagrams.Core.Behaviors;
+using Blazor.Diagrams.Core.Events;
+using Blazor.Diagrams.Core.Geometry;
+using Xunit;
+
+namespace Blazor.Diagrams.Core.Tests.Behaviors
+{
+ public class PanBehaviorTests
+ {
+ [Fact]
+ public void Behavior_WhenBehaviorEnabled_ShouldPan()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior();
+ diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));
+
+ Assert.Equal(0, diagram.Pan.X);
+ Assert.Equal(0, diagram.Pan.Y);
+
+ // Act
+ diagram.TriggerPointerDown(null,
+ new PointerEventArgs(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+ diagram.TriggerPointerMove(null,
+ new PointerEventArgs(200, 200, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+
+ // Assert
+ Assert.Equal(100, diagram.Pan.X);
+ Assert.Equal(100, diagram.Pan.Y);
+ }
+
+ [Fact]
+ public void Behavior_WhenBehaviorDisabled_ShouldNotPan()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramDragBehavior = null;
+ diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));
+
+ Assert.Equal(0, diagram.Pan.X);
+ Assert.Equal(0, diagram.Pan.Y);
+
+ // Act
+ diagram.TriggerPointerDown(null,
+ new PointerEventArgs(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+ diagram.TriggerPointerMove(null,
+ new PointerEventArgs(200, 200, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+
+ // Assert
+ Assert.Equal(0, diagram.Pan.X);
+ Assert.Equal(0, diagram.Pan.Y);
+ }
+ }
+}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Behaviors/ScrollBehaviorTests.cs b/tests/Blazor.Diagrams.Core.Tests/Behaviors/ScrollBehaviorTests.cs
new file mode 100644
index 000000000..d18be5ed3
--- /dev/null
+++ b/tests/Blazor.Diagrams.Core.Tests/Behaviors/ScrollBehaviorTests.cs
@@ -0,0 +1,43 @@
+using Blazor.Diagrams.Core.Behaviors;
+using Blazor.Diagrams.Core.Events;
+using Blazor.Diagrams.Core.Geometry;
+using Xunit;
+
+namespace Blazor.Diagrams.Core.Tests.Behaviors
+{
+ public class ScrollBehaviorTests
+ {
+ [Fact]
+ public void Behavior_WhenBehaviorEnabled_ShouldScroll()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior();
+ diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));
+ diagram.Options.Zoom.ScaleFactor = 1.05;
+
+ // Act
+ diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, false, false, 100, 200, 0, 0));
+
+ // Assert
+ Assert.Equal(-100, diagram.Pan.X);
+ Assert.Equal(-200, diagram.Pan.Y);
+ }
+
+ [Fact]
+ public void Behavior_WhenBehaviorDisabled_ShouldNotScroll()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramWheelBehavior = null;
+ diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));
+
+ // Act
+ diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, false, false, 100, 200, 0, 0));
+
+ // Assert
+ Assert.Equal(0, diagram.Pan.X);
+ Assert.Equal(0, diagram.Pan.Y);
+ }
+ }
+}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Behaviors/SelectionBoxBehaviorTests.cs b/tests/Blazor.Diagrams.Core.Tests/Behaviors/SelectionBoxBehaviorTests.cs
new file mode 100644
index 000000000..a394e0333
--- /dev/null
+++ b/tests/Blazor.Diagrams.Core.Tests/Behaviors/SelectionBoxBehaviorTests.cs
@@ -0,0 +1,227 @@
+using Blazor.Diagrams.Core.Behaviors;
+using Blazor.Diagrams.Core.Events;
+using Blazor.Diagrams.Core.Geometry;
+using Blazor.Diagrams.Core.Models;
+using Xunit;
+
+namespace Blazor.Diagrams.Core.Tests.Behaviors
+{
+ public class SelectionBoxBehaviorTests
+ {
+ [Fact]
+ public void Behavior_WhenBehaviorEnabled_ShouldUpdateSelectionBounds()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior();
+ diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));
+
+ var selectionBoxBehavior = diagram.GetBehavior()!;
+ bool boundsChangedEventInvoked = false;
+ Rectangle? lastBounds = null;
+ selectionBoxBehavior.SelectionBoundsChanged += (_, newBounds) =>
+ {
+ boundsChangedEventInvoked = true;
+ lastBounds = newBounds;
+ };
+
+ // Act
+ diagram.TriggerPointerDown(null,
+ new PointerEventArgs(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+ diagram.TriggerPointerMove(null,
+ new PointerEventArgs(200, 150, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+
+ // Assert
+ Assert.True(boundsChangedEventInvoked);
+ Assert.Equal(100, lastBounds!.Width);
+ Assert.Equal(50, lastBounds.Height);
+ Assert.Equal(100, lastBounds.Top);
+ Assert.Equal(100, lastBounds.Left);
+ }
+
+ [Fact]
+ public void Behavior_WhenBehaviorEnabled_ShouldUpdateSelectionBoundsOnScroll()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior();
+ diagram.BehaviorOptions.DiagramShiftDragBehavior = diagram.GetBehavior();
+ diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior();
+ diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));
+
+ var selectionBoxBehavior = diagram.GetBehavior()!;
+ bool boundsChangedEventInvoked = false;
+ Rectangle? lastBounds = null;
+ selectionBoxBehavior.SelectionBoundsChanged += (_, newBounds) =>
+ {
+ boundsChangedEventInvoked = true;
+ lastBounds = newBounds;
+ };
+
+ // Act
+ diagram.TriggerPointerDown(null,
+ new PointerEventArgs(100, 100, 0, 0, false, true, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+ diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, true, false, 200, 150, 0, 0));
+
+ // Assert
+ Assert.True(boundsChangedEventInvoked);
+ Assert.Equal(200, lastBounds!.Width);
+ Assert.Equal(150, lastBounds.Height);
+ Assert.Equal(-50, lastBounds.Top);
+ Assert.Equal(-100, lastBounds.Left);
+ }
+
+ [Fact]
+ public void Behavior_WhenBehaviorDisabled_ShouldNotUpdateSelectionBounds()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramDragBehavior = null;
+ diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));
+
+ var selectionBoxBehavior = diagram.GetBehavior()!;
+ bool boundsChangedEventInvoked = false;
+ Rectangle? lastBounds = null;
+ selectionBoxBehavior.SelectionBoundsChanged += (_, newBounds) =>
+ {
+ boundsChangedEventInvoked = true;
+ lastBounds = newBounds;
+ };
+
+ // Act
+ diagram.TriggerPointerDown(null,
+ new PointerEventArgs(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+ diagram.TriggerPointerMove(null,
+ new PointerEventArgs(200, 150, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+
+ // Assert
+ Assert.False(boundsChangedEventInvoked);
+ Assert.Null(lastBounds);
+ }
+
+ [Fact]
+ public void Behavior_WithBoundsChangedDelegate_ShouldSelectNodesInsideArea()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior();
+ diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));
+
+ var selectionBoxBehavior = diagram.GetBehavior()!;
+ selectionBoxBehavior.SelectionBoundsChanged += (_, _) => { };
+
+ var node = new NodeModel()
+ {
+ Size = new Size(100, 100),
+ Position = new Point(150, 150)
+ };
+ diagram.Nodes.Add(node);
+
+ // Act
+ diagram.TriggerPointerDown(null,
+ new PointerEventArgs(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+ diagram.TriggerPointerMove(null,
+ new PointerEventArgs(300, 300, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+
+ // Assert
+ Assert.True(node.Selected);
+
+ diagram.TriggerPointerMove(null,
+ new PointerEventArgs(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+ Assert.False(node.Selected);
+ }
+
+ [Fact]
+ public void Behavior_WithBoundsChangedDelegate_ShouldSelectNodesInsideAreaWhenScrolling()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior();
+ diagram.BehaviorOptions.DiagramShiftDragBehavior = diagram.GetBehavior();
+ diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior();
+ diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));
+
+ var selectionBoxBehavior = diagram.GetBehavior()!;
+ selectionBoxBehavior.SelectionBoundsChanged += (_, _) => { };
+
+ var node = new NodeModel()
+ {
+ Size = new Size(100, 100),
+ Position = new Point(150, 150)
+ };
+ diagram.Nodes.Add(node);
+
+ // Act
+ diagram.TriggerPointerDown(null,
+ new PointerEventArgs(100, 100, 0, 0, false, true, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+ diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, true, false, 200, 200, 0, 0));
+
+ // Assert
+ Assert.True(node.Selected);
+
+ diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, true, false, -200, -200, 0, 0));
+
+ Assert.False(node.Selected);
+ }
+
+ [Fact]
+ public void Behavior_WithoutBoundsChangedDelegate_ShouldNotSelectNodesInsideArea()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior();
+ diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));
+
+ var node = new NodeModel()
+ {
+ Size = new Size(100, 100),
+ Position = new Point(150, 150)
+ };
+ diagram.Nodes.Add(node);
+
+ // Act
+ diagram.TriggerPointerDown(null,
+ new PointerEventArgs(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+ diagram.TriggerPointerMove(null,
+ new PointerEventArgs(300, 300, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+
+ // Assert
+ Assert.False(node.Selected);
+
+ diagram.TriggerPointerMove(null,
+ new PointerEventArgs(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+ Assert.False(node.Selected);
+ }
+
+ [Fact]
+ public void Behavior_WithoutBoundsChangedDelegate_ShouldNotSelectNodesInsideAreaWhenScrolling()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior();
+ diagram.BehaviorOptions.DiagramShiftDragBehavior = diagram.GetBehavior();
+ diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior();
+ diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));
+
+ var node = new NodeModel()
+ {
+ Size = new Size(100, 100),
+ Position = new Point(150, 150)
+ };
+ diagram.Nodes.Add(node);
+
+ // Act
+ diagram.TriggerPointerDown(null,
+ new PointerEventArgs(100, 100, 0, 0, false, true, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+ diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, true, false, 200, 200, 0, 0));
+
+
+ // Assert
+ Assert.False(node.Selected);
+
+ diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, true, false, -200, -200, 0, 0));
+
+ Assert.False(node.Selected);
+ }
+ }
+}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Behaviors/ZoomBehaviorTests.cs b/tests/Blazor.Diagrams.Core.Tests/Behaviors/ZoomBehaviorTests.cs
new file mode 100644
index 000000000..526c9b6c9
--- /dev/null
+++ b/tests/Blazor.Diagrams.Core.Tests/Behaviors/ZoomBehaviorTests.cs
@@ -0,0 +1,40 @@
+using Blazor.Diagrams.Core.Behaviors;
+using Blazor.Diagrams.Core.Events;
+using Blazor.Diagrams.Core.Geometry;
+using Xunit;
+
+namespace Blazor.Diagrams.Core.Tests.Behaviors
+{
+ public class ZoomBehaviorTests
+ {
+ [Fact]
+ public void Behavior_WhenBehaviorEnabled_ShouldZoom()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior();
+ diagram.SetContainer(new Rectangle(0, 0, 100, 100));
+
+ // Act
+ diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, false, false, 0, 100, 0, 0));
+
+ // Assert
+ Assert.Equal(1.05, diagram.Zoom);
+ }
+
+ [Fact]
+ public void Behavior_WhenBehaviorDisabled_ShouldNotZoom()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramWheelBehavior = null;
+ diagram.SetContainer(new Rectangle(0, 0, 100, 100));
+
+ // Act
+ diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, false, false, 0, 100, 0, 0));
+
+ // Assert
+ Assert.Equal(1, diagram.Zoom);
+ }
+ }
+}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Blazor.Diagrams.Core.Tests.csproj b/tests/Blazor.Diagrams.Core.Tests/Blazor.Diagrams.Core.Tests.csproj
index 0e1f0d2ff..879a96c52 100644
--- a/tests/Blazor.Diagrams.Core.Tests/Blazor.Diagrams.Core.Tests.csproj
+++ b/tests/Blazor.Diagrams.Core.Tests/Blazor.Diagrams.Core.Tests.csproj
@@ -1,21 +1,20 @@
-
+
- net6.0
- enable
false
+ True
+ ..\..\src\Blazor.Diagrams\sgKey.snk
-
-
-
-
-
+
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
diff --git a/tests/Blazor.Diagrams.Core.Tests/Controls/ControlsContainerTests.cs b/tests/Blazor.Diagrams.Core.Tests/Controls/ControlsContainerTests.cs
new file mode 100644
index 000000000..33291ca77
--- /dev/null
+++ b/tests/Blazor.Diagrams.Core.Tests/Controls/ControlsContainerTests.cs
@@ -0,0 +1,28 @@
+using Blazor.Diagrams.Core.Controls;
+using Blazor.Diagrams.Core.Events;
+using Blazor.Diagrams.Core.Models;
+using Xunit;
+
+namespace Blazor.Diagrams.Core.Tests.Controls
+{
+ public class ControlsContainerTests
+ {
+ [Fact]
+ public void AlwaysOnControlType_AlwaysVisible()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+ var node = diagram.Nodes.Add(new NodeModel());
+ var controls = diagram.Controls.AddFor(node, ControlsType.AlwaysOn);
+
+ // Assert
+ Assert.True(controls.Visible);
+
+ node.Selected = true;
+ Assert.True(controls.Visible);
+
+ diagram.TriggerPointerEnter(node, new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+ Assert.True(controls.Visible);
+ }
+ }
+}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Controls/RemoveControlTests.cs b/tests/Blazor.Diagrams.Core.Tests/Controls/RemoveControlTests.cs
new file mode 100644
index 000000000..0929bfe4d
--- /dev/null
+++ b/tests/Blazor.Diagrams.Core.Tests/Controls/RemoveControlTests.cs
@@ -0,0 +1,267 @@
+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.Options;
+using Moq;
+using Xunit;
+
+namespace Blazor.Diagrams.Core.Tests.Controls
+{
+ public class RemoveControlTests
+ {
+ public PointerEventArgs PointerEventArgs
+ => new(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true);
+
+ [Fact]
+ public async Task OnPointerDown_NoConstraints_RemovesNode()
+ {
+ // Arrange
+ RemoveControl removeControl = new(0, 0);
+ Diagram diagram = new TestDiagram();
+ var nodeMock = new Mock(Point.Zero);
+ var node = diagram.Nodes.Add(nodeMock.Object);
+
+ // Act
+ await removeControl.OnPointerDown(diagram, node, PointerEventArgs);
+
+ // Assert
+ Assert.Empty(diagram.Nodes);
+ }
+
+ [Fact]
+ public async Task OnPointerDown_ShouldDeleteNodeTrue_RemovesNode()
+ {
+ // Arrange
+ RemoveControl removeControl = new(0, 0);
+ Diagram diagram = new TestDiagram(
+ new DiagramOptions
+ {
+ Constraints =
+ {
+ ShouldDeleteNode = (node) => ValueTask.FromResult(true)
+ }
+ });
+ var nodeMock = new Mock(Point.Zero);
+ var node = diagram.Nodes.Add(nodeMock.Object);
+
+ // Act
+ await removeControl.OnPointerDown(diagram, node, PointerEventArgs);
+
+ // Assert
+ Assert.Empty(diagram.Nodes);
+ }
+
+ [Fact]
+ public async Task OnPointerDown_ShouldDeleteNodeFalse_KeepsNode()
+ {
+ // Arrange
+ RemoveControl removeControl = new(0, 0);
+ Diagram diagram = new TestDiagram(
+ new DiagramOptions
+ {
+ Constraints =
+ {
+ ShouldDeleteNode = (node) => ValueTask.FromResult(false)
+ }
+ });
+ var nodeMock = new Mock(Point.Zero);
+ var node = diagram.Nodes.Add(nodeMock.Object);
+
+ // Act
+ await removeControl.OnPointerDown(diagram, node, PointerEventArgs);
+
+ // Assert
+ Assert.Contains(node, diagram.Nodes);
+ }
+
+ [Fact]
+ public async Task OnPointerDown_NoConstraints_RemovesLink()
+ {
+ // Arrange
+ RemoveControl removeControl = new(0, 0);
+ Diagram diagram = new TestDiagram();
+
+ var node1 = new NodeModel(new Point(50, 50));
+ var node2 = new NodeModel(new Point(300, 300));
+ diagram.Nodes.Add(new[] { node1, node2 });
+ node1.AddPort(PortAlignment.Right);
+ node2.AddPort(PortAlignment.Left);
+
+ var link = new LinkModel(
+ node1.GetPort(PortAlignment.Right)!,
+ node2.GetPort(PortAlignment.Left)!
+ );
+
+ diagram.Links.Add(link);
+
+ // Act
+ await removeControl.OnPointerDown(diagram, link, PointerEventArgs);
+
+ // Assert
+ Assert.Empty(diagram.Links);
+ }
+
+ [Fact]
+ public async Task OnPointerDown_ShouldDeleteLinkTrue_RemovesLink()
+ {
+ // Arrange
+ RemoveControl removeControl = new(0, 0);
+ Diagram diagram = new TestDiagram(
+ new DiagramOptions
+ {
+ Constraints =
+ {
+ ShouldDeleteLink = (node) => ValueTask.FromResult(true)
+ }
+ });
+
+ var node1 = new NodeModel(new Point(50, 50));
+ var node2 = new NodeModel(new Point(300, 300));
+ diagram.Nodes.Add(new[] { node1, node2 });
+ node1.AddPort(PortAlignment.Right);
+ node2.AddPort(PortAlignment.Left);
+
+ var link = new LinkModel(
+ node1.GetPort(PortAlignment.Right)!,
+ node2.GetPort(PortAlignment.Left)!
+ );
+
+ diagram.Links.Add(link);
+
+ // Act
+ await removeControl.OnPointerDown(diagram, link, PointerEventArgs);
+
+ // Assert
+ Assert.Empty(diagram.Links);
+ }
+
+ [Fact]
+ public async Task OnPointerDown_ShouldDeleteLinkFalse_KeepsLink()
+ {
+ // Arrange
+ RemoveControl removeControl = new(0, 0);
+ Diagram diagram = new TestDiagram(
+ new DiagramOptions
+ {
+ Constraints =
+ {
+ ShouldDeleteLink = (node) => ValueTask.FromResult(false)
+ }
+ });
+
+ var node1 = new NodeModel(new Point(50, 50));
+ var node2 = new NodeModel(new Point(300, 300));
+ diagram.Nodes.Add(new[] { node1, node2 });
+ node1.AddPort(PortAlignment.Right);
+ node2.AddPort(PortAlignment.Left);
+
+ var link = new LinkModel(
+ node1.GetPort(PortAlignment.Right)!,
+ node2.GetPort(PortAlignment.Left)!
+ );
+
+ diagram.Links.Add(link);
+
+ // Act
+ await removeControl.OnPointerDown(diagram, link, PointerEventArgs);
+
+ // Assert
+ Assert.Contains(link, diagram.Links);
+ }
+
+ [Fact]
+ public async Task OnPointerDown_NoConstraints_RemovesGroup()
+ {
+ // Arrange
+ RemoveControl removeControl = new(0, 0);
+ Diagram diagram = new TestDiagram();
+
+ var node1 = new NodeModel(new Point(50, 50));
+ var node2 = new NodeModel(new Point(300, 300));
+ diagram.Nodes.Add(new[] { node1, node2 });
+ node1.AddPort(PortAlignment.Right);
+ node2.AddPort(PortAlignment.Left);
+
+ var group = new GroupModel(new[] { node1, node2 });
+
+
+ diagram.Groups.Add(group);
+
+ // Act
+ await removeControl.OnPointerDown(diagram, group, PointerEventArgs);
+
+ // Assert
+ Assert.Empty(diagram.Groups);
+ Assert.Empty(diagram.Nodes);
+ }
+
+ [Fact]
+ public async Task OnPointerDown_ShouldDeleteGroupTrue_RemovesGroup()
+ {
+ // Arrange
+ RemoveControl removeControl = new(0, 0);
+ Diagram diagram = new TestDiagram(
+ new DiagramOptions
+ {
+ Constraints =
+ {
+ ShouldDeleteGroup = (node) => ValueTask.FromResult(true)
+ }
+ });
+
+ var node1 = new NodeModel(new Point(50, 50));
+ var node2 = new NodeModel(new Point(300, 300));
+ diagram.Nodes.Add(new[] { node1, node2 });
+ node1.AddPort(PortAlignment.Right);
+ node2.AddPort(PortAlignment.Left);
+
+ var group = new GroupModel(new[] { node1, node2 });
+
+
+ diagram.Groups.Add(group);
+
+ // Act
+ await removeControl.OnPointerDown(diagram, group, PointerEventArgs);
+
+ // Assert
+ Assert.Empty(diagram.Groups);
+ Assert.Empty(diagram.Nodes);
+ }
+
+ [Fact]
+ public async Task OnPointerDown_ShouldDeleteGroupFalse_KeepsGroup()
+ {
+ // Arrange
+ RemoveControl removeControl = new(0, 0);
+ Diagram diagram = new TestDiagram(
+ new DiagramOptions
+ {
+ Constraints =
+ {
+ ShouldDeleteGroup = (node) => ValueTask.FromResult(false)
+ }
+ });
+
+ var node1 = new NodeModel(new Point(50, 50));
+ var node2 = new NodeModel(new Point(300, 300));
+ diagram.Nodes.Add(new[] { node1, node2 });
+ node1.AddPort(PortAlignment.Right);
+ node2.AddPort(PortAlignment.Left);
+
+ var group = new GroupModel(new[] { node1, node2 });
+
+
+ diagram.Groups.Add(group);
+
+ // Act
+ await removeControl.OnPointerDown(diagram, group, PointerEventArgs);
+
+ // Assert
+ Assert.Contains(group, diagram.Groups);
+ Assert.Contains(node1, diagram.Nodes);
+ Assert.Contains(node2, diagram.Nodes);
+ }
+
+ }
+}
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..543ecb6f0
--- /dev/null
+++ b/tests/Blazor.Diagrams.Core.Tests/Controls/ResizeControlTests.cs
@@ -0,0 +1,74 @@
+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);
+ }
+}
\ No newline at end of file
diff --git a/tests/Blazor.Diagrams.Core.Tests/DiagramOrderingTests.cs b/tests/Blazor.Diagrams.Core.Tests/DiagramOrderingTests.cs
index 5493e51fa..b5db2c566 100644
--- a/tests/Blazor.Diagrams.Core.Tests/DiagramOrderingTests.cs
+++ b/tests/Blazor.Diagrams.Core.Tests/DiagramOrderingTests.cs
@@ -1,6 +1,4 @@
using Blazor.Diagrams.Core.Models;
-using FluentAssertions;
-using System;
using Xunit;
namespace Blazor.Diagrams.Core.Tests;
@@ -17,7 +15,7 @@ public void GetMinOrder_ShouldReturnZeroWhenNoModelsHaveBeenAdded()
var minOrder = diagram.GetMinOrder();
// Assert
- minOrder.Should().Be(0);
+ Assert.Equal(0, minOrder);
}
[Fact]
@@ -33,7 +31,7 @@ public void GetMinOrder_ShouldReturnCorrectValue()
var minOrder = diagram.GetMinOrder();
// Assert
- minOrder.Should().Be(1);
+ Assert.Equal(1, minOrder);
}
[Fact]
@@ -46,7 +44,7 @@ public void GetMaxOrder_ShouldReturnZeroWhenNoModelsHaveBeenAdded()
var maxOrder = diagram.GetMaxOrder();
// Assert
- maxOrder.Should().Be(0);
+ Assert.Equal(0, maxOrder);
}
[Fact]
@@ -62,7 +60,7 @@ public void GetMaxOrder_ShouldReturnCorrectValue()
var maxOrder = diagram.GetMaxOrder();
// Assert
- maxOrder.Should().Be(3);
+ Assert.Equal(3, maxOrder);
}
[Fact]
@@ -77,8 +75,8 @@ public void Diagram_ShouldReSortWhenModelOrderChanges()
node1.Order = 10;
// Assert
- diagram.OrderedSelectables[0].Should().Be(node2);
- diagram.OrderedSelectables[1].Should().Be(node1);
+ Assert.Equal(node2, diagram.OrderedSelectables[0]);
+ Assert.Equal(node1, diagram.OrderedSelectables[1]);
}
[Fact]
@@ -95,7 +93,7 @@ public void Diagram_ShouldRefreshOnceWhenModelOrderChanges()
node1.Order = 10;
// Assert
- refreshes.Should().Be(1);
+ Assert.Equal(1, refreshes);
}
[Fact]
@@ -111,14 +109,14 @@ public void SendToBack_ShouldInsertAtZeroAndFixOrders()
diagram.SendToBack(node3);
// Assert
- diagram.OrderedSelectables[0].Should().Be(node3);
- diagram.OrderedSelectables[0].Order.Should().Be(1);
+ Assert.Equal(node3, diagram.OrderedSelectables[0]);
+ Assert.Equal(1, diagram.OrderedSelectables[0].Order);
- diagram.OrderedSelectables[1].Should().Be(node1);
- diagram.OrderedSelectables[1].Order.Should().Be(2);
+ Assert.Equal(node1, diagram.OrderedSelectables[1]);
+ Assert.Equal(2, diagram.OrderedSelectables[1].Order);
- diagram.OrderedSelectables[2].Should().Be(node2);
- diagram.OrderedSelectables[2].Order.Should().Be(3);
+ Assert.Equal(node2, diagram.OrderedSelectables[2]);
+ Assert.Equal(3, diagram.OrderedSelectables[2].Order);
}
[Fact]
@@ -134,14 +132,14 @@ public void SendToFront_ShouldAddAndFixOrder()
diagram.SendToFront(node1);
// Assert
- diagram.OrderedSelectables[0].Should().Be(node2);
- diagram.OrderedSelectables[0].Order.Should().Be(2);
+ Assert.Equal(node2, diagram.OrderedSelectables[0]);
+ Assert.Equal(2, diagram.OrderedSelectables[0].Order);
- diagram.OrderedSelectables[1].Should().Be(node3);
- diagram.OrderedSelectables[1].Order.Should().Be(3);
+ Assert.Equal(node3, diagram.OrderedSelectables[1]);
+ Assert.Equal(3, diagram.OrderedSelectables[1].Order);
- diagram.OrderedSelectables[2].Should().Be(node1);
- diagram.OrderedSelectables[2].Order.Should().Be(4);
+ Assert.Equal(node1, diagram.OrderedSelectables[2]);
+ Assert.Equal(4, diagram.OrderedSelectables[2].Order);
}
[Fact]
@@ -159,7 +157,7 @@ public void Diagram_ShouldRefreshOnceWhenMultipleModelsWereRemoved()
diagram.Nodes.Remove(node1);
// Assert
- refreshes.Should().Be(1);
+ Assert.Equal(1, refreshes);
}
[Fact]
@@ -175,8 +173,8 @@ public void Diagram_ShouldNotUpdateOrders_WhenSuspendSortingIsTrue()
node1.Order = 10;
// Assert
- diagram.OrderedSelectables[0].Should().Be(node1);
- diagram.OrderedSelectables[1].Should().Be(node2);
+ Assert.Equal(node1, diagram.OrderedSelectables[0]);
+ Assert.Equal(node2, diagram.OrderedSelectables[1]);
}
[Fact]
@@ -191,7 +189,7 @@ public void RefreshOrders_ShouldSortModels()
diagram.RefreshOrders();
// Assert
- diagram.OrderedSelectables[0].Should().Be(node2);
- diagram.OrderedSelectables[1].Should().Be(node1);
+ Assert.Equal(node2, diagram.OrderedSelectables[0]);
+ Assert.Equal(node1, diagram.OrderedSelectables[1]);
}
}
diff --git a/tests/Blazor.Diagrams.Core.Tests/DiagramTests.cs b/tests/Blazor.Diagrams.Core.Tests/DiagramTests.cs
index 85a812dfc..54fe9b983 100644
--- a/tests/Blazor.Diagrams.Core.Tests/DiagramTests.cs
+++ b/tests/Blazor.Diagrams.Core.Tests/DiagramTests.cs
@@ -1,7 +1,5 @@
using Blazor.Diagrams.Core.Geometry;
using Blazor.Diagrams.Core.Models;
-using FluentAssertions;
-using System;
using Xunit;
namespace Blazor.Diagrams.Core.Tests;
@@ -21,8 +19,8 @@ public void GetScreenPoint_ShouldReturnCorrectPoint()
var pt = diagram.GetScreenPoint(100, 200);
// Assert
- pt.X.Should().Be(203.4); // 2*X + panX + left
- pt.Y.Should().Be(361.8); // 2*Y + panY + top
+ Assert.Equal(203.4, pt.X);// 2*X + panX + left
+ Assert.Equal(361.8, pt.Y);// 2*Y + panY + top
}
[Fact]
@@ -41,9 +39,9 @@ public void ZoomToFit_ShouldUseSelectedNodesIfAny()
diagram.ZoomToFit(10);
// Assert
- diagram.Zoom.Should().BeApproximately(7.68, 0.001);
- diagram.Pan.X.Should().Be(-307.2);
- diagram.Pan.Y.Should().Be(-307.2);
+ Assert.InRange(diagram.Zoom, 7.679, 7.681);
+ Assert.Equal(-307.2, diagram.Pan.X);
+ Assert.Equal(-307.2, diagram.Pan.Y);
}
[Fact]
@@ -61,9 +59,9 @@ public void ZoomToFit_ShouldUseNodesWhenNoneSelected()
diagram.ZoomToFit(10);
// Assert
- diagram.Zoom.Should().BeApproximately(7.68, 0.001);
- diagram.Pan.X.Should().Be(-307.2);
- diagram.Pan.Y.Should().Be(-307.2);
+ Assert.InRange(diagram.Zoom, 7.679, 7.681);
+ Assert.Equal(-307.2, diagram.Pan.X);
+ Assert.Equal(-307.2, diagram.Pan.Y);
}
[Fact]
@@ -84,13 +82,13 @@ public void ZoomToFit_ShouldTriggerAppropriateEvents()
// Act
diagram.Changed += () => refreshes++;
diagram.ZoomChanged += () => zoomChanges++;
- diagram.PanChanged += () => panChanges++;
+ diagram.PanChanged += (deltaX, deltaY) => panChanges++;
diagram.ZoomToFit(10);
// Assert
- refreshes.Should().Be(1);
- zoomChanges.Should().Be(1);
- panChanges.Should().Be(1);
+ Assert.Equal(1, refreshes);
+ Assert.Equal(1, zoomChanges);
+ Assert.Equal(1, panChanges);
}
[Theory]
@@ -122,4 +120,17 @@ public void ZoomOptions_ThrowExceptionWhenLessThan0(double zoomValue)
var diagram = new TestDiagram();
Assert.Throws(() => diagram.Options.Zoom.Minimum = zoomValue);
}
+
+ [Fact]
+ public void SetContainer_ShouldAcceptNullGracefully()
+ {
+ // Arrange
+ var diagram = new TestDiagram();
+
+ //Act
+ var exception = Record.Exception(() => diagram.SetContainer(null));
+
+ // Assert
+ Assert.Null(exception);
+ }
}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Geometry/PointTests.cs b/tests/Blazor.Diagrams.Core.Tests/Geometry/PointTests.cs
index 104103578..0f5af52c7 100644
--- a/tests/Blazor.Diagrams.Core.Tests/Geometry/PointTests.cs
+++ b/tests/Blazor.Diagrams.Core.Tests/Geometry/PointTests.cs
@@ -1,7 +1,5 @@
using Blazor.Diagrams.Core.Geometry;
-using FluentAssertions;
using Xunit;
-
namespace Blazor.Diagrams.Core.Tests.Geometry;
public class PointTests
@@ -15,6 +13,6 @@ public void DistanceTo(double x1, double y1, double x2, double y2, double expect
{
var pt1 = new Point(x1, y1);
var pt2 = new Point(x2, y2);
- pt1.DistanceTo(pt2).Should().BeApproximately(expected, 0.0001);
+ Assert.InRange(pt1.DistanceTo(pt2), expected - 0.0001, expected + 0.0001);
}
}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Layers/GroupLayerTests.cs b/tests/Blazor.Diagrams.Core.Tests/Layers/GroupLayerTests.cs
index c17398c6b..2c4a49d7d 100644
--- a/tests/Blazor.Diagrams.Core.Tests/Layers/GroupLayerTests.cs
+++ b/tests/Blazor.Diagrams.Core.Tests/Layers/GroupLayerTests.cs
@@ -1,5 +1,4 @@
using Blazor.Diagrams.Core.Models;
-using FluentAssertions;
using System;
using Xunit;
@@ -24,7 +23,7 @@ public void Group_ShouldCallFactoryThenAddMethod()
diagram.Groups.Group(Array.Empty());
// Assert
- factoryCalled.Should().BeTrue();
+ Assert.True(factoryCalled);
}
[Fact]
@@ -42,7 +41,7 @@ public void Remove_ShouldRemoveAllPortLinks()
diagram.Groups.Remove(group);
// Assert
- diagram.Links.Should().BeEmpty();
+ Assert.Empty(diagram.Links);
}
[Fact]
@@ -58,7 +57,7 @@ public void Remove_ShouldRemoveAllLinks()
diagram.Groups.Remove(group);
// Assert
- diagram.Links.Should().BeEmpty();
+ Assert.Empty(diagram.Links);
}
[Fact]
@@ -73,8 +72,8 @@ public void Remove_ShouldRemoveItselfFromParentGroup()
diagram.Groups.Remove(group1);
// Assert
- group2.Children.Should().BeEmpty();
- group1.Group.Should().BeNull();
+ Assert.Empty(group2.Children);
+ Assert.Null(group1.Group);
}
[Fact]
@@ -89,8 +88,8 @@ public void Remove_ShouldUngroup()
diagram.Groups.Remove(group);
// Assert
- group.Children.Should().BeEmpty();
- node.Group.Should().BeNull();
+ Assert.Empty(group.Children);
+ Assert.Null(node.Group);
}
[Fact]
@@ -105,7 +104,7 @@ public void Delete_ShouldDeleteChildGroup()
diagram.Groups.Delete(group2);
// Assert
- diagram.Groups.Should().BeEmpty();
+ Assert.Empty(diagram.Groups);
}
[Fact]
@@ -120,8 +119,8 @@ public void Delete_ShouldRemoveChild()
diagram.Groups.Delete(group);
// Assert
- diagram.Groups.Should().BeEmpty();
- diagram.Nodes.Should().BeEmpty();
+ Assert.Empty(diagram.Groups);
+ Assert.Empty(diagram.Nodes);
}
[Fact]
@@ -136,7 +135,7 @@ public void Add_ShouldRefreshDiagramOnce()
var group = diagram.Groups.Add(new GroupModel(Array.Empty()));
// Assert
- refreshes.Should().Be(1);
+ Assert.Equal(1, refreshes);
}
[Fact]
@@ -152,7 +151,7 @@ public void Remove_ShouldRefreshDiagramOnce()
diagram.Groups.Remove(group);
// Assert
- refreshes.Should().Be(1);
+ Assert.Equal(1,refreshes);
}
[Fact]
@@ -169,6 +168,6 @@ public void Delete_ShouldRefreshDiagramOnce()
diagram.Groups.Delete(group);
// Assert
- refreshes.Should().Be(1);
+ Assert.Equal(1,refreshes);
}
}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Layers/NodeLayerTests.cs b/tests/Blazor.Diagrams.Core.Tests/Layers/NodeLayerTests.cs
index 7c5718ef4..3316f3e00 100644
--- a/tests/Blazor.Diagrams.Core.Tests/Layers/NodeLayerTests.cs
+++ b/tests/Blazor.Diagrams.Core.Tests/Layers/NodeLayerTests.cs
@@ -1,5 +1,4 @@
using Blazor.Diagrams.Core.Models;
-using FluentAssertions;
using Xunit;
namespace Blazor.Diagrams.Core.Tests.Layers;
@@ -21,7 +20,7 @@ public void Remove_ShouldRemoveAllPortLinks()
diagram.Nodes.Remove(node1);
// Assert
- diagram.Links.Should().BeEmpty();
+ Assert.Empty(diagram.Links);
}
[Fact]
@@ -37,7 +36,7 @@ public void Remove_ShouldRemoveAllLinks()
diagram.Nodes.Remove(node1);
// Assert
- diagram.Links.Should().BeEmpty();
+ Assert.Empty(diagram.Links);
}
[Fact]
@@ -52,8 +51,8 @@ public void Remove_ShouldRemoveItselfFromParentGroup()
diagram.Nodes.Remove(node);
// Assert
- group.Children.Should().BeEmpty();
- node.Group.Should().BeNull();
+ Assert.Empty(group.Children);
+ Assert.Null(node.Group);
}
[Fact]
@@ -68,7 +67,7 @@ public void Add_ShouldRefreshDiagramOnce()
var node = diagram.Nodes.Add(new NodeModel());
// Assert
- refreshes.Should().Be(1);
+ Assert.Equal(1,refreshes);
}
[Fact]
@@ -86,7 +85,7 @@ public void Remove_ShouldRefreshDiagramOnce()
diagram.Nodes.Remove(node1);
// Assert
- refreshes.Should().Be(1);
+ Assert.Equal(1,refreshes);
}
[Fact]
@@ -101,6 +100,6 @@ public void Remove_ShouldRemoveControls()
diagram.Nodes.Remove(node);
// Assert
- diagram.Controls.GetFor(node).Should().BeNull();
+ Assert.Null(diagram.Controls.GetFor(node));
}
}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Models/Base/BaseLinkModelTests.cs b/tests/Blazor.Diagrams.Core.Tests/Models/Base/BaseLinkModelTests.cs
index c4566e861..0d6e339f3 100644
--- a/tests/Blazor.Diagrams.Core.Tests/Models/Base/BaseLinkModelTests.cs
+++ b/tests/Blazor.Diagrams.Core.Tests/Models/Base/BaseLinkModelTests.cs
@@ -4,7 +4,6 @@
using Blazor.Diagrams.Core.Models.Base;
using Blazor.Diagrams.Core.PathGenerators;
using Blazor.Diagrams.Core.Routers;
-using FluentAssertions;
using Xunit;
namespace Blazor.Diagrams.Core.Tests.Models.Base;
@@ -36,12 +35,12 @@ public void SetSource_ShouldChangePropertiesAndTriggerEvent()
link.SetSource(sp);
// Assert
- eventsTriggered.Should().Be(1);
- link.Source.Should().BeSameAs(sp);
- oldSp.Should().NotBeNull();
- newSp.Should().BeSameAs(sp);
- linkInstance.Should().BeSameAs(link);
- link.Source.Model.Should().BeSameAs(port);
+ Assert.Equal(1, eventsTriggered);
+ Assert.Same(sp, link.Source);
+ Assert.NotNull(oldSp);
+ Assert.Same(sp, newSp);
+ Assert.Same(link, linkInstance);
+ Assert.Same(port, link.Source.Model);
}
[Fact]
@@ -69,12 +68,12 @@ public void SetTarget_ShouldChangePropertiesAndTriggerEvent()
link.SetTarget(tp);
// Assert
- eventsTriggered.Should().Be(1);
- link.Target.Should().BeSameAs(tp);
- oldTp.Should().BeOfType();
- newTp.Should().BeSameAs(tp);
- linkInstance.Should().BeSameAs(link);
- link.Target!.Model.Should().BeSameAs(port);
+ Assert.Equal(1, eventsTriggered);
+ Assert.Same(tp, link.Target);
+ Assert.IsType(oldTp);
+ Assert.Same(tp, newTp);
+ Assert.Same(link, linkInstance);
+ Assert.Same(port, link.Target!.Model);
}
[Fact]
@@ -91,9 +90,9 @@ public void GetBounds_ShouldReturnPathBBox()
var bounds = link.GetBounds()!;
// Assert
- bounds.Left.Should().Be(10);
- bounds.Top.Should().Be(5);
- bounds.Width.Should().Be(90);
- bounds.Height.Should().Be(75);
+ Assert.Equal(10, bounds.Left);
+ Assert.Equal(5, bounds.Top);
+ Assert.Equal(90, bounds.Width);
+ Assert.Equal(75, bounds.Height);
}
}
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);
+ }
+ }
+}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Options/DiagramBehaviorOptionsTests.cs b/tests/Blazor.Diagrams.Core.Tests/Options/DiagramBehaviorOptionsTests.cs
new file mode 100644
index 000000000..62e73a38f
--- /dev/null
+++ b/tests/Blazor.Diagrams.Core.Tests/Options/DiagramBehaviorOptionsTests.cs
@@ -0,0 +1,127 @@
+using Blazor.Diagrams.Core.Behaviors;
+using Blazor.Diagrams.Core.Events;
+using Blazor.Diagrams.Core.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Blazor.Diagrams.Core.Tests.Options
+{
+ public class DiagramBehaviorOptionsTests
+ {
+ [Fact]
+ public void DiagramBehaviorOptions_DragBehavior_IsBehaviorEnabled()
+ {
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramDragBehavior = null;
+ Assert.False(diagram.GetBehavior()!.IsBehaviorEnabled(new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true)));
+
+ diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior();
+ Assert.True(diagram.GetBehavior()!.IsBehaviorEnabled(new PointerEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true)));
+ }
+
+ [Fact]
+ public void DiagramBehaviorOptions_AltDragBehavior_IsBehaviorEnabled()
+ {
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior();
+ diagram.BehaviorOptions.DiagramAltDragBehavior = null;
+ Assert.True(diagram.GetBehavior()!.IsBehaviorEnabled(new PointerEventArgs(0, 0, 0, 0, false, false, true, 0, 0, 0, 0, 0, 0, string.Empty, true)));
+
+ diagram.BehaviorOptions.DiagramDragBehavior = null;
+ Assert.False(diagram.GetBehavior()!.IsBehaviorEnabled(new PointerEventArgs(0, 0, 0, 0, false, false, true, 0, 0, 0, 0, 0, 0, string.Empty, true)));
+
+ diagram.BehaviorOptions.DiagramAltDragBehavior = diagram.GetBehavior();
+ Assert.True(diagram.GetBehavior()!.IsBehaviorEnabled(new PointerEventArgs(0, 0, 0, 0, false, false, true, 0, 0, 0, 0, 0, 0, string.Empty, true)));
+ }
+
+ [Fact]
+ public void DiagramBehaviorOptions_CtrlDragBehavior_IsBehaviorEnabled()
+ {
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior();
+ diagram.BehaviorOptions.DiagramCtrlDragBehavior = null;
+ Assert.True(diagram.GetBehavior()!.IsBehaviorEnabled(new PointerEventArgs(0, 0, 0, 0, true, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true)));
+
+ diagram.BehaviorOptions.DiagramDragBehavior = null;
+ Assert.False(diagram.GetBehavior()!.IsBehaviorEnabled(new PointerEventArgs(0, 0, 0, 0, true, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true)));
+
+ diagram.BehaviorOptions.DiagramCtrlDragBehavior = diagram.GetBehavior();
+ Assert.True(diagram.GetBehavior()!.IsBehaviorEnabled(new PointerEventArgs(0, 0, 0, 0, true, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true)));
+ }
+
+ [Fact]
+ public void DiagramBehaviorOptions_ShiftDragBehavior_IsBehaviorEnabled()
+ {
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior();
+ diagram.BehaviorOptions.DiagramShiftDragBehavior = null;
+ Assert.True(diagram.GetBehavior()!.IsBehaviorEnabled(new PointerEventArgs(0, 0, 0, 0, false, true, false, 0, 0, 0, 0, 0, 0, string.Empty, true)));
+
+ diagram.BehaviorOptions.DiagramDragBehavior = null;
+ Assert.False(diagram.GetBehavior()!.IsBehaviorEnabled(new PointerEventArgs(0, 0, 0, 0, false, true, false, 0, 0, 0, 0, 0, 0, string.Empty, true)));
+
+ diagram.BehaviorOptions.DiagramShiftDragBehavior = diagram.GetBehavior();
+ Assert.True(diagram.GetBehavior()!.IsBehaviorEnabled(new PointerEventArgs(0, 0, 0, 0, false, true, false, 0, 0, 0, 0, 0, 0, string.Empty, true)));
+ }
+
+ [Fact]
+ public void DiagramBehaviorOptions_DefaultScrollBehavior_IsBehaviorEnabled()
+ {
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramWheelBehavior = null;
+ Assert.False(diagram.GetBehavior()!.IsBehaviorEnabled(new WheelEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0)));
+
+ diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior();
+ Assert.True(diagram.GetBehavior()!.IsBehaviorEnabled(new WheelEventArgs(0, 0, 0, 0, false, false, false, 0, 0, 0, 0)));
+ }
+
+ [Fact]
+ public void DiagramBehaviorOptions_AltScrollBehavior_IsBehaviorEnabled()
+ {
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior();
+ diagram.BehaviorOptions.DiagramAltWheelBehavior = null;
+ Assert.True(diagram.GetBehavior()!.IsBehaviorEnabled(new WheelEventArgs(0, 0, 0, 0, false, false, true, 0, 0, 0, 0)));
+
+ diagram.BehaviorOptions.DiagramWheelBehavior = null;
+ Assert.False(diagram.GetBehavior()!.IsBehaviorEnabled(new WheelEventArgs(0, 0, 0, 0, false, false, true, 0, 0, 0, 0)));
+
+ diagram.BehaviorOptions.DiagramAltWheelBehavior = diagram.GetBehavior();
+ Assert.True(diagram.GetBehavior()!.IsBehaviorEnabled(new WheelEventArgs(0, 0, 0, 0, false, false, true, 0, 0, 0, 0)));
+ }
+
+ [Fact]
+ public void DiagramBehaviorOptions_CtrlScrollBehavior_IsBehaviorEnabled()
+ {
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior();
+ diagram.BehaviorOptions.DiagramCtrlWheelBehavior = null;
+ Assert.True(diagram.GetBehavior()!.IsBehaviorEnabled(new WheelEventArgs(0, 0, 0, 0, true, false, false, 0, 0, 0, 0)));
+
+ diagram.BehaviorOptions.DiagramWheelBehavior = null;
+ Assert.False(diagram.GetBehavior()!.IsBehaviorEnabled(new WheelEventArgs(0, 0, 0, 0, true, false, false, 0, 0, 0, 0)));
+
+ diagram.BehaviorOptions.DiagramCtrlWheelBehavior = diagram.GetBehavior();
+ Assert.True(diagram.GetBehavior()!.IsBehaviorEnabled(new WheelEventArgs(0, 0, 0, 0, true, false, false, 0, 0, 0, 0)));
+ }
+
+ [Fact]
+ public void DiagramBehaviorOptions_ShiftScrollBehavior_IsBehaviorEnabled()
+ {
+ var diagram = new TestDiagram();
+ diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior();
+ diagram.BehaviorOptions.DiagramShiftWheelBehavior = null;
+ Assert.True(diagram.GetBehavior()!.IsBehaviorEnabled(new WheelEventArgs(0, 0, 0, 0, false, true, false, 0, 0, 0, 0)));
+
+ diagram.BehaviorOptions.DiagramWheelBehavior = null;
+ Assert.False(diagram.GetBehavior()!.IsBehaviorEnabled(new WheelEventArgs(0, 0, 0, 0, false, true, false, 0, 0, 0, 0)));
+
+ diagram.BehaviorOptions.DiagramShiftWheelBehavior = diagram.GetBehavior();
+ Assert.True(diagram.GetBehavior()!.IsBehaviorEnabled(new WheelEventArgs(0, 0, 0, 0, false, true, false, 0, 0, 0, 0)));
+ }
+ }
+}
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..5287508da
--- /dev/null
+++ b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomLeftResizerProviderTests.cs
@@ -0,0 +1,174 @@
+using Blazor.Diagrams.Core.Behaviors;
+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 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
+ Assert.Equal(0, node.Position.X);
+ Assert.Equal(0, node.Position.Y);
+ Assert.Equal(100, node.Size.Width);
+ Assert.Equal(200, node.Size.Height);
+
+
+ // 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
+ Assert.Equal(10, node.Position.X);
+ Assert.Equal(0, node.Position.Y);
+ Assert.Equal(90, node.Size.Width);
+ Assert.Equal(215, node.Size.Height);
+ }
+
+ [Fact]
+ public void PanChanged_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);
+ diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior();
+
+ // before resize
+ Assert.Equal(0, node.Position.X);
+ Assert.Equal(0, node.Position.Y);
+ Assert.Equal(100, node.Size.Width);
+ Assert.Equal(200, node.Size.Height);
+
+ // 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);
+ diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, false, false, 10, 100, 0, 0));
+
+
+ // after resize
+ Assert.Equal(10, node.Position.X);
+ Assert.Equal(0, node.Position.Y);
+ Assert.Equal(90, node.Size.Width);
+ Assert.Equal(300, node.Size.Height);
+ }
+
+ [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(300, 300);
+ node.MinimumDimensions = new Size(50, 100);
+ var control = new ResizeControl(new BottomLeftResizerProvider());
+ diagram.Controls.AddFor(node).Add(control);
+ diagram.SelectModel(node, false);
+
+ // before resize
+ Assert.Equal(0, node.Position.X);
+ Assert.Equal(0, node.Position.Y);
+ Assert.Equal(300, node.Size.Width);
+ Assert.Equal(300, node.Size.Height);
+
+ // resize
+ var eventArgs = new PointerEventArgs(0, 300, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true);
+ control.OnPointerDown(diagram, node, eventArgs);
+ eventArgs = new PointerEventArgs(150, 150, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true);
+ diagram.TriggerPointerMove(null, eventArgs);
+ eventArgs = new PointerEventArgs(400, -100, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true);
+ diagram.TriggerPointerMove(null, eventArgs);
+
+ // after resize
+ Assert.Equal(250, node.Position.X);
+ Assert.Equal(0, node.Position.Y);
+ Assert.Equal(50, node.Size.Width);
+ Assert.Equal(100, node.Size.Height);
+ }
+
+ [Fact]
+ public void DragResizer_ShouldResizeNode_WhenDiagramZoomedOut()
+ {
+ // 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
+ Assert.Equal(0, node.Position.X);
+ Assert.Equal(0, node.Position.Y);
+ Assert.Equal(100, node.Size.Width);
+ Assert.Equal(200, node.Size.Height);
+
+ // 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
+ Assert.Equal(20, node.Position.X);
+ Assert.Equal(0, node.Position.Y);
+ Assert.Equal(80, node.Size.Width);
+ Assert.Equal(230, node.Size.Height);
+ }
+
+ [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
+ Assert.Equal(0, node.Position.X);
+ Assert.Equal(0, node.Position.Y);
+ Assert.Equal(100, node.Size.Width);
+ Assert.Equal(200, node.Size.Height);
+
+ // 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
+ Assert.Equal(5, node.Position.X);
+ Assert.Equal(0, node.Position.Y);
+ Assert.Equal(95, node.Size.Width);
+ Assert.Equal(207.5, node.Size.Height);
+ }
+}
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..e2a69adba
--- /dev/null
+++ b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/BottomRightResizerProviderTests.cs
@@ -0,0 +1,171 @@
+using Blazor.Diagrams.Core.Behaviors;
+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 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
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(100,node.Size.Width);
+ Assert.Equal(200,node.Size.Height);
+
+ // 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
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(110,node.Size.Width);
+ Assert.Equal(215,node.Size.Height);
+ }
+
+ [Fact]
+ public void PanChanged_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);
+ diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior();
+
+
+ // before resize
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(100,node.Size.Width);
+ Assert.Equal(200,node.Size.Height);
+
+ // 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);
+ diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, false, false, 10, 100, 0, 0));
+
+
+ // after resize
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(110,node.Size.Width);
+ Assert.Equal(300,node.Size.Height);
+ }
+
+ [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
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(100,node.Size.Width);
+ Assert.Equal(200,node.Size.Height);
+
+ // 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
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(0,node.Size.Width);
+ Assert.Equal(0,node.Size.Height);
+ }
+
+ [Fact]
+ public void DragResizer_ShouldResizeNode_WhenDiagramZoomedOut()
+ {
+ // 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
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(100,node.Size.Width);
+ Assert.Equal(200,node.Size.Height);
+
+ // 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
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(120,node.Size.Width);
+ Assert.Equal(230,node.Size.Height);
+ }
+
+ [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
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(100,node.Size.Width);
+ Assert.Equal(200,node.Size.Height);
+
+ // 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
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(105,node.Size.Width);
+ Assert.Equal(207.5,node.Size.Height);
+ }
+}
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..07a4ee815
--- /dev/null
+++ b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopLeftResizerProviderTests.cs
@@ -0,0 +1,174 @@
+using Blazor.Diagrams.Core.Behaviors;
+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 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
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(100,node.Size.Width);
+ Assert.Equal(200,node.Size.Height);
+
+ // 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
+ Assert.Equal(10,node.Position.X);
+ Assert.Equal(15,node.Position.Y);
+ Assert.Equal(90,node.Size.Width);
+ Assert.Equal(185,node.Size.Height);
+ }
+
+ [Fact]
+ public void PanChanged_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);
+ diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior();
+
+
+ // before resize
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(100,node.Size.Width);
+ Assert.Equal(200,node.Size.Height);
+
+ // 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);
+ diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, false, false, 10, -100, 0, 0));
+
+
+ // after resize
+ Assert.Equal(10,node.Position.X);
+ Assert.Equal(-100,node.Position.Y);
+ Assert.Equal(90,node.Size.Width);
+ Assert.Equal(300,node.Size.Height);
+ }
+
+ [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(300, 300);
+ node.MinimumDimensions = new Size(50, 100);
+ var control = new ResizeControl(new TopLeftResizerProvider());
+ diagram.Controls.AddFor(node).Add(control);
+ diagram.SelectModel(node, false);
+
+ // before resize
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(300,node.Size.Width);
+ Assert.Equal(300,node.Size.Height);
+
+ // 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(150, 150, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true);
+ diagram.TriggerPointerMove(null, eventArgs);
+ eventArgs = new PointerEventArgs(400, 400, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true);
+ diagram.TriggerPointerMove(null, eventArgs);
+
+ // after resize
+ Assert.Equal(250,node.Position.X);
+ Assert.Equal(200,node.Position.Y);
+ Assert.Equal(50,node.Size.Width);
+ Assert.Equal(100,node.Size.Height);
+ }
+
+ [Fact]
+ public void DragResizer_ShouldResizeNode_WhenDiagramZoomedOut()
+ {
+ // 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
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(100,node.Size.Width);
+ Assert.Equal(200,node.Size.Height);
+
+ // 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
+ Assert.Equal(20,node.Position.X);
+ Assert.Equal(30,node.Position.Y);
+ Assert.Equal(80,node.Size.Width);
+ Assert.Equal(170,node.Size.Height);
+ }
+
+ [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
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(100,node.Size.Width);
+ Assert.Equal(200,node.Size.Height);
+
+ // 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
+ Assert.Equal(5,node.Position.X);
+ Assert.Equal(7.5,node.Position.Y);
+ Assert.Equal(95,node.Size.Width);
+ Assert.Equal(192.5,node.Size.Height);
+ }
+}
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..9aaa1b566
--- /dev/null
+++ b/tests/Blazor.Diagrams.Core.Tests/Positions/Resizing/TopRightResizerProviderTests.cs
@@ -0,0 +1,172 @@
+using Blazor.Diagrams.Core.Behaviors;
+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 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
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(100,node.Size.Width);
+ Assert.Equal(200,node.Size.Height);
+
+ // 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
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(15,node.Position.Y);
+ Assert.Equal(110,node.Size.Width);
+ Assert.Equal(185,node.Size.Height);
+ }
+
+ [Fact]
+ public void PanChanged_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);
+ diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior();
+
+ // before resize
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(100,node.Size.Width);
+ Assert.Equal(200,node.Size.Height);
+
+ // 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);
+ diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, false, false, 10, -100, 0, 0));
+
+ // after resize
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(-100,node.Position.Y);
+ Assert.Equal(110,node.Size.Width);
+ Assert.Equal(300,node.Size.Height);
+ }
+
+ [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(300, 300);
+ node.MinimumDimensions = new Size(50, 100);
+ var control = new ResizeControl(new TopRightResizerProvider());
+ diagram.Controls.AddFor(node).Add(control);
+ diagram.SelectModel(node, false);
+
+ // before resize
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(300,node.Size.Width);
+ Assert.Equal(300,node.Size.Height);
+
+ // resize
+ var eventArgs = new PointerEventArgs(300, 0, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true);
+ control.OnPointerDown(diagram, node, eventArgs);
+ eventArgs = new PointerEventArgs(150, 150, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true);
+ diagram.TriggerPointerMove(null, eventArgs);
+ eventArgs = new PointerEventArgs(-100, 400, 0, 0, false, false, false, 1, 1, 1, 1, 1, 1, "arrow", true);
+ diagram.TriggerPointerMove(null, eventArgs);
+
+ // after resize
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(200,node.Position.Y);
+ Assert.Equal(50,node.Size.Width);
+ Assert.Equal(100,node.Size.Height);
+ }
+
+ [Fact]
+ public void DragResizer_ShouldResizeNode_WhenDiagramZoomedOut()
+ {
+ // 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
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(100,node.Size.Width);
+ Assert.Equal(200,node.Size.Height);
+
+ // 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
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(30,node.Position.Y);
+ Assert.Equal(120,node.Size.Width);
+ Assert.Equal(170,node.Size.Height);
+ }
+
+ [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
+ Assert.Equal(0,node.Position.X);
+ Assert.Equal(0,node.Position.Y);
+ Assert.Equal(100,node.Size.Width);
+ Assert.Equal(200,node.Size.Height);
+
+ // 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
+ Assert.Equal(0, node.Position.X);
+ Assert.Equal(7.5, node.Position.Y);
+ Assert.Equal(105, node.Size.Width);
+ Assert.Equal(192.5, node.Size.Height);
+ }
+}
diff --git a/tests/Blazor.Diagrams.Core.Tests/Positions/ShapeAnglePositionProviderTests.cs b/tests/Blazor.Diagrams.Core.Tests/Positions/ShapeAnglePositionProviderTests.cs
index 205cad5b8..bb915b333 100644
--- a/tests/Blazor.Diagrams.Core.Tests/Positions/ShapeAnglePositionProviderTests.cs
+++ b/tests/Blazor.Diagrams.Core.Tests/Positions/ShapeAnglePositionProviderTests.cs
@@ -1,7 +1,6 @@
using Blazor.Diagrams.Core.Geometry;
using Blazor.Diagrams.Core.Models;
using Blazor.Diagrams.Core.Positions;
-using FluentAssertions;
using Moq;
using Xunit;
@@ -39,7 +38,7 @@ public void GetPosition_ShouldUseOffset_WhenProvided()
var position = provider.GetPosition(nodeMock.Object);
// Assert
- position!.X.Should().Be(105);
- position.Y.Should().Be(40);
+ Assert.Equal(105, position!.X);
+ Assert.Equal(40, position.Y);
}
}
\ No newline at end of file
diff --git a/tests/Blazor.Diagrams.Tests/Blazor.Diagrams.Tests.csproj b/tests/Blazor.Diagrams.Tests/Blazor.Diagrams.Tests.csproj
index dead3f03e..949bf1c97 100644
--- a/tests/Blazor.Diagrams.Tests/Blazor.Diagrams.Tests.csproj
+++ b/tests/Blazor.Diagrams.Tests/Blazor.Diagrams.Tests.csproj
@@ -1,30 +1,24 @@
-
+
- net6.0
- enable
false
- true
+ true
+ True
+ ..\..\src\Blazor.Diagrams\sgKey.snk
-
-
-
-
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
+
+
+
+
+
+
+
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..ee4aa80a1
--- /dev/null
+++ b/tests/Blazor.Diagrams.Tests/Components/Controls/ResizeControlWidgetTests.cs
@@ -0,0 +1,24 @@
+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("");
+ }
+}
diff --git a/tests/Blazor.Diagrams.Tests/Components/ControlsLayerRendererTests.cs b/tests/Blazor.Diagrams.Tests/Components/ControlsLayerRendererTests.cs
new file mode 100644
index 000000000..bf922ad38
--- /dev/null
+++ b/tests/Blazor.Diagrams.Tests/Components/ControlsLayerRendererTests.cs
@@ -0,0 +1,95 @@
+using Bunit;
+using Xunit;
+using Blazor.Diagrams.Components.Controls;
+using Blazor.Diagrams.Core.Models.Base;
+
+namespace Blazor.Diagrams.Tests.Components
+{
+ public class ControlsLayerRendererTests
+ {
+ [Fact]
+ public async Task Rendering_WithChangingModels_ShouldNotThrowException()
+ {
+ // Arrange
+ using var ctx = new TestContext();
+ var diagram = new BlazorDiagram();
+
+ var model1 = new CustomModel();
+ var model2 = new CustomModel();
+
+ diagram.Controls.AddFor(model1);
+ diagram.Controls.AddFor(model2);
+
+ var renderStarted = new ManualResetEventSlim(false);
+ var modificationStarted = new ManualResetEventSlim(false);
+ var exceptionThrown = false;
+
+ IRenderedComponent? cut = null;
+
+ // Task to render the component
+ var renderTask = Task.Run(async () =>
+ {
+ try
+ {
+ cut = ctx.RenderComponent(parameters => parameters
+ .Add(c => c.BlazorDiagram, diagram));
+
+ renderStarted.Set(); // Indicate that rendering has started
+
+ // Force Blazor to update while modifications happen
+ for (int i = 0; i < 10; i++)
+ {
+ await cut.InvokeAsync(() =>
+ {
+ cut.Render();
+ });
+ Thread.Sleep(5); // Let it process
+ }
+
+ modificationStarted.Wait(); // Wait for modifications
+ }
+ catch (InvalidOperationException)
+ {
+ exceptionThrown = true;
+ }
+ });
+
+ // Wait to ensure rendering starts first
+ renderStarted.Wait();
+ await Task.Delay(10); // Allow time for rendering
+
+ // Task to modify the collection while rendering happens
+ var modifyTask = Task.Run(async () =>
+ {
+ try
+ {
+ foreach (var model in diagram.Controls.Models)
+ {
+ if (model == model1)
+ {
+ await cut.InvokeAsync(() =>
+ {
+ diagram.Controls.RemoveFor(model1);
+ });
+ }
+ }
+ }
+ catch (InvalidOperationException)
+ {
+ exceptionThrown = true;
+ }
+ finally
+ {
+ modificationStarted.Set();
+ }
+ });
+
+ // Wait for tasks to complete
+ await Task.WhenAll(renderTask, modifyTask);
+
+ // Assert
+ Assert.False(exceptionThrown, "Iteration should not throw an exception when using .ToList()");
+ }
+ private class CustomModel : Model { }
+ }
+}
diff --git a/tests/Blazor.Diagrams.Tests/Components/DiagramCanvasTests.cs b/tests/Blazor.Diagrams.Tests/Components/DiagramCanvasTests.cs
new file mode 100644
index 000000000..f3852758b
--- /dev/null
+++ b/tests/Blazor.Diagrams.Tests/Components/DiagramCanvasTests.cs
@@ -0,0 +1,28 @@
+using Blazor.Diagrams.Components;
+using Blazor.Diagrams.Core.Geometry;
+using Bunit;
+using Xunit;
+
+namespace Blazor.Diagrams.Tests.Components
+{
+ public class DiagramCanvasTests
+ {
+ [Fact]
+ public void Behavior_WhenDisposing_ShouldUnsubscribeToResizes()
+ {
+ // Arrange
+ JSRuntimeInvocationHandler call;
+ using (var ctx = new TestContext())
+ {
+ ctx.JSInterop.Setup("ZBlazorDiagrams.getBoundingClientRect", _ => true);
+ call = ctx.JSInterop.SetupVoid("ZBlazorDiagrams.unobserve", _ => true).SetVoidResult();
+
+ // Act
+ var cut = ctx.RenderComponent(p => p.Add(n => n.BlazorDiagram, new BlazorDiagram()));
+ }
+
+ // Assert
+ call.VerifyInvoke("ZBlazorDiagrams.unobserve", calledTimes: 1);
+ }
+ }
+}
diff --git a/tests/Blazor.Diagrams.Tests/Components/DiagramCursorTests.cs b/tests/Blazor.Diagrams.Tests/Components/DiagramCursorTests.cs
new file mode 100644
index 000000000..c81538730
--- /dev/null
+++ b/tests/Blazor.Diagrams.Tests/Components/DiagramCursorTests.cs
@@ -0,0 +1,48 @@
+using AngleSharp.Css.Dom;
+using Blazor.Diagrams.Components;
+using Blazor.Diagrams.Core.Geometry;
+using Bunit;
+using Xunit;
+
+namespace Blazor.Diagrams.Core.Tests.Behaviors
+{
+ public class DiagramCursorTests
+ {
+ [Fact]
+ public void Behavior_WhenPanningOptionIsAllowed_CursorShouldBeGrab()
+ {
+ // Arrange
+ using var ctx = new TestContext();
+ var diagram = new BlazorDiagram();
+ diagram.Options.AllowPanning = true;
+ ctx.JSInterop.Setup("ZBlazorDiagrams.getBoundingClientRect", _ => true);
+
+ // Act
+ var cut = ctx.RenderComponent(parameters => parameters
+ .Add(n => n.BlazorDiagram, diagram));
+ var diagramCanvas = cut.Find(".diagram-canvas");
+
+ // Assert
+ Assert.Contains("cursor: grab; cursor: -webkit-grab;", diagramCanvas.ToMarkup());
+ }
+
+ [Fact]
+ public void Behavior_WhenPanningOptionIsNotAllowed_CursorShouldBeDefault()
+ {
+ // Arrange
+ using var ctx = new TestContext();
+ var diagram = new BlazorDiagram();
+ diagram.Options.AllowPanning = false;
+ ctx.JSInterop.Setup("ZBlazorDiagrams.getBoundingClientRect", _ => true);
+
+ // Act
+ var cut = ctx.RenderComponent(parameters => parameters
+ .Add(n => n.BlazorDiagram, diagram));
+ var diagramCanvas = cut.Find(".diagram-canvas");
+ var canvasStyle = diagramCanvas.GetStyle().CssText;
+
+ // Assert
+ Assert.Contains("cursor: default", canvasStyle);
+ }
+ }
+}
diff --git a/tests/Blazor.Diagrams.Tests/Components/LinkVertexWidgetTests.cs b/tests/Blazor.Diagrams.Tests/Components/LinkVertexWidgetTests.cs
index 9c4678099..29b985ebc 100644
--- a/tests/Blazor.Diagrams.Tests/Components/LinkVertexWidgetTests.cs
+++ b/tests/Blazor.Diagrams.Tests/Components/LinkVertexWidgetTests.cs
@@ -3,7 +3,6 @@
using Blazor.Diagrams.Core.Models;
using Blazor.Diagrams.Tests.TestComponents;
using Bunit;
-using FluentAssertions;
using Microsoft.AspNetCore.Components.Web;
using System.Threading.Tasks;
using Xunit;
@@ -76,9 +75,9 @@ public void ShouldRerender_WhenVertexIsRefreshed()
.Add(n => n.BlazorDiagram, new BlazorDiagram()));
// Assert
- cut.RenderCount.Should().Be(1);
+ Assert.Equal(1, cut.RenderCount);
vertex.Refresh();
- cut.RenderCount.Should().Be(2);
+ Assert.Equal(2, cut.RenderCount);
}
[Fact]
@@ -104,8 +103,8 @@ public async Task ShouldDeleteItselfAndRefreshParent_WhenDoubleClicked()
await cut.Find("circle").DoubleClickAsync(new MouseEventArgs());
// Assert
- link.Vertices.Should().BeEmpty();
- linkRefreshes.Should().Be(1);
+ Assert.Empty(link.Vertices);
+ Assert.Equal(1,linkRefreshes);
}
[Fact]
diff --git a/tests/Blazor.Diagrams.Tests/Components/NodeWidgetTests.cs b/tests/Blazor.Diagrams.Tests/Components/NodeWidgetTests.cs
index dfabb012d..b3cb656bb 100644
--- a/tests/Blazor.Diagrams.Tests/Components/NodeWidgetTests.cs
+++ b/tests/Blazor.Diagrams.Tests/Components/NodeWidgetTests.cs
@@ -5,7 +5,6 @@
using Bunit;
-using FluentAssertions;
using Xunit;
@@ -26,11 +25,11 @@ public void DefaultNodeWidget_ShouldHaveSingleClassAndNoPorts_WhenItHasNoPortsAn
// Assert
var content = cut.Find("div.default-node");
- content.ClassList.Should().ContainSingle();
- content.ClassList[0].Should().Be("default-node");
- content.TextContent.Trim().Should().Be("Title");
+ Assert.Single(content.ClassList);
+ Assert.Equal("default-node", content.ClassList[0]);
+ Assert.Equal("Title", content.TextContent.Trim());
var ports = cut.FindComponents();
- ports.Should().BeEmpty();
+ Assert.Empty(ports);
}
}
diff --git a/tests/Blazor.Diagrams.Tests/Components/Renderers/PortRendererTest.cs b/tests/Blazor.Diagrams.Tests/Components/Renderers/PortRendererTest.cs
new file mode 100644
index 000000000..912f2a309
--- /dev/null
+++ b/tests/Blazor.Diagrams.Tests/Components/Renderers/PortRendererTest.cs
@@ -0,0 +1,22 @@
+using Blazor.Diagrams.Components.Renderers;
+using Blazor.Diagrams.Core.Models;
+using Bunit;
+using Xunit;
+
+namespace Blazor.Diagrams.Tests.Components.Renderers;
+
+public class PortRendererTest
+{
+ [Fact]
+ void UpdateDimensionsDoesNotCrashWithNullContainer()
+ {
+ using var ctx = new TestContext();
+ ctx.JSInterop.Mode = JSRuntimeMode.Loose;
+ var node = new NodeModel();
+ var portModel = new PortModel(node, PortAlignment.Bottom);
+
+ var component = ctx.RenderComponent(parameters => parameters
+ .Add(n => n.Port, portModel)
+ .Add(n => n.BlazorDiagram, new BlazorDiagram()));
+ }
+}
\ No newline at end of file
diff --git a/tests/Blazor.Diagrams.Tests/Components/Widgets/SelectionBoxWidgetTests.cs b/tests/Blazor.Diagrams.Tests/Components/Widgets/SelectionBoxWidgetTests.cs
new file mode 100644
index 000000000..11d913539
--- /dev/null
+++ b/tests/Blazor.Diagrams.Tests/Components/Widgets/SelectionBoxWidgetTests.cs
@@ -0,0 +1,41 @@
+using Bunit;
+using Xunit;
+using Blazor.Diagrams.Components.Widgets;
+using AngleSharp.Css.Dom;
+using Blazor.Diagrams.Core.Events;
+using Blazor.Diagrams.Core.Geometry;
+using Blazor.Diagrams.Core.Behaviors;
+
+namespace Blazor.Diagrams.Tests.Components.Widgets
+{
+ public class SelectionBoxWidgetTests
+ {
+ [Fact]
+ public void SelectionBoxWidget_SelectionBoundsChanged_RendersSelectionBoxWidgetInCorrectLocation()
+ {
+ // Arrange
+ using var ctx = new TestContext();
+ var diagram = new BlazorDiagram();
+ diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior();
+ diagram.SetPan(-75, -100);
+ diagram.SetContainer(new Rectangle(new Point(0, 0), new Size(500, 500)));
+
+ // Act
+ var cut = ctx.RenderComponent(parameters => parameters
+ .Add(n => n.BlazorDiagram, diagram));
+ Assert.Throws(() => cut.Find("div"));
+ diagram.TriggerPointerDown(null,
+ new PointerEventArgs(100, 150, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+ diagram.TriggerPointerMove(null,
+ new PointerEventArgs(200, 250, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
+
+
+ // Assert
+ var widget = cut.Find("div");
+ Assert.Equal("100px", widget.GetStyle().GetWidth());
+ Assert.Equal("100px", widget.GetStyle().GetHeight());
+ Assert.Equal("150px", widget.GetStyle().GetTop());
+ Assert.Equal("100px", widget.GetStyle().GetLeft());
+ }
+ }
+}
diff --git a/tests/Blazor.Diagrams.Tests/DiagramTests.cs b/tests/Blazor.Diagrams.Tests/DiagramTests.cs
index a61abc64b..5e6ba0d17 100644
--- a/tests/Blazor.Diagrams.Tests/DiagramTests.cs
+++ b/tests/Blazor.Diagrams.Tests/DiagramTests.cs
@@ -1,7 +1,6 @@
using Blazor.Diagrams.Components;
using Blazor.Diagrams.Core.Models;
using Blazor.Diagrams.Core.Models.Base;
-using FluentAssertions;
using Microsoft.AspNetCore.Components;
using Xunit;
@@ -20,7 +19,7 @@ public void GetComponentForModel_ShouldReturnComponentType_WhenModelTypeWasRegis
var componentType = diagram.GetComponent();
// Assert
- componentType.Should().Be(typeof(NodeWidget));
+ Assert.Equal(typeof(NodeWidget), componentType);
}
[Fact]
@@ -33,7 +32,7 @@ public void GetComponentForModel_ShouldReturnNull_WhenModelTypeWasNotRegistered(
var componentType = diagram.GetComponent();
// Assert
- componentType.Should().BeNull();
+ Assert.Null(componentType);
}
[Fact]
@@ -47,7 +46,7 @@ public void GetComponentForModel_ShouldReturnComponentType_WhenInheritedModelTyp
var componentType = diagram.GetComponent();
// Assert
- componentType.Should().Be(typeof(NodeWidget));
+ Assert.Equal(typeof(NodeWidget), componentType);
}
[Fact]
@@ -62,7 +61,7 @@ public void GetComponentForModel_ShouldReturnSpecificComponentType_WhenInherited
var componentType = diagram.GetComponent();
// Assert
- componentType.Should().Be(typeof(CustomWidget));
+ Assert.Equal(typeof(CustomWidget), componentType);
}
[Fact]
@@ -76,7 +75,7 @@ public void GetComponentForModel_ShouldReturnNull_WhenCheckSubclassesIsFalse()
var componentType = diagram.GetComponent(false);
// Assert
- componentType.Should().BeNull();
+ Assert.Null(componentType);
}
private class CustomModel : Model { }
diff --git a/tests/Blazor.Diagrams.Tests/TestComponents/CustomVertexWidget.razor b/tests/Blazor.Diagrams.Tests/TestComponents/CustomVertexWidget.razor
index 21bc519c4..73d2b4d8a 100644
--- a/tests/Blazor.Diagrams.Tests/TestComponents/CustomVertexWidget.razor
+++ b/tests/Blazor.Diagrams.Tests/TestComponents/CustomVertexWidget.razor
@@ -1,6 +1,6 @@
@using Blazor.Diagrams.Core.Models;
-
+
@code {
[Parameter] public LinkVertexModel Vertex { get; set; } = null!;
diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props
new file mode 100644
index 000000000..ce4aec516
--- /dev/null
+++ b/tests/Directory.Build.props
@@ -0,0 +1,8 @@
+
+
+ net8.0;net6.0
+ enable
+ enable
+ true
+
+
\ No newline at end of file