From 07710f0e403132a1f90ec12bdbb6a938cdd29904 Mon Sep 17 00:00:00 2001 From: ClemensFischer Date: Sat, 14 Jan 2023 18:41:10 +0100 Subject: [PATCH] Add MapBorderPanel --- MapControl/Shared/MapBorderPanel.cs | 94 ++++++++++++++++++++++++++++ MapControl/Shared/MapPanel.cs | 7 +-- MapControl/UWP/MapControl.UWP.csproj | 3 + MapControl/WPF/MapPanel.WPF.cs | 7 ++- MapControl/WinUI/MapPanel.WinUI.cs | 7 ++- 5 files changed, 112 insertions(+), 6 deletions(-) create mode 100644 MapControl/Shared/MapBorderPanel.cs diff --git a/MapControl/Shared/MapBorderPanel.cs b/MapControl/Shared/MapBorderPanel.cs new file mode 100644 index 00000000..9d96fad5 --- /dev/null +++ b/MapControl/Shared/MapBorderPanel.cs @@ -0,0 +1,94 @@ +// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control +// Copyright © 2023 Clemens Fischer +// Licensed under the Microsoft Public License (Ms-PL) + +#if WINUI +using Microsoft.UI.Xaml; +#elif UWP +using Windows.UI.Xaml; +#else +using System.Windows; +#endif + +namespace MapControl +{ + /// + /// A MapPanel that adjusts the ViewPosition property of its child elements so that + /// elements that would be outside the current viewport are arranged on a border area. + /// Such elements are arranged at a distance of BorderWidth/2 from the edges of the + /// MapBorderPanel in direction of their original azimuth from the map center. + /// + public class MapBorderPanel : MapPanel + { + public static readonly DependencyProperty BorderWidthProperty = DependencyProperty.Register( + nameof(BorderWidth), typeof(double), typeof(MapBorderPanel), null); + + public static readonly DependencyProperty OnBorderProperty = DependencyProperty.Register( + "OnBorder", typeof(bool), typeof(MapBorderPanel), null); + + public double BorderWidth + { + get => (double)GetValue(BorderWidthProperty); + set => SetValue(BorderWidthProperty, value); + } + + public static bool GetOnBorder(FrameworkElement element) + { + return (bool)element.GetValue(OnBorderProperty); + } + + protected override void SetViewPosition(FrameworkElement element, ref Point? position) + { + var onBorder = false; + var w = ParentMap.RenderSize.Width; + var h = ParentMap.RenderSize.Height; + var minX = BorderWidth / 2d; + var minY = BorderWidth / 2d; + var maxX = w - BorderWidth / 2d; + var maxY = h - BorderWidth / 2d; + + if (position.HasValue && + (position.Value.X < minX || position.Value.X > maxX || + position.Value.Y < minY || position.Value.Y > maxY)) + { + var dx = position.Value.X - w / 2d; + var dy = position.Value.Y - h / 2d; + var cx = (maxX - minX) / 2d; + var cy = (maxY - minY) / 2d; + double x, y; + + if (dx < 0d) + { + x = minX; + y = minY + cy - cx * dy / dx; + } + else + { + x = maxX; + y = minY + cy + cx * dy / dx; + } + + if (y < minY || y > maxY) + { + if (dy < 0d) + { + x = minX + cx - cy * dx / dy; + y = minY; + } + else + { + x = minX + cx + cy * dx / dy; + y = maxY; + } + } + + position = new Point(x, y); + onBorder = true; + } + + element.SetValue(OnBorderProperty, onBorder); + + base.SetViewPosition(element, ref position); + } + } +} diff --git a/MapControl/Shared/MapPanel.cs b/MapControl/Shared/MapPanel.cs index 3858f2b3..c7937892 100644 --- a/MapControl/Shared/MapPanel.cs +++ b/MapControl/Shared/MapPanel.cs @@ -105,8 +105,7 @@ namespace MapControl } /// - /// Gets the view position of an element with Location - /// or null when the element has no Location. + /// Gets the view position of an element with Location. /// public static Point? GetViewPosition(FrameworkElement element) { @@ -161,7 +160,7 @@ namespace MapControl var location = GetLocation(element); var position = location != null ? GetViewPosition(location) : null; - SetViewPosition(element, position); + SetViewPosition(element, ref position); if (GetAutoCollapse(element)) { @@ -203,7 +202,7 @@ namespace MapControl return finalSize; } - protected virtual Point? GetViewPosition(Location location) + protected Point? GetViewPosition(Location location) { var position = parentMap.LocationToView(location); diff --git a/MapControl/UWP/MapControl.UWP.csproj b/MapControl/UWP/MapControl.UWP.csproj index cbdd7b58..014af40b 100644 --- a/MapControl/UWP/MapControl.UWP.csproj +++ b/MapControl/UWP/MapControl.UWP.csproj @@ -104,6 +104,9 @@ MapBase.cs + + MapBorderPanel.cs + MapGraticule.cs diff --git a/MapControl/WPF/MapPanel.WPF.cs b/MapControl/WPF/MapPanel.WPF.cs index 818a08b1..eb0c4954 100644 --- a/MapControl/WPF/MapPanel.WPF.cs +++ b/MapControl/WPF/MapPanel.WPF.cs @@ -39,7 +39,12 @@ namespace MapControl return (MapBase)element.GetValue(ParentMapProperty); } - private static void SetViewPosition(FrameworkElement element, Point? position) + /// + /// Sets the attached ViewPosition property of an element. The method is called during + /// ArrangeOverride and may be overridden to modify the actual view position value. + /// An overridden method should call this method to set the attached property. + /// + protected virtual void SetViewPosition(FrameworkElement element, ref Point? position) { element.SetValue(ViewPositionPropertyKey, position); } diff --git a/MapControl/WinUI/MapPanel.WinUI.cs b/MapControl/WinUI/MapPanel.WinUI.cs index cee45253..007781c6 100644 --- a/MapControl/WinUI/MapPanel.WinUI.cs +++ b/MapControl/WinUI/MapPanel.WinUI.cs @@ -67,7 +67,12 @@ namespace MapControl return parentMap; } - private static void SetViewPosition(FrameworkElement element, Point? position) + /// + /// Sets the attached ViewPosition property of an element. The method is called during + /// ArrangeOverride and may be overridden to modify the actual view position value. + /// An overridden method should call this method to set the attached property. + /// + protected virtual void SetViewPosition(FrameworkElement element, ref Point? position) { element.SetValue(ViewPositionProperty, position); }