Skip to content

Commit

Permalink
Use Controls to implement node resizing (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
Heathermcx committed Dec 12, 2023
1 parent 11798a1 commit 69c8198
Show file tree
Hide file tree
Showing 22 changed files with 876 additions and 25 deletions.
35 changes: 35 additions & 0 deletions site/Site/Pages/Documentation/Controls/Overview.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
@using Blazor.Diagrams.Core.Controls;
@using Blazor.Diagrams.Core.PathGenerators;
@using Blazor.Diagrams.Core.Positions;
@using Blazor.Diagrams.Core.Positions.Resizing;
@using Blazor.Diagrams.Core.Routers;
@layout DocumentationLayout
@inherits DocumentationPage
Expand Down Expand Up @@ -135,6 +136,26 @@ Diagram.Controls.AddFor(SomeModel)
</CascadingValue>
</div>

<h3>Resize Control</h3>

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

<pre><code class="language-cs">
Diagram.Controls.AddFor(SomeModel).Add(new ResizeControl(new BottomRightResizerProvider()));
Diagram.Controls.AddFor(SomeModel).Add(new ResizeControl(new BottomLeftResizerProvider()));
Diagram.Controls.AddFor(SomeModel).Add(new ResizeControl(new TopRightResizerProvider()));
Diagram.Controls.AddFor(SomeModel).Add(new ResizeControl(new TopLeftResizerProvider()));
</code></pre>

<div class="diagram-container" style="width: 100%; height: 300px;">
<CascadingValue Value="_resizerDiagram" IsFixed="true">
<DiagramCanvas></DiagramCanvas>
</CascadingValue>
</div>

<NavigationButtons NextTitle="Customization"
NextLink="/documentation/controls-customization" />

Expand All @@ -143,6 +164,7 @@ Diagram.Controls.AddFor(SomeModel)
private BlazorDiagram _rDiagram = new();
private BlazorDiagram _ahDiagram = new();
private BlazorDiagram _dnlDiagram = new();
private BlazorDiagram _resizerDiagram = new();

protected override void OnInitialized()
{
Expand Down Expand Up @@ -198,5 +220,18 @@ Diagram.Controls.AddFor(SomeModel)
_dnlDiagram.Controls.AddFor(dnlNode2).Add(new DragNewLinkControl(0, 0.5, offsetX: -20));
_dnlDiagram.SelectModel(dnlNode1, false);
_dnlDiagram.SelectModel(dnlNode2, false);

// Resize Control
var resizeNode1 = _resizerDiagram.Nodes.Add(new NodeModel(new Point(100, 100)));
var resizeNode2 = _resizerDiagram.Nodes.Add(new NodeModel(new Point(500, 150)));
resizeNode1.Title = "Title";
resizeNode2.Title = "Title";
_resizerDiagram.Controls.AddFor(resizeNode1, ControlsType.OnSelection).Add(new ResizeControl(new BottomRightResizerProvider()));
_resizerDiagram.Controls.AddFor(resizeNode1, ControlsType.OnSelection).Add(new ResizeControl(new BottomLeftResizerProvider()));
_resizerDiagram.Controls.AddFor(resizeNode1, ControlsType.OnSelection).Add(new ResizeControl(new TopRightResizerProvider()));
_resizerDiagram.Controls.AddFor(resizeNode1, ControlsType.OnSelection).Add(new ResizeControl(new TopLeftResizerProvider()));
_resizerDiagram.Controls.AddFor(resizeNode2, ControlsType.OnSelection).Add(new ResizeControl(new BottomRightResizerProvider()));
_resizerDiagram.SelectModel(resizeNode1, false);
_resizerDiagram.SelectModel(resizeNode2, false);
}
}
38 changes: 38 additions & 0 deletions src/Blazor.Diagrams.Core/Controls/Default/ResizeControl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Blazor.Diagrams.Core.Events;
using Blazor.Diagrams.Core.Geometry;
using Blazor.Diagrams.Core.Models.Base;
using Blazor.Diagrams.Core.Positions.Resizing;
using System.Threading.Tasks;

