Skip to content

Commit eddd879

Browse files
authored
Merge pull request #40 from WiseTechGlobal/RAL/WI00655146/Implement_selectionBox_while_scrolling
SelectionBox now updates when scrolling
2 parents 7182eaa + 63b8622 commit eddd879

File tree

2 files changed

+151
-19
lines changed

2 files changed

+151
-19
lines changed

src/Blazor.Diagrams.Core/Behaviors/SelectionBoxBehavior.cs

Lines changed: 55 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,25 @@ public class SelectionBoxBehavior : DragBehavior
1212
private Point? _initialClientPoint;
1313

1414
public event EventHandler<Rectangle?>? SelectionBoundsChanged;
15+
private double? _lastClientX;
16+
private double? _lastClientY;
17+
private Point? _initialPan;
1518

1619
public SelectionBoxBehavior(Diagram diagram)
1720
: base(diagram)
1821
{
1922
Diagram.PointerDown += OnPointerDown;
2023
Diagram.PointerMove += OnPointerMove;
2124
Diagram.PointerUp += OnPointerUp;
25+
Diagram.PanChanged += OnPanChanged;
2226
}
2327

2428
public override void Dispose()
2529
{
2630
Diagram.PointerDown -= OnPointerDown;
2731
Diagram.PointerMove -= OnPointerMove;
2832
Diagram.PointerUp -= OnPointerUp;
33+
Diagram.PanChanged -= OnPanChanged;
2934
}
3035

3136
protected override void OnPointerDown(Model? model, PointerEventArgs e)
@@ -34,37 +39,32 @@ protected override void OnPointerDown(Model? model, PointerEventArgs e)
3439
return;
3540

3641
_initialClientPoint = new Point(e.ClientX, e.ClientY);
42+
_lastClientX = e.ClientX;
43+
_lastClientY = e.ClientY;
44+
_initialPan = Diagram.Pan;
3745
}
3846

3947
protected override void OnPointerMove(Model? model, PointerEventArgs e)
4048
{
4149
if (_initialClientPoint == null)
4250
return;
4351

44-
UpdateSelectionBox(e);
52+
_lastClientX = e.ClientX;
53+
_lastClientY = e.ClientY;
4554

46-
var start = Diagram.GetRelativeMousePoint(_initialClientPoint.X, _initialClientPoint.Y);
47-
var end = Diagram.GetRelativeMousePoint(e.ClientX, e.ClientY);
48-
var (sX, sY) = (Math.Min(start.X, end.X), Math.Min(start.Y, end.Y));
49-
var (eX, eY) = (Math.Max(start.X, end.X), Math.Max(start.Y, end.Y));
50-
var bounds = new Rectangle(sX, sY, eX, eY);
55+
UpdateSelectionBox(e.ClientX, e.ClientY);
56+
SelectNodesInBounds(e.ClientX, e.ClientY);
57+
}
5158

52-
foreach (var node in Diagram.Nodes)
59+
void UpdateSelectionBox(double clientX, double clientY)
60+
{
61+
if(_initialClientPoint == null || _initialPan == null)
5362
{
54-
var nodeBounds = node.GetBounds();
55-
if (nodeBounds == null)
56-
continue;
57-
58-
if (bounds.Overlap(nodeBounds))
59-
Diagram.SelectModel(node, false);
60-
else if (node.Selected) Diagram.UnselectModel(node);
63+
return;
6164
}
62-
}
6365

64-
void UpdateSelectionBox(MouseEventArgs e)
65-
{
66-
var start = Diagram.GetRelativePoint(_initialClientPoint!.X, _initialClientPoint.Y);
67-
var end = Diagram.GetRelativePoint(e.ClientX, e.ClientY);
66+
var start = Diagram.GetRelativePoint(_initialClientPoint.X + Diagram.Pan.X - _initialPan.X, _initialClientPoint.Y + Diagram.Pan.Y - _initialPan.Y);
67+
var end = Diagram.GetRelativePoint(clientX, clientY);
6868
var (sX, sY) = (Math.Min(start.X, end.X), Math.Min(start.Y, end.Y));
6969
var (eX, eY) = (Math.Max(start.X, end.X), Math.Max(start.Y, end.Y));
7070
SelectionBoundsChanged?.Invoke(this, new Rectangle(sX, sY, eX, eY));
@@ -74,6 +74,42 @@ protected override void OnPointerUp(Model? model, PointerEventArgs e)
7474
{
7575
_initialClientPoint = null;
7676
SelectionBoundsChanged?.Invoke(this, null);
77+
_lastClientX = null;
78+
_lastClientY = null;
79+
_initialPan = null;
80+
}
81+
82+
public void OnPanChanged(double deltaX, double deltaY)
83+
{
84+
if (_initialClientPoint == null || _lastClientX == null || _lastClientY == null)
85+
return;
86+
87+
UpdateSelectionBox((double) _lastClientX, (double) _lastClientY);
88+
SelectNodesInBounds((double) _lastClientX, (double) _lastClientY);
89+
}
90+
91+
void SelectNodesInBounds(double clientX, double clientY)
92+
{
93+
if(_initialClientPoint == null || _initialPan == null)
94+
{
95+
return;
96+
}
97+
98+
var start = Diagram.GetRelativeMousePoint(_initialClientPoint.X + Diagram.Pan.X - _initialPan.X, _initialClientPoint.Y + Diagram.Pan.Y - _initialPan.Y);
99+
var end = Diagram.GetRelativeMousePoint(clientX, clientY);
100+
var (sX, sY) = (Math.Min(start.X, end.X), Math.Min(start.Y, end.Y));
101+
var (eX, eY) = (Math.Max(start.X, end.X), Math.Max(start.Y, end.Y));
102+
var bounds = new Rectangle(sX, sY, eX, eY);
103+
104+
foreach (var node in Diagram.Nodes)
105+
{
106+
var nodeBounds = node.GetBounds();
107+
if (nodeBounds == null)
108+
continue;
109+
if (bounds.Overlap(nodeBounds))
110+
Diagram.SelectModel(node, false);
111+
else if (node.Selected) Diagram.UnselectModel(node);
112+
}
77113
}
78114
}
79115
}

