diff options
| author | Dennis Brentjes <d.brentjes@gmail.com> | 2019-12-15 22:30:38 +0100 |
|---|---|---|
| committer | Dennis Brentjes <d.brentjes@gmail.com> | 2019-12-15 22:30:38 +0100 |
| commit | 0f98b398520a3f5cc6a299e7fd3b8fab494480d7 (patch) | |
| tree | a1c0ab173723c47adf23d7dc5c1894185052cc39 /Views/Image/ImageControl.xaml.cs | |
| download | avalar-0f98b398520a3f5cc6a299e7fd3b8fab494480d7.tar.gz avalar-0f98b398520a3f5cc6a299e7fd3b8fab494480d7.tar.bz2 avalar-0f98b398520a3f5cc6a299e7fd3b8fab494480d7.zip | |
Initial commit, skeleton project.
Diffstat (limited to 'Views/Image/ImageControl.xaml.cs')
| -rw-r--r-- | Views/Image/ImageControl.xaml.cs | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/Views/Image/ImageControl.xaml.cs b/Views/Image/ImageControl.xaml.cs new file mode 100644 index 0000000..2189bb0 --- /dev/null +++ b/Views/Image/ImageControl.xaml.cs @@ -0,0 +1,100 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Markup.Xaml; +using Avalonia.Media; +using System; + +namespace Avalar.Views.Image +{ + public class ImageControl : UserControl + { + private const double ZoomTick = 0.1; + private double CurrentZoom { get; set; } = 1.0; + + private double InvCurrentZoom => 1 / CurrentZoom; + + private ImageBrush Image { get; } + + private Canvas ImageCanvas { get; } + public ImageControl() + { + InitializeComponent(); + + Image = this.FindResource("ImageBrush") as ImageBrush ?? throw new System.ArgumentException("ImageBrush"); + ImageCanvas = this.FindControl<Canvas>("ImageCanvas"); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + private Point MousePointerInImageSpace(Point mouseCoordinates) + { + var imageSize = Image.Source.Size; + var canvasSize = new Size(ImageCanvas.Bounds.Width, ImageCanvas.Bounds.Height); + + double focalPointX; + double focalPointY; + + if (canvasSize.AspectRatio > imageSize.AspectRatio) + { + focalPointY = mouseCoordinates.Y / canvasSize.Height; + + var halfUnusedX = (canvasSize.AspectRatio - imageSize.AspectRatio) * canvasSize.Width / 2; + var clampedX = Math.Clamp(mouseCoordinates.X - halfUnusedX, 0, imageSize.Width); + + focalPointX = clampedX / imageSize.Width; + } + else + { + focalPointX = mouseCoordinates.X / canvasSize.Width; + + var halfUnusedY = 1 / (canvasSize.AspectRatio - imageSize.AspectRatio) * canvasSize.Height / 2; + var clampedY = Math.Clamp(mouseCoordinates.Y - halfUnusedY, 0, imageSize.Height); + + focalPointY = clampedY / imageSize.Height; + } + + return new Point(focalPointX, focalPointY); + } + + private Point TransformToSourceRectSpace(Point from) + { + var sourceRectPosition = Image.SourceRect.Rect.Position; + var sourceRectSize = Image.SourceRect.Rect.Size; + return new Point( + from.X * sourceRectSize.Width + sourceRectPosition.X, + from.Y * sourceRectSize.Height + sourceRectPosition.Y + ); + } + + public void OnPointerWheelChanged(object sender, PointerWheelEventArgs e) + { + var invOldZoom = InvCurrentZoom; + var zoomFactor = e.Delta.Y * ZoomTick + 1.0; + CurrentZoom = Math.Clamp(CurrentZoom * zoomFactor, 1, double.PositiveInfinity); + + var sourceRect = Image.SourceRect.Rect; + + var canvasMouseCoordinates = e.GetPosition(ImageCanvas); + + var currentCenter = sourceRect.Center; + var desiredCenterInImageCoords = MousePointerInImageSpace(canvasMouseCoordinates); + if(e.Delta.Y < 0) + { + desiredCenterInImageCoords = new Point(1 - desiredCenterInImageCoords.X, 1 - desiredCenterInImageCoords.Y); + } + var desiredCenter = TransformToSourceRectSpace(desiredCenterInImageCoords); + + var maxTravelDistance = Math.Abs(invOldZoom - InvCurrentZoom); + + var newCenterX = Math.Clamp(desiredCenter.X, currentCenter.X - maxTravelDistance, currentCenter.X + maxTravelDistance); + var newCenterY = Math.Clamp(desiredCenter.Y, currentCenter.Y - maxTravelDistance, currentCenter.Y + maxTravelDistance); + + var sourceRectNewTopLeft = new Point(newCenterX - InvCurrentZoom / 2, newCenterY - InvCurrentZoom / 2); + Image.SourceRect = new RelativeRect(sourceRectNewTopLeft, new Size(InvCurrentZoom, InvCurrentZoom), RelativeUnit.Relative); + } + } +} |
