google map測距的實(shí)現(xiàn)和分析
不斷有傳聞google map在今年的7月1號之后在大陸停止運(yùn)營,具體原因是因?yàn)樘斐呐普諉栴},這個(gè)就不多講了,可以發(fā)現(xiàn)現(xiàn)在搜房網(wǎng)的地圖,和安居客等的地圖紛紛都撤下 google map,而重新選擇了mapabc或baidu,當(dāng)然網(wǎng)易房產(chǎn)地圖也不例外,現(xiàn)在也在使用mapabc作為網(wǎng)易房產(chǎn)地圖的開發(fā),預(yù)計(jì)將在6月底前上線,到 時(shí)再跟大家分享一下mapabc的一些開發(fā)實(shí)踐。
還是說回google map的開發(fā),自從上次建了個(gè)qq群就有不少人在問測距怎么實(shí)現(xiàn),當(dāng)然很多人想的是拿來主義的,當(dāng)時(shí)是拿http://xf.house.163.com /gz/map/000B.html的例子出來,但確實(shí)頁面上進(jìn)行了封裝也寫得比較亂,所以還是比較難以抽離,先給個(gè)簡單實(shí)現(xiàn)的例子:
不斷有傳聞google map在今年的7月1號之后在大陸停止運(yùn)營,具體原因是因?yàn)樘斐呐普諉栴},這個(gè)就不多講了,可以發(fā)現(xiàn)現(xiàn)在搜房網(wǎng)的地圖,和安居客等的地圖紛紛都撤下 google map,而重新選擇了mapabc或baidu,當(dāng)然網(wǎng)易房產(chǎn)地圖也不例外,現(xiàn)在也在使用mapabc作為網(wǎng)易房產(chǎn)地圖的開發(fā),預(yù)計(jì)將在6月底前上線,到 時(shí)再跟大家分享一下mapabc的一些開發(fā)實(shí)踐。
還是說回google map的開發(fā),自從上次建了個(gè)qq群就有不少人在問測距怎么實(shí)現(xiàn),當(dāng)然很多人想的是拿來主義的,當(dāng)時(shí)是拿http://xf.house.163.com /gz/map/000B.html的例子出來,但確實(shí)頁面上進(jìn)行了封裝也寫得比較亂,所以還是比較難以抽離,先給個(gè)簡單實(shí)現(xiàn)的例子:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=GBK"/>
<title>163網(wǎng)易房產(chǎn)</title>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
var map;
function initialize() {
var myLatlng = new google.maps.LatLng(23.116193,113.374525);
var myOptions = {
zoom: 15,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
}
var polyline;
var polylinesArray = [];
//距離標(biāo)記數(shù)組
var lenArray = [];
var rule = null;
//距離
function getDistance(){
//啟動(dòng)整個(gè)地圖的click偵聽
rule = google.maps.event.addListener(map,"click",function(event){
addMarker(event.latLng);
});
}
//添加新標(biāo)記
function addMarker(location){
//標(biāo)記選項(xiàng)
var myOptions = {
position : location,
draggable :false,
map : map,
};
marker = new google.maps.Marker(myOptions);
//將標(biāo)記壓入數(shù)組
lenArray.push(marker);
//計(jì)算距離
drawOverlay();
}
//畫出路徑覆蓋層
function drawOverlay(){
//路線數(shù)組
var flightPlanCoordinates = [];
//將坐標(biāo)壓入路線數(shù)組
if (lenArray) {
for (i in lenArray) {
flightPlanCoordinates.push(lenArray[i].getPosition());
}
}
//路徑選項(xiàng)
var polylineOptions = {
path : flightPlanCoordinates,
map : map,
strokeColor : "#FF0000",
strokeOpacity : 1.0,
strokeWeight : 2
};
polyline = new google.maps.Polyline(polylineOptions);
//清除原有折線路徑
if (polylinesArray) {
for (i in polylinesArray) {
polylinesArray[i].setMap(null);
}
polylinesArray = [];
}
polyline.setMap(map);
polylinesArray.push(polyline);
alert((polyline.getLength()/1000).toFixed(3) + "km");
}
google.maps.LatLng.prototype.distanceFrom = function(latlng) {
var lat = [this.lat(), latlng.lat()]
var lng = [this.lng(), latlng.lng()]
var R = 6378137;
var dLat = (lat[1] - lat[0]) * Math.PI / 180;
var dLng = (lng[1] - lng[0]) * Math.PI / 180;
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat[0] * Math.PI / 180) * Math.cos(lat[1] * Math.PI / 180) * Math.sin(dLng / 2) * Math.sin(dLng / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return Math.round(d);
}
google.maps.Marker.prototype.distanceFrom = function(marker) {
return this.getPosition().distanceFrom(marker.getPosition());
}
google.maps.Polyline.prototype.getLength = function() {
var d = 0;
var path = this.getPath();
var latlng;
for (var i = 0; i < path.getLength() - 1; i++) {
latlng = [path.getAt(i), path.getAt(i + 1)];
d += latlng[0].distanceFrom(latlng[1]);
}
return d;
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas" style="width: 500px; height: 400px"></div>
<a href="#this" onclick="getDistance();">開始測距</a>
</body>
</html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=GBK"/>
<title>163網(wǎng)易房產(chǎn)</title>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
var map;
function initialize() {
var myLatlng = new google.maps.LatLng(23.116193,113.374525);
var myOptions = {
zoom: 15,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
}
var polyline;
var polylinesArray = [];
//距離標(biāo)記數(shù)組
var lenArray = [];
var rule = null;
//距離
function getDistance(){
//啟動(dòng)整個(gè)地圖的click偵聽
rule = google.maps.event.addListener(map,"click",function(event){
addMarker(event.latLng);
});
}
//添加新標(biāo)記
function addMarker(location){
//標(biāo)記選項(xiàng)
var myOptions = {
position : location,
draggable :false,
map : map,
};
marker = new google.maps.Marker(myOptions);
//將標(biāo)記壓入數(shù)組
lenArray.push(marker);
//計(jì)算距離
drawOverlay();
}
//畫出路徑覆蓋層
function drawOverlay(){
//路線數(shù)組
var flightPlanCoordinates = [];
//將坐標(biāo)壓入路線數(shù)組
if (lenArray) {
for (i in lenArray) {
flightPlanCoordinates.push(lenArray[i].getPosition());
}
}
//路徑選項(xiàng)
var polylineOptions = {
path : flightPlanCoordinates,
map : map,
strokeColor : "#FF0000",
strokeOpacity : 1.0,
strokeWeight : 2
};
polyline = new google.maps.Polyline(polylineOptions);
//清除原有折線路徑
if (polylinesArray) {
for (i in polylinesArray) {
polylinesArray[i].setMap(null);
}
polylinesArray = [];
}
polyline.setMap(map);
polylinesArray.push(polyline);
alert((polyline.getLength()/1000).toFixed(3) + "km");
}
google.maps.LatLng.prototype.distanceFrom = function(latlng) {
var lat = [this.lat(), latlng.lat()]
var lng = [this.lng(), latlng.lng()]
var R = 6378137;
var dLat = (lat[1] - lat[0]) * Math.PI / 180;
var dLng = (lng[1] - lng[0]) * Math.PI / 180;
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat[0] * Math.PI / 180) * Math.cos(lat[1] * Math.PI / 180) * Math.sin(dLng / 2) * Math.sin(dLng / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return Math.round(d);
}
google.maps.Marker.prototype.distanceFrom = function(marker) {
return this.getPosition().distanceFrom(marker.getPosition());
}
google.maps.Polyline.prototype.getLength = function() {
var d = 0;
var path = this.getPath();
var latlng;
for (var i = 0; i < path.getLength() - 1; i++) {
latlng = [path.getAt(i), path.getAt(i + 1)];
d += latlng[0].distanceFrom(latlng[1]);
}
return d;
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas" style="width: 500px; height: 400px"></div>
<a href="#this" onclick="getDistance();">開始測距</a>
</body>
</html>

例子給完了,其中測距的計(jì)算是抄了google的示例,想簡單拿來應(yīng)用的到這里就可以結(jié)束了,還有點(diǎn)興趣的可以看看下面的簡單分析:
說到測距無非就是線的計(jì)算,根據(jù)google map api,測距的線性實(shí)現(xiàn)我們采用Polyline類,Polyline是折線是地圖上的連接線段的線性疊加層,擴(kuò)展自MVCObject。
測距是由線組成,然后根據(jù)一組線的長短計(jì)算出線的啟動(dòng)和終點(diǎn)線的距離,根據(jù)這個(gè)思路,我們定義出
var polyline;
var polylinesArray = [];
其中polyline是當(dāng)前畫出來這條線,polylinesArray是一個(gè)數(shù)組,當(dāng)每話出一條線就將這條線push到polylinesArray這個(gè)數(shù)組中去。
var polyline;
var polylinesArray = [];
其中polyline是當(dāng)前畫出來這條線,polylinesArray是一個(gè)數(shù)組,當(dāng)每話出一條線就將這條線push到polylinesArray這個(gè)數(shù)組中去。
另外一條線其實(shí)是由兩個(gè)點(diǎn),始點(diǎn)和終點(diǎn)所組成,所以我們也定義一個(gè)
var lenArray = [];
lenArray是一個(gè)數(shù)組,用來記錄鼠標(biāo)點(diǎn)過的每一個(gè)點(diǎn)的信息
也就是說整個(gè)測距是由每一條線所組成,而一條線是由2個(gè)點(diǎn)組成。
思路理清楚了,接著一步一步看
當(dāng)我們點(diǎn)擊了開始測距時(shí),就需要啟動(dòng)一個(gè)事件的監(jiān)聽,對整個(gè)map的click事件監(jiān)聽
rule = google.maps.event.addListener(map,"click",function(event){
addMarker(event.latLng);
});
當(dāng)我們在地圖上進(jìn)行點(diǎn)擊時(shí),就會(huì)新增一個(gè)maker點(diǎn),并且將這個(gè)maker壓入lenArray數(shù)組,以便于后面的計(jì)算
function addMarker(location){
...
marker = new google.maps.Marker(myOptions);
...
lenArray.push(marker);
drawOverlay();
接著會(huì)調(diào)用drawOverlay();使用polyline來畫線
var flightPlanCoordinates = [];
//將坐標(biāo)壓入路線數(shù)組
if (lenArray) {
for (i in lenArray) {
flightPlanCoordinates.push(lenArray[i].getPosition());
}
}
var polylineOptions = {
path : flightPlanCoordinates,
map : map,
strokeColor : "#FF0000",
strokeOpacity : 1.0,
strokeWeight : 2
};
polyline = new google.maps.Polyline(polylineOptions);
var lenArray = [];
lenArray是一個(gè)數(shù)組,用來記錄鼠標(biāo)點(diǎn)過的每一個(gè)點(diǎn)的信息
也就是說整個(gè)測距是由每一條線所組成,而一條線是由2個(gè)點(diǎn)組成。
思路理清楚了,接著一步一步看
當(dāng)我們點(diǎn)擊了開始測距時(shí),就需要啟動(dòng)一個(gè)事件的監(jiān)聽,對整個(gè)map的click事件監(jiān)聽
rule = google.maps.event.addListener(map,"click",function(event){
addMarker(event.latLng);
});
當(dāng)我們在地圖上進(jìn)行點(diǎn)擊時(shí),就會(huì)新增一個(gè)maker點(diǎn),并且將這個(gè)maker壓入lenArray數(shù)組,以便于后面的計(jì)算
function addMarker(location){
...
marker = new google.maps.Marker(myOptions);
...
lenArray.push(marker);
drawOverlay();
接著會(huì)調(diào)用drawOverlay();使用polyline來畫線
var flightPlanCoordinates = [];
//將坐標(biāo)壓入路線數(shù)組
if (lenArray) {
for (i in lenArray) {
flightPlanCoordinates.push(lenArray[i].getPosition());
}
}
var polylineOptions = {
path : flightPlanCoordinates,
map : map,
strokeColor : "#FF0000",
strokeOpacity : 1.0,
strokeWeight : 2
};
polyline = new google.maps.Polyline(polylineOptions);
其中polylineOptions的path參數(shù)是折線坐標(biāo)的有序序列。可以使用一個(gè)簡單的 LatLng 數(shù)組或者 LatLng 的 MVCArray 指定此路徑。請注意,如果您傳
遞簡單的數(shù)組,則它會(huì)轉(zhuǎn)換為 MVCArray。在 MVCArray 中插入或刪除 LatLng 將自動(dòng)更新地圖上的折線。
flightPlanCoordinates數(shù)組用于存儲(chǔ)在上面我們定義的lenArray數(shù)組的坐標(biāo)值,每點(diǎn)擊一次就壓入一對坐標(biāo)值。
strokeColor和strokeOpacity,strokeWeight是一些樣式的參數(shù),如指定線條的寬度等等。
最后我們將定義的polyline進(jìn)行setMap,在地圖上展現(xiàn),并將polyline壓入到polylinesArray數(shù)組中去。
polyline.setMap(map);
polylinesArray.push(polyline);
到這里,線和點(diǎn)的展現(xiàn)已經(jīng)完成了,接下來是需要將這些點(diǎn)線轉(zhuǎn)換成我們需要的距離值。
google.maps.Polyline.prototype.getLength = function() {
var d = 0;
var path = this.getPath();
var latlng;
for (var i = 0; i < path.getLength() - 1; i++) {
latlng = [path.getAt(i), path.getAt(i + 1)];
d += latlng[0].distanceFrom(latlng[1]);
}
return d;
}
遞簡單的數(shù)組,則它會(huì)轉(zhuǎn)換為 MVCArray。在 MVCArray 中插入或刪除 LatLng 將自動(dòng)更新地圖上的折線。
flightPlanCoordinates數(shù)組用于存儲(chǔ)在上面我們定義的lenArray數(shù)組的坐標(biāo)值,每點(diǎn)擊一次就壓入一對坐標(biāo)值。
strokeColor和strokeOpacity,strokeWeight是一些樣式的參數(shù),如指定線條的寬度等等。
最后我們將定義的polyline進(jìn)行setMap,在地圖上展現(xiàn),并將polyline壓入到polylinesArray數(shù)組中去。
polyline.setMap(map);
polylinesArray.push(polyline);
到這里,線和點(diǎn)的展現(xiàn)已經(jīng)完成了,接下來是需要將這些點(diǎn)線轉(zhuǎn)換成我們需要的距離值。
google.maps.Polyline.prototype.getLength = function() {
var d = 0;
var path = this.getPath();
var latlng;
for (var i = 0; i < path.getLength() - 1; i++) {
latlng = [path.getAt(i), path.getAt(i + 1)];
d += latlng[0].distanceFrom(latlng[1]);
}
return d;
}
這里需要講明的是this.getPath();它的說明是檢索第一條路徑。并且返回值是一組MVCArray.<LatLng>,也就是實(shí)際存儲(chǔ)了一條線的坐標(biāo)值,在這里取出這些坐標(biāo)的數(shù)組,并且進(jìn)行循環(huán)distanceFrom計(jì)算
google.maps.LatLng.prototype.distanceFrom = function(latlng) {
var lat = [this.lat(), latlng.lat()]
var lng = [this.lng(), latlng.lng()]
var R = 6378137;
var dLat = (lat[1] - lat[0]) * Math.PI / 180;
var dLng = (lng[1] - lng[0]) * Math.PI / 180;
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat[0] * Math.PI / 180) * Math.cos(lat[1] * Math.PI / 180) * Math.sin(dLng / 2) * Math.sin(dLng / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return Math.round(d);
}
這段計(jì)算實(shí)際上是抄自google map示例的,是將我們的坐標(biāo)值轉(zhuǎn)換成我們需要計(jì)算的距離值,這里就不分析,有興趣可以玩玩,沒興趣就直接抄過去吧。
結(jié)果出來了,這個(gè)就是我們需要的測距的距離,當(dāng)然你也可以用其他方式進(jìn)行展現(xiàn)
alert((polyline.getLength()/1000).toFixed(3) + "km");
google.maps.LatLng.prototype.distanceFrom = function(latlng) {
var lat = [this.lat(), latlng.lat()]
var lng = [this.lng(), latlng.lng()]
var R = 6378137;
var dLat = (lat[1] - lat[0]) * Math.PI / 180;
var dLng = (lng[1] - lng[0]) * Math.PI / 180;
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat[0] * Math.PI / 180) * Math.cos(lat[1] * Math.PI / 180) * Math.sin(dLng / 2) * Math.sin(dLng / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return Math.round(d);
}
這段計(jì)算實(shí)際上是抄自google map示例的,是將我們的坐標(biāo)值轉(zhuǎn)換成我們需要計(jì)算的距離值,這里就不分析,有興趣可以玩玩,沒興趣就直接抄過去吧。
結(jié)果出來了,這個(gè)就是我們需要的測距的距離,當(dāng)然你也可以用其他方式進(jìn)行展現(xiàn)
alert((polyline.getLength()/1000).toFixed(3) + "km");
只要閱讀google api和自己思路清楚,一個(gè)測距的demo很快就完成了,稍加裝飾基本就可以應(yīng)用于生產(chǎn)上
如果你也在進(jìn)行g(shù)oogle map的開發(fā),歡迎賜教和討論,建了個(gè)qq群:11029590