tests/Blazor.Diagrams.Core.Tests/Behaviors/SelectionBoxBehaviorTests.cs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,38 @@ public void Behavior_WhenBehaviorEnabled_ShouldUpdateSelectionBounds()
3939
Assert.Equal(100, lastBounds.Left);
4040
}
4141

42+
[Fact]
43+
public void Behavior_WhenBehaviorEnabled_ShouldUpdateSelectionBoundsOnScroll()
44+
{
45+
// Arrange
46+
var diagram = new TestDiagram();
47+
diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior<PanBehavior>();
48+
diagram.BehaviorOptions.DiagramShiftDragBehavior = diagram.GetBehavior<SelectionBoxBehavior>();
49+
diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior<ScrollBehavior>();
50+
diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));
51+
52+
var selectionBoxBehavior = diagram.GetBehavior<SelectionBoxBehavior>()!;
53+
bool boundsChangedEventInvoked = false;
54+
Rectangle? lastBounds = null;
55+
selectionBoxBehavior.SelectionBoundsChanged += (_, newBounds) =>
56+
{
57+
boundsChangedEventInvoked = true;
58+
lastBounds = newBounds;
59+
};
60+
61+
// Act
62+
diagram.TriggerPointerDown(null,
63+
new PointerEventArgs(100, 100, 0, 0, false, true, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
64+
diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, true, false, 200, 150, 0, 0));
65+
66+
// Assert
67+
Assert.True(boundsChangedEventInvoked);
68+
Assert.Equal(200, lastBounds!.Width);
69+
Assert.Equal(150, lastBounds.Height);
70+
Assert.Equal(-50, lastBounds.Top);
71+
Assert.Equal(-100, lastBounds.Left);
72+
}
73+
4274
[Fact]
4375
public void Behavior_WhenBehaviorDisabled_ShouldNotUpdateSelectionBounds()
4476
{
@@ -99,6 +131,39 @@ public void Behavior_WithBoundsChangedDelegate_ShouldSelectNodesInsideArea()
99131
Assert.False(node.Selected);
100132
}
101133

134+
[Fact]
135+
public void Behavior_WithBoundsChangedDelegate_ShouldSelectNodesInsideAreaWhenScrolling()
136+
{
137+
// Arrange
138+
var diagram = new TestDiagram();
139+
diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior<PanBehavior>();
140+
diagram.BehaviorOptions.DiagramShiftDragBehavior = diagram.GetBehavior<SelectionBoxBehavior>();
141+
diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior<ScrollBehavior>();
142+
diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));
143+
144+
var selectionBoxBehavior = diagram.GetBehavior<SelectionBoxBehavior>()!;
145+
selectionBoxBehavior.SelectionBoundsChanged += (_, _) => { };
146+
147+
var node = new NodeModel()
148+
{
149+
Size = new Size(100, 100),
150+
Position = new Point(150, 150)
151+
};
152+
diagram.Nodes.Add(node);
153+
154+
// Act
155+
diagram.TriggerPointerDown(null,
156+
new PointerEventArgs(100, 100, 0, 0, false, true, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
157+
diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, true, false, 200, 200, 0, 0));
158+
159+
// Assert
160+
Assert.True(node.Selected);
161+
162+
diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, true, false, -200, -200, 0, 0));
163+
164+
Assert.False(node.Selected);
165+
}
166+
102167
[Fact]
103168
public void Behavior_WithoutBoundsChangedDelegate_ShouldNotSelectNodesInsideArea()
104169
{
@@ -127,5 +192,36 @@ public void Behavior_WithoutBoundsChangedDelegate_ShouldNotSelectNodesInsideArea
127192
new PointerEventArgs(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
128193
Assert.False(node.Selected);
129194
}
195+
196+
[Fact]
197+
public void Behavior_WithoutBoundsChangedDelegate_ShouldNotSelectNodesInsideAreaWhenScrolling()
198+
{
199+
// Arrange
200+
var diagram = new TestDiagram();
201+
diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior<PanBehavior>();
202+
diagram.BehaviorOptions.DiagramShiftDragBehavior = diagram.GetBehavior<SelectionBoxBehavior>();
203+
diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior<ScrollBehavior>();
204+
diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));
205+
206+
var node = new NodeModel()
207+
{
208+
Size = new Size(100, 100),
209+
Position = new Point(150, 150)
210+
};
211+
diagram.Nodes.Add(node);
212+
213+
// Act
214+
diagram.TriggerPointerDown(null,
215+
new PointerEventArgs(100, 100, 0, 0, false, true, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
216+
diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, true, false, 200, 200, 0, 0));
217+
218+
219+
// Assert
220+
Assert.False(node.Selected);
221+
222+
diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, true, false, -200, -200, 0, 0));
223+
224+
Assert.False(node.Selected);
225+
}
130226
}
131227
}

0 commit comments

Comments
 (0)