diff --git a/MapControl/Avalonia/Map.Avalonia.cs b/MapControl/Avalonia/Map.Avalonia.cs index 0cbd70c7..4c87aa8c 100644 --- a/MapControl/Avalonia/Map.Avalonia.cs +++ b/MapControl/Avalonia/Map.Avalonia.cs @@ -3,6 +3,7 @@ // Licensed under the Microsoft Public License (Ms-PL) using Avalonia.Input; +using System; namespace MapControl { @@ -14,7 +15,10 @@ namespace MapControl public static readonly StyledProperty MouseWheelZoomDeltaProperty = DependencyPropertyHelper.Register(nameof(MouseWheelZoomDelta), 0.25); - private Point? mousePosition; + private IPointer pointer1; + private IPointer pointer2; + private Point position1; + private Point position2; /// /// Gets or sets the amount by which the ZoomLevel property changes by a MouseWheel event. @@ -39,10 +43,21 @@ namespace MapControl var point = e.GetCurrentPoint(this); - if (point.Properties.IsLeftButtonPressed) + if (pointer2 == null && + (point.Properties.IsLeftButtonPressed || point.Pointer.Type == PointerType.Touch)) { - e.Pointer.Capture(this); - mousePosition = point.Position; + point.Pointer.Capture(this); + + if (pointer1 == null) + { + pointer1 = point.Pointer; + position1 = point.Position; + } + else + { + pointer2 = point.Pointer; + position2 = point.Position; + } } } @@ -50,10 +65,17 @@ namespace MapControl { base.OnPointerReleased(e); - if (mousePosition.HasValue) + if (e.Pointer == pointer1 || e.Pointer == pointer2) { e.Pointer.Capture(null); - mousePosition = null; + + if (e.Pointer == pointer1) + { + pointer1 = pointer2; + position1 = position2; + } + + pointer2 = null; } } @@ -61,11 +83,38 @@ namespace MapControl { base.OnPointerMoved(e); - if (mousePosition.HasValue) + if (e.Pointer == pointer1 || e.Pointer == pointer2) { var position = e.GetPosition(this); - TranslateMap(position - mousePosition.Value); - mousePosition = position; + + if (pointer2 == null) + { + TranslateMap(position - position1); + position1 = position; + } + else + { + Point oldOrigin = new((position1.X + position2.X) / 2d, (position1.Y + position2.Y) / 2d); + Vector oldDistance = position2 - position1; + + if (e.Pointer == pointer1) + { + position1 = position; + } + else + { + position2 = position; + } + + Point newOrigin = new((position1.X + position2.X) / 2d, (position1.Y + position2.Y) / 2d); + Vector newDistance = position2 - position1; + + var oldAngle = Math.Atan2(oldDistance.Y, oldDistance.X) * 180d / Math.PI; + var newAngle = Math.Atan2(newDistance.Y, newDistance.X) * 180d / Math.PI; + var scale = newDistance.Length / oldDistance.Length; + + TransformMap(newOrigin, newOrigin - oldOrigin, newAngle - oldAngle, scale); + } } } } diff --git a/MapControl/Shared/Timer.cs b/MapControl/Shared/Timer.cs index 2f6f790c..47f69e3e 100644 --- a/MapControl/Shared/Timer.cs +++ b/MapControl/Shared/Timer.cs @@ -4,18 +4,20 @@ using System; #if WPF +using System.Windows; using System.Windows.Threading; #elif UWP using Windows.UI.Xaml; #elif AVALONIA using Avalonia.Threading; +using DependencyObject = Avalonia.AvaloniaObject; #endif namespace MapControl { internal static class Timer { - public static DispatcherTimer CreateTimer(this object _, TimeSpan interval) + public static DispatcherTimer CreateTimer(this DependencyObject _, TimeSpan interval) { return new DispatcherTimer { Interval = interval }; }