diff --git a/MapControl/Avalonia/Map.Avalonia.cs b/MapControl/Avalonia/Map.Avalonia.cs index 82a57b1f..22d5e6ce 100644 --- a/MapControl/Avalonia/Map.Avalonia.cs +++ b/MapControl/Avalonia/Map.Avalonia.cs @@ -6,11 +6,24 @@ using System; namespace MapControl { + [Flags] + public enum ManipulationModes + { + None = 0, + Translate = 1, + Rotate = 2, + Scale = 4, + All = Translate | Rotate | Scale + } + /// /// MapBase with default input event handling. /// public class Map : MapBase { + public static readonly StyledProperty ManipulationModesProperty = + DependencyPropertyHelper.Register(nameof(ManipulationModes), ManipulationModes.Translate | ManipulationModes.Scale); + public static readonly StyledProperty MouseWheelZoomDeltaProperty = DependencyPropertyHelper.Register(nameof(MouseWheelZoomDelta), 0.25); @@ -19,6 +32,12 @@ namespace MapControl private Point position1; private Point position2; + public ManipulationModes ManipulationModes + { + get => GetValue(ManipulationModesProperty); + set => SetValue(ManipulationModesProperty, value); + } + /// /// Gets or sets the amount by which the ZoomLevel property changes by a MouseWheel event. /// The default value is 0.25. @@ -38,15 +57,25 @@ namespace MapControl base.OnPointerWheelChanged(e); } - protected override void OnPointerPressed(PointerPressedEventArgs e) + private bool HandleMousePressed(PointerPoint point) { - var point = e.GetCurrentPoint(this); - - if (pointer2 == null && - (point.Properties.IsLeftButtonPressed || point.Pointer.Type == PointerType.Touch)) + var handled = pointer1 == null && point.Properties.IsLeftButtonPressed; + + if (handled) { - point.Pointer.Capture(this); + pointer1 = point.Pointer; + position1 = point.Position; + } + return handled; + } + + private bool HandleTouchPressed(PointerPoint point) + { + var handled = pointer2 == null && ManipulationModes != ManipulationModes.None; + + if (handled) + { if (pointer1 == null) { pointer1 = point.Pointer; @@ -57,6 +86,19 @@ namespace MapControl pointer2 = point.Pointer; position2 = point.Position; } + } + + return handled; + } + + protected override void OnPointerPressed(PointerPressedEventArgs e) + { + var point = e.GetCurrentPoint(this); + + if (point.Pointer.Type == PointerType.Mouse && HandleMousePressed(point) || + point.Pointer.Type == PointerType.Touch && HandleTouchPressed(point)) + { + point.Pointer.Capture(this); e.Handled = true; } @@ -84,21 +126,34 @@ namespace MapControl base.OnPointerReleased(e); } + protected override void OnPointerCaptureLost(PointerCaptureLostEventArgs e) + { + if (e.Pointer == pointer1 || e.Pointer == pointer2) + { + if (e.Pointer == pointer1) + { + pointer1 = pointer2; + position1 = position2; + } + + pointer2 = null; + + e.Handled = true; + } + + base.OnPointerCaptureLost(e); + } + protected override void OnPointerMoved(PointerEventArgs e) { if (e.Pointer == pointer1 || e.Pointer == pointer2) { var position = e.GetPosition(this); - if (pointer2 == null) + 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; + var oldDistance = new Vector(position2.X - position1.X, position2.Y - position1.Y); + var oldOrigin = new Point((position1.X + position2.X) / 2d, (position1.Y + position2.Y) / 2d); if (e.Pointer == pointer1) { @@ -109,14 +164,36 @@ namespace MapControl position2 = position; } - Point newOrigin = new((position1.X + position2.X) / 2d, (position1.Y + position2.Y) / 2d); - Vector newDistance = position2 - position1; + var newDistance = new Vector(position2.X - position1.X, position2.Y - position1.Y); + var newOrigin = oldOrigin; + var translation = new Point(); + var rotation = 0d; + var scale = 1d; - 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; + if (ManipulationModes.HasFlag(ManipulationModes.Translate)) + { + newOrigin = new Point((position1.X + position2.X) / 2d, (position1.Y + position2.Y) / 2d); + translation = newOrigin - oldOrigin; + } - TransformMap(newOrigin, newOrigin - oldOrigin, newAngle - oldAngle, scale); + if (ManipulationModes.HasFlag(ManipulationModes.Rotate)) + { + rotation = 180d / Math.PI + * (Math.Atan2(newDistance.Y, newDistance.X) - Math.Atan2(oldDistance.Y, oldDistance.X)); + } + + if (ManipulationModes.HasFlag(ManipulationModes.Scale)) + { + scale = newDistance.Length / oldDistance.Length; + } + + TransformMap(newOrigin, translation, rotation, scale); + } + else if (e.Pointer.Type != PointerType.Touch || ManipulationModes.HasFlag(ManipulationModes.Translate)) + { + TranslateMap(position - position1); + + position1 = position; } e.Handled = true; diff --git a/MapControl/WPF/Map.WPF.cs b/MapControl/WPF/Map.WPF.cs index 8bae6fb7..57ae1439 100644 --- a/MapControl/WPF/Map.WPF.cs +++ b/MapControl/WPF/Map.WPF.cs @@ -17,7 +17,7 @@ namespace MapControl DependencyPropertyHelper.Register(nameof(MouseWheelZoomDelta), 0.25); public static readonly DependencyProperty ManipulationModeProperty = - DependencyPropertyHelper.Register(nameof(ManipulationMode), ManipulationModes.Scale | ManipulationModes.Translate); + DependencyPropertyHelper.Register(nameof(ManipulationMode), ManipulationModes.Translate | ManipulationModes.Scale); private Point? mousePosition; private double mouseWheelDelta; diff --git a/SampleApps/AvaloniaApp/MainWindow.axaml b/SampleApps/AvaloniaApp/MainWindow.axaml index 40b9a709..19977caf 100644 --- a/SampleApps/AvaloniaApp/MainWindow.axaml +++ b/SampleApps/AvaloniaApp/MainWindow.axaml @@ -13,6 +13,7 @@