WPF简易局部地图 实现标记 绘制轨迹

WPF简易局部地图 实现标记 绘制轨迹

控件可以实现:
在知道显示的地图区域时:

  1. 设定地图的左上角和右下角经纬度;
  2. 设置使用的地图图片路径;
  3. 添加地图图钉或者轨迹点;
  4. 绘制点或轨迹。
    在这里插入图片描述

地图控件所需的数据结构:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;

namespace SmartScreen.Controls.Models
{
    public class MapItem
    {
        public Brush Fill {  get; protected set; }
    }

    public class GeoPint
    {
        public GeoPint(double lat, double lon)
        {
            Latitude = lat;
            Longitude = lon;
        }
        public double Latitude { get; set; }
        public double Longitude { get; set; }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SmartScreen.Controls.Models
{
    public class MapPolyLineItem : MapItem
    {
        public double Longitude { get; set; }
        public double Latitude { get; set; }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;

namespace SmartScreen.Controls.Models
{
    public class MapPushPinItem : MapItem
    {
        public string Title { get; set; }
        public double Longitude { get; set; }
        public double Latitude { get; set; }

        private int warnningStatus;
        /// <summary>
        /// 警示状态,0:安全 1:预警 -1:警告
        /// </summary>
        public int WarnningStatus
        {
            get { return warnningStatus; }
            set
            {
                warnningStatus = value;
                if (warnningStatus == 0)
                {
                    Fill = (SolidColorBrush)Application.Current.FindResource("SafeColor");
                }
                else if (warnningStatus == 1)
                {
                    Fill = (SolidColorBrush)Application.Current.FindResource("WarnningColor");
                }
                else if (warnningStatus == -1)
                {

                    Fill = (SolidColorBrush)Application.Current.FindResource("DangerColor");
                }
            }
        }

    }
}

地图控件XAML(可以去掉zoomPanel:ZoomAndPanControl):

<UserControl x:Class="SmartScreen.Controls.MapControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:SmartScreen.Controls" xmlns:zoomPanel="clr-namespace:ZoomAndPan;assembly=ZoomAndPan"
             mc:Ignorable="d" 
             x:Name="root"
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>
        <Style TargetType="Line">
            <Setter Property="Stroke" Value="{StaticResource DangerColor}"/>
            <Setter Property="StrokeThickness" Value="2"/>
            <Setter Property="Effect">
                <Setter.Value>
                    <DropShadowEffect Color="Gray" BlurRadius="8" ShadowDepth="0"/>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>
    <Grid>
        <zoomPanel:ZoomAndPanControl x:Name="zoomPanel"  
                                     MouseWheel="map_MouseWheel"
                                     MaxContentScale="2.5"
                                     MinContentScale="1"
                                     MouseLeftButtonDown="Grid_MouseLeftButtonDown" 
                                     MouseLeftButtonUp="Grid_MouseLeftButtonUp" 
                                     MouseMove="Grid_MouseMove">
            <zoomPanel:ZoomAndPanControl.RenderTransform>
                <TransformGroup>
                    <TranslateTransform x:Name="trans"/>
                    <ScaleTransform x:Name="scale"/>
                </TransformGroup>
            </zoomPanel:ZoomAndPanControl.RenderTransform>
            <Grid>
                <Image x:Name="bottomImage" Width="{Binding ElementName=root,Path=ActualWidth}" Height="{Binding ElementName=root,Path=ActualHeight}" 
               Stretch="Fill" RenderOptions.BitmapScalingMode="Fant"/>
                <!--标记层 ../Images/maptest.png-->
                <Canvas x:Name="PushPincanvas">
                </Canvas>
                <Canvas x:Name="PolyLinecanvas">
                </Canvas>
            </Grid>
        </zoomPanel:ZoomAndPanControl>
    </Grid>
</UserControl>

    

地图控件后台代码:

using SmartScreen.Controls.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SmartScreen.Controls
{
    /// <summary>
    /// MapControl.xaml 的交互逻辑
    /// </summary>
    public partial class MapControl : UserControl
    {
        public MapControl()
        {
            InitializeComponent();
            SizeChanged += (s, e) => { RefreshPushPin(); RefreshPolyline(); };
        }

        /// <summary>
        /// 地图图片的路径
        /// </summary>
        public Uri MapPath
        {
            get { return (Uri)GetValue(MapPathProperty); }
            set { SetValue(MapPathProperty, value); }
        }
        public static readonly DependencyProperty MapPathProperty =
            DependencyProperty.Register("MapPath", typeof(Uri), typeof(MapControl), new PropertyMetadata(default(Uri), OnMapPathChanged));

        private static void OnMapPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MapControl ctrl = (MapControl)d;
            ctrl.bottomImage.Source = new BitmapImage(ctrl.MapPath);
        }

        /// <summary>
        /// 左上角经纬度
        /// </summary>
        public Point LeftTop
        {
            get { return (Point)GetValue(LeftTopProperty); }
            set { SetValue(LeftTopProperty, value); }
        }
        public static readonly DependencyProperty LeftTopProperty =
            DependencyProperty.Register("LeftTop", typeof(Point), typeof(MapControl), new PropertyMetadata(default(Point), OnMapReDrawChanged));

        /// <summary>
        /// 右下角经纬度
        /// </summary>
        public Point RightBottom
        {
            get { return (Point)GetValue(RightBottomProperty); }
            set { SetValue(RightBottomProperty, value); }
        }
        public static readonly DependencyProperty RightBottomProperty =
            DependencyProperty.Register("RightBottom", typeof(Point), typeof(MapControl), new PropertyMetadata(default(Point), OnMapReDrawChanged));



        /// <summary>
        /// 地图显示的图钉部件
        /// </summary>
        public ObservableCollection<MapPushPinItem> PushPins
        {
            get { return (ObservableCollection<MapPushPinItem>)GetValue(PushPinsProperty); }
            set { SetValue(PushPinsProperty, value); }
        }
        public static readonly DependencyProperty PushPinsProperty =
            DependencyProperty.Register("PushPins", typeof(ObservableCollection<MapPushPinItem>), typeof(MapControl), new PropertyMetadata(null, OnPushpinChanged));

        private static void OnPushpinChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is MapControl map)
            {
                if (map.PushPins != null)
                {
                    map.PushPins.CollectionChanged += (s, er) => map.RefreshPushPin();
                }
                map.RefreshPushPin();
            }
        }


        /// <summary>
        /// 地图显示的轨迹线段
        /// </summary>
        public ObservableCollection<MapPolyLineItem> PolyLines
        {
            get { return (ObservableCollection<MapPolyLineItem>)GetValue(PolyLinesProperty); }
            set { SetValue(PolyLinesProperty, value); }
        }
        public static readonly DependencyProperty PolyLinesProperty =
            DependencyProperty.Register("PolyLines", typeof(ObservableCollection<MapPolyLineItem>), typeof(MapControl), new PropertyMetadata(null, OnPolyLineChaned));

        private static void OnPolyLineChaned(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is MapControl map)
            {
                if (map.PolyLines != null)
                {
                    map.PolyLines.CollectionChanged += (s, er) => map.RefreshPolyline();
                }
                map.RefreshPolyline();
            }
        }

