XAML-Map-Control/MapControl/WinUI/MapBase.WinUI.cs

368 lines
13 KiB
C#
Raw Normal View History

// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
2024-02-03 21:01:53 +01:00
// Copyright © 2024 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
2024-05-22 11:25:32 +02:00
#if UWP
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
2024-05-21 13:51:10 +02:00
using Windows.UI.Xaml.Media.Animation;
2024-05-22 11:25:32 +02:00
#else
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Animation;
2021-06-14 21:41:37 +02:00
#endif
namespace MapControl
{
public partial class MapBase
{
2024-05-24 15:14:05 +02:00
public static readonly DependencyProperty ForegroundProperty =
DependencyPropertyHelper.Register<MapBase, Brush>(nameof(Foreground),
new SolidColorBrush(Colors.Black));
2024-05-21 13:51:10 +02:00
public static readonly DependencyProperty AnimationEasingFunctionProperty =
DependencyPropertyHelper.Register<MapBase, EasingFunctionBase>(nameof(AnimationEasingFunction),
new QuadraticEase { EasingMode = EasingMode.EaseOut });
2024-05-21 13:51:10 +02:00
public static readonly DependencyProperty CenterProperty =
2024-05-23 18:22:52 +02:00
DependencyPropertyHelper.Register<MapBase, Location>(nameof(Center), new Location(),
2024-05-21 13:51:10 +02:00
(map, oldValue, newValue) => map.CenterPropertyChanged(newValue));
2024-05-21 13:51:10 +02:00
public static readonly DependencyProperty TargetCenterProperty =
2024-05-23 18:22:52 +02:00
DependencyPropertyHelper.Register<MapBase, Location>(nameof(TargetCenter), new Location(),
2024-05-21 13:51:10 +02:00
(map, oldValue, newValue) => map.TargetCenterPropertyChanged(newValue));
2024-05-21 13:51:10 +02:00
public static readonly DependencyProperty MinZoomLevelProperty =
DependencyPropertyHelper.Register<MapBase, double>(nameof(MinZoomLevel), 1d,
2024-05-21 13:51:10 +02:00
(map, oldValue, newValue) => map.MinZoomLevelPropertyChanged(newValue));
2024-05-21 13:51:10 +02:00
public static readonly DependencyProperty MaxZoomLevelProperty =
2024-05-23 18:22:52 +02:00
DependencyPropertyHelper.Register<MapBase, double>(nameof(MaxZoomLevel), 20d,
2024-05-21 13:51:10 +02:00
(map, oldValue, newValue) => map.MaxZoomLevelPropertyChanged(newValue));
2024-05-21 13:51:10 +02:00
public static readonly DependencyProperty ZoomLevelProperty =
DependencyPropertyHelper.Register<MapBase, double>(nameof(ZoomLevel), 1d,
2024-05-21 13:51:10 +02:00
(map, oldValue, newValue) => map.ZoomLevelPropertyChanged(newValue));
2024-05-21 13:51:10 +02:00
public static readonly DependencyProperty TargetZoomLevelProperty =
DependencyPropertyHelper.Register<MapBase, double>(nameof(TargetZoomLevel), 1d,
2024-05-21 13:51:10 +02:00
(map, oldValue, newValue) => map.TargetZoomLevelPropertyChanged(newValue));
2022-11-02 19:49:18 +01:00
2024-05-21 13:51:10 +02:00
public static readonly DependencyProperty HeadingProperty =
2024-05-23 18:22:52 +02:00
DependencyPropertyHelper.Register<MapBase, double>(nameof(Heading), 0d,
2024-05-21 13:51:10 +02:00
(map, oldValue, newValue) => map.HeadingPropertyChanged(newValue));
public static readonly DependencyProperty TargetHeadingProperty =
2024-05-23 18:22:52 +02:00
DependencyPropertyHelper.Register<MapBase, double>(nameof(TargetHeading), 0d,
2024-05-21 13:51:10 +02:00
(map, oldValue, newValue) => map.TargetHeadingPropertyChanged(newValue));
public static readonly DependencyProperty ViewScaleProperty =
DependencyPropertyHelper.Register<MapBase, double>(nameof(ViewScale));
2024-05-21 13:51:10 +02:00
2024-05-21 14:06:36 +02:00
private static readonly DependencyProperty AnimatedCenterProperty =
2024-05-24 15:14:05 +02:00
DependencyPropertyHelper.Register<MapBase, Windows.Foundation.Point>(nameof(AnimatedCenter),
new Windows.Foundation.Point(),
2024-05-23 18:22:52 +02:00
(map, oldValue, newValue) => map.Center = new Location(newValue.Y, newValue.X));
2024-05-21 14:06:36 +02:00
private Windows.Foundation.Point AnimatedCenter => (Windows.Foundation.Point)GetValue(AnimatedCenterProperty);
2024-05-21 13:51:10 +02:00
private PointAnimation centerAnimation;
private DoubleAnimation zoomLevelAnimation;
private DoubleAnimation headingAnimation;
2017-09-05 20:57:17 +02:00
public MapBase()
{
2022-11-30 22:18:45 +01:00
// Set Background by Style to enable resetting by ClearValue in MapLayerPropertyChanged.
2024-05-24 09:13:41 +02:00
// There is no default Style in Generic.xaml because MapBase has no DefaultStyleKey property.
2022-11-30 22:18:45 +01:00
//
var style = new Style(typeof(MapBase));
2021-01-17 21:39:42 +01:00
style.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.White)));
Style = style;
2021-06-14 21:41:37 +02:00
SizeChanged += OnSizeChanged;
}
2017-10-07 17:43:28 +02:00
2024-05-21 13:51:10 +02:00
/// <summary>
/// Gets or sets the EasingFunction of the Center, ZoomLevel and Heading animations.
/// The default value is a QuadraticEase with EasingMode.EaseOut.
/// </summary>
public EasingFunctionBase AnimationEasingFunction
{
get => (EasingFunctionBase)GetValue(AnimationEasingFunctionProperty);
set => SetValue(AnimationEasingFunctionProperty, value);
}
/// <summary>
/// Gets the scaling factor from projected map coordinates to view coordinates,
/// as pixels per meter.
/// </summary>
2024-05-22 09:42:21 +02:00
public double ViewScale
2024-05-21 13:51:10 +02:00
{
2024-05-22 09:42:21 +02:00
get => (double)GetValue(ViewScaleProperty);
private set => SetValue(ViewScaleProperty, value);
2024-05-21 13:51:10 +02:00
}
2021-06-14 21:41:37 +02:00
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
Clip = new RectangleGeometry
{
Rect = new Windows.Foundation.Rect(0d, 0d, e.NewSize.Width, e.NewSize.Height)
};
2021-06-14 21:41:37 +02:00
ResetTransformCenter();
UpdateTransform();
}
2022-11-02 19:49:18 +01:00
2024-05-21 13:51:10 +02:00
private void CenterPropertyChanged(Location value)
{
if (!internalPropertyChange)
{
var center = CoerceCenterProperty(value);
if (!center.Equals(value))
{
SetValueInternal(CenterProperty, center);
}
UpdateTransform();
if (centerAnimation == null)
{
SetValueInternal(TargetCenterProperty, center);
}
}
}
private void TargetCenterPropertyChanged(Location value)
{
if (!internalPropertyChange)
{
ResetTransformCenter();
2024-05-21 13:51:10 +02:00
var targetCenter = CoerceCenterProperty(value);
if (!targetCenter.Equals(value))
{
SetValueInternal(TargetCenterProperty, targetCenter);
}
if (!targetCenter.Equals(Center))
{
if (centerAnimation != null)
{
centerAnimation.Completed -= CenterAnimationCompleted;
}
centerAnimation = new PointAnimation
{
From = new Windows.Foundation.Point(Center.Longitude, Center.Latitude),
To = new Windows.Foundation.Point(CoerceLongitude(targetCenter.Longitude), targetCenter.Latitude),
2024-05-21 13:51:10 +02:00
Duration = AnimationDuration,
EasingFunction = AnimationEasingFunction,
EnableDependentAnimation = true
};
centerAnimation.Completed += CenterAnimationCompleted;
2024-05-21 22:05:01 +02:00
BeginAnimation(nameof(AnimatedCenter), centerAnimation);
2024-05-21 13:51:10 +02:00
}
}
}
private void CenterAnimationCompleted(object sender, object e)
{
if (centerAnimation != null)
{
centerAnimation.Completed -= CenterAnimationCompleted;
centerAnimation = null;
2024-06-17 08:48:32 +02:00
SetValueInternal(CenterProperty, TargetCenter);
UpdateTransform();
2024-05-21 13:51:10 +02:00
}
}
private void MinZoomLevelPropertyChanged(double value)
{
var minZoomLevel = CoerceMinZoomLevelProperty(value);
if (minZoomLevel != value)
{
SetValueInternal(MinZoomLevelProperty, minZoomLevel);
}
if (ZoomLevel < minZoomLevel)
{
ZoomLevel = minZoomLevel;
}
}
private void MaxZoomLevelPropertyChanged(double value)
{
var maxZoomLevel = CoerceMaxZoomLevelProperty(value);
if (maxZoomLevel != value)
{
SetValueInternal(MaxZoomLevelProperty, maxZoomLevel);
}
if (ZoomLevel > maxZoomLevel)
{
ZoomLevel = maxZoomLevel;
}
}
private void ZoomLevelPropertyChanged(double value)
{
if (!internalPropertyChange)
{
var zoomLevel = CoerceZoomLevelProperty(value);
if (zoomLevel != value)
{
SetValueInternal(ZoomLevelProperty, zoomLevel);
}
UpdateTransform();
if (zoomLevelAnimation == null)
{
SetValueInternal(TargetZoomLevelProperty, zoomLevel);
}
}
}
private void TargetZoomLevelPropertyChanged(double value)
{
if (!internalPropertyChange)
{
var targetZoomLevel = CoerceZoomLevelProperty(value);
if (targetZoomLevel != value)
{
SetValueInternal(TargetZoomLevelProperty, targetZoomLevel);
}
if (targetZoomLevel != ZoomLevel)
{
if (zoomLevelAnimation != null)
{
zoomLevelAnimation.Completed -= ZoomLevelAnimationCompleted;
}
zoomLevelAnimation = new DoubleAnimation
{
To = targetZoomLevel,
Duration = AnimationDuration,
EasingFunction = AnimationEasingFunction,
EnableDependentAnimation = true
};
zoomLevelAnimation.Completed += ZoomLevelAnimationCompleted;
2024-05-21 22:05:01 +02:00
BeginAnimation(nameof(ZoomLevel), zoomLevelAnimation);
2024-05-21 13:51:10 +02:00
}
}
}
private void ZoomLevelAnimationCompleted(object sender, object e)
{
if (zoomLevelAnimation != null)
{
zoomLevelAnimation.Completed -= ZoomLevelAnimationCompleted;
zoomLevelAnimation = null;
2024-06-17 08:48:32 +02:00
SetValueInternal(ZoomLevelProperty, TargetZoomLevel);
UpdateTransform(true);
2024-05-21 13:51:10 +02:00
}
}
private void HeadingPropertyChanged(double value)
{
if (!internalPropertyChange)
{
var heading = CoerceHeadingProperty(value);
if (heading != value)
{
SetValueInternal(HeadingProperty, heading);
}
UpdateTransform();
if (headingAnimation == null)
{
SetValueInternal(TargetHeadingProperty, heading);
}
}
}
private void TargetHeadingPropertyChanged(double value)
{
if (!internalPropertyChange)
{
var targetHeading = CoerceHeadingProperty(value);
if (targetHeading != value)
{
SetValueInternal(TargetHeadingProperty, targetHeading);
}
if (targetHeading != Heading)
{
var delta = targetHeading - Heading;
if (delta > 180d)
{
delta -= 360d;
}
else if (delta < -180d)
{
delta += 360d;
}
if (headingAnimation != null)
{
headingAnimation.Completed -= HeadingAnimationCompleted;
}
headingAnimation = new DoubleAnimation
{
By = delta,
Duration = AnimationDuration,
EasingFunction = AnimationEasingFunction,
EnableDependentAnimation = true
};
headingAnimation.Completed += HeadingAnimationCompleted;
2024-05-21 22:05:01 +02:00
BeginAnimation(nameof(Heading), headingAnimation);
2024-05-21 13:51:10 +02:00
}
}
}
private void HeadingAnimationCompleted(object sender, object e)
{
if (headingAnimation != null)
{
headingAnimation.Completed -= HeadingAnimationCompleted;
headingAnimation = null;
2024-06-17 08:48:32 +02:00
SetValueInternal(HeadingProperty, TargetHeading);
UpdateTransform();
2024-05-21 13:51:10 +02:00
}
}
2024-05-21 22:05:01 +02:00
2024-05-21 22:06:14 +02:00
private void BeginAnimation(string property, Timeline animation)
2024-05-21 22:05:01 +02:00
{
Storyboard.SetTarget(animation, this);
Storyboard.SetTargetProperty(animation, property);
var storyboard = new Storyboard();
storyboard.Children.Add(animation);
storyboard.Begin();
}
}
}