分享一下如何制作专业的手绘电子地图

分享一下如何制作专业的手绘电子地图。

 

一、智慧导览系统介绍

手绘电子地图,就是把手绘地图覆盖到地图上,游客或者普通用户,可以在手机上通过地图的链接(或者现在流行的小程序)打开使用。是一种使用非常方便,集“视、听、路径规划、实时导航”等诸多功能于一体的智慧导览系统。也是现在很多景区为游客提供的增加便捷性和游玩体验的一项功能。

最重要的两点,我认为是:

1.手绘图本身

手绘图的美观度、清晰度、完整度、准确度,决定了图的档次格调的高低,也是手绘设计师的技术水平、设计能力、规划能力、沟通能力等综合性体现。

2.实时导航功能

如果说手绘图本身是面子,让人对地图有第一印象和直观感受,那么实时导航功能则是地图的灵魂和里子。没有实时定位和动态路径规划导航功能的地图,只是一个可观而不可用的花瓶,没有使用价值。没有准确的而高效的实时导航算法,就不能把地图价值在游客手里发挥到最大。

因为多年的从业经验,我从一个纯技术的角度来分享一下如何实现这样的“智慧导览系统”。

 

二、智慧导览系统功能

先看一个参考示例图(根据实际情况,只添加了必要的功能):

​ 

参考示例图

1.基础功能

地图功能的设计,包括需要哪些功能,需要怎么展示,地图点位的图标等细节,不一而足。每个需求方可能要的也不一样。但总体来说,可能包含如下:

景点介绍:这是智慧导览系统最基础的功能之一。在系统后台可以在地图上添加景点标注,并完善相应的介绍信息,包括图片、文字、图文、语音、视频等内容。

服务设施:在地图上添加区域内的服务设施,如厕所、游客中心、停车场等内容。

商家信息:在地图上添加区域内的商家,如酒店、餐饮、特产等商家。用户可查看商家介绍、商家产品,并可支付下单购买。

景区公告:在后台添加景区最新公告,如闭园通知、开园通知、最新活动等信息。

线路推荐:在后台设置推荐的线路及景点,游客在地图上可点击查看,并在地图上直观的规划出推荐的路径,模拟导览游览。非常直观明了。

咨询电话:可在后台设置景区的咨询、客服的联系方式,如电话、微信、微博等。

景区720:可拍摄制作景区的720全景,并在地图上标注展示,更直观的向游客展示景点的实景。

2.增强功能

智慧导览系统还应该具备如下增强功能,才能更好的增强客户的服务能力、满足用户的使用需求。这也是当前电子手绘地图系统的重点和难点。

实时定位:基于客户端的位置获取接口(如上文,可能大部分是微信环境里,或者浏览器环境),实时获取用户当前的位置信息。当然,位置的精度可能会受到诸多方面因素的影响,如天气、建筑物遮挡、设备本身的性能或GPS模块的精度、网络状况等。在理想的情况下,精度甚至可达到10到20米左右的偏差。这种精度,在民用已经算是极致了。为什么不给出更精确的精度,可能一方面是设备、技术等因素限制,另一方面,从安全角度来看,可能这也超出民用的范畴。当然,话说回来,从我们的实际使用场景来看,这样的精度其实已经远远的满足我们的需求了。这里说个题外话,为什么我们在手机上使用地图APP导航的时候,不管是驾车还是步行,看上去都能做到精准无误呢?(如驾车,在路口转向时,基本上达到米级的精度)关于这一点,我是这样思考的:地图APP是基于设备的定位,然后再结合当前使用者的导航方式、路径规划、设备朝向、速度等多方面综合的因素,用强大的后台算法为用户的当前位置做了智能的“纠偏”。那为什么我们智慧导览系统不做这样的纠偏呢。从实际出发,这一方面是我们的数据量远远不够丰富完善,另一方面是“性价比”不高。在园区内的导航,不需要这样的“纠偏”已经可以满足需求,而要做这样的“锦上添花”的功能,则需要付出指数级甚至更高的成本和代价。