        private static void OnMapReDrawChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MapControl control = (MapControl)d;
            control.RefreshPushPin();
            control.RefreshPolyline();
        }

        /// <summary>
        /// 刷新标记点的显示
        /// </summary>
        private void RefreshPushPin()
        {
            if (RightBottom == default(Point) || LeftTop == default(Point))
            {
                return;
            }

            var mapWidth = ActualWidth;
            var mapHeight = ActualHeight;
            var xRange = RightBottom.X - LeftTop.X;
            var yRange = LeftTop.Y - RightBottom.Y;

            if (PushPins != null)
            {
                PushPincanvas.Children.Clear();

                foreach (var pushpin in PushPins)
                {
                    // 先计算在X Y 轴上的位置
                    var canvasLeft = (pushpin.Longitude - LeftTop.X) / xRange * mapWidth;
                    var canvasTop = (LeftTop.Y - pushpin.Latitude) / yRange * mapHeight;
                    var pushpinCtrl = new MapPushPin();
                    pushpinCtrl.DataContext = pushpin;
                    Canvas.SetLeft(pushpinCtrl, canvasLeft);
                    Canvas.SetTop(pushpinCtrl, canvasTop);
                    PushPincanvas.Children.Add(pushpinCtrl);
                }
            }
        }

        /// <summary>
        /// 刷新轨迹的显示
        /// </summary>
        private void RefreshPolyline()
        {
            if (RightBottom == default(Point) || LeftTop == default(Point))
            {
                return;
            }

            var mapWidth = ActualWidth;
            var mapHeight = ActualHeight;
            var xRange = RightBottom.X - LeftTop.X;
            var yRange = LeftTop.Y - RightBottom.Y;
            if (PolyLines != null)
            {
                PolyLinecanvas.Children.Clear();
                MapPolyLineItem lastPoint = null;
                foreach (var polyline in PolyLines)
                {
                    if (lastPoint == null)
                    {
                        lastPoint = polyline;
                        continue;
                    }

                    Line line = new Line();
                    line.DataContext = polyline;
                    line.X1 = 0;
                    line.Y1 = 0;

                    var canvasLeft = (lastPoint.Longitude - LeftTop.X) / xRange * mapWidth;
                    var canvasTop = (LeftTop.Y - lastPoint.Latitude) / yRange * mapHeight;

                    var point2x = (polyline.Longitude - LeftTop.X) / xRange * mapWidth - canvasLeft;
                    var point2y = (LeftTop.Y - polyline.Latitude) / yRange * mapHeight - canvasTop;
                    line.X2 = point2x;
                    line.Y2 = point2y;

                    Canvas.SetLeft(line, canvasLeft);
                    Canvas.SetTop(line, canvasTop);
                    PolyLinecanvas.Children.Add(line);

                    lastPoint = polyline;
                }
            }
        }

