咱們都知道地球是圓的,電腦顯示器是平的,要想讓位於球面的形狀顯示在平面的顯示器上就必然須要一個轉換過程,這個過程就叫作投影(Projection)。在地球上咱們經過經緯度來描述某個位置,而通過投影以後的地圖也有本身的座標系統,本篇文章就來詳細介紹在百度地圖API中涉及的各類座標體系。 html
在百度地圖API中,你須要瞭解以下座標系: git
- 經緯度:經過經度(longitude)和緯度(latitude)描述的地球上的某個位置。
- 平面座標:投影以後的座標(用x和y描述),用於在平面上標識某個位置。
- 可視區域座標:地圖可視區域的座標系(用x和y描述)。
- 覆蓋物座標:覆蓋物相對於容器的座標(用x和y描述)。
別被這麼多的座標系嚇着,看完了後面的講解相信你會逐漸理解它們。 api
經緯度 this
這個就很少說了,不熟悉的能夠翻翻地理書。但須要注意的是即使同是經緯度座標也可能屬於不一樣的座標體系。通常GPS設備獲取的經緯度屬於WGS84座標系,這是一個比較通用的座標體系。因爲某些緣由國內不能直接使用WGS84座標,所以百度地圖API的經緯度是通過加密偏移的。 加密
平面座標 spa
前面說過,球面上的形狀須要通過投影才能變換爲平面上的形狀,變換後就須要有一個平面座標系統來描述地圖上某個位置。百度地圖API默認使用墨卡託投影(Mercator Projection),一樣須要注意的是因爲投影參數不一樣,一樣是墨卡託投影也會有所差異。 htm
平面座標系的原點與經緯度的原點一致,即赤道與0度經線相交的位置: 圖片
在百度地圖API中,平面座標是以最大級別18級爲基準的。就是說在18級下,平面座標的一個單位就表明了屏幕上的1個像素。平面座標與地圖所展現的級別沒有關係,也就是說在1級和18級下,天安門位置的平面座標都是一致的。那麼如何知道某個位置的平面座標呢?可經過BMap.MercatorProjection類來完成,該類提供經緯度與平面座標互相轉換的方法。例如天安門的經緯度大約爲116.404, 39.915,通過轉換便可獲得平面座標: ip
var projection =new BMap.MercatorProjection();
var point = projection.lngLatToPoint(new BMap.Point(116.404, 39.915));
alert(point.x +", "+ point.y);
結果以下: utf-8
這個就是平面座標。你能夠這樣理解它的含義:第18級下,天安門距離座標原點的位置差爲:12958175, 4825923.77,單位爲像素。
像素座標
在第18級下,咱們直接將平面座標向下取整就獲得了像素座標,而在其餘級別下能夠經過以下公式進行換算(這裏取整爲向下取整):
像素座標 = |平面座標 × 2 zoom -18|
好比通過計算,在第4級天安門位置的像素座標是:790, 294
不一樣級別下,同一個地理位置的像素座標是不同的,它與當前地圖的級別相關。
圖塊座標
百度地圖API在展現地圖時是將整個地圖圖片切割成若干圖塊來顯示的,當地圖初始化或是地圖級別、中心點位置發生變化時,地圖API會根據當前像素座標計算出視野內須要的圖塊座標(也叫圖塊編號),從而加載對應的圖塊用以顯示地圖。
百度地圖的圖塊座標原點與平面座標一致,從原點向右上方開始編號爲0, 0:
如何知道某個位置的圖塊座標呢?經過以下公式計算便可(這裏爲向下取整):
256其實是每一個圖塊的寬度和高度,咱們用像素座標除以這個數就知道圖塊座標了。還以天安門爲例,在第4級下天安門所在的圖塊編號爲:3, 1,而在第18級下,圖塊編號爲:50617, 18851
可視區域座標
地圖都是顯示在肯定大小的矩形框中的,這個矩形框一般是開發者在初始化地圖傳入的某個容器元素。這個矩形框也有本身的座標系,在百度地圖API中稱之爲可視區域座標系,它的原點位於矩形的左上角。
經過Map類的pointToPixel和pixelToPoint方法能夠相互轉換經緯度座標與可視區域座標。
覆蓋物座標
覆蓋物在實現上就是若干DOM元素,這些元素會被放在若干覆蓋物容器內(具體請參考地圖API開發指南),那麼覆蓋物的座標實際上就是相對於這些覆蓋物容器的座標。在地圖初始化完成後,覆蓋物容器的左上角與地圖可視區域左上角位置相同,一旦地圖被移動、縮放,覆蓋物容器位置就會發生變化。在自定義覆蓋物的時候API提供經緯度信息,而開發者須要自行將經緯度轉換爲覆蓋物的像素座標,從而覆蓋物才能顯示在正確的位置上。這個轉換過程能夠經過Map的pointToOverlayPixel和overlayPixelToPoint兩個方法來實現。
講這麼多都快暈了吧,咱們最後經過一個完整的代碼示例來回顧上面所提到的座標系概念:
<!
DOCTYPE html
>
<
html
>
<
head
>
<
meta
charset
="utf-8"
/>
<
title
>
地圖座標概念
</
title
>
<
script
src
="http://api.map.baidu.com/api?v=1.2"
></
script
>
</
head
>
<
body
>
<
div
id
="map_container"
style
="width:500px;height:320px;"
></
div
>
<
script
>
var
map
=
new
BMap.Map(
'
map_container
'
, {defaultCursor:
'
default
'
});
map.centerAndZoom(
new
BMap.Point(
116.404
,
39.915
),
11
);
var
TILE_SIZE
=
256
;
map.addEventListener(
'
click
'
,
function
(e){
var
info
=
new
BMap.InfoWindow(
''
, {width:
260
});
var
projection
=
this
.getMapType().getProjection();
var
lngLat
=
e.point;
var
lngLatStr
=
"
經緯度:
"
+
lngLat.lng
+
"
,
"
+
lngLat.lat;
var
worldCoordinate
=
projection.lngLatToPoint(lngLat);
var
worldCoordStr
=
"
<br />平面座標:
"
+
worldCoordinate.x
+
"
,
"
+
worldCoordinate.y;
var
pixelCoordinate
=
new
BMap.Pixel(Math.floor(worldCoordinate.x
*
Math.pow(
2
,
this
.getZoom()
-
18
)),
Math.floor(worldCoordinate.y
*
Math.pow(
2
,
this
.getZoom()
-
18
)));
var
pixelCoordStr
=
"
<br />像素座標:
"
+
pixelCoordinate.x
+
"
,
"
+
pixelCoordinate.y;
var
tileCoordinate
=
new
BMap.Pixel(Math.floor(pixelCoordinate.x
/
256
),
Math.floor(pixelCoordinate.y
/
256
));
var
tileCoordStr
=
"
<br />圖塊座標:
"
+
tileCoordinate.x
+
"
,
"
+
tileCoordinate.y;
var
viewportCoordinate
=
map.pointToPixel(lngLat);
var
viewportCoordStr
=
"
<br />可視區域座標:
"
+
viewportCoordinate.x
+
"
,
"
+
viewportCoordinate.y;
var
overlayCoordinate
=
map.pointToOverlayPixel(lngLat);
var
overlayCoordStr
=
"
<br />覆蓋物座標:
"
+
overlayCoordinate.x
+
"
,
"
+
overlayCoordinate.y;
info.setContent(lngLatStr
+
worldCoordStr
+
pixelCoordStr
+
tileCoordStr
+
viewportCoordStr
+
overlayCoordStr);
map.openInfoWindow(info, lngLat);
});
</
script
>
</
body
>
</
html
>
效果如圖: