前些日子在做景区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/scenic_pointer_gril@2x.png", UriKind.RelativeOrAbsolute));
else
el.Source = new BitmapImage(new Uri("/MapPage/scenic_pointer@2x.png", 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会出现卡通人物头像 没去过的则不出现卡通人物头像):

WindowsPhone开发—— 使用手绘图片做景区导览地图的更多相关文章

  1. AI应用开发实战 - 手写识别应用入门

    AI应用开发实战 - 手写识别应用入门 手写体识别的应用已经非常流行了,如输入法,图片中的文字识别等.但对于大多数开发人员来说,如何实现这样的一个应用,还是会感觉无从下手.本文从简单的MNIST训练出 ...

  2. 给手绘图着色(添加颜色或色彩):CVPR2020论文点评

    给手绘图着色(添加颜色或色彩):CVPR2020论文点评 Learning to Shade Hand-drawn Sketches 论文链接:https://arxiv.org/pdf/2002.1 ...

  3. Windows Phone开发(21):做一个简单的绘图板

    原文:Windows Phone开发(21):做一个简单的绘图板 其实我们今天要说的就是一个控件--InkPresenter,这个控件并不是十分强大,没办法和WPF中的InkCanvas相比,估计在实 ...

  4. roughViz 一个可重用,功能强大的手绘图表组件

    前段时间介绍过一个chart.xkcd 的手绘图表组件,roughViz 是另外一个,同时也提供了 比较多的图表类型,api 参考文档也比较全 支持的图表类型 Bar Horizontal Bar D ...

  5. 如何在WindowsPhone Bing Map控件中显示必应中国中文地图、谷歌中国中文地图。

    原文:如何在WindowsPhone Bing Map控件中显示必应中国中文地图.谷歌中国中文地图. 最近正好有点业余时间,所以在做做各种地图.Bing Map控件本身就能显示必应地图,但是很遗憾微软 ...

  6. C# Windows Phone 8 WP8 高级开发,制作不循环 Pivot ,图片(Gallery)导览不求人! 内附图文教学!!

    原文:C# Windows Phone 8 WP8 高级开发,制作不循环 Pivot ,图片(Gallery)导览不求人! 内附图文教学!! 一般我们在开发Winodws Phone APP 的时候往 ...

  7. 3D Touch开发全面教程之Peek and Pop - 预览和弹出

    ## 3D Touch开发全面教程之Peek and Pop - 预览和弹出 --- ### 了解3D Touch 在iPhone 6s和iPhone 6s Plus中Apple引入了3D Touch ...

  8. 记一次IE浏览器做图片预览的坑

    随便写写吧,被坑死了 IE 10 及 IE10以上,可以使用FileReader的方式,来做图片预览,加载本地图片显示 IE 9 8 7 没有FileReader这个对象,所以只能使用微软自己的东西来 ...

  9. AI应用开发实战 - 手写算式计算器

    扩展手写数字识别应用 识别并计算简单手写数学表达式 主要知识点 了解MNIST数据集 了解如何扩展数据集 实现手写算式计算器 简介 本文将介绍一例支持识别手写数学表达式并对其进行计算的人工智能应用的开 ...

随机推荐

  1. [问题2015S08] 复旦高等代数 II(14级)每周一题(第九教学周)

    [问题2015S08]  设 \(A\) 为 \(n\) 阶复方阵, 证明: \(A\overline{A}\) 与 \(\overline{A}A\) 相似, 其中 \(\overline{A}\) ...

  2. GZAPI框架初识

    新建一个MVC项目(GZAPIFramework.Demo): mvc:用于API接口文档查看,Log日志查看 webapi:api调用 新建一个Biz类库并添加nuget引用: 搜索GZAPI.Co ...

  3. 怎样让webservice在浏览器远程浏览时像在本地浏览一样有参数输入框

    从远程客户端访问服务器上的WebService能够显示,但点击调用相关的方法时显示“只能用于来自本地计算机的请求”,这时提醒我们还需要在服务器进行相关的配置才能让其他机器正常访问该WebService ...

  4. (原创)详解Quartus导出网表文件:.qxp和.vqm

    当项目过程中,不想给甲方源码时,该如何?我们可以用网表文件qxp或者vqm对资源进行保护. 下面讲解这两个文件的具体生成步骤: 一.基本概念 QuartusII的qxp文件为QuartusII Exp ...

  5. 探究chrome下的开发工具的各功能

    F12 一.网页寻找js事件的位置,或者某一个次究竟在哪个相关的文件中可以全局搜索: ①控制台右上角的:(Customize and control DevTools)三个点点开,---->Se ...

  6. git ignore 添加忽略文件不生效解决办法

    在git中如果想忽略掉某个文件,不让这个文件提交到版本库中,可以使用修改根目录中 .gitignore 文件的方法(如无,则需自己手工建立此文件).这个文件每一行保存了一个匹配的规则例如: /targ ...

  7. View绘制--onMeasure() 、onLayout()

    绘制需要经过多次 measure() layout() 过程, measure:测量,不可被子类继承,调用onMeasure()方法 onMeasure():测量,测量结束后每一个View都保存了自己 ...

  8. 如何让popWindow显示在view上方

    看了bilibili的客户端搜索按钮,很喜欢大爱!自己也想做个类似的(相似度 10% 哈哈) popWin的出现退出动画也可以自己设定,用过其方法setAnimationStyle(R.style.x ...

  9. JavaWeb前端: JavaScript 简介

    JavaScript基本概念 什么是JavaScript JS是运行在浏览器里的解释性语言,能实现浏览器端和用户的直接交互(HTML输出/响应事件/改变HTML内容图像样式):除了变量不区分类型以外, ...

  10. 无法查找或打开pdb文件

    工具->选项->调试{常规->启动源服务支持,符号->Microsoft符号服务器} 如果再不行.要重新生成一下,(不是重新生成解决方案)