add zoom and panning

zoom: ctrl + wheel, zoomed image:
ctrl + move mousr
This commit is contained in:
Alex Bezdieniezhnykh
2025-06-30 00:01:20 +03:00
parent 627e63e543
commit c42faa1e2e
4 changed files with 108 additions and 28 deletions
+14 -1
View File
@@ -315,7 +315,7 @@
<ColumnDefinition Width="28" /> <!-- 10 --> <ColumnDefinition Width="28" /> <!-- 10 -->
<ColumnDefinition Width="28" /> <!-- 11 --> <ColumnDefinition Width="28" /> <!-- 11 -->
<ColumnDefinition Width="28" /> <!-- 12 --> <ColumnDefinition Width="28" /> <!-- 12 -->
<ColumnDefinition Width="0" /> <!-- 13 --> <ColumnDefinition Width="28" /> <!-- 13 -->
<ColumnDefinition Width="*" /> <!-- 14--> <ColumnDefinition Width="*" /> <!-- 14-->
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Button Grid.Column="0" Padding="5" ToolTip="Включити програвання" Background="Black" BorderBrush="Black" <Button Grid.Column="0" Padding="5" ToolTip="Включити програвання" Background="Black" BorderBrush="Black"
@@ -602,6 +602,19 @@
</Image.Source> </Image.Source>
</Image> </Image>
</Button> </Button>
<Button Grid.Column="13"
Padding="2"
Width="25"
Height="25"
ToolTip="Аналіз стану БПЛА. Клавіша: [K]" Background="Black" BorderBrush="Black"
Click="RunDroneMaintenance">
<Path Stretch="Fill" Fill="LightGray" Data="
M128,7.10542736e-15 C198.692448,7.10542736e-15 256,57.307552 256,128 C256,140.931179 254.082471,153.414494 250.516246,165.181113 L384,298.666667
C407.564149,322.230816 407.564149,360.435851 384,384 C360.435851,407.564149 322.230816,407.564149 298.666667,384 L165.181113,250.516246
C153.414494,254.082471 140.931179,256 128,256 C57.307552,256 7.10542736e-15,198.692448 7.10542736e-15,128 C7.10542736e-15,114.357909
2.13416363,101.214278 6.08683609,88.884763 L66.6347809,149.333333 L126.649,129.346 L129.329,126.666 L149.333333,66.7080586 L88.7145729,6.14152881
C101.0933,2.15385405 114.29512,7.10542736e-15 128,7.10542736e-15 Z" />
</Button>
<StatusBar Grid.Column="14" <StatusBar Grid.Column="14"
Background="#252525" Background="#252525"
Foreground="White"> Foreground="White">
+13 -2
View File
@@ -304,7 +304,7 @@ public partial class Annotator
{ {
if (File.Exists(annotation.ImagePath)) if (File.Exists(annotation.ImagePath))
{ {
Editor.Background = new ImageBrush { ImageSource = await annotation.ImagePath.OpenImage() }; Editor.SetImageSource(await annotation.ImagePath.OpenImage());
_formState.BackgroundTime = annotation.Time; _formState.BackgroundTime = annotation.Time;
videoSize = Editor.RenderSize; videoSize = Editor.RenderSize;
} }
@@ -578,10 +578,21 @@ public partial class Annotator
} }
} }
#region Denys Wishes
private void SoundDetections(object sender, RoutedEventArgs e) private void SoundDetections(object sender, RoutedEventArgs e)
{ {
_logger.LogInformation("To be implemented"); MessageBox.Show("Функція Аудіоаналіз знаходиться в стадії розробки","Система", MessageBoxButton.OK, MessageBoxImage.Information);
_logger.LogInformation("Denys wishes #1. To be implemented");
} }
private void RunDroneMaintenance(object sender, RoutedEventArgs e)
{
MessageBox.Show("Функція Аналіз стану БПЛА знаходиться в стадії розробки","Система", MessageBoxButton.OK, MessageBoxImage.Information);
_logger.LogInformation("Denys wishes #2. To be implemented");
}
#endregion
} }
public class GradientStyleSelector : StyleSelector public class GradientStyleSelector : StyleSelector
+69 -14
View File
@@ -3,11 +3,12 @@ using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
using Azaion.Annotator.DTO;
using Azaion.Common.DTO; using Azaion.Common.DTO;
using MediatR; using MediatR;
using Color = System.Windows.Media.Color; using Color = System.Windows.Media.Color;
using Image = System.Windows.Controls.Image;
using Point = System.Windows.Point; using Point = System.Windows.Point;
using Rectangle = System.Windows.Shapes.Rectangle; using Rectangle = System.Windows.Shapes.Rectangle;
using Size = System.Windows.Size; using Size = System.Windows.Size;
@@ -29,9 +30,14 @@ public class CanvasEditor : Canvas
private Rectangle _curRec = new(); private Rectangle _curRec = new();
private DetectionControl _curAnn = null!; private DetectionControl _curAnn = null!;
private readonly MatrixTransform _matrixTransform = new();
private Point _panStartPoint;
private bool _isZoomedIn;
private const int MIN_SIZE = 20; private const int MIN_SIZE = 20;
private readonly TimeSpan _viewThreshold = TimeSpan.FromMilliseconds(400); private readonly TimeSpan _viewThreshold = TimeSpan.FromMilliseconds(400);
private Image _backgroundImage { get; set; } = new() { Stretch = Stretch.Fill };
public IMediator Mediator { get; set; } = null!; public IMediator Mediator { get; set; } = null!;
public static readonly DependencyProperty GetTimeFuncProp = public static readonly DependencyProperty GetTimeFuncProp =
@@ -107,13 +113,42 @@ public class CanvasEditor : Canvas
MouseUp += CanvasMouseUp; MouseUp += CanvasMouseUp;
SizeChanged += CanvasResized; SizeChanged += CanvasResized;
Cursor = Cursors.Cross; Cursor = Cursors.Cross;
Children.Insert(0, _backgroundImage);
Children.Add(_newAnnotationRect); Children.Add(_newAnnotationRect);
Children.Add(_horizontalLine); Children.Add(_horizontalLine);
Children.Add(_verticalLine); Children.Add(_verticalLine);
Children.Add(_classNameHint); Children.Add(_classNameHint);
Loaded += Init; Loaded += Init;
RenderTransform = _matrixTransform;
MouseWheel += CanvasWheel;
}
public void SetImageSource(ImageSource? source)
{
_backgroundImage.Source = source;
}
private void CanvasWheel(object sender, MouseWheelEventArgs e)
{
if (Keyboard.Modifiers != ModifierKeys.Control)
return;
var mousePos = e.GetPosition(this);
var scale = e.Delta > 0 ? 1.1 : 1 / 1.1;
var matrix = _matrixTransform.Matrix;
if (scale < 1 && matrix.M11 * scale < 1.0)
{
_matrixTransform.Matrix = Matrix.Identity;
_isZoomedIn = false;
}
else
{
matrix.ScaleAt(scale, scale, mousePos.X, mousePos.Y);
_matrixTransform.Matrix = matrix;
_isZoomedIn = true;
}
} }
private void Init(object sender, RoutedEventArgs e) private void Init(object sender, RoutedEventArgs e)
@@ -127,6 +162,12 @@ public class CanvasEditor : Canvas
private void CanvasMouseDown(object sender, MouseButtonEventArgs e) private void CanvasMouseDown(object sender, MouseButtonEventArgs e)
{ {
ClearSelections(); ClearSelections();
if (Keyboard.Modifiers == ModifierKeys.Control && _isZoomedIn)
{
_panStartPoint = e.GetPosition(this);
SelectionState = SelectionState.PanZoomMoving;
}
else
NewAnnotationStart(sender, e); NewAnnotationStart(sender, e);
} }
@@ -138,16 +179,31 @@ public class CanvasEditor : Canvas
SetLeft(_classNameHint, pos.X + 10); SetLeft(_classNameHint, pos.X + 10);
SetTop(_classNameHint, pos.Y - 30); SetTop(_classNameHint, pos.Y - 30);
if (e.LeftButton != MouseButtonState.Pressed) switch (SelectionState)
return; {
if (SelectionState == SelectionState.NewAnnCreating) case SelectionState.NewAnnCreating:
NewAnnotationCreatingMove(sender, e); NewAnnotationCreatingMove(sender, e);
break;
if (SelectionState == SelectionState.AnnResizing) case SelectionState.AnnResizing:
AnnotationResizeMove(sender, e); AnnotationResizeMove(sender, e);
break;
if (SelectionState == SelectionState.AnnMoving) case SelectionState.AnnMoving:
AnnotationPositionMove(sender, e); AnnotationPositionMove(sender, e);
break;
case SelectionState.PanZoomMoving:
PanZoomMove(sender, e);
break;
}
}
private void PanZoomMove(object sender, MouseEventArgs e)
{
var currentPoint = e.GetPosition(this);
var delta = currentPoint - _panStartPoint;
var matrix = _matrixTransform.Matrix;
matrix.Translate(delta.X, delta.Y);
_matrixTransform.Matrix = matrix;
} }
private void CanvasMouseUp(object sender, MouseButtonEventArgs e) private void CanvasMouseUp(object sender, MouseButtonEventArgs e)
@@ -173,16 +229,13 @@ public class CanvasEditor : Canvas
}); });
control.UpdateLayout(); control.UpdateLayout();
CheckLabelBoundaries(control); CheckLabelBoundaries(control);
SelectionState = SelectionState.None;
e.Handled = true;
} }
else else if (SelectionState != SelectionState.PanZoomMoving)
{
CheckLabelBoundaries(_curAnn); CheckLabelBoundaries(_curAnn);
SelectionState = SelectionState.None; SelectionState = SelectionState.None;
e.Handled = true; e.Handled = true;
} }
}
private void CheckLabelBoundaries(DetectionControl detectionControl) private void CheckLabelBoundaries(DetectionControl detectionControl)
{ {
@@ -213,6 +266,8 @@ public class CanvasEditor : Canvas
{ {
_horizontalLine.X2 = e.NewSize.Width; _horizontalLine.X2 = e.NewSize.Width;
_verticalLine.Y2 = e.NewSize.Height; _verticalLine.Y2 = e.NewSize.Height;
_backgroundImage.Width = e.NewSize.Width;
_backgroundImage.Height = e.NewSize.Height;
} }
#region Annotation Resizing & Moving #region Annotation Resizing & Moving
+3 -2
View File
@@ -1,9 +1,10 @@
namespace Azaion.Annotator.DTO; namespace Azaion.Common.DTO;
public enum SelectionState public enum SelectionState
{ {
None = 0, None = 0,
NewAnnCreating = 1, NewAnnCreating = 1,
AnnResizing = 2, AnnResizing = 2,
AnnMoving = 3 AnnMoving = 3,
PanZoomMoving = 4,
} }