WindowsPhone开发—— 使用手绘图片做景区导览地图

  前些日子在做景区App遇到需求,使用手绘图片做一个简易的地图,支持放大缩小平移以及显示景点Mark,安卓上可以使用一个叫做“mAppWidget”的开源库来完成,WP上有人建议用ArcGIS,但是考虑到只是简单的放大缩小平移以及展示Mark标记,没必要再去花费精力去大费周折的研究ArcGIS,于是就各种搜索WP下的放大缩小平移图片的文章,还好很庆幸找到一篇(连接地址给忘记了原作者如果看到的话希望能提醒下给加上原链接)。解决了对图片放大缩小平移的问题,剩下的就是在上面添加Mark标记点了以及解决每次放大缩小后的Mark重新定位的问题。不多说。上代码!

 

前端XAML:

    <!--LayoutRoot 是包含所有页面内容的根网格-->

    <Grid x:Name="LayoutRoot" Background="White">

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto"/>

            <RowDefinition Height="*"/>

        </Grid.RowDefinitions>

        <Border Padding="12,12,0,18"  Grid.Row="0" Style="{StaticResource SinglePageHeardStyle}"  >

            <TextBlock FontSize="28" Text="地图导览"/>

        </Border>



        <Grid x:Name="ContentPanel" Grid.Row="1" >

            <ViewportControl  x:Name="Viewport" HorizontalAlignment="Left" VerticalAlignment="Top">

                <Canvas x:Name="can_Map" Width="480" Height="800">

                    <Image x:Name="Image" Stretch="Uniform"

                       CacheMode="BitmapCache"

                       ManipulationStarted="Viewport_ManipulationStarted" 

                       ManipulationDelta="Viewport_ManipulationDelta"

                       ManipulationCompleted="Viewport_ManipulationCompleted" >

                    </Image>

                </Canvas>

            </ViewportControl>

        </Grid>

    </Grid>



  