动态路线规划:基于前端设备“实时定位”的能力,智慧导览系统实时计算用户当前位置和指定目的地的路径。指定的目的地,可以是地图上标注的任意一个点位,如景点、服务设施、商家等。这一点,和地图APP的导航功能非常类似。园区内很多情况下,没有地图APP平台采集路线,所以需要我们人工在智慧导览系统后台标注和实际情况一致的路线,或者通过智慧导览系统提供的路线采集工具,安排人员现场采集。其实,地图平台的路线采集也是这样做的。各大地图平台,都有国家发放的专业牌照,然后通过路线采集人员驾车或步行,采集、更新每个城市的道路(仔细想想,这是一个多大的工作量和成本,我们每个人都可以免费的使用这些服务,感谢他们的付出成本和辛苦)。

自动触发:基于“实时定位”和“动态路线规划”能力,用户达到系统设置的点位附近时,可以自动触发后台配置的各种功能,如自动播放景点的语音讲解、展示图文内容,或推送商家的优惠券等。为用户提供便利、人性化的智慧服务。

多语言:多语言是智慧导览系统满足国际化需求的一个增强功能。系统具备基本的汉语、英语选择,还具备很便捷的扩展其他语种的设计和功能。

3.地图个性化

智慧导览系统不应该是一个单纯的功能性的系统,还应该有更多丰富的、多元化的功能,为用户提供更多个性化、趣味化的服务。

个人中心:系统具备用户个人中心的功能。用户可以对地图上的景点进行点赞、评论等操作,然后可在个人中心查看。

营销、广告:后台可在地图上添加固定的营销、广告等信息,增强能力和满足运营需求。

优惠券:后台可设置地图上的商家发送优惠券,吸引、导流游客进店,带动消费。

寻宝游戏等活动:后台可在地图上添加寻宝指引点位,引导游客到指定地点扫码积星对话奖品。

标注图标动效:所有标注点的图标,可设置一些动效,增加地图的趣味性和个性化。

 

三、技术栈的选择

从这里开始后面的内容,有一定的行业背景或经验的人,能更好的理解。我尽量说得通俗易懂一些。如果你觉得一些专业名词不明白是什么意思,可以直接跳过。

现在绝大部分业务系统的开发,都是基于一个成熟的技术栈来实现。这样可以极大的节约基础设施的成本,而且效率得到极大的提高。甚至某些系统或行业的应用及系统,不基于一些成熟的技术栈,想要完全自主开发,几乎是不可实现的。

智慧导览系统,建议基于这样的一个技术栈:

1.服务器

使用成熟的云平台,国内成熟好用的几家,业内人都知道。

2.前端平台

如今最大的前端平台是微信小程序,还有就是浏览器直接通过链接打开。不过就智慧导览系统来说,大部分情况下,微信小程序也是基于Webview控件来调用,本质上和浏览器的直接打开没什么区别,就是HTML5+JavaScript+CSS3来实现。但是微信的生态内,会有一些微信开放的额外的一些接口和功能,比如说:可以使用微信提供的位置获取接口,来为游客获取更精准的定位。

3.地图平台

智慧导览系统只能基于地图的开放平台来实现。目前国内几家大而成熟的地图平台:高德地图、百度地图、腾讯地图。建议首选高德地图,次选百度地图。为什么呢?

地图有个“层级(Zoom)”的概念,就是用户打开地图,放大缩小,就是显示的不同的层级。现在地图平台开放的层级,高德地图最大为19级,百度地图为18级,而同级别的情况下,高德地图也更大一些。因此,建议选择高德地图,可以做更精细化的地图。腾讯地图多不做介绍。

另外,如果涉及国外的景区或地点,那谷歌地图是不二的选择。国内的地图在国外没有完整的内容,而且访问速度也很随缘。

 

四、开发介绍

具体开发内容,这里主要介绍涉及地图核心的部分。其他比如数据库设计、后台管理系统等不做过多介绍。

1.开发语言选择

后端开发:目前流行的开发语言如Java、PHP、Python等都是不错的选择,每个语言都有自己的特色。就个人而言,我比较喜欢Java和PHP,Java纯面向对象,适合大型项目,运行速度较快;PHP灵活简单,开发效率很高,现在利用有Swoole这样的扩展,也可以做到运行速度很快。

前端开发:前端开发老生常谈,JavaScript+HTML5+CSS3,千年不变的三板斧。但是可选择的框架或者库现在比较多,JavaScript有之前非常流行的JQuery库,也有现在很火的Vue等框架。总之,做为开发者,你最擅长的可能就是最适合的选择。当然,你也可以选择学习新的知识和技术代替曾经最擅长的。

2.地图基础知识

这一点,是核心,基础中的基础,原理也比较复杂。因为地球是一个球体,是立体的,并不是天圆地方的一个平面,所以,首先,需要引入一个叫“坐标系统”的概念。

当前常见的坐标系主要有三种:

地球坐标系:WGS84,常见于GPS设备,Gooogle地图(非中国区域)等国际标准的坐标体系 。

火星坐标系:GCJ-02,中国国内使用的被强制加密后的坐标系,如高德地图、腾讯地图、谷歌地图(中国区域)的坐标就属于此类坐标系。

百度坐标系:BD-09,百度地图所特有的坐标体系,它在火星坐标系的基础上又进行了一次加密处理。

但是我们使用地图的时候,却又只能看到平面的地图,因此,又有了另外一个概念:墨卡托投影。

墨卡托投影的主要功能,就是让三维立体的地图坐标能在二维平面上显示。有点类似于《三体》里的二向箔的功能,把三维系统二维化。

二维化之后的平面,会被分割为一片一片的小图,或者换句话说,由一片一片的小图拼成了二维的地图。而这个小图,叫“瓦片图”。这又是一个重要的概念。后文会继续细说。

而瓦片图的开始点(最左上角,或最左下角)在地球的什么地方呢,因为坐标系的不同,每个地图可能也不一样。所以,同一个经纬度,在不同的地图平台上,对应的瓦片图的序号可能都是不一样的。其中详细的原理和规则算法,这篇文章说得比较详细:

国内主要地图瓦片坐标系定义及计算原理

3.地图平台介绍

高德、百度、腾讯、谷歌地图开放平台介绍。

首先祭出开放平台文档,这是基于平台开发的基础:

高德地图:https://lbs.amap.com/api/javascript-api/summary

百度地图:https://lbsyun.baidu.com/index.php?title=jspopular3.0

腾讯地图:https://lbs.qq.com/webApi/javascriptGL/glGuide/glBasic

谷歌地图:https://developers.google.com/maps/documentation/javascript

每个地图的API,大同小异。从细节来说,腾讯地图的接口和高德地图差别最小。

值得一提的是,在地图上画线(主要是导航的线路规划标识),谷歌地图没有直接给出绘制虚线的接口,而国内的地图平台都有。这一点也体现了国内和国外的一种思维的差异。

另外还有一个细节,标注图标旋转(比如导航时,箭头图标跟随人的方向旋转)接口,高德地图的旋转的中心点不是图标中心,而是图标外层父元素的点位,因此转向时,给人的感觉是自身的位置也在画一个圆圈,而百度地图没有这个问题。当然这个问题也不是无法解决,我们可以通过自己编写转向的CSS,利用JavaScript来控制图标以中心点来转向。

  图标围绕父元素边点转向

 

  图标围绕中心点正常转向

 

每个地图平台在手机端的表现和体验也有些差异。我个人觉得高德地图最流畅顺滑,百度地图次之。

还有另外一点细节,就是关于瓦片图(后文细说),一样的图,在腾讯地图上会有非常细微的差别(腾讯地图允许级别Zoom为小数,在两个级别之间,还可以有多个过度值,而其他地图只能是整数,这是一个更人性化的设计,但却导致了瓦片图变得模糊了一点)。

4.瓦片图覆盖到地图上

瓦片图是尺寸为256px*256px的正方形图片。这样的图片,像瓦片盖房一样,覆盖为整个地图,所以称为“瓦片图”。

瓦片图的设计是一个非常精妙的设计,解决了地图图片太大的根本性问题,节约了服务器、客户端设备的内存,按视觉范围内加载图片,也节约了网络流量。

这是一种前端的“懒加载”思想的体现,也是和前端的“雪碧图”刚好相反的设计(关于“懒加载”和“雪碧图”,这里不做过多介绍)。

因此我们可以发现,不管什么解决方案,都有相应的使用场景,也有相反的局限性。不可脱离场景,一概而论。

瓦片图覆盖到地图,这是整个手绘电子地图最核心、最基础的设施和功能。因为此,我们自己绘制的精美地图,才能够覆盖到地图平台上,做成我们个性化需求的地图。具体的实现,并没有想象的那么复杂。当然,经验丰富的程序员,可以设计出更科学的算法和加载逻辑。这里抛砖引玉,做一个示例(高德地图):

 1 var fileHost = 'https://yourfilehost.com/';  2 var tileLayer = new AMap.TileLayer.Flexible({  3     createTile: function (x, y, zoom, success, fail) {  4         var imagePath = fileHost + '/tilefile/' + zoom + '/x + '_' + y + '.png';  5           
 6         var div = document.createElement('div');  7         var img = document.createElement('img');  8  img.onload = function () {  9  div.appendChild(img); 10  }; 11  img.crossOrigin = "anonymous"; 12  img.onerror = function () { 13  fail() 14  }; 15  img.src = imagePath; 16 
17  success(div); 18          
19  } 20 }); 21 tileLayer.setMap(map);

