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

289 lines
11 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)
using System.Windows;
2024-05-24 15:14:05 +02:00
using System.Windows.Documents;
using System.Windows.Media;
2024-05-21 13:51:10 +02:00
using System.Windows.Media.Animation;
namespace MapControl
{
public partial class MapBase
{
2024-05-24 15:14:05 +02:00
public static readonly DependencyProperty ForegroundProperty =
2024-09-03 12:11:04 +02:00
DependencyPropertyHelper.AddOwner<MapBase, Brush>(TextElement.ForegroundProperty, Brushes.Black);
2024-05-24 15:14:05 +02:00
2024-05-21 13:51:10 +02:00
public static readonly DependencyProperty AnimationEasingFunctionProperty =
DependencyPropertyHelper.Register<MapBase, IEasingFunction>(nameof(AnimationEasingFunction),
new QuadraticEase { EasingMode = EasingMode.EaseOut });
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-23 18:22:52 +02:00
(map, value) => map.CoerceCenterProperty(value),
true);
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-23 18:22:52 +02:00
(map, value) => map.CoerceCenterProperty(value),
true);
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),
(map, value) => map.CoerceMinZoomLevelProperty(value));
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-22 09:42:21 +02:00
(map, value) => map.CoerceMaxZoomLevelProperty(value));
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-23 18:22:52 +02:00
(map, value) => map.CoerceZoomLevelProperty(value),
true);
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),
2024-05-23 18:22:52 +02:00
(map, value) => map.CoerceZoomLevelProperty(value),
true);
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),
2024-05-23 18:22:52 +02:00
(map, value) => map.CoerceHeadingProperty(value),
true);
2024-05-21 13:51:10 +02:00
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),
2024-05-23 18:22:52 +02:00
(map, value) => map.CoerceHeadingProperty(value),
true);
2024-05-21 13:51:10 +02:00
private static readonly DependencyPropertyKey ViewScalePropertyKey =
DependencyPropertyHelper.RegisterReadOnly<MapBase, double>(nameof(ViewScale));
2022-11-02 19:49:18 +01:00
public static readonly DependencyProperty ViewScaleProperty = ViewScalePropertyKey.DependencyProperty;
2024-05-21 13:51:10 +02:00
private LocationAnimation centerAnimation;
private DoubleAnimation zoomLevelAnimation;
private DoubleAnimation headingAnimation;
static MapBase()
{
2024-07-05 09:20:30 +02:00
BackgroundProperty.OverrideMetadata(typeof(MapBase), new FrameworkPropertyMetadata(Brushes.White));
ClipToBoundsProperty.OverrideMetadata(typeof(MapBase), new FrameworkPropertyMetadata(true));
2021-01-17 21:39:42 +01:00
DefaultStyleKeyProperty.OverrideMetadata(typeof(MapBase), new FrameworkPropertyMetadata(typeof(MapBase)));
2024-09-03 12:11:04 +02:00
FlowDirectionProperty.OverrideMetadata(typeof(MapBase), new FrameworkPropertyMetadata(FlowDirection.LeftToRight) { Inherits = false });
}
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 IEasingFunction AnimationEasingFunction
{
get => (IEasingFunction)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(ViewScalePropertyKey, value);
2024-05-21 13:51:10 +02:00
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
ResetTransformCenter();
UpdateTransform();
}
2022-11-02 19:49:18 +01:00
2024-05-21 13:51:10 +02:00
private void CenterPropertyChanged(Location center)
{
if (!internalPropertyChange)
{
UpdateTransform();
if (centerAnimation == null)
{
SetValueInternal(TargetCenterProperty, center);
}
}
}
private void TargetCenterPropertyChanged(Location targetCenter)
{
if (!internalPropertyChange && !targetCenter.Equals(Center))
{
ResetTransformCenter();
2024-05-21 13:51:10 +02:00
if (centerAnimation != null)
{
centerAnimation.Completed -= CenterAnimationCompleted;
}
centerAnimation = new LocationAnimation
{
To = new Location(targetCenter.Latitude, CoerceLongitude(targetCenter.Longitude)),
2024-05-21 13:51:10 +02:00
Duration = AnimationDuration,
2024-05-21 21:16:22 +02:00
EasingFunction = AnimationEasingFunction,
FillBehavior = FillBehavior.Stop
2024-05-21 13:51:10 +02:00
};
centerAnimation.Completed += CenterAnimationCompleted;
BeginAnimation(CenterProperty, centerAnimation);
}
}
private void CenterAnimationCompleted(object sender, object e)
{
if (centerAnimation != null)
{
centerAnimation.Completed -= CenterAnimationCompleted;
centerAnimation = null;
BeginAnimation(CenterProperty, 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 minZoomLevel)
{
if (ZoomLevel < minZoomLevel)
{
ZoomLevel = minZoomLevel;
}
}
private void MaxZoomLevelPropertyChanged(double maxZoomLevel)
{
if (ZoomLevel > maxZoomLevel)
{
ZoomLevel = maxZoomLevel;
}
}
private void ZoomLevelPropertyChanged(double zoomLevel)
{
if (!internalPropertyChange)
{
UpdateTransform();
if (zoomLevelAnimation == null)
{
SetValueInternal(TargetZoomLevelProperty, zoomLevel);
}
}
}
private void TargetZoomLevelPropertyChanged(double targetZoomLevel)
{
if (!internalPropertyChange && targetZoomLevel != ZoomLevel)
{
if (zoomLevelAnimation != null)
{
zoomLevelAnimation.Completed -= ZoomLevelAnimationCompleted;
}
zoomLevelAnimation = new DoubleAnimation
{
To = targetZoomLevel,
Duration = AnimationDuration,
2024-05-21 21:16:22 +02:00
EasingFunction = AnimationEasingFunction,
FillBehavior = FillBehavior.Stop
2024-05-21 13:51:10 +02:00
};
zoomLevelAnimation.Completed += ZoomLevelAnimationCompleted;
BeginAnimation(ZoomLevelProperty, zoomLevelAnimation);
}
}
private void ZoomLevelAnimationCompleted(object sender, object e)
{
if (zoomLevelAnimation != null)
{
zoomLevelAnimation.Completed -= ZoomLevelAnimationCompleted;
zoomLevelAnimation = null;
BeginAnimation(ZoomLevelProperty, 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 heading)
{
if (!internalPropertyChange)
{
UpdateTransform();
if (headingAnimation == null)
{
SetValueInternal(TargetHeadingProperty, heading);
}
}
}
private void TargetHeadingPropertyChanged(double targetHeading)
{
if (!internalPropertyChange && 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,
2024-05-21 21:16:22 +02:00
EasingFunction = AnimationEasingFunction,
FillBehavior = FillBehavior.Stop
2024-05-21 13:51:10 +02:00
};
headingAnimation.Completed += HeadingAnimationCompleted;
BeginAnimation(HeadingProperty, headingAnimation);
}
}
private void HeadingAnimationCompleted(object sender, object e)
{
if (headingAnimation != null)
{
headingAnimation.Completed -= HeadingAnimationCompleted;
headingAnimation = null;
BeginAnimation(HeadingProperty, null);
2024-06-17 08:48:32 +02:00
SetValueInternal(HeadingProperty, TargetHeading);
UpdateTransform();
2024-05-21 13:51:10 +02:00
}
}
}
}