        #region 缩放移动

        public FrameworkElement Container
        {
            get { return (FrameworkElement)GetValue(ContainerProperty); }
            set { SetValue(ContainerProperty, value); }
        }
        public static readonly DependencyProperty ContainerProperty =
            DependencyProperty.Register("Container", typeof(FrameworkElement), typeof(MapControl), new PropertyMetadata(null));



        public bool EnableZoomPan
        {
            get { return (bool)GetValue(EnableZoomPanProperty); }
            set { SetValue(EnableZoomPanProperty, value); }
        }

        public static readonly DependencyProperty EnableZoomPanProperty =
            DependencyProperty.Register("EnableZoomPan", typeof(bool), typeof(MapControl), new PropertyMetadata(false));


        Point lastPoint = default;

        private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (!EnableZoomPan)
            {
                return;
            }
            lastPoint = e.GetPosition(Container);
            zoomPanel.CaptureMouse();
        }

        private void Grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (!EnableZoomPan)
            {
                return;
            }

            lastPoint = default;
            zoomPanel.ReleaseMouseCapture();
        }

        private void Grid_MouseMove(object sender, MouseEventArgs e)
        {
            if (!EnableZoomPan)
            {
                return;
            }

            if (e.LeftButton == MouseButtonState.Pressed)
            {
                var nowPoint = e.GetPosition(Container);

                if (lastPoint == default)
                {
                    lastPoint = nowPoint;
                    return;
                }
                var offsetX = (nowPoint.X - lastPoint.X) / scale.ScaleX;
                var offsetY = (nowPoint.Y - lastPoint.Y) / scale.ScaleX;

                lastPoint = nowPoint;
                trans.X += offsetX;
                trans.Y += offsetY;
            }
        }

        private void map_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (!EnableZoomPan)
            {
                return;
            }

            var nowMouse = e.GetPosition(this);

            if (e.Delta > 0)
            {
                zoomPanel.ZoomIn(nowMouse);
            }
            else
            {
                zoomPanel.ZoomOut(nowMouse);
            }

            if (zoomPanel.ContentScale == 1)
            {
                trans.X = 0;
                trans.Y = 0;
            }
        }
        #endregion

    }
}

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
利用GMap实现运动轨迹,可以通过在地图上添加Marker,并设置Marker的位置来实现。具体步骤如下: 1. 在XAML文件中,定义一个GMapControl控件,并设置属性,比如地图类型、中心点坐标、缩放级别等。 ``` <local:GMapControl x:Name="gMapControl" MapType="GoogleMap" Center="39.9087, 116.3975" Zoom="12"/> ``` 2. 在代码中,定义一个List<Marker>类型的变量,用于存储所有的Marker,以便于后续操作。 ``` List<Marker> markers = new List<Marker>(); ``` 3. 在代码中,定义一个定时器,用于更新Marker的位置。在定时器的Tick事件中,更新Marker的位置,并重新设置Marker的位置。 ``` private void timer_Tick(object sender, EventArgs e) { // 更新Marker的位置 double lat = ...; // 获取当前的纬度 double lng = ...; // 获取当前的经度 // 设置Marker的位置 markers[0].Position = new PointLatLng(lat, lng); // 刷新地图 gMapControl.Refresh(); } ``` 4. 在代码中,添加Marker,并将Marker添加到List<Marker>变量中。 ``` // 添加Marker GMapMarker marker = new GMapMarker(new PointLatLng(lat, lng)); marker.Shape = new Ellipse { Width = 10, Height = 10, Fill = Brushes.Red }; // 将Marker添加到List<Marker>变量中 markers.Add(marker); // 在地图上添加Marker gMapControl.Markers.Add(marker); ``` 5. 启动定时器,即可在地图上看到运动轨迹。 ``` // 启动定时器 timer.Start(); ``` 通过以上步骤,即可利用GMap实现运动轨迹的效果。需要注意的是,定时器的间隔时间要根据实际情况进行调整,以达到更好的效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不知名君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值