我眼中的高德Map ABC企业级地图
- 来源:中国信息化周报 smarty:if $article.tag?>
- 关键字:漏洞,博客,高德地图 smarty:/if?>
- 发布时间:2015-03-20 15:29
Map ABC与a map
走在大街小巷,或是浏览电视节目,我们常会看到高德地图的广告,有心人会发现高德地图标识是a map,而在百度搜索中搜寻“高德地图”,偶尔也会看到Map ABC的网站, 进入网页就会发现a map和Map ABC的网站截然不同,它们之间并非“李逵”和“李鬼”,而是同属于高德公司,有着千丝万缕的联系。首先来了解下a map,a map最开始是由Map ABC的手机端产品迷你地图演变而来,开始叫高德地图,目前作为高德旗下的移动事业部。主要运营高德地图,2012年初开始上线PC端地图,并开放API接口,未来的定位是运营的模式,提供服务,主打免费模式,跟百度地图,谷歌地图一样,经过市场变革,a map更加偏向移动端应用程序以及API的提供;而Map ABC虽然同属高德旗下产业,但是定位于企业服务。主要是针对企业级用户以及行业应用,针对不同行业的特别为其开发个性化的地图服务。以满足各行业对地图的深层次应用,如个性化地图服务,物流行业的SAAS应用等,经过市场变革,逐渐淘汰了包括Sliver light和Flash在内的API,保留下JS和Flex的API,并逐渐向移动端(Android及IOS)倾斜,成为主打移动端的多平台地图服务厂商。
初识地图——简单的功能
一个地图服务之所以被称之为地图服务,是因为它满足人们使用所需的各种功能,无论是使用移动设备、平板电脑、笔记本电脑或是台式机,流畅的拖动地图、快速的定位与查询是地图服务最基本的配置,例如:我们寻找一家餐厅,在地图上输入餐厅的名称,地图快速定位到该餐厅所在位置,我们可以拖动地图查看周边的标志性建筑以便前往,这就是地图带给用户最直观的体验之一。以Map ABC地图为例,当你在浏览地图时,地图上绝不会是白茫茫的一片,而是有山有海有河流有国界,放大地图甚至可以看到省、市边界、道路网等等,这些信息都是通过图层展现出来,所谓图层,维基百科给的解释是:图层是应用在图像编辑软件上的概念,图层就像一层层相叠,但彼此独立的的透明底片,其好处是,在一个图层上绘制及编辑的物件,并不会影响另一个图层上的物件。所以我们就知道地图图层是将一个个地图中的内容叠加从而展现给用户,这么多内容,如果在用户打开时直接加载进来势必会导致用户流量疯狂上涨,而且在加载完成前不会显示地图,Map ABC做的很好,将一整张地图分隔成若干个小图片,平缓的加载进网页,为用户提供了良好的体验环境。
有了地图,只能说有了界面,地图还要能拖动、放大、缩小。那么,让我们先来看什么是地图拖动?把一张图片从左拖到右?亦或是图片过大,通过拖动来看到全部?这些是我原来的想法,但现在我要说的都不是这些,至少在我看过了Map ABC的拖动后是这样认为的,Map ABC地图采用“无极”拖动,无论是从右向左还是从左向右,永远不会拖动到终点,像一个筒状结构,当你觉得到终点时,又会转回到起点(注:“无极”拖动曾出现过Bug,即拖动地图一圈后回到原点,但是之前添加的对象会消失不见,该Bug已被修复)。
大部分地图应用程序都是二次开发人员基于地图服务API开发出来的,Map ABC提供了地图的展现,接下来就该由开发人员使用其中的接口进行开发了,API应当提供包含点、线、面在内的基础对象模型,提供关于基础对象在地图中的添加、编辑、删除等操作,而Map ABC Flex版API提供了10类覆盖物对象,分别为:面类、圆类、背景图片类、文字标签类、点标注类、覆盖物基类、多边形类、折线类、雷达标注类、矩形类,Map ABC其他版本API无出其右。10种对象其实并不多,实际上,开发中用到的会更少一些,主要是面、圆、文字、点、多边形和折线,例如:大众点评网的每家商户页面都有一个小地图,地图中只有一个点对象,标注了商户所在位置。这是最简单的应用,当然,真正去做二次开发所实现的功能一定会复杂的多。
地图进阶——复杂的功能
什么是在地图上实现复杂的功能?更多的点、更多的线、更多的对象?但这只是复杂功能中的一部分,由于B/S结构下在地图添加大量覆盖物(或称密集覆盖物)势必会使浏览器所占内存飙升,因此这种方法也是检验地图服务是否优秀的手段之一,作者在接触Map ABC Flex版之前使用过Super Map Desk pro.Net 6(这是超图公司早期的软件,严格说起来,该软件并不算地图服务,主要是测绘、航拍、建模等作图功能,同时不提供地图,用户使用时需要自己配置地图),在地图上添加将近三百条线段的时候,浏览器开始崩溃,而使用Map ABC做这样一个程序:在指定范围内,每隔5秒随机生成2000个点。虽然内存会上涨,但页面显示依然流畅。但是如果在随机生成2000个点的同时分配监听事件,这个程序的效率将会直线下降,时间越长,效率越低,虽然不至于浏览器崩溃,但是在拖动地图时卡顿感明显增强,这是因为过多的监听事件以及频繁的监听会使地图负荷增大,如果不能及时释放资源,内存占用量就会越来越大。为了最大程度解决这种大数据量的展示,API里提供了点聚合功能,用于海量数据的展示,点聚合的效果体现在不同地图级别下将自动根据地图上点的密集程度将密集度大的区域聚合成一个点,这个被聚合成的点将显示该区域内点的数量,如果地图在极大比例下是有可能将2000个点聚合成一个点的,点聚合解决了海量数据视觉效果混乱的劣势并在一定程度上提升了密集点下程序的效率(我之所以只说在“一定程度上”,是因为即便使用点聚合,也只是隐藏点,而不是销毁点,点的属性和事件依旧存在,只是不可见而已)。而二次开发人员能够做的也只是及时的销毁不用的对象而已,是无法从地图内部进行深层次的优化的。
我认为在使用API中提供的功能,除去对点、线、面以及地图本身的基本操作功能外,其他功能应当都属于复杂功能,Map ABC官方示例中列举了10大项共计57个示例(Js版本的API中分类更加详细),其中包含右键菜单、GPS应用示例、叠加层示例、地图工具示例、鼠标工具示例、海量数据展示在内的六项应当都属于复杂功能,这些功能为用户深度开发地图应用提供了良好的接口。
我曾使用API中的GPS功能开发了基于Map ABC Flex版的定位系统(API的实例展示了实时追踪和轨迹回放,但我发现,这两个功能其实是一样的,不得不说这是API中的一大败笔),这个功能就是GPS功能的深度开发,实际上,由于速度的不可控性,我放弃了实例中实时追踪的平滑显示的方式,改为用单点显示并显示历史轨迹,在速度不过快的时候,是可以模拟出平滑效果的。而历史回放则沿用API中轨迹回放的效果。再如叠加层功能,因为项目需求的地图效果与默认的地图效果不符,所以我使用一张白色地图作为底图,在上面叠加自定义的图层,呈现出一个完全不同于默认地图的效果图(叠加图层的文件必须是一张地图,个人用户基本不具备制作该地图的环境,我也是通过Map ABC官方提出的需求,由他们负责制作,因此,叠加层功能不建议轻易尝试)。我之所以将这两个经历拿出来作为例子,是想说使用API中复杂功能不同于基础功能,复杂功能更加细致,使用者需要对地图的了解有一定基础才能很好的掌控复杂功能,同时,单独使用复杂功能会令人匪夷所思,因为其功能的针对性更强,往往只为某一些特定需求提供服务,例如海量数据中的点聚合功能针对大数据量覆盖物的密集分布,如果仅仅是数十个点,完全没有必要使用,所以使用复杂功能进行深入开发时一定要有对应的使用环境。
“看不见的功能”
Flash有些功能并不是原生API里就提供的,需要二次开发人员对原生API进行扩展,我称这些被扩展出的功能为“看不见的功能”。扩展出的功能可能千奇百怪,各不相同,无法一一列举,因此,我只举一些可能较为常用的加以说明。
为什么我们要对原生API进行扩展?一个再完善的API也不可能面面俱到,满足所有开发者的需求,别人开发的地图应用里有框体拖动效果、有画半圆的效果,而Map ABC的原生API是不提供这种效果的,怎么办?当然不能就这么算了,所以需要对原生API进行扩展,比如框体拖动效果是指存在一个信息框体,该框体内信息指向地图中的某一个特定覆盖物,显示该覆盖物的详细信息,我们不希望这个框体只能僵硬的放在相对于这个覆盖物的特定位置,它应当是可以拖动的,应当有一根细线用来连接覆盖物和信息框,以便告知用户该信息框体是属于这个覆盖物的,那么如何来做?百度?我也经常百度,但显然对于这个问题是百度不出任何可用的结果的,那么只好自己来解决,要实现这个效果首先要有三个对象:覆盖物对象、线对象、框体对象,两点可以确定一条直线,覆盖物对象与框体对象无论怎么移动,它们的经纬度以及x,y坐标是可以确定的。如果覆盖物对象移动了,可以知道与上一次位置的偏移量,根据偏移量就可以确定线对象以及框体对象的新位置;如果框体对象被拖动了,那么可以知道框体对象被放下的位置,更新线对象的坐标即可,至此,对象间的组合已完成,三个对象已经形成一个联动的整体,但是这并不算完,因为还没有将地图考虑在内,点对象和线对象是地图原生API的内置对象,但是框体不是,所以必须在地图移动的时候动态更新框体位置以模拟出框体随着地图的移动而移动,这需要使用Map Mouse Event中的地图事件。
原生API中提供了画圆的方法,里面有很多方法:二态性、大小、偏移、透明度、色值等等,但是遍寻API,一定不会找到画半圆或四分之一圆的方法,这个时候百度依然不是万能的,只好自己来实现,我们可以将圆描绘成点,点与点间用直线相连,如果点足够密集,完全可以模拟出一个圆,同理也可以模拟出半圆,至于方法就需要用到数学里的根据圆心、半径以及夹角计算出圆上任一点坐标。
之所以列举上述两个方法,是因为它们极具代表性,框体拖动效果完全基于API原生方法中的对象进行组合,并使用事件控制组合后的对象,协调其内部不同对象间的同步;而画半圆的方法则是脱离原生API中画圆方法,通过使用足够多的基础点对象描绘出半圆形状,再进行绘制。所以说,原生API中不提供方法并不能成为一个二次开发者无法实现功能的借口,也许,这个功能只是“看不见”而已呢?
地图中存在的漏洞
漏洞是伴随着应用程序而生,因此我们只能尽力去消除它,我曾在我发表的一篇博客中列举了至今为止我发现的所有原生API中的漏洞,不过,我在这里不打算将它们全部复述一遍,而是只挑出其中一些常见的漏洞来告知读者,希望今后在遇到的时候能够以人为的方法去修补和跳过这些漏洞。
1、tip功能是指覆盖物弹出的信息窗口,其支持open tip和close tip,即窗口打开/关闭事件,但是close tip在第一次使用的时候会触发open tip事件,也就是想要关闭就必须得打开一次,这样两个事件就相互重复了,但是如果第二次使用close tip就不会出现这种错误。
解决办法 第一次触发点击操作时,注销tip close事件或者不注册tip close事件。增加一全局变量isFirst标注是否是第一次click事件触发,如果是第一次加载,就不处理tip close事件,如果不是,就处理tip close事件。但是我建议抛弃tip功能,tip功能的可重写性不高, 所以尽量自己去写类似tip这种鼠标移上弹出的功能, 可操作性比较好。
2、pan To和zoom In事件,一个是将地图移动到当前点,一个是放大地图,单独用都没有问题,但是一旦两个连接起来用就会发现pan To在第一次点击的时候不起作用。
解决办法 只能是再点一次了,还有一种办法就是在pan To和zoomIn中间加入间隔时间:flash.utils.setTimeout(zoom,2000)。
3、轨迹回放,对覆盖物使用用户定义的图片时,放大缩小地图都会导致覆盖物不随地图缩放级别变化而变化。
解决办法 使用API中默认的图标,如果需求使用自定义图片,尚无好的解决方案。
4、叠加图层和地图监听事件有冲突。不能把地图监听事件(比如zoom事件)放在叠加图层添加事件前面执行(map Obj.add Tile Layer(tilelayer);),这样会导致监听事件失效。
解决办法避免这种情况发生需要先添加完所有叠加图层,然后再一个个的添加地图事件。
经验之谈
现在,我仍然会参考API手册中的示例代码,不是因为不会写,而是因为文档中的示例代码非常规范,声明与调用逻辑性很强,即便是面对一些属性繁多的对象,文档示例也会按顺序、按分类去调用。但是即便手册示例再多,再详细也很难涵盖用户在使用过程中遇到的一切情况,我很想把自己的体会完全写出来,这样读者在看完文章后就能完全明白API中所有的方法,但碍于篇幅,我只将一些自己认为比较重要的经验和教训罗列一下。
1、MQLngLat方法构造一个经纬度对象,一定要记住参数lng是经度,参数lat是纬度,经纬度写反地图是不会报错的,只是会超出地图范围,显示在地图以外的地方,这就造成用户会以为设置的经纬度没有起作用,然后不停的去检查自己的添加覆盖物代码。
2、动态更新覆盖物方法update Overlay,在API的帮助文档里该方法被解释成更新覆盖物信息,无法对对象的经纬度信息进行更新。这里一定是注意的是,该方法无法更新点类型的覆盖物经纬度,而对线对象、多边形对象是可以进行更新的。
3、地图提供remove Overlay方法去移除已存在的覆盖物,但是请注意,在移除对象后,请对内存进行回收,地图是非常占用内存的,覆盖物也一样。
4、当我们为一个地图覆盖物对象添加监听事件时,请确保这个对象已经被添加进地图,否则是会报错的。另外,无法在当前对象的监听事件里对这个对象进行动态更新的。
5、每个覆盖物都可以设置label文本框,但是无法对文本框进行更新,想要更新文本框,可以单独创建一个M label地图文本框对象,它是可以跟随覆盖物并进行更新的。
6、地图坐标与平面坐标是两个完全不相同的概念,切勿将其混淆,地图坐标是指经纬度坐标,平面坐标是指屏幕容器内的坐标,虽然API中提供了转换方法from LngLat To Container Pixel和from Container Pixel To LngLat,但是这里仍要提醒使用者,在对基于地图的对象进行定位请使用地图坐标,对地图中的非地图对象操作请将地图坐标转换为平面坐标。如果希望自己进行手动转换,请使用WGS84坐标系。
7、使用Map ABC自带的全屏后,是无法与后台交互的,Map ABC全屏机制其实就是flex中的全屏机制,flex的全屏在文本框内输入信息递交表单后是无法与后台进行操作的,也就是全屏后前后台的交互被隔绝了,但是自动执行的行为还在,所以在全屏后尽量不要再有递交表单等行为的出现。
以上所写的这些经验和教训并不多,对于整个API来说甚至可以称得上是“沧海一粟”,但我觉得这些问题很可能会令开发者困守一隅,却找不到解决问题的出路,因此将它们罗列出来,希望读者能有所收获,并在之后的开发工作中获得便利。
写在最后
尽管Map ABC官方基本停止了对Flex版API的更新,但我仍然坚守着、不停的对其进行二次开发,毕竟这是我的工作,而这篇文章尽管非常的言简意赅,却是我的经验之谈,也是用成千上万行代码换来的。我希望能通过这篇文章让后来者们对他们即将碰触的地图有一个大致的了解,多一个通向精通API的捷径。
民航电信开发有限责任公司 江麟