diff --git a/Caching/FileDbCache.UWP/Properties/AssemblyInfo.cs b/Caching/FileDbCache.UWP/Properties/AssemblyInfo.cs
index 64204363..87c45105 100644
--- a/Caching/FileDbCache.UWP/Properties/AssemblyInfo.cs
+++ b/Caching/FileDbCache.UWP/Properties/AssemblyInfo.cs
@@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
-[assembly: AssemblyVersion("4.0.1")]
-[assembly: AssemblyFileVersion("4.0.1")]
+[assembly: AssemblyVersion("4.1.0")]
+[assembly: AssemblyFileVersion("4.1.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
diff --git a/Caching/FileDbCache.WPF/Properties/AssemblyInfo.cs b/Caching/FileDbCache.WPF/Properties/AssemblyInfo.cs
index 78795e47..18a184ab 100644
--- a/Caching/FileDbCache.WPF/Properties/AssemblyInfo.cs
+++ b/Caching/FileDbCache.WPF/Properties/AssemblyInfo.cs
@@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
-[assembly: AssemblyVersion("4.0.1")]
-[assembly: AssemblyFileVersion("4.0.1")]
+[assembly: AssemblyVersion("4.1.0")]
+[assembly: AssemblyFileVersion("4.1.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
diff --git a/MapControl/Shared/MapScale.cs b/MapControl/Shared/MapScale.cs
new file mode 100644
index 00000000..0d94ed61
--- /dev/null
+++ b/MapControl/Shared/MapScale.cs
@@ -0,0 +1,141 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2017 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+using System;
+#if WINDOWS_UWP
+using Windows.Foundation;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Data;
+using Windows.UI.Xaml.Media;
+using Windows.UI.Xaml.Shapes;
+#else
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Media;
+using System.Windows.Shapes;
+#endif
+
+namespace MapControl
+{
+ ///
+ /// Draws a map scale overlay.
+ ///
+ public class MapScale : MapOverlay
+ {
+ public static readonly DependencyProperty PaddingProperty = DependencyProperty.Register(
+ nameof(Padding), typeof(Thickness), typeof(MapScale), null);
+
+ private TextBlock label = new TextBlock();
+ private Polyline line = new Polyline();
+
+ public MapScale()
+ {
+ IsHitTestVisible = false;
+ MinWidth = 100d;
+ Padding = new Thickness(4d);
+ HorizontalAlignment = HorizontalAlignment.Left;
+ VerticalAlignment = VerticalAlignment.Bottom;
+
+ label.HorizontalAlignment = HorizontalAlignment.Left;
+ label.VerticalAlignment = VerticalAlignment.Top;
+ label.TextAlignment = TextAlignment.Center;
+
+ label.SetBinding(TextBlock.ForegroundProperty,
+ GetBindingExpression(ForegroundProperty)?.ParentBinding ??
+ new Binding
+ {
+ Source = this,
+ Path = new PropertyPath("Foreground")
+ });
+
+ line.SetBinding(Shape.StrokeProperty,
+ GetBindingExpression(StrokeProperty)?.ParentBinding ??
+ new Binding
+ {
+ Source = this,
+ Path = new PropertyPath("Stroke")
+ });
+
+ line.SetBinding(Shape.StrokeThicknessProperty,
+ GetBindingExpression(StrokeThicknessProperty)?.ParentBinding ??
+ new Binding
+ {
+ Source = this,
+ Path = new PropertyPath("StrokeThickness")
+ });
+
+ Children.Add(line);
+ Children.Add(label);
+ }
+
+ public Thickness Padding
+ {
+ get { return (Thickness)GetValue(PaddingProperty); }
+ set { SetValue(PaddingProperty, value); }
+ }
+
+ protected override Size MeasureOverride(Size availableSize)
+ {
+ var size = new Size();
+
+ if (ParentMap != null && ParentMap.ScaleTransform.ScaleX > 0d)
+ {
+ var length = MinWidth / ParentMap.ScaleTransform.ScaleX;
+ var magnitude = Math.Pow(10d, Math.Floor(Math.Log10(length)));
+
+ if (length / magnitude < 2d)
+ {
+ length = 2d * magnitude;
+ }
+ else if (length / magnitude < 5d)
+ {
+ length = 5d * magnitude;
+ }
+ else
+ {
+ length = 10d * magnitude;
+ }
+
+ size.Width = length * ParentMap.ScaleTransform.ScaleX + StrokeThickness + Padding.Left + Padding.Right;
+ size.Height = 1.25 * FontSize + StrokeThickness + Padding.Top + Padding.Bottom;
+
+ var x1 = Padding.Left + StrokeThickness / 2d;
+ var x2 = size.Width - Padding.Right - StrokeThickness / 2d;
+ var y1 = size.Height / 2d;
+ var y2 = size.Height - Padding.Bottom - StrokeThickness / 2d;
+ var points = new PointCollection();
+ points.Add(new Point(x1, y1));
+ points.Add(new Point(x1, y2));
+ points.Add(new Point(x2, y2));
+ points.Add(new Point(x2, y1));
+
+ line.Points = points;
+ line.Measure(size);
+
+ if (FontFamily != null)
+ {
+ label.FontFamily = FontFamily;
+ }
+
+ label.FontSize = FontSize;
+ label.FontStyle = FontStyle;
+ label.FontStretch = FontStretch;
+ label.FontWeight = FontWeight;
+ label.Text = length >= 1000d ? string.Format("{0:0} km", length / 1000d) : string.Format("{0:0} m", length);
+ label.Width = size.Width;
+ label.Height = size.Height;
+ label.Measure(size);
+ }
+
+ return size;
+ }
+
+ protected override void OnViewportChanged(ViewportChangedEventArgs e)
+ {
+ InvalidateMeasure();
+ }
+ }
+}
diff --git a/MapControl/UWP/MapControl.UWP.csproj b/MapControl/UWP/MapControl.UWP.csproj
index 3b674d9e..ad8d5913 100644
--- a/MapControl/UWP/MapControl.UWP.csproj
+++ b/MapControl/UWP/MapControl.UWP.csproj
@@ -103,6 +103,9 @@
MapProjection.cs
+
+ MapScale.cs
+
MapTileLayer.cs
diff --git a/MapControl/UWP/MapOverlay.UWP.cs b/MapControl/UWP/MapOverlay.UWP.cs
index 740f43fe..c6d18f93 100644
--- a/MapControl/UWP/MapOverlay.UWP.cs
+++ b/MapControl/UWP/MapOverlay.UWP.cs
@@ -12,7 +12,7 @@ namespace MapControl
public partial class MapOverlay
{
public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register(
- nameof(FontSize), typeof(double), typeof(MapOverlay), new PropertyMetadata(10d));
+ nameof(FontSize), typeof(double), typeof(MapOverlay), new PropertyMetadata(12d));
public static readonly DependencyProperty FontFamilyProperty = DependencyProperty.Register(
nameof(FontFamily), typeof(FontFamily), typeof(MapOverlay), new PropertyMetadata(null));
diff --git a/MapControl/UWP/Properties/AssemblyInfo.cs b/MapControl/UWP/Properties/AssemblyInfo.cs
index 3ab8cb70..1360c2f0 100644
--- a/MapControl/UWP/Properties/AssemblyInfo.cs
+++ b/MapControl/UWP/Properties/AssemblyInfo.cs
@@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
-[assembly: AssemblyVersion("4.0.1")]
-[assembly: AssemblyFileVersion("4.0.1")]
+[assembly: AssemblyVersion("4.1.0")]
+[assembly: AssemblyFileVersion("4.1.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
diff --git a/MapControl/WPF/MapControl.WPF.csproj b/MapControl/WPF/MapControl.WPF.csproj
index 0c83f055..f970cadf 100644
--- a/MapControl/WPF/MapControl.WPF.csproj
+++ b/MapControl/WPF/MapControl.WPF.csproj
@@ -114,6 +114,9 @@
MapProjection.cs
+
+ MapScale.cs
+
MapTileLayer.cs
@@ -155,7 +158,6 @@
-
diff --git a/MapControl/WPF/MapGraticule.WPF.cs b/MapControl/WPF/MapGraticule.WPF.cs
index 137a6b56..23904949 100644
--- a/MapControl/WPF/MapGraticule.WPF.cs
+++ b/MapControl/WPF/MapGraticule.WPF.cs
@@ -48,8 +48,14 @@ namespace MapControl
var lonLabelStart = Math.Ceiling(bounds.West / lineDistance) * lineDistance;
var latLabels = new List