diff --git a/MapControl/Shared/Map.cs b/MapControl/Shared/Map.cs new file mode 100644 index 00000000..68a416a7 --- /dev/null +++ b/MapControl/Shared/Map.cs @@ -0,0 +1,45 @@ +// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control +// © 2020 Clemens Fischer +// Licensed under the Microsoft Public License (Ms-PL) + +#if WINDOWS_UWP +using Windows.UI.Xaml; +#else +using System.Windows; +#endif + +namespace MapControl +{ + /// + /// MapBase with default input event handling. + /// + public partial class Map : MapBase + { + public static readonly DependencyProperty MouseWheelZoomDeltaProperty = DependencyProperty.Register( + nameof(MouseWheelZoomDelta), typeof(double), typeof(Map), new PropertyMetadata(1d)); + + /// + /// Gets or sets the amount by which the ZoomLevel property changes during a MouseWheel event. + /// The default value is 1. + /// + public double MouseWheelZoomDelta + { + get { return (double)GetValue(MouseWheelZoomDeltaProperty); } + set { SetValue(MouseWheelZoomDeltaProperty, value); } + } + + private Vector translation; + private double rotation; + private double scale = 1d; + private bool transformPending; + + private void ResetTransform() + { + translation.X = 0d; + translation.Y = 0d; + rotation = 0d; + scale = 1d; + transformPending = false; + } + } +} diff --git a/MapControl/UWP/Map.UWP.cs b/MapControl/UWP/Map.UWP.cs index 95c723c9..f8f0d50d 100644 --- a/MapControl/UWP/Map.UWP.cs +++ b/MapControl/UWP/Map.UWP.cs @@ -3,72 +3,48 @@ // Licensed under the Microsoft Public License (Ms-PL) using System; -using Windows.UI.Xaml; +using Windows.UI.Core; using Windows.UI.Xaml.Input; namespace MapControl { - /// - /// MapBase with default input event handling. - /// - public class Map : MapBase + public partial class Map { - public static readonly DependencyProperty MouseWheelZoomDeltaProperty = DependencyProperty.Register( - nameof(MouseWheelZoomDelta), typeof(double), typeof(Map), new PropertyMetadata(1d)); - - private bool transformPending; - private Vector transformTranslation; - private double transformRotation; - private double transformScale = 1d; - public Map() { - ManipulationMode = ManipulationModes.Scale | - ManipulationModes.TranslateX | ManipulationModes.TranslateY | ManipulationModes.TranslateInertia; + ManipulationMode = ManipulationModes.Scale + | ManipulationModes.TranslateX + | ManipulationModes.TranslateY + | ManipulationModes.TranslateInertia; ManipulationDelta += OnManipulationDelta; PointerWheelChanged += OnPointerWheelChanged; } - /// - /// Gets or sets the amount by which the ZoomLevel property changes during a MouseWheel event. - /// - public double MouseWheelZoomDelta + private async void OnManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) { - get { return (double)GetValue(MouseWheelZoomDeltaProperty); } - set { SetValue(MouseWheelZoomDeltaProperty, value); } - } - - protected virtual void OnPointerWheelChanged(object sender, PointerRoutedEventArgs e) - { - var point = e.GetCurrentPoint(this); - var zoomChange = MouseWheelZoomDelta * point.Properties.MouseWheelDelta / 120d; - - ZoomMap(point.Position, TargetZoomLevel + zoomChange); - } - - protected virtual async void OnManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) - { - transformTranslation.X += e.Delta.Translation.X; - transformTranslation.Y += e.Delta.Translation.Y; - transformRotation += e.Delta.Rotation; - transformScale *= e.Delta.Scale; + translation.X += e.Delta.Translation.X; + translation.Y += e.Delta.Translation.Y; + rotation += e.Delta.Rotation; + scale *= e.Delta.Scale; if (!transformPending) { transformPending = true; - await Dispatcher.RunIdleAsync(a => - { - TransformMap(e.Position, transformTranslation, transformRotation, transformScale); + await Dispatcher.RunAsync(CoreDispatcherPriority.Low, + () => TransformMap(e.Position, translation, rotation, scale)); - transformPending = false; - transformTranslation.X = 0d; - transformTranslation.Y = 0d; - transformRotation = 0d; - transformScale = 1d; - }); + ResetTransform(); } } + + private void OnPointerWheelChanged(object sender, PointerRoutedEventArgs e) + { + var point = e.GetCurrentPoint(this); + var zoomDelta = MouseWheelZoomDelta * point.Properties.MouseWheelDelta / 120d; + + ZoomMap(point.Position, TargetZoomLevel + zoomDelta); + } } } diff --git a/MapControl/UWP/MapControl.UWP.csproj b/MapControl/UWP/MapControl.UWP.csproj index 803cc78b..14a0acb6 100644 --- a/MapControl/UWP/MapControl.UWP.csproj +++ b/MapControl/UWP/MapControl.UWP.csproj @@ -86,6 +86,9 @@ LocationEx.cs + + Map.cs + MapBase.cs diff --git a/MapControl/WPF/Map.WPF.cs b/MapControl/WPF/Map.WPF.cs index ae255ede..36d0a446 100644 --- a/MapControl/WPF/Map.WPF.cs +++ b/MapControl/WPF/Map.WPF.cs @@ -2,21 +2,21 @@ // © 2020 Clemens Fischer // Licensed under the Microsoft Public License (Ms-PL) +using System; +using System.Threading.Tasks; using System.Windows; using System.Windows.Input; +using System.Windows.Threading; namespace MapControl { - /// - /// MapBase with default input event handling. - /// - public class Map : MapBase + public partial class Map { public static readonly DependencyProperty ManipulationModeProperty = DependencyProperty.Register( nameof(ManipulationMode), typeof(ManipulationModes), typeof(Map), new PropertyMetadata(ManipulationModes.All)); - public static readonly DependencyProperty MouseWheelZoomDeltaProperty = DependencyProperty.Register( - nameof(MouseWheelZoomDelta), typeof(double), typeof(Map), new PropertyMetadata(1d)); + public static readonly DependencyProperty TransformDelayProperty = DependencyProperty.Register( + nameof(TransformDelay), typeof(TimeSpan), typeof(Map), new PropertyMetadata(TimeSpan.FromMilliseconds(50))); private Point? mousePosition; @@ -25,6 +25,16 @@ namespace MapControl IsManipulationEnabledProperty.OverrideMetadata(typeof(Map), new FrameworkPropertyMetadata(true)); } + public Map() + { + ManipulationStarted += OnManipulationStarted; + ManipulationDelta += OnManipulationDelta; + MouseLeftButtonDown += OnMouseLeftButtonDown; + MouseLeftButtonUp += OnMouseLeftButtonUp; + MouseMove += OnMouseMove; + MouseWheel += OnMouseWheel; + } + /// /// Gets or sets a value that specifies how the map control handles manipulations. /// @@ -35,36 +45,57 @@ namespace MapControl } /// - /// Gets or sets the amount by which the ZoomLevel property changes during a MouseWheel event. + /// Gets or sets a delay interval between adjacent calls to TranslateMap or TransformMap during mouse pan and manipulation. + /// The default value is 50 milliseconds. /// - public double MouseWheelZoomDelta + public TimeSpan TransformDelay { - get { return (double)GetValue(MouseWheelZoomDeltaProperty); } - set { SetValue(MouseWheelZoomDeltaProperty, value); } + get { return (TimeSpan)GetValue(TransformDelayProperty); } + set { SetValue(TransformDelayProperty, value); } } - protected override void OnMouseWheel(MouseWheelEventArgs e) + private async Task InvokeTransformAsync(Action action) { - base.OnMouseWheel(e); + if (!transformPending) + { + transformPending = true; - var zoomDelta = MouseWheelZoomDelta * e.Delta / 120d; - ZoomMap(e.GetPosition(this), TargetZoomLevel + zoomDelta); + if (TransformDelay > TimeSpan.Zero) + { + await Task.Delay(TransformDelay); + } + + await Dispatcher.InvokeAsync(action); + + ResetTransform(); + } } - protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + private void OnManipulationStarted(object sender, ManipulationStartedEventArgs e) { - base.OnMouseLeftButtonDown(e); + Manipulation.SetManipulationMode(this, ManipulationMode); + } + private async void OnManipulationDelta(object sender, ManipulationDeltaEventArgs e) + { + translation.X += e.DeltaManipulation.Translation.X; + translation.Y += e.DeltaManipulation.Translation.Y; + rotation += e.DeltaManipulation.Rotation; + scale *= (e.DeltaManipulation.Scale.X + e.DeltaManipulation.Scale.Y) / 2d; + + await InvokeTransformAsync(() => TransformMap(e.ManipulationOrigin, translation, rotation, scale)); + } + + private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { if (CaptureMouse()) { mousePosition = e.GetPosition(this); } } - protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) + private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e) { - base.OnMouseLeftButtonUp(e); - if (mousePosition.HasValue) { mousePosition = null; @@ -72,32 +103,23 @@ namespace MapControl } } - protected override void OnMouseMove(MouseEventArgs e) + private async void OnMouseMove(object sender, MouseEventArgs e) { - base.OnMouseMove(e); - if (mousePosition.HasValue) { var position = e.GetPosition(this); - TranslateMap(position - mousePosition.Value); + translation += position - mousePosition.Value; mousePosition = position; + + await InvokeTransformAsync(() => TranslateMap(translation)); } } - protected override void OnManipulationStarted(ManipulationStartedEventArgs e) + private void OnMouseWheel(object sender, MouseWheelEventArgs e) { - base.OnManipulationStarted(e); + var zoomDelta = MouseWheelZoomDelta * e.Delta / 120d; - Manipulation.SetManipulationMode(this, ManipulationMode); - } - - protected override void OnManipulationDelta(ManipulationDeltaEventArgs e) - { - base.OnManipulationDelta(e); - - TransformMap(e.ManipulationOrigin, - e.DeltaManipulation.Translation, e.DeltaManipulation.Rotation, - (e.DeltaManipulation.Scale.X + e.DeltaManipulation.Scale.Y) / 2d); + ZoomMap(e.GetPosition(this), TargetZoomLevel + zoomDelta); } } }