namespace Blazor.Diagrams.Core.Controls.Default
{
public class ResizeControl : ExecutableControl
{
private readonly IResizerProvider _resizeProvider;

public ResizeControl(IResizerProvider resizeProvider)
{
_resizeProvider = resizeProvider;
}

public override Point? GetPosition(Model model) => _resizeProvider.GetPosition(model);

public string? Class => _resizeProvider.Class;

public override ValueTask OnPointerDown(Diagram diagram, Model model, PointerEventArgs e)
{
_resizeProvider.OnResizeStart(diagram, model, e);
diagram.PointerMove += _resizeProvider.OnPointerMove;
diagram.PointerUp += _resizeProvider.OnResizeEnd;
diagram.PointerUp += (_, _) => OnResizeEnd(diagram);

return ValueTask.CompletedTask;
}

void OnResizeEnd(Diagram diagram)
{
diagram.PointerMove -= _resizeProvider.OnPointerMove;
diagram.PointerUp -= _resizeProvider.OnResizeEnd;
}
}
}
26 changes: 8 additions & 18 deletions src/Blazor.Diagrams.Core/Models/GroupModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,10 @@ public void AddChild(NodeModel child)
{
_children.Add(child);
child.Group = this;
child.SizeChanged += OnNodeChanged;
child.SizeChanging += OnNodeChanged;
child.Moving += OnNodeChanged;

if (UpdateDimensions())
{
Refresh();
}
UpdateDimensions();
}

public void RemoveChild(NodeModel child)
Expand All @@ -42,14 +39,10 @@ public void RemoveChild(NodeModel child)
return;

child.Group = null;
child.SizeChanged -= OnNodeChanged;
child.SizeChanging -= OnNodeChanged;
child.Moving -= OnNodeChanged;

if (UpdateDimensions())
{
Refresh();
RefreshLinks();
}
UpdateDimensions();
}

public override void SetPosition(double x, double y)
Expand Down Expand Up @@ -83,7 +76,7 @@ public void Ungroup()
foreach (var child in Children)
{
child.Group = null;
child.SizeChanged -= OnNodeChanged;
child.SizeChanging -= OnNodeChanged;
child.Moving -= OnNodeChanged;
}

Expand All @@ -96,7 +89,7 @@ private void Initialize(IEnumerable<NodeModel> children)
{
_children.Add(child);
child.Group = this;
child.SizeChanged += OnNodeChanged;
child.SizeChanging += OnNodeChanged;
child.Moving += OnNodeChanged;
}

Expand All @@ -105,10 +98,7 @@ private void Initialize(IEnumerable<NodeModel> children)

private void OnNodeChanged(NodeModel node)
{
if (UpdateDimensions())
{
Refresh();
}
UpdateDimensions();
}

private bool UpdateDimensions()
Expand All @@ -128,7 +118,7 @@ private bool UpdateDimensions()
TriggerMoving();
}

Size = new Size(bounds.Width + Padding * 2, bounds.Height + Padding * 2);
SetSize(bounds.Width + Padding * 2, bounds.Height + Padding * 2);
return true;
}
}
23 changes: 19 additions & 4 deletions src/Blazor.Diagrams.Core/Models/NodeModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ public class NodeModel : MovableModel, IHasBounds, IHasShape, ILinkable
private readonly List<PortModel> _ports = new();
private readonly List<BaseLinkModel> _links = new();
private Size? _size;
public Size MinimumDimensions { get; set; } = new Size(0, 0);

public event Action<NodeModel>? SizeChanging;
public event Action<NodeModel>? SizeChanged;
public event Action<NodeModel>? Moving;

Expand All @@ -28,11 +30,7 @@ public Size? Size
get => _size;
set
{
if (value?.Equals(_size) == true)
return;

_size = value;
SizeChanged?.Invoke(this);
}
}
public bool ControlledSize { get; init; }
Expand Down Expand Up @@ -103,6 +101,23 @@ public override void SetPosition(double x, double y)
Moving?.Invoke(this);
}

public void SetSize(double width, double height)
{
var newSize = new Size(width, height);
if (newSize.Equals(_size) == true)
return;

Size = newSize;
Refresh();
RefreshLinks();
SizeChanging?.Invoke(this);
}

public void TriggerSizeChanged()
{
SizeChanged?.Invoke(this);
}