后台cs:

    public partial class MapPage : PhoneApplicationPage

    {

        private const double IMAGE_MAX_WIDTH = 2048;



        private const double IMAGE_MAX_HEIGHT = 2048;



        private double _width = 0;



        private double _height = 0;



        private double _scale = 1.0;

        private Point _relativeCenter;

        private bool _pinching = false;



        private WriteableBitmap _writeableBitmap;



        public MapPage()

        {

            InitializeComponent();

            this.Loaded += MainPage_Loaded;

        }



        private void MainPage_Loaded(object sender, RoutedEventArgs e)

        {

            var bitmapImage = GetImgForRes();

            _writeableBitmap = new WriteableBitmap(bitmapImage);



            double scale;



            if (_writeableBitmap.PixelWidth > _writeableBitmap.PixelHeight)

            {

                scale = IMAGE_MAX_WIDTH / _writeableBitmap.PixelWidth;

            }

            else

            {

                scale = IMAGE_MAX_HEIGHT / _writeableBitmap.PixelHeight;

            }



            _width = _writeableBitmap.PixelWidth * scale;

            _height = _writeableBitmap.PixelHeight * scale;







            this.Image.Source = _writeableBitmap;

            ConfigureViewport();



            App.MapViewModel.GetSp(App.GetUserAcction());

            App.MapViewModel.GetMapSpCompleted += () =>

            {

                foreach (var item in App.MapViewModel.ScencParentByMobile.Data)

                {

                    //计算当前每个Mark的宽高与当前手绘图片的宽高缩放比例

                    item.Sh = (item.MapY -30) / _height;

                    item.Sw = (item.MapX - 30) / _width;

                    Image el = new Image();

                    //SetLeft 和SetTop 是根据元素的(0,0)点坐标开始的 所以放置坐标Mark的时候要减去元素宽的一半和元素高度

                    Canvas.SetLeft(el, (Image.Width * item.Sw) - 30);

                    Canvas.SetTop(el, (Image.Height * item.Sh) - 60);

                    el.Height = el.Width = 60;

                    el.Stretch = Stretch.Uniform;

                    //根据业务区选择加载哪个图片

                    if (item.IsFlag == 1)

                        el.Source = new BitmapImage(new Uri("/MapPage/[email protected]", UriKind.RelativeOrAbsolute));

                    else

                        el.Source = new BitmapImage(new Uri("/MapPage/[email protected]", UriKind.RelativeOrAbsolute));

                    el.Tag = item.SCID + "|" + item.Sw + "|" + item.Sh;   //记录每个Mark的id 宽高缩放比例到Tag以备用

                    can_Map.Children.Add(el);

                }

            };

        }



        private void ConfigureViewport()

        {

            if (_width < _height)

            {

                _scale = Viewport.ActualHeight / _height;

            }

            else

            {

                _scale = Viewport.ActualWidth / _width;

            }



            Image.Width = _width * _scale;

            Image.Height = _height * _scale;



            Viewport.Bounds = new Rect(0, 0, Image.Width, Image.Height);

            Viewport.SetViewportOrigin(new Point(Image.Width / 2 - Viewport.Viewport.Width / 2, Image.Height / 2 - Viewport.Viewport.Height / 2));



        }



        private static BitmapImage GetImgForRes()

        {

            string fileName = "/QWCProject;component/MapPage/map.jpg";



            using (Stream stream = Application.GetResourceStream(new Uri(fileName, UriKind.Relative)).Stream)

            {

                BitmapImage bitmapImage = new BitmapImage();

                bitmapImage.SetSource(stream);

                return bitmapImage;

            }

        }



        private void Viewport_ManipulationStarted(object sender, System.Windows.Input.ManipulationStartedEventArgs e)

        {

            if (_pinching)

            {

                e.Handled = true;



                CompletePinching();

            }

        }



        private void CompletePinching()

        {

            _pinching = false;



            double sw = Image.Width / _width;

            double sh = Image.Height / _height;



            _scale = Math.Min(sw, sh);



            //完成缩放放大后获取所有Mark点集合

            var markList = WPTools.VisualTreeTool.GetChildObjects<Image>(can_Map, typeof(Image));

            foreach (var item in markList)

            {

                //过滤手绘图片

                if (item.Tag == null)

                    continue;

                //根据当前Image(手绘图片)的宽高乘以该Mark的坐标缩放比例得出缩放放大后的每个Mark的坐标

                Canvas.SetLeft(item, (Image.Width * double.Parse(item.Tag.ToString().Split('|')[1])) - 30);

                Canvas.SetTop(item, (Image.Height * double.Parse(item.Tag.ToString().Split('|')[2])) - 60);

                item.Visibility = Visibility.Visible;

            }

        }



        private void Viewport_ManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)

        {

            if (e.PinchManipulation != null)

            {

                //获取所有Mark 在缩放放大时候隐藏所有Mark

                var markList = WPTools.VisualTreeTool.GetChildObjects<Image>(can_Map, typeof(Image));

                foreach (var item in markList)

                {

                    if (item.Tag == null)

                        continue;

                    item.Visibility = Visibility.Collapsed;

                }



                e.Handled = true;



                if (!_pinching)

                {

                    _pinching = true;



                    _relativeCenter = new Point(e.PinchManipulation.Original.Center.X / Image.Width, e.PinchManipulation.Original.Center.Y / Image.Height);

                }



                double w, h;



                if (_width < _height)

                {

                    h = _height * _scale * e.PinchManipulation.CumulativeScale;

                    h = Math.Max(Viewport.ActualHeight, h);

                    h = Math.Min(h, _height);



                    w = h * _width / _height;

                }

                else

                {

                    w = _width * _scale * e.PinchManipulation.CumulativeScale;

                    w = Math.Max(Viewport.ActualWidth, w);

                    w = Math.Min(w, _width);



                    h = w * _height / _width;

                }



                Image.Width = w;

                Image.Height = h;



                Viewport.Bounds = new Rect(0, 0, w, h);







                GeneralTransform transform = Image.TransformToVisual(Viewport);

                Point p = transform.Transform(e.PinchManipulation.Original.Center);



                double x = _relativeCenter.X * w - p.X;

                double y = _relativeCenter.Y * h - p.Y;



                if (w < _width && h < _height)

                {

                    System.Diagnostics.Debug.WriteLine("Viewport.ActualWidth={0} .ActualHeight={1} Origin.X={2} .Y={3} Image.Width={4} .Height={5}",

                        Viewport.ActualWidth, Viewport.ActualHeight, x, y, Image.Width, Image.Height);



                    Viewport.SetViewportOrigin(new Point(x, y));





                }

            }

            else if (_pinching)

            {

                e.Handled = true;



                CompletePinching();

            }

        }



        private void Viewport_ManipulationCompleted(object sender, System.Windows.Input.ManipulationCompletedEventArgs e)

        {

            if (_pinching)

            {

                e.Handled = true;



                CompletePinching();

            }

        }

    }

  

 

另外还有个获取指定元素下的所有指定类型子元素的方法:

      public static List<T> GetChildObjects<T>(DependencyObject obj, Type typename) where T : FrameworkElement

        {

            DependencyObject child = null;

            List<T> childList = new List<T>();



            for (int i = 0; i <= VisualTreeHelper.GetChildrenCount(obj) - 1; i++)

            {

                child = VisualTreeHelper.GetChild(obj, i);



                if (child is T && (((T)child).GetType() == typename))

                {

                    childList.Add((T)child);

                }

                childList.AddRange(GetChildObjects<T>(child, typename));

            }

            return childList;

        }

  

要注意的是:地图图片文件的生成资源要改为:Resource  不然没法获取到图片!坐标信息是从服务器获取的,在MainPage_Loaded()方法内—— App.MapViewModel.GetSp()方法

 

最后上个演示视频(手绘地图上用户去过的景点的Mark会出现卡通人物头像 没去过的则不出现卡通人物头像):

你可能感兴趣的:(windows)