房產地圖google map的初步應用點滴.1)
房產地圖google map的初步應用點滴.2)
房產地圖google map的初步應用點滴.3)
本來是想將房產地圖google map的應用記錄一個系列,但繼1)記錄完之后總找不到時間繼續記錄下去,1)中主要解決了Google Maps JavaScript API V3 與 Google Local Search API兩者由于版本問題帶來的一系列麻煩,思路是使用一個iframe作為兼容的跳板,子頁面應用Local Search API獲得查詢的result后返回給父頁面,下面再記錄一些地圖坐標的定位和一些UI的組成。
效果可參考 http://xf.house.163.com/gz/map/00Xa.html
1.坐標定位
打開一個樓盤的地圖,首先需要將此樓盤定位為此地圖的中心點
<!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>
這里要注意的是我們引進了http://maps.google.com/maps/api/js?sensor=false,這是google MAP API V3版本的連接點
創建了一個div <div id="map-canvas" style="width: 600px; height: 500px"></div>作為地圖的容器,然后對地圖基本類Map進行創建
google.maps.Map 是google map的容器實現,在指定的 HTML 容器中創建新的地圖,該容器通常是一個DIV元素
在初始化地圖,還要創建一個地圖的初始化變量,這些變量包括了上面的center,zoom,mapTypeId等等
google.maps.LatLng 是一個以緯度和經度表示的地理坐標點,在上面我們使用一個定義好的LatLng類確定了整個地圖的中心點,其中lat 和 lng 分別為我們樓盤的經緯度值
zoom 為地圖展開的級別
google.maps.MapTypeId.ROADMAP 是地圖顯示的類型,通常有ROADMAP,SATELLITE,TERRAIN等等,這里選擇的ROADMAP類型是顯示為普通的街道地圖
2.為定位的樓盤添加圖標
在上面完成了將樓盤顯示到整個地圖的中心處,下面為該樓盤添加圖標,給樓盤坐標的位置添加圖標,實際上也就是在地圖上添加一個疊加層,在google MAP API中擁有大量的實現類,如Marker,為我們上面的程序加多個Marker實現,樓盤的圖標就可以顯示出來
<!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>
但是呢,這個圖標并不是我們想要的,我們想要的是在此樓盤經緯度處放入自己的圖片,設置是一段html的顯示代碼來組成自定義的疊加層,并且這個疊加層可以監聽各種事件,可以對拖動地圖的DOM元素中指定的地理位置像素坐標進行計算
<!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);
}
//擴展自OverlayView;OverlayView擴展自MVCObject,實際上也擴展自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>";
//這個div的對象需要Listener事件,必須先用trigger(me)先進行偵聽
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>
實現效果如下
我們創建一個CustomMarker類,擴展自OverlayView;OverlayView擴展自MVCObject,實際上也擴展自MVCObject
這里需要詳細說說OverlayView,我們繼承了此類,方法是將疊加層的 prototype 設置為 new OverlayView.prototype。必須實現三個方法,即 onAdd()、draw() 和 onRemove()。在 add() 方法中,您應當創建 DOM 對象,并將其作為窗格的子對象附加。在 draw() 方法中,應放置這些元素。在 onRemove() 方法中,應將對象從 DOM 中刪除。您必須調用包含有效地圖對象的 setMap(),以觸發對 onAdd() 方法和 setMap(null) 的調用,這樣才能觸發 onRemove() 方法。可以在構建疊加層時調用 setMap() 方法,也可以在需要重新顯示已刪除疊加層的任何時候調用該方法。每當地圖屬性更改時都會調用 draw() 方法,該方法可以更改元素的位置,如縮放、中心或地圖類型。
把疊加層的繪圖放在draw()方法中,我們再此方法中創建了一個DIV,并且使用innerHTML屬性將要顯示的html代碼寫回div中,并且如果需要對此屬性加添加Listener事件時,則必須先使用trigger(me)先進行偵聽,這樣才能對外部的event事件進行反應,在構建完div后還需要獲得panes窗口,panes包含渲染疊加層的 DOM 元素,作為顯示此 OverlayView 的窗格,記住它是必須在draw 方法調用后才能實用。
onRemove() 實現此方法可將您的元素從 DOM 刪除。調用 setMap(null) 之后立即調用此方法。
getProjection() 返回與相應 OverlayView 相關聯的 MapCanvasProjection 對象。僅在調用 draw 函數后才可用
3.點擊樓盤圖標填出樓盤信息盒子
下面再需要實現的效果是點擊剛才創建的樓盤圖標,則彈出一個樓盤信息盒子
先上代碼,再上效果圖
<!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);
}
//擴展自OverlayView;OverlayView擴展自MVCObject,實際上也擴展自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>";
//這個div的對象需要Listener事件,必須先用trigger(me)先進行偵聽
google.maps.event.addDomListener(div, "click", function(event) {
google.maps.event.trigger(me, "click");
});
var panes = this.getPanes();
panes.overlayImage.appendChild(div);
}
//計算存放可拖動地圖的 DOM 元素中指定地理位置的像素坐標
var point = this.getProjection().fromLatLngToDivPixel(this.latlng_);
//div的像素坐標
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==樓盤icon點擊后彈出的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;
//監聽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() {
// 創建element
this.createElement();
if (!this.div_)
return;
var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
if (!pixPosition)
return;
// top,left減去width,height達到右下角對齊的效果
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 的窗格。僅在調用 draw 函數后才可用。
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發生變化,移除此div
div.parentNode.removeChild(div);
panes.floatPane.appendChild(div);
} else {
}
}
/*
* 對InfoBox的pan進行調整,調整到居中值減去偏移值,控制infobox的位置
*/
InfoBox.prototype.panMap = function() {
var map = this.map_;
//返回當前視口的緯度/經度范圍。如果還未啟動地圖(即 mapType 仍為 Null),或者沒有設置中心和縮放,則結果為 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;
// 像素的計算
var mapDiv = map.getDiv();
var mapWidth = mapDiv.offsetWidth;
var mapHeight = mapDiv.offsetHeight;
var boundsSpan = bounds.toSpan();////將指定的地圖范圍轉換為緯度/經度跨度。
var longSpan = boundsSpan.lng();//
var latSpan = boundsSpan.lat();//緯度的地圖跨度
var degPixelX = longSpan / mapWidth;
var degPixelY = latSpan / mapHeight;
// 地圖界面跳動的定位
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;
// 向居中的偏移計算
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;
//***********************************************************
// 重新確定并顯示樓盤為地圖的中心點 ps:此處取消重新定位
map.setCenter(new google.maps.LatLng(centerY, centerX));
//***********************************************************
// 移除上面bounds監聽值“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">房產地圖</h2>
<div class="tabTilHouse">
<ul>
<li class="on">樓盤信息</li>
</ul>
</div>
<div class="datas">
<div class="infos">
<span class="equal">本月均價:<strong class="cDRed">¥1000</strong></span>
<span class="blank3"></span>
地址:廣州廣州廣州廣州廣州廣州廣州<br />
電話:123123123123
<p class="about">簡介簡介簡介簡介簡介簡介簡介簡介簡介簡介簡介簡介簡介簡介簡介簡介簡介簡介簡介簡介簡介簡介 <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>
下面是效果圖
看似有點恐怖增加了很多代碼,其實只是增加了一個InfoBox類,也是擴展自OverlayView,基本上實現的道理跟上面的CustomMarker一樣,不過里面多了很多細節,最重要一點是div的偏移計算,因為這個box對應的方位是右下角,而div在定義時候與像素的對應點是在左上角,所以這里涉及到一個對InfoBox的pan進行調整,調整到居中值減去偏移值,控制infobox的位置,可見代碼 InfoBox.prototype.panMap = function() {},當然啦,偏移值是跟你的div實際情況有關的,記住要將偏移像素值換算成地圖的經緯度值,這部分計算的細節很多,要安裝實際情況進行轉換。
var marker = new CustomMarker(map.getCenter(), map);
google.maps.event.addListener(marker, "click", function(e) {
var infoBox = new InfoBox({
latlng : marker.getPosition(),
map : map
});
});
為樓盤圖標添加一個addListener click事件,只要觸動click就會相應new InfoBox,其實google的event非常多,下一節再說說這個
如果你也在進行google map的開發,歡迎賜教和討論,建了個qq群:11029590
----------------------------------------
by 陳于喆
QQ:34174409
Mail: dongbule@163.com