深入浅出百度地图API开发系列(1):前言
百度地图API目前在地图API领域越来越受到众多开发者的关注,许多应用都使用到了百度地图API服务,包括博主me,我自己使用做的是Javascript API,根据经验,我想整理出一份系列教程,如果能给想使用百度地图API的开发者带来一点帮助的话,那就太好了,也希望大家能够互相交流,共同学习。
写在前面的话:如果各位真的想深入了解地图的JSAPI,首先一些基础的GIS概念必不可少,GIS就是地理信息系统,可能很多程序猿没听过,简单地说,GIS就是通过计算机软件技术将地理信息进行可视化管理,地图就是一个最重要的地理信息应用。涉及到地图的GIS基础概念,首先有投影、坐标系、坐标转换、瓦片图和矢量图。先不要晕,更复杂还在后面呢。
现在很多网络地图都是使用Web墨卡托投影当做主要的投影方法,包括Google Map和百度地图,具体的投影原理和方法这里就不脑补了。百度百科就解释的很清楚。想了解细节的可以去深入挖掘。投影的目的就是讲球面的形状显示在平面的显示器上形成地图,投影之后的地图就有自己的坐标系统。比如很多人都知道的经纬度坐标系来描述地球上的某一位置。而百度地图API中的涉及到的坐标系就不仅仅只有经纬度坐标系了。
你需要了解到以下的坐标系:
- 经纬度:通过经度纬度来描述某一点位置。如BMap.Point(116.404, 39.915)。注意:一般GPS设备获取的经纬度属于WGS84坐标系。在国内地图厂商使用的经纬度坐标都不是WGS84经纬度坐标,都是经过gc02加密之后的。而百度地图在gc02加密的基础上又进行一次bd09加密。所以使用原始GPS获取的经纬度直接在百度地图上进行打点的话就会有偏移。使用原始的GPS经纬度坐标在地图上打点需要先调用百度地图的Geoconv API 对原始坐标进行坐标转换。传送门:坐标转换API。
- 平面坐标:球面的形状通过投影变换成平面上的形状,在平面,就需要一个平面坐标系来描述某一个位置,百度地图API默认使用墨卡托投影。投影之后就有一个平面坐标系。在百度地图API中,平面坐标就是想象成把球形展开在一张平面上,坐标原点和经纬度原点一致,赤道和0度经线相交的位置。百度地图API将地图分为了18个级别,平面坐标是以最大的级别18级为准的,也就是说在18级下,平面坐标的一个单位就代表了屏幕上的1个像素。平面坐标与地图所展示的级别没有关系,也就是说在1级和18级下,天安门位置的平面坐标都是一致的。那么如何知道某个位置的平面坐标呢?可通过BMap.MercatorProjection类来完成,该类提供经纬度与平面坐标互相转换的方法。例如天安门的经纬度大约为116.404, 39.915,经过转换即可得到平面坐标:
1 var projection =new BMap.MercatorProjection(); 2 var point = projection.lngLatToPoint(new BMap.Point(116.404, 39.915)); 3 alert(point.x +", "+ point.y);
最后得到的结果就是:12958175,4825923.77。
- 像素坐标:像素坐标表示的是在某一缩放级别下位置的显示坐标,在18级别下,像素坐标可以通过将平面坐标向下取整得到,对,像素坐标都是整数值。因为它代表中屏幕上的像素值。在其他的级别下,我们可以使用如下公式获取像素坐标。
像素坐标 = Math.floor(平面坐标 * 2zoom-18) - 图块坐标:百度地图API在网页上显示地图的时候是将整个地图切分成若干块地图瓦片来显示的,每一个地图显示级别都包含若干块瓦片图。图块坐标表示的就是某一级别下的某一张瓦片图,有三个属性,x, y, z。z表示缩放级别。x,y 表示坐标。x,y的计算如下所示:
图块坐标 = 像素坐标 / 256
因为百度地图中每一张瓦片图的大小都是256*256的。所以像素坐标/256就可以得到需要在平面上显示的图块坐标了。下面一张图或许更容易理解。
还是以像素坐标原点(等于平面坐标原点)以基准,先计算像素坐标值,然后再计算得到点所在的图块坐标。注意,不同的缩放级别下,相同的点所在的图块坐标是不一样的。 - 可视区坐标:这个坐标肯定是大家会经常用到的,它就是相对于你的地图容器的坐标,地图容器就是初始化地图的时候传入的Dom元素,原点是这个Dom元素的左上角,在实际的开发过程中,可以使用API中的Map类的pointToPixel和PixelToPoint方法将经纬度和可视区坐标进行相互转化。
- 覆盖物坐标:这个坐标相对来说使用的场景较少,覆盖物在实现上就是若干DOM元素,这些元素会被放在若干覆盖物容器内,那么覆盖物的坐标实际上就是相对于这些覆盖物容器的坐标。在地图初始化完成后,覆盖物容器的左上角与地图可视区域左上角位置相同,一旦地图被移动、缩放,覆盖物容器位置就会发生变化。在自定义覆盖物的时候API提供经纬度信息,而开发者需要自行将经纬度转换为覆盖物的像素坐标,从而覆盖物才能显示在正确的位置上。可以使用API中的Map类的pointToOverlayPixel和overlayPixelToPoint两个方法来实现。
这些坐标系统,在地图API开发中肯定会经常用到,如果对这些基础概念不是很了解的话可能有时候就会产生疑惑,甚至在一些功能开发上找不到思路。如果深入理解了基础概念,那么在使用地图API开发的过程中就能够熟练的运用API提供的一些方法。
说了这么多,来个代码示例给大家回顾一下概念:
1 <!DOCTYPE html>
2 <html>
3
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6 <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
7 <title>Map Coordinate</title>
8 <style type="text/css">
9 /*<![CDATA[*/
10
11 html {
12 height: 100%;
13 }
14 body {
15 height: 100%;
16 margin: 0px;
17 padding: 0px;
18 }
19 #map_container {
20 height: 100%;
21 }
22 /*]]>*/
23 </style>
24
25 </head>
26
27 <body>
28 <div id="map_container"></div>
29 </body>
30 <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=wWy2A8K94nhntYTYUHS19RXW"></script>
31 <script type="text/javascript">
32 var mp = new BMap.Map('map_container', {
33 enableHighResolution: true
34 });
35 mp.centerAndZoom('北京', 15);
36 mp.enableScrollWheelZoom();
37
38 var TILE_SIZE = 256;
39
40 mp.addEventListener('click', function(e) {
41 var info = new BMap.InfoWindow('');
42 var pos = e.point;
43 var projection = this.getMapType().getProjection();
44 var lngLatStr = "经纬度:" + pos.lng + ", " + pos.lat;
45 var worldCoordinate = projection.lngLatToPoint(pos);
46 var worldCoordStr = "<br />平面坐标:" + worldCoordinate.x + ", " + worldCoordinate.y;
47 var pixelCoordinate = new BMap.Pixel(Math.floor(worldCoordinate.x * Math.pow(2, this.getZoom() - 18)),
48 Math.floor(worldCoordinate.y * Math.pow(2, this.getZoom() - 18)));
49 var pixelCoordStr = "<br />像素坐标:" + pixelCoordinate.x + ", " + pixelCoordinate.y;
50 var tileCoordinate = new BMap.Pixel(Math.floor(pixelCoordinate.x / 256),
51 Math.floor(pixelCoordinate.y / 256));
52 var tileCoordStr = "<br />图块坐标:" + tileCoordinate.x + ", " + tileCoordinate.y;
53 var viewportCoordinate = mp.pointToPixel(pos);
54 var viewportCoordStr = "<br />可视区域坐标:" + viewportCoordinate.x + ", " + viewportCoordinate.y;
55
56 var overlayCoordinate = mp.pointToOverlayPixel(pos);
57 var overlayCoordStr = "<br />覆盖物坐标:" + overlayCoordinate.x + ", " + overlayCoordinate.y;
58
59 info.setContent(lngLatStr + worldCoordStr + pixelCoordStr + tileCoordStr +
60 viewportCoordStr + overlayCoordStr);
61 mp.openInfoWindow(info, pos);
62 });
63 </script>
64
65 </html>
浏览器运行,然后鼠标点击地图上某一位置后,弹框如下:
结语:在使用百度地图API开发的过程中,坐标系的概念非常重要,因为涉及到在地图上显示,而很多时候开发者拿到的坐标都是经纬度坐标,甚至都是GPS坐标,这些坐标数据要想在百度地图上标注出正确的位置,一定要记的按照上述的坐标系概念进行转换。要不然结果是不准确的。好了,后续,我会陆续发出关于如何使用地图API开发,介绍百度地图API的一些js原理的系列文章。