public virtual void UpdatePositionSilently(double deltaX, double deltaY)
{
base.SetPosition(Position.X + deltaX, Position.Y + deltaY);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using Blazor.Diagrams.Core.Events;
using Blazor.Diagrams.Core.Geometry;
using Blazor.Diagrams.Core.Models;
using Blazor.Diagrams.Core.Models.Base;

namespace Blazor.Diagrams.Core.Positions.Resizing
{
public class BottomLeftResizerProvider : IResizerProvider
{
public string? Class => "bottomleft";

private Size _originalSize = null!;
private Point _originalPosition = null!;
private Point _originalMousePosition = null!;
private NodeModel _nodeModel = null!;

public Point? GetPosition(Model model)
{
if (model is NodeModel nodeModel && nodeModel.Size is not null)
{
return new Point(nodeModel.Position.X - 5, nodeModel.Position.Y + nodeModel.Size.Height + 5);
}
return null;
}

public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventArgs)
{
if (model is NodeModel nodeModel)
{
_originalPosition = new Point(nodeModel.Position.X, nodeModel.Position.Y);
_originalMousePosition = new Point(eventArgs.ClientX, eventArgs.ClientY);
_originalSize = nodeModel.Size!;
_nodeModel = nodeModel;
}
}

public void OnPointerMove(Model? model, PointerEventArgs args)
{
if (_nodeModel is null)
{
return;
}

var height = _originalSize.Height + (args.ClientY - _originalMousePosition.Y);
var width = _originalSize.Width - (args.ClientX - _originalMousePosition.X);

var positionX = _originalPosition.X + (args.ClientX - _originalMousePosition.X);
var positionY = _originalPosition.Y;

if (width < _nodeModel.MinimumDimensions.Width)
{
width = _nodeModel.MinimumDimensions.Width;
positionX = _nodeModel.Position.X;
}
if (height < _nodeModel.MinimumDimensions.Height)
{
height = _nodeModel.MinimumDimensions.Height;
positionY = _nodeModel.Position.Y;
}

_nodeModel.SetPosition(positionX, positionY);
_nodeModel.SetSize(width, height);
}

public void OnResizeEnd(Model? model, PointerEventArgs args)
{
_nodeModel?.TriggerSizeChanged();
_originalSize = null!;
_originalPosition = null!;
_originalMousePosition = null!;
_nodeModel = null!;
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Blazor.Diagrams.Core.Events;
using Blazor.Diagrams.Core.Geometry;
using Blazor.Diagrams.Core.Models;
using Blazor.Diagrams.Core.Models.Base;

namespace Blazor.Diagrams.Core.Positions.Resizing
{
public class BottomRightResizerProvider : IResizerProvider
{
public string? Class => "bottomright";

private Size _originalSize = null!;
private Point _originalMousePosition = null!;
private NodeModel _nodeModel = null!;

public Point? GetPosition(Model model)
{
if (model is NodeModel nodeModel && nodeModel.Size is not null)
{
return new Point(nodeModel.Position.X + nodeModel.Size.Width + 5, nodeModel.Position.Y + nodeModel.Size.Height + 5);
}
return null;
}

public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventArgs)
{
if (model is NodeModel nodeModel)
{
_originalMousePosition = new Point(eventArgs.ClientX, eventArgs.ClientY);
_originalSize = nodeModel.Size!;
_nodeModel = nodeModel;
}
}

public void OnPointerMove(Model? model, PointerEventArgs args)
{
if (_nodeModel is null)
{
return;
}

var height = _originalSize.Height + (args.ClientY - _originalMousePosition.Y);
var width = _originalSize.Width + (args.ClientX - _originalMousePosition.X);

if (width < _nodeModel.MinimumDimensions.Width)
{
width = _nodeModel.MinimumDimensions.Width;
}
if (height < _nodeModel.MinimumDimensions.Height)
{
height = _nodeModel.MinimumDimensions.Height;
}

_nodeModel.SetSize(width, height);
}

public void OnResizeEnd(Model? model, PointerEventArgs args)
{
_nodeModel?.TriggerSizeChanged();
_originalSize = null!;
_originalMousePosition = null!;
_nodeModel = null!;
}

}
}
14 changes: 14 additions & 0 deletions src/Blazor.Diagrams.Core/Positions/Resizing/IResizerProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Blazor.Diagrams.Core.Events;
using Blazor.Diagrams.Core.Models;
using Blazor.Diagrams.Core.Models.Base;

namespace Blazor.Diagrams.Core.Positions.Resizing
{
public interface IResizerProvider : IPositionProvider
{
public string? Class { get; }
public void OnResizeStart(Diagram diagram, Model model, PointerEventArgs eventArgs);
public void OnPointerMove(Model? model, PointerEventArgs args);
public void OnResizeEnd(Model? model, PointerEventArgs args);
}
}
Loading

0 comments on commit 69c8198

Please sign in to comment.