这里AMap.TileLayer.Flexible方法是核心,这是高德地图提供的使用瓦片图的一个接口。他提供了一个div层(className为“amap-layer amap-flexible”)覆盖在底图之上,然后允许此方法返回仁义的元素,填充在256*256的瓦片图的方格里。因此,这里其实也可以更简单的直接返回一个img元素而不用div:

 1 var fileHost = 'https://yourfilehost.com/';  2 var tileLayer = new AMap.TileLayer.Flexible({  3     createTile: function (x, y, zoom, success, fail) {  4         var imagePath = fileHost + '/tilefile/' + zoom + '/x + '_' + y + '.png';  5         var img = document.createElement('img');  6  img.onload = function () {  7  success(img);  8  };  9  img.crossOrigin = "anonymous"; 10  img.onerror = function () { 11  fail() 12  }; 13  img.src = imagePath; 14  } 15 }); 16 tileLayer.setMap(map);

以上为高德地图的示例,其他地图原理相差不大,因此不再赘述。当然,这里只给了最基础的加载瓦片图的逻辑。事实上,根据实际情况,这里面还会做很多必要的其他业务逻辑的判断,比如,系统应当存储当前地图的瓦片图范围,超出范围的,就不要加载图片,或者加载一张透明的小图等。

这里列一下地图平台瓦片图的接口名,便于有需要的搜索使用:

AMap.TileLayer.Flexible // 高德地图
 BMap.TileLayer // 百度地图
 TMap.ImageTileLayer // 腾讯地图
 google.maps.ImageMapType // 谷歌地图

  //需要注意的是,一些地图的接口允许传入参数:瓦片图的尺寸。不过建议默认为256较好,毕竟这是通用的默认尺寸。

 

5.瓦片图的制作

既然瓦片图是基础,那么我们如何从一张完整的手绘图制作成为256*256的多张瓦片图呢?可能设计师都能想到,直接用Photoshop切图即可,很简单。是的,常理来说是这样,但这有2个问题:

(1)我们设计的图,往往不是刚好为256px的倍数,那么第一张切图,从什么地方开始?(即便是刚好为256的倍数,也不能从0像素开始切,后文细说)

(2)我们切图出来之后,结合前文的地图基础知识,通过上面示例代码可见,最关键的是每个图的文件名,要和地图的级别Zoom、X轴的数值x、Y轴的数值y相对应。否则切出来的图,没有任何意义。

这两个问题,是制作有用的瓦片图的根本问题。

其实,在我们绘制手绘图片文件之前,就已经清晰的知道,我们绘制的内容到底是处于地图的什么区域。然后应当记录这个区域的起始点的经纬度。

前面说了瓦片图可能从地图的最左下角或左上角开始。具体情况是这样的:高德、谷歌、腾讯地图是从左下角,高德地图是从左上角开始。

然后通过经纬度、抹卡托、可见区域像素三者的转换算法,计算出当前手绘图分别在X轴和Y轴的第二张瓦片图的偏移像素,然后从此像素位置开始切图,并把计算得到的层级(Zoom)、X坐标(x)、Y坐标(y)的值作为对应的文件名保存切图。因此,说到这里,我们便都知道,这切图工作没办法由设计师来人工执行,只能由设计的专门算法的系统执行。

这里因为一些商业保密和其他的原因,我不能对这个切图算法做更仔细的讲解,非常抱歉。

瓦片图切好之后,放到专门的文件服务器,然后前端代码便可调用,实现瓦片图覆盖于地图底图上展示。个性又漂亮的手绘地图便基本成型了(如上图“参考示例图”)。

6.动态规划路径的实现

漂亮个性的手绘电子地图完成之后,这还只是一个纯纯的地图展示,谈不上功能性的使用,更别说“智慧”。因此,我们还需要增加各项智慧能力的功能。这其中,最基础的又应当是“实时定位”及“动态路径规划”了。

其实这两项功能,就是地图APP的基础的导航功能。但是因为大部分我们的园区内根本没有地图的路线,或者不全面,因此需要我们自己来实现这个功能。

具体如何实现,原理很简单。前端通过定位接口获取到用户当前的位置(需要注意的是,为了支持更全面的使用场景,可以考虑兼容微信及HTML5原生接口),然后系统计算当前位置与指定的点位之间的路线。

因此,这就需要我们根据实际情况,事先在系统里标注园区内的点位和路线,路线越详细越好。而通过这些点位和路线,要计算得到最短路径,关键则在于最短路径的“寻路算法”。算法可以自己设计,而目前很多伟大的科学家公开的很多最短路径算法则更为推荐。因为自己设计的算法难免可能会出现一些不可预料的BUG,而这些公开的算法经过严密的证明和大量使用的验证,使得计算效率以及可靠性都有很好的保证。

这也是我的个人经验,曾经我们自己设计的一个算法,在大部分情况下都能计算出正确的最短路径结果,但在某些情况下,却得到意外的结果,或发生计算消耗较多时间,效率低下的情况。

我推荐“迪杰斯特拉”算法,或“佛洛依德”算法。

 1 //C语言版本的迪杰斯特拉算法
 2 int a[1000][1000];  3 int d[1000];//d表示源节点到该节点的最小距离
 4 int p[1000];//p标记访问过的节点
 5 int i, j, k;  6 int m;//m代表边数
 7 int n;//n代表点数
 8 int main()  9 { 10     scanf("%d%d",&n,&m); 11     int min1; 12     int x,y,z; 13     for(i=1;i<=m;i++) 14  { 15         scanf("%d%d%d",&x,&y,&z); 16         a[x][y]=z; 17         a[y][x]=z; 18  } 19     for( i=1; i<=n; i++) 20         d[i]=max1; 21     d[1]=0; 22     for(i=1;i<=n;i++) 23  { 24         min1 = max1; 25         for(j=1;j<=n;j++) 26             if(!p[j]&&d[j]<min1) 27  { 28                 min1=d[j]; 29                 k=j; 30  } 31         p[k] = 1; 32         for(j=1;j<=n;j++) 33             if(a[k][j]!=0&&!p[j]&&d[j]>d[k]+a[k][j]) 34                 d[j]=d[k]+a[k][j]; 35  } 36     for(i=1;i<n;i++) 37         printf("%d->",d[i]); 38     printf("%d\n",d[n]); 39     return 0; 40 }

当然这些公开算法,都是最基本的核心和原理,要能让我们可在地图上做最短路径寻找,还需要我们自己根据实际业务和逻辑,做相应的变种。

根据对当前用户的实时定位,通过最短路径算法,便能实现动态路径的规划。这便使得我们的手绘电子地图具备了最基础、最重要的导航功能。

7.自动触发的实现

通过实时定位获取到用户当前位置,系统判断位置是否和后台设定的点位接近。当距离已小于设置值的时候,电子地图系统便自动展示当前点位的介绍信息、语音讲解,或者商家推送的优惠券等。因此,我们的电子地图系统便越来越智能了。

而在此基础之上,我们可以相当的所有功能,都可以加载到电子地图系统上。由此我们的系统便优化成为真正的“智慧导览系统”。其他的更多的功能的实现,我便不再赘述,只对下列三个比较特别的功能再做一些简述。

8.多语言的实现

多语言是一个老生常谈的需求,也是一个系统国际化所必备的功能。对于智慧导览系统而言,我觉得有两个值得注意的点:

(1)地图本身的文案,包括提示信息、按钮文字等。这可以在代码层面做多语言的配置。

(2)地图标注点位相关的内容,包括图文介绍、语音讲解等内容,这里需要在后台系统设计可添加多语言内容的管理。

9.实现国内国外可同时访问地图

这一点需求,是根据实际情况来提的。因为国内和国外的地图基本上不能互通,因此我们的智慧导览系统应当解决这一痛点。

10.地图路线的采集和标注

系统的“动态路径规划”功能需要园区的路线数据为基础,因此系统应当提供路线采集和标注的配套工具,方便工作人员从现场采集路线的经纬度等信息。

 

五、结尾

本文是我个人基于“智慧导览系统”开发经验的一个大致的概括。整体来讲,写得比较粗陋和简略。很难作为一个方案或者教程,只当是我个人做一个总结罢了。如有不当之处,欢迎指正。也欢迎有兴趣的一起讨论。

张贴在2