百度地圖API, 文檔不全,例子不細致。 在網上還沒有太多有用的例子。比如說下面幾個需求的解決方案就找不到:
1. 如何用百度地圖API查詢一個地點的經緯度。
2. 如何用百度地圖通過一個經緯度查詢商圈和地址。
3.點擊百度地圖時, 獲得點擊位置的經緯度。
4. 如果按照時間軸動態顯示熱力圖的變化。
我昨天玩了一下午百度地圖javascript API,解決了上面的幾個問題,順道用少量打車用戶的抽樣數據做一個數據可視化, 給大家提供一個可以參考的例子
首先數據是來自北京市某個周日的出行數據, 其中包含出發地點和到達地點的經緯度。
{"passenger_phone":"XXX","start_location_lng":"116.31414794922","start_location_lat":"40.080762261285","end_location_lng":"116.3363","end_location_lat":"40.07079"}
{"passenger_phone":"XXX","start_location_lng":"116.734490","start_location_lat":"39.903438","end_location_lng":"116.735160","end_location_lat":"39.962470"}
由於數據是從spark里查詢出來放在hadoop上,是map后的一個結果, 因此每條數據的間隔符號是換行。這導致我必須在js里把數據文件命名為txt文件, 並且在js里做一些特殊處理。
百度地圖API, 因為需要頻繁在js里根據鼠標點擊獲得地理位置和商圈信息, 因此在html創建了一個不可見的container用來加載地圖查詢模塊
<div id="dummy" style ="display:none"></div>
用來加載百度地圖javascript model用來查詢地理信息。
var bmap4search= new BMap.Map("dummy");
var localSearch = new BMap.LocalSearch(bmap4search);
由於需要找出鼠標點擊位置五公里范圍內的人數, 因此需要一個計算地理距離的函數。
function rad(d)
{
return d * Math.PI / 180.0;
}
function getDistance(lng1,lat1, lng2,lat2)
{
radLat1 = rad(lat1);
radLat2 = rad(lat2);
a = radLat1 - radLat2;
b = rad(lng1) - rad(lng2);
s=2*Math.asin(
Math.sqrt(Math.pow(Math.sin(a/2), 2.0)+
Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2), 2.0)));
EARTH_RADIUS = 6378.137;
s = s * EARTH_RADIUS;
s = Math.round(s*10000) / 10000;
return s;
}
頁面加載后, 首先顯示用戶出發熱力圖, 看上去回龍觀還真像是北京的宇宙中心, 出行用戶最密集。
用鼠標點擊地圖上的某一個點, 可以獲得該點的地址信息。參考下一張圖。
用鼠標點擊回龍觀位置, 動態獲得一個坐標后, 按鈕“點擊顯示5公里內......”亮了。 點擊按鈕可以查看這些回龍觀的用戶, 周日出行目的地是哪里。結果發現回龍觀的群眾周末大多數也只在回龍觀附近晃盪。
至於播放時間軸熱力圖變化的問題, 其實是通過重新設置option時間的,方法與上圖完全相同
myChart.setOption(map_option);
下面幾張圖是回龍觀群眾在臨晨1點~5點按時間軸變化的出行熱力圖
臨晨3點
臨晨5點
早晨7點
可以看到上面亮了幾個點, 放大地圖看看。
發現分別是, 漢王大廈, 融澤嘉園售樓處, 回龍觀鎮醫院。還有一個高速公路收費站口
下面是部分代碼。
<!DOCTYPE html>
<html style="height: 100%">
<head>
<meta charset="utf-8">
<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=ZUONbpqGBsYGXNIYHicvbAbM"></script>
</head>
<body style="height: 100%; margin: 0">
<div style ="z-index=999">
<input type="button" value="點擊切換到出發熱力圖" onclick="chg(0)" disabled=disabled ID="startBtn" NAME="Button1">
<input type="button" value="點擊切換到到達熱力圖" onclick="chg(1)" ID="endBtn" NAME="Button1">
</div>
<div>
<div id=mytips style="z-order=999;background-color:#F0F8FF;width:100;height:16;border:2px solid gray;display:none;filter:progid:DXImageTransform.Microsoft.Shadow(color=#666666,direction=135,strength=5);left:5;top:5"></div>
<input type="button" value="點擊顯示5公里內嘀嘀新客的目的地或者來源" disabled=disabled onclick="showDS()" ID="src_dest_Btn" NAME="Button1">
</div>
<div id="dummy" style ="display:none"></div>
<div id="container" style="height: 100%">
</div>
<!-- 新添加的jQuery -->
<script type="text/javascript" src="./js/jquery-3.1.0.js"></script>
<!-- End -->
<script type="text/javascript" src="./js/echarts.js"></script>
<script type="text/javascript" src="./js/dataTool.js"></script>
<script type="text/javascript" src="./js/bmap.js"></script>
<script type="text/javascript">
var bmap4search= new BMap.Map("dummy");
var localSearch = new BMap.LocalSearch(bmap4search);
var dom = document.getElementById("container");
var myChart = echarts.init(dom);
var app = {};
option = null;
app.title = '熱力圖與百度地圖擴展';
var startPoints=[];
var endPoints=[];
var dsPoints=[];
var radium=5;
var gc = new BMap.Geocoder();
var map_option;
var map_status="default";//全部乘客的出發或者達到
//$.get('./js/data/bejing_track_end.json', function (data) {
$.get('./js/data/test.txt', function (data) {
var array = data.split('\n');
for(var i in array)
{
if(array[i]!="")
{
eval("temp="+array[i]);
startPoints[i]=[temp.start_location_lng, temp.start_location_lat].concat([1]);
endPoints[i]=[temp.end_location_lng, temp.end_location_lat].concat([1]);
}
}
option_start = {
animation: true,
bmap: {
center: [116.301670, 39.971690],
zoom: 11,
roam: true
},
visualMap: {
show: false,
top: 'top',
min: 0,
max: 5,
seriesIndex: 0,
calculable: true,
inRange: {
color: ['blue', 'blue', 'green', 'yellow', 'red']
}
},
series: [{
type: 'heatmap',
coordinateSystem: 'bmap',
data: startPoints,
pointSize: 10,
blurSize: 6
}]
}
option_end = {
animation: true,
bmap: {
center: [116.301670, 39.971690],
zoom: 11,
roam: true
},
visualMap: {
show: false,
top: 'top',
min: 0,
max: 5,
seriesIndex: 0,
calculable: true,
inRange: {
color: ['blue', 'blue', 'green', 'yellow', 'red']
}
},
series: [{
type: 'heatmap',
coordinateSystem: 'bmap',
data: endPoints,
pointSize: 10,
blurSize: 6
}]
}
//用來展示5公里范圍的人都去到那里, 或者從哪里來的。
option_ds = {
animation: true,
bmap: {
center: [116.301670, 39.971690],
zoom: 11,
roam: true
},
visualMap: {
show: false,
top: 'top',
min: 0,
max: 5,
seriesIndex: 0,
calculable: true,
inRange: {
color: ['blue', 'blue', 'green', 'yellow', 'red']
}
},
series: [{
type: 'heatmap',
coordinateSystem: 'bmap',
data: dsPoints,
pointSize: 10,
blurSize: 6
}]
}
var callback=function(center_point){
option_start.bmap.center = [center_point.lng, center_point.lat];
option_end.bmap.center = [center_point.lng, center_point.lat];
option_ds.bmap.center = [center_point.lng, center_point.lat];
map_option=option_start;
myChart.setOption(map_option);
var bmap = myChart.getModel().getComponent('bmap').getBMap();
bmap.addEventListener("click", function(e){ //鼠標點擊事件
var pt = e.point;
if(map_status=="default")
$("#src_dest_Btn").removeAttr("disabled");
else
$("#src_dest_Btn").attr("disabled","disabled");
seashowtip(1, pt.lng,pt.lat);
}
);
if (!app.inNode) {
// 添加百度地圖插件
bmap.addControl(new BMap.MapTypeControl());
}
}
searchByStationName("北京",callback);
});
function chg(type)
{
map_status="default";
if(type==0)
{
map_option = option_start;
$("#endBtn").removeAttr("disabled");
$("#startBtn").attr("disabled","disabled");
}else
{
map_option = option_end;
$("#startBtn").removeAttr("disabled");
$("#endBtn").attr("disabled","disabled");
}
$("#src_dest_Btn").attr("disabled","disabled");
myChart.setOption(map_option);
var my_tips=document.all.mytips;
my_tips.style.display="none";
};
function showDS()
{
//顯示5公里范圍內的新客的目的地或者來源。
if(dsPoints && dsPoints.length>0)
{
map_status="passenger_within5km";
$("#startBtn").removeAttr("disabled");
$("#endBtn").removeAttr("disabled");
option_ds.series[0].data=dsPoints;
map_option=option_ds;
myChart.setOption(map_option);
}
}
function calPopulationAround2(ln, la)
{
var result=[];
var points = map_option.series[0].data;
for(var i in points)
{
var track = points[i];
if(getDistance(track[0],track[1], ln, la)<radium/2)
{
result[index] = track;
index+=1;
}
}
return result;
};
function calPopulationAround(ln, la)
{
//計算5公里內的乘客坐標, 以及他們的來源或者目的地。
if(map_status!="default")
return calPopulationAround2(ln, la);
var result=[];
var points = startPoints;
var ds_points = endPoints;
if(!$("#startBtn").attr("disabled"))
{
points = endPoints;
ds_points=startPoints;
}
dsPoints=[];
var index=0;
for(var i in points)
{
var track = points[i];
if(getDistance(track[0],track[1], ln, la)<radium/2)
{
result[index] = track;
dsPoints[index] = ds_points[i];
index+=1;
}
}
return result;
};
function seashowtip(flag,ln,la){
var my_tips=document.all.mytips;
var points= calPopulationAround(ln,la);
searchByPoint(ln,la, function(result){
var tipsName = ""+result.address+",附近商圈:("+ result.business +"),坐標("+ln+","+la+")周圍"+radium+"公里范圍內首單人數:"+points.length+"人";
if(flag){
my_tips.innerHTML=tipsName;//為div塊上添加內容
my_tips.style.display="";
my_tips.style.width=150;
my_tips.style.zIndex=999;
my_tips.style.display="block";
//my_tips.style.left=event.clientX+10+document.body.scrollLeft;
//my_tips.style.top=event.clientY+document.body.scrollTop;
}else{
my_tips.style.display="none";
}
});
}
function rad(d)
{
return d * Math.PI / 180.0;
}
function getDistance(lng1,lat1, lng2,lat2)
{
radLat1 = rad(lat1);
radLat2 = rad(lat2);
a = radLat1 - radLat2;
b = rad(lng1) - rad(lng2);
s=2*Math.asin(
Math.sqrt(Math.pow(Math.sin(a/2), 2.0)+
Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2), 2.0)));
EARTH_RADIUS = 6378.137;
s = s * EARTH_RADIUS;
s = Math.round(s*10000) / 10000;
return s;
}
function searchByStationName(keyword, cb) {
//var keyword = "石景山區";
//根據地址來查詢經緯度。
localSearch.setSearchCompleteCallback(function (searchResult) {
var poi = searchResult.getPoi(0);
cb(poi.point);
});
localSearch.search(keyword);
}
function searchByPoint(lng,lat, cb)
{//根據經緯度查詢地址
var poi= new BMap.Point(lng,lat);
gc.getLocation(poi, function(rs){
cb(rs);
});
}
</script>
</body>
</html>