房產(chǎn)地圖google map的初步應(yīng)用點(diǎn)滴.1)
房產(chǎn)地圖google map的初步應(yīng)用點(diǎn)滴.2)
房產(chǎn)地圖google map的初步應(yīng)用點(diǎn)滴.3)
本來(lái)是想將房產(chǎn)地圖google map的應(yīng)用記錄一個(gè)系列,但繼1)記錄完之后總找不到時(shí)間繼續(xù)記錄下去,1)中主要解決了Google Maps JavaScript API V3 與 Google Local Search API兩者由于版本問(wèn)題帶來(lái)的一系列麻煩,思路是使用一個(gè)iframe作為兼容的跳板,子頁(yè)面應(yīng)用Local Search API獲得查詢(xún)的result后返回給父頁(yè)面,下面再記錄一些地圖坐標(biāo)的定位和一些UI的組成。
效果可參考 http://xf.house.163.com/gz/map/00Xa.html
1.坐標(biāo)定位
打開(kāi)一個(gè)樓盤(pán)的地圖,首先需要將此樓盤(pán)定位為此地圖的中心點(diǎn)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=GBK"/>
<title></title>
<style type="text/css">
</style>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
var map;
var lat = 23.1257424;
var lng = 113.37404225;
function init() {
var mapDiv = document.getElementById('map-canvas');
map = new google.maps.Map(mapDiv, {
center: new google.maps.LatLng(lat,lng),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
}
google.maps.event.addDomListener(window, 'load', init);
</script>
</head>
<body style="">
<div id="map-canvas" style="width: 600px; height: 500px"></div>
</body>
</html>
這里要注意的是我們引進(jìn)了http://maps.google.com/maps/api/js?sensor=false,這是google MAP API V3版本的連接點(diǎn)
創(chuàng)建了一個(gè)div <div id="map-canvas" style="width: 600px; height: 500px"></div>作為地圖的容器,然后對(duì)地圖基本類(lèi)Map進(jìn)行創(chuàng)建
google.maps.Map 是google map的容器實(shí)現(xiàn),在指定的 HTML 容器中創(chuàng)建新的地圖,該容器通常是一個(gè)DIV元素
在初始化地圖,還要?jiǎng)?chuàng)建一個(gè)地圖的初始化變量,這些變量包括了上面的center,zoom,mapTypeId等等
google.maps.LatLng 是一個(gè)以緯度和經(jīng)度表示的地理坐標(biāo)點(diǎn),在上面我們使用一個(gè)定義好的LatLng類(lèi)確定了整個(gè)地圖的中心點(diǎn),其中l(wèi)at 和 lng 分別為我們樓盤(pán)的經(jīng)緯度值
zoom 為地圖展開(kāi)的級(jí)別
google.maps.MapTypeId.ROADMAP 是地圖顯示的類(lèi)型,通常有ROADMAP,SATELLITE,TERRAIN等等,這里選擇的ROADMAP類(lèi)型是顯示為普通的街道地圖
2.為定位的樓盤(pán)添加圖標(biāo)
在上面完成了將樓盤(pán)顯示到整個(gè)地圖的中心處,下面為該樓盤(pán)添加圖標(biāo),給樓盤(pán)坐標(biāo)的位置添加圖標(biāo),實(shí)際上也就是在地圖上添加一個(gè)疊加層,在google MAP API中擁有大量的實(shí)現(xiàn)類(lèi),如Marker,為我們上面的程序加多個(gè)Marker實(shí)現(xiàn),樓盤(pán)的圖標(biāo)就可以顯示出來(lái)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=GBK"/>
<title></title>
<style type="text/css">
</style>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
var map;
var lat = 23.1257424;
var lng = 113.37404225;
function initialize() {
var mapDiv = document.getElementById('map-canvas');
map = new google.maps.Map(mapDiv, {
center: new google.maps.LatLng(lat,lng),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var marker = new google.maps.Marker({
position: new google.maps.LatLng(lat,lng),
map: map
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body style="">
<div id="map-canvas" style="width: 600px; height: 500px"></div>
</body>
</html>
但是呢,這個(gè)圖標(biāo)并不是我們想要的,我們想要的是在此樓盤(pán)經(jīng)緯度處放入自己的圖片,設(shè)置是一段html的顯示代碼來(lái)組成自定義的疊加層,并且這個(gè)疊加層可以監(jiān)聽(tīng)各種事件,可以對(duì)拖動(dòng)地圖的DOM元素中指定的地理位置像素坐標(biāo)進(jìn)行計(jì)算
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=GBK"/>
<title></title>
<style type="text/css">
</style>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
var map;
var lat = 23.1257424;
var lng = 113.37404225;
function initialize() {
var mapDiv = document.getElementById('map-canvas');
map = new google.maps.Map(mapDiv, {
center: new google.maps.LatLng(lat,lng),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
new CustomMarker(map.getCenter(), map);
}
function CustomMarker(latlng,map) {
this.latlng_ = latlng;
this.setMap(map);
}
//擴(kuò)展自O(shè)verlayView;OverlayView擴(kuò)展自MVCObject,實(shí)際上也擴(kuò)展自MVCObject
CustomMarker.prototype = new google.maps.OverlayView();
CustomMarker.prototype.draw = function() {
var me = this;
var div = this.div_;
if (!div) {
div = this.div_ = document.createElement('DIV');
div.style.position = "absolute";
div.innerHTML = "<span><img src='http://gmaps-utility-library.googlecode.com/svn/trunk/markermanager/release/examples/images/house.png'/></span>";
//這個(gè)div的對(duì)象需要Listener事件,必須先用trigger(me)先進(jìn)行偵聽(tīng)
google.maps.event.addDomListener(div, "click", function(event) {
google.maps.event.trigger(me, "click");
});
var panes = this.getPanes();
panes.overlayImage.appendChild(div);
}
CustomMarker.prototype.remove = function() {
if (this.div_) {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
}
};
//獲取Position
CustomMarker.prototype.getPosition = function() {
return this.latlng_;
};
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body style="">
<div id="map-canvas" style="width: 500px; height: 400px"></div>
</body>
</html>
實(shí)現(xiàn)效果如下
我們創(chuàng)建一個(gè)CustomMarker類(lèi),擴(kuò)展自O(shè)verlayView;OverlayView擴(kuò)展自MVCObject,實(shí)際上也擴(kuò)展自MVCObject
這里需要詳細(xì)說(shuō)說(shuō)OverlayView,我們繼承了此類(lèi),方法是將疊加層的 prototype 設(shè)置為 new OverlayView.prototype。必須實(shí)現(xiàn)三個(gè)方法,即 onAdd()、draw() 和 onRemove()。在 add() 方法中,您應(yīng)當(dāng)創(chuàng)建 DOM 對(duì)象,并將其作為窗格的子對(duì)象附加。在 draw() 方法中,應(yīng)放置這些元素。在 onRemove() 方法中,應(yīng)將對(duì)象從 DOM 中刪除。您必須調(diào)用包含有效地圖對(duì)象的 setMap(),以觸發(fā)對(duì) onAdd() 方法和 setMap(null) 的調(diào)用,這樣才能觸發(fā) onRemove() 方法。可以在構(gòu)建疊加層時(shí)調(diào)用 setMap() 方法,也可以在需要重新顯示已刪除疊加層的任何時(shí)候調(diào)用該方法。每當(dāng)?shù)貓D屬性更改時(shí)都會(huì)調(diào)用 draw() 方法,該方法可以更改元素的位置,如縮放、中心或地圖類(lèi)型。
把疊加層的繪圖放在draw()方法中,我們?cè)俅朔椒ㄖ袆?chuàng)建了一個(gè)DIV,并且使用innerHTML屬性將要顯示的html代碼寫(xiě)回div中,并且如果需要對(duì)此屬性加添加Listener事件時(shí),則必須先使用trigger(me)先進(jìn)行偵聽(tīng),這樣才能對(duì)外部的event事件進(jìn)行反應(yīng),在構(gòu)建完div后還需要獲得panes窗口,panes包含渲染疊加層的 DOM 元素,作為顯示此 OverlayView 的窗格,記住它是必須在draw 方法調(diào)用后才能實(shí)用。
onRemove() 實(shí)現(xiàn)此方法可將您的元素從 DOM 刪除。調(diào)用 setMap(null) 之后立即調(diào)用此方法。
getProjection() 返回與相應(yīng) OverlayView 相關(guān)聯(lián)的 MapCanvasProjection 對(duì)象。僅在調(diào)用 draw 函數(shù)后才可用
3.點(diǎn)擊樓盤(pán)圖標(biāo)填出樓盤(pán)信息盒子
下面再需要實(shí)現(xiàn)的效果是點(diǎn)擊剛才創(chuàng)建的樓盤(pán)圖標(biāo),則彈出一個(gè)樓盤(pán)信息盒子
先上代碼,再上效果圖
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=GBK"/>
<title></title>
<style type="text/css">
@import url("http://img1.cache.netease.com/cnews/css07/style.css");
@import url("http://img1.cache.netease.com/cnews/img09/channel_nav.css");
@import url("http://xf.house.163.com/product/css/ydmap.css");
</style>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
var map;
var lat = 23.1257424;
var lng = 113.37404225;
function initialize() {
var mapDiv = document.getElementById('map-canvas');
map = new google.maps.Map(mapDiv, {
center: new google.maps.LatLng(lat,lng),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var marker = new CustomMarker(map.getCenter(), map);
google.maps.event.addListener(marker, "click", function(e) {
var infoBox = new InfoBox({
latlng : marker.getPosition(),
map : map
});
});
}
function CustomMarker(latlng,map) {
this.latlng_ = latlng;
this.setMap(map);
}
//擴(kuò)展自O(shè)verlayView;OverlayView擴(kuò)展自MVCObject,實(shí)際上也擴(kuò)展自MVCObject
CustomMarker.prototype = new google.maps.OverlayView();
CustomMarker.prototype.draw = function() {
var me = this;
var div = this.div_;
if (!div) {
div = this.div_ = document.createElement('DIV');
div.style.position = "absolute";
div.innerHTML = "<span><img src='http://gmaps-utility-library.googlecode.com/svn/trunk/markermanager/release/examples/images/house.png'/></span>";
//這個(gè)div的對(duì)象需要Listener事件,必須先用trigger(me)先進(jìn)行偵聽(tīng)
google.maps.event.addDomListener(div, "click", function(event) {
google.maps.event.trigger(me, "click");
});
var panes = this.getPanes();
panes.overlayImage.appendChild(div);
}
//計(jì)算存放可拖動(dòng)地圖的 DOM 元素中指定地理位置的像素坐標(biāo)
var point = this.getProjection().fromLatLngToDivPixel(this.latlng_);
//div的像素坐標(biāo)
if (point) {
div.style.left = point.x + 'px';
div.style.top = point.y + 'px';
}
};
CustomMarker.prototype.remove = function() {
if (this.div_) {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
}
};
//獲取Position
CustomMarker.prototype.getPosition = function() {
return this.latlng_;
};
/*********************************************************************************************************************************************************
* InfoBox==樓盤(pán)icon點(diǎn)擊后彈出的box窗口,繼承OverlayView,
*/
function InfoBox(opts) {
google.maps.OverlayView.call(this);
this.latlng_ = opts.latlng;
this.map_ = opts.map;
this.offsetVertical_ = -260;
this.offsetHorizontal_ = -450;
//div偏移的像素
this.height_ = 260;
this.width_ = 460;
var me = this;
//監(jiān)聽(tīng)bounds
this.boundsChangedListener_ = google.maps.event.addListener(this.map_,
"bounds_changed", function() {
return me.panMap.apply(me);
});
this.setMap(this.map_);
}
InfoBox.prototype = new google.maps.OverlayView();
//移除div
InfoBox.prototype.remove = function() {
if (this.div_) {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
}
};
InfoBox.prototype.draw = function() {
// 創(chuàng)建element
this.createElement();
if (!this.div_)
return;
var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
if (!pixPosition)
return;
// top,left減去width,height達(dá)到右下角對(duì)齊的效果
this.div_.style.width = this.width_ + "px";
this.div_.style.left = (pixPosition.x + this.offsetHorizontal_ )+ "px";
this.div_.style.height = this.height_ + "px";
this.div_.style.top = (pixPosition.y + this.offsetVertical_ )+ "px";
this.div_.style.display = 'block';
};
InfoBox.prototype.createElement = function() {
//返回可在其中顯示此 OverlayView 的窗格。僅在調(diào)用 draw 函數(shù)后才可用。
var panes = this.getPanes();
var div = this.div_;
if (!div) {
div = this.div_ = document.createElement("div");
var content = document.getElementById("houseInfoBox_template").value;
div.style.border = "0px none";
div.style.position = "absolute";
div.innerHTML = content;
panes.floatPane.appendChild(div);
this.panMap();
} else if (div.parentNode != panes.floatPane) {
// 如果panes發(fā)生變化,移除此div
div.parentNode.removeChild(div);
panes.floatPane.appendChild(div);
} else {
}
}
/*
* 對(duì)InfoBox的pan進(jìn)行調(diào)整,調(diào)整到居中值減去偏移值,控制infobox的位置
*/
InfoBox.prototype.panMap = function() {
var map = this.map_;
//返回當(dāng)前視口的緯度/經(jīng)度范圍。如果還未啟動(dòng)地圖(即 mapType 仍為 Null),或者沒(méi)有設(shè)置中心和縮放,則結(jié)果為 Null。
var bounds = map.getBounds();
if (!bounds)
return;
// InfoBox的位置
var position = this.latlng_;
// InfoBox的尺寸
var iwWidth = this.width_;
var iwHeight = this.height_;
// infobox位置和尺寸的抵消
var iwOffsetX = this.offsetHorizontal_;
var iwOffsetY = this.offsetVertical_;
var padX = 40;
var padY = 40;
// 像素的計(jì)算
var mapDiv = map.getDiv();
var mapWidth = mapDiv.offsetWidth;
var mapHeight = mapDiv.offsetHeight;
var boundsSpan = bounds.toSpan();////將指定的地圖范圍轉(zhuǎn)換為緯度/經(jīng)度跨度。
var longSpan = boundsSpan.lng();//
var latSpan = boundsSpan.lat();//緯度的地圖跨度
var degPixelX = longSpan / mapWidth;
var degPixelY = latSpan / mapHeight;
// 地圖界面跳動(dòng)的定位
var mapWestLng = bounds.getSouthWest().lng();
var mapEastLng = bounds.getNorthEast().lng();
var mapNorthLat = bounds.getNorthEast().lat();
var mapSouthLat = bounds.getSouthWest().lat();
// infowindow的bounds
var iwWestLng = position.lng() + (iwOffsetX - padX) * degPixelX;
var iwEastLng = position.lng() + (iwOffsetX + iwWidth + padX) * degPixelX;
var iwNorthLat = position.lat() - (iwOffsetY - padY) * degPixelY;
var iwSouthLat = position.lat() - (iwOffsetY + iwHeight + padY) * degPixelY;
// 向居中的偏移計(jì)算
var shiftLng = (iwWestLng < mapWestLng ? mapWestLng - iwWestLng : 0) ;
var shiftLat = (iwNorthLat > mapNorthLat ? mapNorthLat - iwNorthLat : 0) ;
// 居中值
var center = map.getCenter();
// 居中值減去偏移值,得到infobox的位置
var centerX = center.lng() - shiftLng;
var centerY = center.lat() - shiftLat;
//***********************************************************
// 重新確定并顯示樓盤(pán)為地圖的中心點(diǎn) ps:此處取消重新定位
map.setCenter(new google.maps.LatLng(centerY, centerX));
//***********************************************************
// 移除上面bounds監(jiān)聽(tīng)值“this.boundsChangedListener_”
google.maps.event.removeListener(this.boundsChangedListener_);
this.boundsChangedListener_ = null;
};
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body style="">
<div id="map-canvas" style="width: 600px; height: 400px"></div>
<textarea name="houseInfoBox_template" id="houseInfoBox_template">
<div class="houseInfoBox" style="width:460px;height:200px;">
<div class="boxc2"></div>
<div class="boxc1"></div>
<div class="boxc3"></div>
<div class="boxc5">
<div class="boxc4"></div>
<div class="houseDataMap">
<h2 class="title">房產(chǎn)地圖</h2>
<div class="tabTilHouse">
<ul>
<li class="on">樓盤(pán)信息</li>
</ul>
</div>
<div class="datas">
<div class="infos">
<span class="equal">本月均價(jià):<strong class="cDRed">¥1000</strong></span>
<span class="blank3"></span>
地址:廣州廣州廣州廣州廣州廣州廣州<br />
電話:123123123123
<p class="about">簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介簡(jiǎn)介 <span class="cDRed"><a href="">»查看詳情</a></span></p>
</div>
<div class="prePic"><a href=""><img src="http://img2.cache.netease.com/photo/0087/2009-07-13/1247479037333.jpg" width="160" height="120" /></a></div>
</div>
</div>
<div class="boxc6"></div>
</div>
<div class="boxc7"></div>
<div class="boxc8"></div>
<div class="boxc9" ></div>
<span class="close" id="infohouse_close"></span>
</div>
</textarea>
</body>
</html>
下面是效果圖
看似有點(diǎn)恐怖增加了很多代碼,其實(shí)只是增加了一個(gè)InfoBox類(lèi),也是擴(kuò)展自O(shè)verlayView,基本上實(shí)現(xiàn)的道理跟上面的CustomMarker一樣,不過(guò)里面多了很多細(xì)節(jié),最重要一點(diǎn)是div的偏移計(jì)算,因?yàn)檫@個(gè)box對(duì)應(yīng)的方位是右下角,而div在定義時(shí)候與像素的對(duì)應(yīng)點(diǎn)是在左上角,所以這里涉及到一個(gè)對(duì)InfoBox的pan進(jìn)行調(diào)整,調(diào)整到居中值減去偏移值,控制infobox的位置,可見(jiàn)代碼 InfoBox.prototype.panMap = function() {},當(dāng)然啦,偏移值是跟你的div實(shí)際情況有關(guān)的,記住要將偏移像素值換算成地圖的經(jīng)緯度值,這部分計(jì)算的細(xì)節(jié)很多,要安裝實(shí)際情況進(jìn)行轉(zhuǎn)換。
var marker = new CustomMarker(map.getCenter(), map);
google.maps.event.addListener(marker, "click", function(e) {
var infoBox = new InfoBox({
latlng : marker.getPosition(),
map : map
});
});
為樓盤(pán)圖標(biāo)添加一個(gè)addListener click事件,只要觸動(dòng)click就會(huì)相應(yīng)new InfoBox,其實(shí)google的event非常多,下一節(jié)再說(shuō)說(shuō)這個(gè)
如果你也在進(jìn)行g(shù)oogle map的開(kāi)發(fā),歡迎賜教和討論,建了個(gè)qq群:11029590
----------------------------------------
by 陳于喆
QQ:34174409
Mail: dongbule@163.com