mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2025-12-06 07:12:04 +01:00
Added classes MapOverlay and MapScale.
This commit is contained in:
parent
27cdfe77ae
commit
e52698586b
|
|
@ -56,6 +56,8 @@
|
|||
<Compile Include="MapPanel.cs" />
|
||||
<Compile Include="MapPolygon.cs" />
|
||||
<Compile Include="MapPolyline.cs" />
|
||||
<Compile Include="MapOverlay.cs" />
|
||||
<Compile Include="MapScale.cs" />
|
||||
<Compile Include="Pushpin.cs" />
|
||||
<Compile Include="MapTransform.cs" />
|
||||
<Compile Include="MapBase.cs" />
|
||||
|
|
|
|||
|
|
@ -5,107 +5,24 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Draws a graticule overlay. The minimum spacing in pixels between adjacent
|
||||
/// graticule lines is specified by the MinLineSpacing property.
|
||||
/// Draws a graticule overlay.
|
||||
/// </summary>
|
||||
public class MapGraticule : MapElement
|
||||
public class MapGraticule : MapOverlay
|
||||
{
|
||||
public static readonly DependencyProperty ForegroundProperty = Control.ForegroundProperty.AddOwner(
|
||||
typeof(MapGraticule), new FrameworkPropertyMetadata((o, e) => ((MapGraticule)o).UpdateBrush()));
|
||||
|
||||
public static readonly DependencyProperty FontSizeProperty = Control.FontSizeProperty.AddOwner(
|
||||
typeof(MapGraticule));
|
||||
|
||||
public static readonly DependencyProperty FontFamilyProperty = Control.FontFamilyProperty.AddOwner(
|
||||
typeof(MapGraticule), new FrameworkPropertyMetadata((o, e) => ((MapGraticule)o).typeface = null));
|
||||
|
||||
public static readonly DependencyProperty FontStyleProperty = Control.FontStyleProperty.AddOwner(
|
||||
typeof(MapGraticule), new FrameworkPropertyMetadata((o, e) => ((MapGraticule)o).typeface = null));
|
||||
|
||||
public static readonly DependencyProperty FontWeightProperty = Control.FontWeightProperty.AddOwner(
|
||||
typeof(MapGraticule), new FrameworkPropertyMetadata((o, e) => ((MapGraticule)o).typeface = null));
|
||||
|
||||
public static readonly DependencyProperty FontStretchProperty = Control.FontStretchProperty.AddOwner(
|
||||
typeof(MapGraticule), new FrameworkPropertyMetadata((o, e) => ((MapGraticule)o).typeface = null));
|
||||
|
||||
public static readonly DependencyProperty StrokeProperty = Shape.StrokeProperty.AddOwner(
|
||||
typeof(MapGraticule), new FrameworkPropertyMetadata((o, e) => ((MapGraticule)o).UpdateBrush()));
|
||||
|
||||
public static readonly DependencyProperty StrokeThicknessProperty = Shape.StrokeThicknessProperty.AddOwner(
|
||||
typeof(MapGraticule), new FrameworkPropertyMetadata(0.5, (o, e) => ((MapGraticule)o).pen.Thickness = (double)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty MinLineSpacingProperty = DependencyProperty.Register(
|
||||
"MinLineSpacing", typeof(double), typeof(MapGraticule), new FrameworkPropertyMetadata(100d));
|
||||
|
||||
public static double[] Spacings =
|
||||
/// <summary>
|
||||
/// Graticule line spacings in degrees.
|
||||
/// </summary>
|
||||
public static double[] LineSpacings =
|
||||
new double[] { 1d / 60d, 1d / 30d, 1d / 12d, 1d / 6d, 1d / 4d, 1d / 3d, 1d / 2d, 1d, 2d, 5d, 10d, 15d, 20d, 30d, 45d };
|
||||
|
||||
private readonly DrawingVisual visual = new DrawingVisual();
|
||||
private readonly Pen pen;
|
||||
private Typeface typeface;
|
||||
|
||||
public MapGraticule()
|
||||
{
|
||||
pen = new Pen(null, StrokeThickness);
|
||||
IsHitTestVisible = false;
|
||||
AddVisualChild(visual);
|
||||
}
|
||||
|
||||
public Brush Foreground
|
||||
{
|
||||
get { return (Brush)GetValue(ForegroundProperty); }
|
||||
set { SetValue(ForegroundProperty, value); }
|
||||
}
|
||||
|
||||
public double FontSize
|
||||
{
|
||||
get { return (double)GetValue(FontSizeProperty); }
|
||||
set { SetValue(FontSizeProperty, value); }
|
||||
}
|
||||
|
||||
public FontFamily FontFamily
|
||||
{
|
||||
get { return (FontFamily)GetValue(FontFamilyProperty); }
|
||||
set { SetValue(FontFamilyProperty, value); }
|
||||
}
|
||||
|
||||
public FontStyle FontStyle
|
||||
{
|
||||
get { return (FontStyle)GetValue(FontStyleProperty); }
|
||||
set { SetValue(FontStyleProperty, value); }
|
||||
}
|
||||
|
||||
public FontWeight FontWeight
|
||||
{
|
||||
get { return (FontWeight)GetValue(FontWeightProperty); }
|
||||
set { SetValue(FontWeightProperty, value); }
|
||||
}
|
||||
|
||||
public FontStretch FontStretch
|
||||
{
|
||||
get { return (FontStretch)GetValue(FontStretchProperty); }
|
||||
set { SetValue(FontStretchProperty, value); }
|
||||
}
|
||||
|
||||
public Brush Stroke
|
||||
{
|
||||
get { return (Brush)GetValue(StrokeProperty); }
|
||||
set { SetValue(StrokeProperty, value); }
|
||||
}
|
||||
|
||||
public double StrokeThickness
|
||||
{
|
||||
get { return (double)GetValue(StrokeThicknessProperty); }
|
||||
set { SetValue(StrokeThicknessProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Minimum spacing in pixels between adjacent graticule lines.
|
||||
/// </summary>
|
||||
|
|
@ -115,90 +32,61 @@ namespace MapControl
|
|||
set { SetValue(MinLineSpacingProperty, value); }
|
||||
}
|
||||
|
||||
protected override int VisualChildrenCount
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
|
||||
protected override Visual GetVisualChild(int index)
|
||||
{
|
||||
return visual;
|
||||
}
|
||||
|
||||
protected override void OnViewportChanged()
|
||||
protected override void OnRender(DrawingContext drawingContext)
|
||||
{
|
||||
MapBase parentMap = ParentMap;
|
||||
Rect bounds = parentMap.ViewportTransform.Inverse.TransformBounds(new Rect(parentMap.RenderSize));
|
||||
Location loc1 = parentMap.MapTransform.TransformBack(bounds.TopLeft);
|
||||
Location loc2 = parentMap.MapTransform.TransformBack(bounds.BottomRight);
|
||||
double minSpacing = MinLineSpacing * 360d / (Math.Pow(2d, parentMap.ZoomLevel) * 256d);
|
||||
double spacing = Spacings[Spacings.Length - 1];
|
||||
double spacing = LineSpacings[LineSpacings.Length - 1];
|
||||
|
||||
if (spacing >= minSpacing)
|
||||
{
|
||||
spacing = Spacings.FirstOrDefault(s => s >= minSpacing);
|
||||
spacing = LineSpacings.FirstOrDefault(s => s >= minSpacing);
|
||||
}
|
||||
|
||||
double latitudeStart = Math.Ceiling(loc1.Latitude / spacing) * spacing;
|
||||
double longitudeStart = Math.Ceiling(loc1.Longitude / spacing) * spacing;
|
||||
|
||||
if (pen.Brush == null)
|
||||
for (double lat = latitudeStart; lat <= loc2.Latitude; lat += spacing)
|
||||
{
|
||||
pen.Brush = Stroke != null ? Stroke : Foreground;
|
||||
drawingContext.DrawLine(Pen,
|
||||
parentMap.LocationToViewportPoint(new Location(lat, loc1.Longitude)),
|
||||
parentMap.LocationToViewportPoint(new Location(lat, loc2.Longitude)));
|
||||
}
|
||||
|
||||
using (DrawingContext drawingContext = visual.RenderOpen())
|
||||
for (double lon = longitudeStart; lon <= loc2.Longitude; lon += spacing)
|
||||
{
|
||||
drawingContext.DrawLine(Pen,
|
||||
parentMap.LocationToViewportPoint(new Location(loc1.Latitude, lon)),
|
||||
parentMap.LocationToViewportPoint(new Location(loc2.Latitude, lon)));
|
||||
}
|
||||
|
||||
if (Foreground != null && Foreground != Brushes.Transparent)
|
||||
{
|
||||
string format = spacing < 1d ? "{0} {1}°{2:00}'" : "{0} {1}°";
|
||||
|
||||
for (double lat = latitudeStart; lat <= loc2.Latitude; lat += spacing)
|
||||
{
|
||||
drawingContext.DrawLine(pen,
|
||||
parentMap.LocationToViewportPoint(new Location(lat, loc1.Longitude)),
|
||||
parentMap.LocationToViewportPoint(new Location(lat, loc2.Longitude)));
|
||||
}
|
||||
|
||||
for (double lon = longitudeStart; lon <= loc2.Longitude; lon += spacing)
|
||||
{
|
||||
drawingContext.DrawLine(pen,
|
||||
parentMap.LocationToViewportPoint(new Location(loc1.Latitude, lon)),
|
||||
parentMap.LocationToViewportPoint(new Location(loc2.Latitude, lon)));
|
||||
}
|
||||
|
||||
if (Foreground != null && Foreground != Brushes.Transparent)
|
||||
{
|
||||
string format = spacing < 1d ? "{0} {1}°{2:00}'" : "{0} {1}°";
|
||||
|
||||
if (typeface == null)
|
||||
for (double lon = longitudeStart; lon <= loc2.Longitude; lon += spacing)
|
||||
{
|
||||
typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
|
||||
}
|
||||
double t = StrokeThickness / 2d;
|
||||
Point p = parentMap.LocationToViewportPoint(new Location(lat, lon));
|
||||
Point latPos = new Point(p.X + t + 2d, p.Y - t - FontSize / 4d);
|
||||
Point lonPos = new Point(p.X + t + 2d, p.Y + t + FontSize);
|
||||
string latString = CoordinateString(lat, format, "NS");
|
||||
string lonString = CoordinateString(Location.NormalizeLongitude(lon), format, "EW");
|
||||
|
||||
for (double lat = latitudeStart; lat <= loc2.Latitude; lat += spacing)
|
||||
{
|
||||
for (double lon = longitudeStart; lon <= loc2.Longitude; lon += spacing)
|
||||
{
|
||||
double t = StrokeThickness / 2d;
|
||||
Point p = parentMap.LocationToViewportPoint(new Location(lat, lon));
|
||||
Point latPos = new Point(p.X + t + 2d, p.Y - t - FontSize / 4d);
|
||||
Point lonPos = new Point(p.X + t + 2d, p.Y + t + FontSize);
|
||||
string latString = CoordinateString(lat, format, "NS");
|
||||
string lonString = CoordinateString(Location.NormalizeLongitude(lon), format, "EW");
|
||||
|
||||
drawingContext.PushTransform(new RotateTransform(parentMap.Heading, p.X, p.Y));
|
||||
drawingContext.DrawGlyphRun(Foreground, GlyphRunText.Create(latString, typeface, FontSize, latPos));
|
||||
drawingContext.DrawGlyphRun(Foreground, GlyphRunText.Create(lonString, typeface, FontSize, lonPos));
|
||||
drawingContext.Pop();
|
||||
}
|
||||
drawingContext.PushTransform(new RotateTransform(parentMap.Heading, p.X, p.Y));
|
||||
drawingContext.DrawGlyphRun(Foreground, GlyphRunText.Create(latString, Typeface, FontSize, latPos));
|
||||
drawingContext.DrawGlyphRun(Foreground, GlyphRunText.Create(lonString, Typeface, FontSize, lonPos));
|
||||
drawingContext.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateBrush()
|
||||
{
|
||||
pen.Brush = null;
|
||||
OnViewportChanged();
|
||||
}
|
||||
|
||||
private static string CoordinateString(double value, string format, string hemispheres)
|
||||
{
|
||||
char hemisphere = hemispheres[0];
|
||||
|
|
|
|||
224
MapControl/MapOverlay.cs
Normal file
224
MapControl/MapOverlay.cs
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||
// Copyright © 2012 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for map overlays with font, background, foreground and stroke properties.
|
||||
/// </summary>
|
||||
public class MapOverlay : MapElement
|
||||
{
|
||||
public static readonly DependencyProperty FontFamilyProperty = Control.FontFamilyProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).typeface = null));
|
||||
|
||||
public static readonly DependencyProperty FontStyleProperty = Control.FontStyleProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).typeface = null));
|
||||
|
||||
public static readonly DependencyProperty FontWeightProperty = Control.FontWeightProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).typeface = null));
|
||||
|
||||
public static readonly DependencyProperty FontStretchProperty = Control.FontStretchProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).typeface = null));
|
||||
|
||||
public static readonly DependencyProperty FontSizeProperty = Control.FontSizeProperty.AddOwner(
|
||||
typeof(MapOverlay));
|
||||
|
||||
public static readonly DependencyProperty BackgroundProperty = Control.BackgroundProperty.AddOwner(
|
||||
typeof(MapOverlay));
|
||||
|
||||
public static readonly DependencyProperty ForegroundProperty = Control.ForegroundProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).ForegroundChanged((Brush)e.NewValue)));
|
||||
|
||||
public static readonly DependencyProperty StrokeProperty = Shape.StrokeProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen.Brush = (Brush)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty StrokeThicknessProperty = Shape.StrokeThicknessProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata(0.5, FrameworkPropertyMetadataOptions.AffectsMeasure, (o, e) => ((MapOverlay)o).pen.Thickness = (double)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty StrokeDashArrayProperty = Shape.StrokeDashArrayProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen.DashStyle = new DashStyle((DoubleCollection)e.NewValue, ((MapOverlay)o).StrokeDashOffset)));
|
||||
|
||||
public static readonly DependencyProperty StrokeDashOffsetProperty = Shape.StrokeDashOffsetProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen.DashStyle = new DashStyle(((MapOverlay)o).StrokeDashArray, (double)e.NewValue)));
|
||||
|
||||
public static readonly DependencyProperty StrokeDashCapProperty = Shape.StrokeDashCapProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen.DashCap = (PenLineCap)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty StrokeStartLineCapProperty = Shape.StrokeStartLineCapProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen.StartLineCap = (PenLineCap)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty StrokeEndLineCapProperty = Shape.StrokeEndLineCapProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen.EndLineCap = (PenLineCap)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty StrokeLineJoinProperty = Shape.StrokeLineJoinProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen.LineJoin = (PenLineJoin)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty StrokeMiterLimitProperty = Shape.StrokeMiterLimitProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen.MiterLimit = (double)e.NewValue));
|
||||
|
||||
private readonly Pen pen;
|
||||
private Typeface typeface;
|
||||
|
||||
static MapOverlay()
|
||||
{
|
||||
UIElement.IsHitTestVisibleProperty.OverrideMetadata(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata(false));
|
||||
}
|
||||
|
||||
public MapOverlay()
|
||||
{
|
||||
pen = new Pen
|
||||
{
|
||||
Brush = Stroke,
|
||||
Thickness = StrokeThickness,
|
||||
DashStyle = new DashStyle(StrokeDashArray, StrokeDashOffset),
|
||||
DashCap = StrokeDashCap,
|
||||
StartLineCap = StrokeStartLineCap,
|
||||
EndLineCap = StrokeEndLineCap,
|
||||
LineJoin = StrokeLineJoin,
|
||||
MiterLimit = StrokeMiterLimit
|
||||
};
|
||||
}
|
||||
|
||||
public FontFamily FontFamily
|
||||
{
|
||||
get { return (FontFamily)GetValue(FontFamilyProperty); }
|
||||
set { SetValue(FontFamilyProperty, value); }
|
||||
}
|
||||
|
||||
public FontStyle FontStyle
|
||||
{
|
||||
get { return (FontStyle)GetValue(FontStyleProperty); }
|
||||
set { SetValue(FontStyleProperty, value); }
|
||||
}
|
||||
|
||||
public FontWeight FontWeight
|
||||
{
|
||||
get { return (FontWeight)GetValue(FontWeightProperty); }
|
||||
set { SetValue(FontWeightProperty, value); }
|
||||
}
|
||||
|
||||
public FontStretch FontStretch
|
||||
{
|
||||
get { return (FontStretch)GetValue(FontStretchProperty); }
|
||||
set { SetValue(FontStretchProperty, value); }
|
||||
}
|
||||
|
||||
public double FontSize
|
||||
{
|
||||
get { return (double)GetValue(FontSizeProperty); }
|
||||
set { SetValue(FontSizeProperty, value); }
|
||||
}
|
||||
|
||||
public Brush Background
|
||||
{
|
||||
get { return (Brush)GetValue(BackgroundProperty); }
|
||||
set { SetValue(BackgroundProperty, value); }
|
||||
}
|
||||
|
||||
public Brush Foreground
|
||||
{
|
||||
get { return (Brush)GetValue(ForegroundProperty); }
|
||||
set { SetValue(ForegroundProperty, value); }
|
||||
}
|
||||
|
||||
public Brush Stroke
|
||||
{
|
||||
get { return (Brush)GetValue(StrokeProperty); }
|
||||
set { SetValue(StrokeProperty, value); }
|
||||
}
|
||||
|
||||
public double StrokeThickness
|
||||
{
|
||||
get { return (double)GetValue(StrokeThicknessProperty); }
|
||||
set { SetValue(StrokeThicknessProperty, value); }
|
||||
}
|
||||
|
||||
public DoubleCollection StrokeDashArray
|
||||
{
|
||||
get { return (DoubleCollection)GetValue(StrokeDashArrayProperty); }
|
||||
set { SetValue(StrokeDashArrayProperty, value); }
|
||||
}
|
||||
|
||||
public double StrokeDashOffset
|
||||
{
|
||||
get { return (double)GetValue(StrokeDashOffsetProperty); }
|
||||
set { SetValue(StrokeDashOffsetProperty, value); }
|
||||
}
|
||||
|
||||
public PenLineCap StrokeDashCap
|
||||
{
|
||||
get { return (PenLineCap)GetValue(StrokeDashCapProperty); }
|
||||
set { SetValue(StrokeDashCapProperty, value); }
|
||||
}
|
||||
|
||||
public PenLineCap StrokeStartLineCap
|
||||
{
|
||||
get { return (PenLineCap)GetValue(StrokeStartLineCapProperty); }
|
||||
set { SetValue(StrokeStartLineCapProperty, value); }
|
||||
}
|
||||
|
||||
public PenLineCap StrokeEndLineCap
|
||||
{
|
||||
get { return (PenLineCap)GetValue(StrokeEndLineCapProperty); }
|
||||
set { SetValue(StrokeEndLineCapProperty, value); }
|
||||
}
|
||||
|
||||
public PenLineJoin StrokeLineJoin
|
||||
{
|
||||
get { return (PenLineJoin)GetValue(StrokeLineJoinProperty); }
|
||||
set { SetValue(StrokeLineJoinProperty, value); }
|
||||
}
|
||||
|
||||
public double StrokeMiterLimit
|
||||
{
|
||||
get { return (double)GetValue(StrokeMiterLimitProperty); }
|
||||
set { SetValue(StrokeMiterLimitProperty, value); }
|
||||
}
|
||||
|
||||
protected Pen Pen
|
||||
{
|
||||
get
|
||||
{
|
||||
if (pen.Brush == null)
|
||||
{
|
||||
pen.Brush = Foreground;
|
||||
}
|
||||
|
||||
return pen;
|
||||
}
|
||||
}
|
||||
|
||||
protected Typeface Typeface
|
||||
{
|
||||
get
|
||||
{
|
||||
if (typeface == null)
|
||||
{
|
||||
typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
|
||||
}
|
||||
|
||||
return typeface;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnViewportChanged()
|
||||
{
|
||||
InvalidateVisual();
|
||||
}
|
||||
|
||||
private void ForegroundChanged(Brush foreground)
|
||||
{
|
||||
if (Stroke == null)
|
||||
{
|
||||
pen.Brush = foreground;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,11 +14,11 @@ namespace MapControl
|
|||
public class MapPolygon : MapPolyline
|
||||
{
|
||||
public static readonly DependencyProperty FillProperty = Shape.FillProperty.AddOwner(
|
||||
typeof(MapPolygon), new FrameworkPropertyMetadata((o, e) => ((MapPolygon)o).drawing.Brush = (Brush)e.NewValue));
|
||||
typeof(MapPolygon), new FrameworkPropertyMetadata((o, e) => ((MapPolygon)o).Drawing.Brush = (Brush)e.NewValue));
|
||||
|
||||
public MapPolygon()
|
||||
{
|
||||
drawing.Brush = Fill;
|
||||
Drawing.Brush = Fill;
|
||||
}
|
||||
|
||||
public Brush Fill
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@
|
|||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
|
|
@ -13,54 +15,68 @@ namespace MapControl
|
|||
/// <summary>
|
||||
/// An open map polygon, defined by a collection of geographic locations in the Locations property.
|
||||
/// </summary>
|
||||
public class MapPolyline : MapElement
|
||||
public class MapPolyline : FrameworkElement
|
||||
{
|
||||
public static readonly DependencyProperty StrokeProperty = Shape.StrokeProperty.AddOwner(
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata(Brushes.Black, (o, e) => ((MapPolyline)o).drawing.Pen.Brush = (Brush)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty StrokeDashArrayProperty = Shape.StrokeDashArrayProperty.AddOwner(
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).drawing.Pen.DashStyle = new DashStyle((DoubleCollection)e.NewValue, ((MapPolyline)o).StrokeDashOffset)));
|
||||
|
||||
public static readonly DependencyProperty StrokeDashOffsetProperty = Shape.StrokeDashOffsetProperty.AddOwner(
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).drawing.Pen.DashStyle = new DashStyle(((MapPolyline)o).StrokeDashArray, (double)e.NewValue)));
|
||||
|
||||
public static readonly DependencyProperty StrokeDashCapProperty = Shape.StrokeDashCapProperty.AddOwner(
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).drawing.Pen.DashCap = (PenLineCap)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty StrokeStartLineCapProperty = Shape.StrokeStartLineCapProperty.AddOwner(
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).drawing.Pen.StartLineCap = (PenLineCap)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty StrokeEndLineCapProperty = Shape.StrokeEndLineCapProperty.AddOwner(
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).drawing.Pen.EndLineCap = (PenLineCap)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty StrokeLineJoinProperty = Shape.StrokeLineJoinProperty.AddOwner(
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).drawing.Pen.LineJoin = (PenLineJoin)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty StrokeMiterLimitProperty = Shape.StrokeMiterLimitProperty.AddOwner(
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).drawing.Pen.MiterLimit = (double)e.NewValue));
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).Drawing.Pen.Brush = (Brush)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty StrokeThicknessProperty = Shape.StrokeThicknessProperty.AddOwner(
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).UpdatePenThickness()));
|
||||
typeof(MapPolyline));
|
||||
|
||||
public static readonly DependencyProperty StrokeDashArrayProperty = Shape.StrokeDashArrayProperty.AddOwner(
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).Drawing.Pen.DashStyle = new DashStyle((DoubleCollection)e.NewValue, ((MapPolyline)o).StrokeDashOffset)));
|
||||
|
||||
public static readonly DependencyProperty StrokeDashOffsetProperty = Shape.StrokeDashOffsetProperty.AddOwner(
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).Drawing.Pen.DashStyle = new DashStyle(((MapPolyline)o).StrokeDashArray, (double)e.NewValue)));
|
||||
|
||||
public static readonly DependencyProperty StrokeDashCapProperty = Shape.StrokeDashCapProperty.AddOwner(
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).Drawing.Pen.DashCap = (PenLineCap)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty StrokeStartLineCapProperty = Shape.StrokeStartLineCapProperty.AddOwner(
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).Drawing.Pen.StartLineCap = (PenLineCap)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty StrokeEndLineCapProperty = Shape.StrokeEndLineCapProperty.AddOwner(
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).Drawing.Pen.EndLineCap = (PenLineCap)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty StrokeLineJoinProperty = Shape.StrokeLineJoinProperty.AddOwner(
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).Drawing.Pen.LineJoin = (PenLineJoin)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty StrokeMiterLimitProperty = Shape.StrokeMiterLimitProperty.AddOwner(
|
||||
typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).Drawing.Pen.MiterLimit = (double)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty TransformStrokeProperty = DependencyProperty.Register(
|
||||
"TransformStroke", typeof(bool), typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).UpdatePenThickness()));
|
||||
"TransformStroke", typeof(bool), typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).SetPenThicknessBinding()));
|
||||
|
||||
public static readonly DependencyProperty LocationsProperty = DependencyProperty.Register(
|
||||
"Locations", typeof(LocationCollection), typeof(MapPolyline), new FrameworkPropertyMetadata((o, e) => ((MapPolyline)o).UpdateGeometry()));
|
||||
|
||||
protected readonly DrawingVisual visual = new DrawingVisual();
|
||||
protected readonly GeometryDrawing drawing = new GeometryDrawing();
|
||||
protected readonly GeometryDrawing Drawing = new GeometryDrawing();
|
||||
|
||||
static MapPolyline()
|
||||
{
|
||||
MapPanel.ParentMapPropertyKey.OverrideMetadata(
|
||||
typeof(MapPolyline),
|
||||
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, ParentMapPropertyChanged));
|
||||
}
|
||||
|
||||
public MapPolyline()
|
||||
{
|
||||
drawing.Pen = new Pen(Stroke, StrokeThickness);
|
||||
|
||||
using (DrawingContext drawingContext = visual.RenderOpen())
|
||||
Drawing.Pen = new Pen
|
||||
{
|
||||
drawingContext.DrawDrawing(drawing);
|
||||
}
|
||||
Brush = Stroke,
|
||||
Thickness = StrokeThickness,
|
||||
DashStyle = new DashStyle(StrokeDashArray, StrokeDashOffset),
|
||||
DashCap = StrokeDashCap,
|
||||
StartLineCap = StrokeStartLineCap,
|
||||
EndLineCap = StrokeEndLineCap,
|
||||
LineJoin = StrokeLineJoin,
|
||||
MiterLimit = StrokeMiterLimit
|
||||
};
|
||||
}
|
||||
|
||||
Loaded += (o, e) => UpdateGeometry();
|
||||
public MapBase ParentMap
|
||||
{
|
||||
get { return MapPanel.GetParentMap(this); }
|
||||
}
|
||||
|
||||
public Brush Stroke
|
||||
|
|
@ -69,6 +85,12 @@ namespace MapControl
|
|||
set { SetValue(StrokeProperty, value); }
|
||||
}
|
||||
|
||||
public double StrokeThickness
|
||||
{
|
||||
get { return (double)GetValue(StrokeThicknessProperty); }
|
||||
set { SetValue(StrokeThicknessProperty, value); }
|
||||
}
|
||||
|
||||
public DoubleCollection StrokeDashArray
|
||||
{
|
||||
get { return (DoubleCollection)GetValue(StrokeDashArrayProperty); }
|
||||
|
|
@ -111,12 +133,6 @@ namespace MapControl
|
|||
set { SetValue(StrokeMiterLimitProperty, value); }
|
||||
}
|
||||
|
||||
public double StrokeThickness
|
||||
{
|
||||
get { return (double)GetValue(StrokeThicknessProperty); }
|
||||
set { SetValue(StrokeThicknessProperty, value); }
|
||||
}
|
||||
|
||||
public bool TransformStroke
|
||||
{
|
||||
get { return (bool)GetValue(TransformStrokeProperty); }
|
||||
|
|
@ -129,43 +145,19 @@ namespace MapControl
|
|||
set { SetValue(LocationsProperty, value); }
|
||||
}
|
||||
|
||||
public double TransformedStrokeThickness
|
||||
{
|
||||
get { return drawing.Pen.Thickness; }
|
||||
}
|
||||
|
||||
public PathGeometry TransformedGeometry
|
||||
{
|
||||
get { return drawing.Geometry as PathGeometry; }
|
||||
get { return Drawing.Geometry as PathGeometry; }
|
||||
}
|
||||
|
||||
protected override int VisualChildrenCount
|
||||
public double TransformedStrokeThickness
|
||||
{
|
||||
get { return 1; }
|
||||
get { return Drawing.Pen.Thickness; }
|
||||
}
|
||||
|
||||
protected override Visual GetVisualChild(int index)
|
||||
protected override void OnRender(DrawingContext drawingContext)
|
||||
{
|
||||
return visual;
|
||||
}
|
||||
|
||||
protected override void OnInitialized(EventArgs e)
|
||||
{
|
||||
base.OnInitialized(e);
|
||||
|
||||
AddVisualChild(visual);
|
||||
}
|
||||
|
||||
protected override void OnViewportChanged()
|
||||
{
|
||||
double scale = 1d;
|
||||
|
||||
if (TransformStroke)
|
||||
{
|
||||
scale = ParentMap.CenterScale * MapBase.MeterPerDegree;
|
||||
}
|
||||
|
||||
drawing.Pen.Thickness = scale * StrokeThickness;
|
||||
drawingContext.DrawDrawing(Drawing);
|
||||
}
|
||||
|
||||
protected virtual void UpdateGeometry()
|
||||
|
|
@ -177,20 +169,11 @@ namespace MapControl
|
|||
{
|
||||
if (ParentMap != null && Locations != null && Locations.Count > 0)
|
||||
{
|
||||
drawing.Geometry = CreateGeometry(Locations, closed);
|
||||
OnViewportChanged();
|
||||
Drawing.Geometry = CreateGeometry(Locations, closed);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawing.Geometry = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePenThickness()
|
||||
{
|
||||
if (ParentMap != null)
|
||||
{
|
||||
OnViewportChanged();
|
||||
Drawing.Geometry = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -213,5 +196,44 @@ namespace MapControl
|
|||
|
||||
return geometry;
|
||||
}
|
||||
|
||||
private void SetPenThicknessBinding()
|
||||
{
|
||||
BindingBase binding = new Binding { Source = this, Path = new PropertyPath(MapPolyline.StrokeThicknessProperty)};
|
||||
|
||||
if (TransformStroke && ParentMap != null)
|
||||
{
|
||||
MultiBinding multiBinding = new MultiBinding { Converter = new PenThicknessConverter() };
|
||||
multiBinding.Bindings.Add(binding);
|
||||
multiBinding.Bindings.Add(new Binding { Source = ParentMap, Path = new PropertyPath(MapBase.CenterScaleProperty)});
|
||||
binding = multiBinding;
|
||||
}
|
||||
|
||||
BindingOperations.SetBinding(Drawing.Pen, Pen.ThicknessProperty, binding);
|
||||
}
|
||||
|
||||
private static void ParentMapPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
MapPolyline polyline = obj as MapPolyline;
|
||||
|
||||
if (polyline != null)
|
||||
{
|
||||
polyline.UpdateGeometry();
|
||||
polyline.SetPenThicknessBinding();
|
||||
}
|
||||
}
|
||||
|
||||
private class PenThicknessConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return (double)values[0] * (double)values[1] * MapBase.MeterPerDegree;
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
92
MapControl/MapScale.cs
Normal file
92
MapControl/MapScale.cs
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
|
||||
// Copyright © 2012 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Draws a map scale overlay.
|
||||
/// </summary>
|
||||
public class MapScale : MapOverlay
|
||||
{
|
||||
public static readonly DependencyProperty PaddingProperty = Control.PaddingProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata(new Thickness(2d)));
|
||||
|
||||
private double length;
|
||||
private Size size;
|
||||
|
||||
static MapScale()
|
||||
{
|
||||
FrameworkElement.MinWidthProperty.OverrideMetadata(
|
||||
typeof(MapScale), new FrameworkPropertyMetadata(100d));
|
||||
|
||||
FrameworkElement.HorizontalAlignmentProperty.OverrideMetadata(
|
||||
typeof(MapScale), new FrameworkPropertyMetadata(HorizontalAlignment.Right));
|
||||
|
||||
FrameworkElement.VerticalAlignmentProperty.OverrideMetadata(
|
||||
typeof(MapScale), new FrameworkPropertyMetadata(VerticalAlignment.Bottom));
|
||||
|
||||
MapOverlay.StrokeStartLineCapProperty.OverrideMetadata(
|
||||
typeof(MapScale), new FrameworkPropertyMetadata(PenLineCap.Round));
|
||||
|
||||
MapOverlay.StrokeEndLineCapProperty.OverrideMetadata(
|
||||
typeof(MapScale), new FrameworkPropertyMetadata(PenLineCap.Round));
|
||||
}
|
||||
|
||||
public Thickness Padding
|
||||
{
|
||||
get { return (Thickness)GetValue(PaddingProperty); }
|
||||
set { SetValue(PaddingProperty, value); }
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
double scale = ParentMap.CenterScale; // px/m
|
||||
length = MinWidth / scale;
|
||||
double 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 * scale + StrokeThickness + Padding.Left + Padding.Right;
|
||||
size.Height = FontSize + 2d * StrokeThickness + Padding.Top + Padding.Bottom;
|
||||
return size;
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext drawingContext)
|
||||
{
|
||||
double x1 = Padding.Left + StrokeThickness / 2d;
|
||||
double x2 = size.Width - Padding.Right - StrokeThickness / 2d;
|
||||
double y1 = size.Height / 2d;
|
||||
double y2 = size.Height - Padding.Bottom - StrokeThickness / 2d;
|
||||
string text = length >= 1000d ? string.Format("{0:0} km", length / 1000d) : string.Format("{0:0} m", length);
|
||||
|
||||
drawingContext.DrawRectangle(Background ?? ParentMap.Background, null, new Rect(size));
|
||||
drawingContext.DrawLine(Pen, new Point(x1, y1), new Point(x1, y2));
|
||||
drawingContext.DrawLine(Pen, new Point(x2, y1), new Point(x2, y2));
|
||||
drawingContext.DrawLine(Pen, new Point(x1, y2), new Point(x2, y2));
|
||||
drawingContext.DrawGlyphRun(Foreground,
|
||||
GlyphRunText.Create(text, Typeface, FontSize, new Vector(size.Width / 2d, y1 - StrokeThickness - 1d)));
|
||||
}
|
||||
|
||||
protected override void OnViewportChanged()
|
||||
{
|
||||
InvalidateMeasure();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -136,6 +136,7 @@
|
|||
ManipulationInertiaStarting="MapManipulationInertiaStarting"
|
||||
MouseMove="MapMouseMove" MouseLeave="MapMouseLeave">
|
||||
<map:MapGraticule Opacity="0.6"/>
|
||||
<map:MapScale Margin="4" Opacity="0.8"/>
|
||||
<map:MapItemsControl ItemsSource="{StaticResource Polylines}"
|
||||
ItemTemplate="{StaticResource PolylineItemTemplate}"/>
|
||||
<map:MapItemsControl ItemsSource="{StaticResource Points}"
|
||||
|
|
@ -152,7 +153,7 @@
|
|||
</MultiBinding>
|
||||
</map:Pushpin.Visibility>
|
||||
</map:Pushpin>
|
||||
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="2,0,0,0" FontSize="10"
|
||||
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="4" FontSize="10"
|
||||
Text="{Binding BaseTileLayer.Description, ElementName=map}"/>
|
||||
</map:Map>
|
||||
<Grid Grid.Row="1" Margin="2">
|
||||
|
|
|
|||
|
|
@ -10,17 +10,17 @@ namespace SampleApplication
|
|||
{
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
Visibility visibility = Visibility.Visible;
|
||||
Visibility visibility = Visibility.Hidden;
|
||||
|
||||
if (values.Length == 2 && values[0] is Map && values[1] is Point? && ((Point?)values[1]).HasValue)
|
||||
{
|
||||
Map parentMap = (Map)values[0];
|
||||
Point position = ((Point?)values[1]).Value;
|
||||
|
||||
if (position.X < 0d || position.X > parentMap.ActualWidth ||
|
||||
position.Y < 0d || position.Y > parentMap.ActualHeight)
|
||||
if (position.X >= 0d && position.X <= parentMap.ActualWidth &&
|
||||
position.Y >= 0d && position.Y <= parentMap.ActualHeight)
|
||||
{
|
||||
visibility = Visibility.Hidden;
|
||||
visibility = Visibility.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue