你可能用到的百度地圖效果(附源碼)

     這段時間須要實現百度地圖的一些展現效果,雖然最終效果作出來了,但是這中間也走了不少的彎路,但願有用到的能夠直接拿來用,少走一些彎路。百度地圖爲開發者提供了一系列的接口,點百度接口去百度接口。本文主要用到了如下幾個效果:php

一、熱力圖顯示html

二、自定義圖標的聚合顯示git

三、雲麻點顯示數據庫

      熱力圖顯示api

      百度地圖熱力圖是經過設置熱力圖半徑、顏色、透明度等參數直觀展現數據分佈狀況,而我這段時間所作的,就是經過一段時間內的訂單數量,再結合經緯度,在地圖上顯示熱力分佈圖。百度地圖官方的API給的示例很Easy,建立地圖實例,初始化參數,生成點的數組,而後建立熱力圖對象,並將熱力圖對象添加到地圖實例,設置數據源,這樣這個熱力圖的效果就能夠展現出來了。(固然申請AK和引入Js就不用說了),這部分源碼比較簡單,就不展現了,只須要看熱力圖API相信都是能夠明白的。數組

      但是本身作的時候,效果卻沒這麼容易出來。我在作的過程當中,開始最大的一處疑問就是,其餘代碼部分代碼都跟官方API示例同樣,只是換了個數據源,熱力圖效果就是出不來。後來在試了無數遍以後,發現若是當前地圖放大的級別過大,也就是有些點沒有在當前地圖可視區域內展現的話,熱力圖效果是不會出來的!固然了,關於這點沒有百度地圖官方的解釋,也沒有獲得求證,只是我在開發過程當中發現的一個解決方案。若是你也在作這部分,剛好遇到這個問題的話不妨試試。其次爲了效果明顯,最好是多添加幾個點,這樣效果會更好一些。如下是效果圖:瀏覽器

 

      自定義圖標聚合顯示服務器

      說到這個聚合顯示,哎,說多了都是淚啊。原本提出的需求只是須要將數據庫中的店鋪展現出來,而後點擊的時候彈出詳細信息的提示框。我一想,這還不簡單?經過Handler從後臺獲取到數據,而後以Json的格式傳給前臺,而後來個for循環,依次添加到地圖不就解決了?初版我確實是這麼幹的。拿到數據以後再作foreach……如下是Js腳本。閉包

function LoadMakers(data) {
    var Maker = "[";
    $(data).each(function () {
        var sContent = "<div  style='text-align: left;'><h4 style='margin:0 0 5px 0;padding:0.2em 0'>" + this.pointerTitle + "</h4>";
        if (this.pointImg) {
            sContent = "<div  style='text-align: left;'><h4 style='margin:0 0 5px 0;padding:0.2em 0; width:300px'>" + this.pointerTitle + "</h4>";
            sContent += "<img style='float:left;margin:4px;width:104px;height:69px' id='imgDemo' src='" + this.pointImg + "'  title='" + this.pointerTitle + "'/>";
        }
        if (this.address) {
            if (this.pointImg) {
                sContent += "<p style='margin:0;line-height:1.5;font-size:13px;width:200px;margin-left:110px'>" + this.address + "</p>";
            } else {
                sContent += "<p style='margin:0;line-height:1.5;font-size:13px;width:200px;'>" + this.address + "</p>";

            }
        }
        if (this.pointerContent) {
            if (this.pointImg) {
                sContent += "<p style='margin:0;line-height:1.5;font-size:13px;width:200px;margin-left:110px'>" + this.pointerContent + "</p>";
            } else {
                sContent += "<p style='margin:0;line-height:1.5;font-size:13px;width:200px;'>" + this.pointerContent + "</p>";
                
            }
        }
        sContent += "</div>";
        Maker += "{supId:"+this.spId+",Longitude:" + this.markersLongitude + ",Dimension:" + this.markersDimension + ",Window: { LoadEvent:'click',Content:\"" + sContent + "\"},enableMassClear:true},";
    });
    Maker += "]";
    return eval(Maker);
}
View Code

      我在本地添加了將近100個點的數據,測試沒問題以後就提交到Svn了,而後跟項目經理說這個東東作完了。而後項目經理將數據切成正式數據,叫我給他演示一下。這一演示沒關係啊,臉全沒了。正式數據庫中有5000多條數據,而我取數據時後臺作了過濾,只提取有經緯度的點,即便這樣也有1500多條記錄。沒錯,1500多條,這意味着瀏覽器客戶端這邊要循環1500屢次來作這個操做!而後奇蹟就發生了,頁面就假死了!不管怎麼刷新都沒有效果了,即便等了很長時間地圖加載出來了,只要稍微一放大或者移動地圖頁面就會直接掛掉。而後項目經理就一頓巴拉巴拉巴拉,這就是你給個人結果麼?jsp

      誰讓我確實這個東東沒作好呢?也沒臉跟別人爭辯,拿回來從新研究吧。因而在網上搜了一下,發現不少人也都遇到了這個問題,就是當點大於必定的數量以後,瀏覽器都會出現假死的狀況。而後上百度論壇瀏覽了一下,確實有提到這個問題,當點的數量在150個之內時,這麼作是沒有問題的,但當點數量大於300個時,這麼作就行不通了。百度給出了兩種解決方案:

No1:Marker聚合:http://tieba.baidu.com/f?kz=1031097376

No2:數據抽希:好比有10個marker,選擇其中6個作爲顯示點。

      這裏對比了一下需求,Marker聚合是將全部的點聚合起來,顯示一個總數,而後點擊的時候再分開;而數據抽希字面的意思是從中選取一部分來展現。而我所接到的任務是展現全部點,顯然數據抽希這裏是用不上了,那就來聚合吧。這是第二版。

      首先簡單介紹一下,百度聚合展現提供了開源的類庫,只須要在頁面中引用便可。如下是Js腳本代碼:

             var map = option.Map||new BMap.Map("MapContent");          // 建立地圖實例
                                var point = new BMap.Point(116.418261, 39.921984);
                                map.centerAndZoom(point, 10);             // 初始化地圖,設置中心點座標和地圖級別
                                map.enableScrollWheelZoom(); // 容許滾輪縮放
                                map.enableKeyboard = true;
                                map.addControl(new BMap.NavigationControl());
                                map.addControl(new BMap.ScaleControl()); // 啓用比例尺。            
                                map.addControl(new BMap.MapTypeControl()); // 是否啓用衛星地圖等等。
                                var MAX = resultData.count;
                                var markers = [];
                                var pt = null, mypt = null;
                                var i = 0;
                                var infoWindow;
                                var myIcon = new BMap.Icon("/Admin/Images/red.png", new BMap.Size(28, 37), {
                                });
                                for (; i < MAX; i++) {
                                    pt = new BMap.Point(resultData.data[i].Longitude, resultData.data[i].Dimension);
                                    mypt = new BMap.Marker(pt);
                                    mypt.setIcon(myIcon);
                                    mypt.addEventListener("click", function (no) {
                                        return function () {
                                            infoWindow = LoadMakerInfo(resultData.data[no]);
                                            this.openInfoWindow(infoWindow);
                                            //createInfoWin(resultData.data[no]).redraw();
                                        };
                                    } (i));
                                    markers.push(mypt);
                                }
                                ////最簡單的用法,生成一個marker數組,而後調用markerClusterer類便可。
                                var markerClusterer = new BMapLib.MarkerClusterer(map, { markers: markers.reverse(), isAverangeCenter: true,girdSize:100,maxZoom:15 });
                            }
View Code

      這段代碼大部分都很簡單,只有一個地方作個簡單的說明,網上不少人也問到了這裏。就是說循環添加點,而後給每個點都綁定了Click事件,而後實際點擊的時候卻彈出的內容都是同樣的。這是因爲Js的做用域以及閉包引發的,詳情請看個人另外一篇博客:那些必需要知道的Javascript,這裏再也不贅述。其中代碼裏setIcon是爲了把百度默認的圖標換成咱們本身預先設定的圖標,下圖是運行以後的效果:

      與初版相比,性能確實有了很大的改進,至少在本地加載個1500多條數據已經沒問題了。但是經過聚合以後又引入了新的問題,就像上圖中的綠色圓圈,有兩個4,一個6,正常這些數據點擊以後都會散開的,當一直點擊的時候應該能夠看到沒有聚合的點。但是這裏出現的問題是有些能夠點開,有些竟然點不開。開始我覺得是數據的問題,覺得相隔比較近的點是沒法展開的,後來就對數據作了處理,若是有相同的數據則經過加減隨機數,確保拿出來的數據沒有相同的,但是這個問題仍是沒有解決。但願有了解的朋友能夠告知一二。經過這樣聚合,展現數據確實比初版快不少,但是當在公網上的時候,頁面縮放或者移動的時候仍是會卡。因此還得從新找解決方案。

     這裏值得一提的就是百度地圖咱們能夠看到那種鼠標在左邊搜索列表滑動,右邊地圖中搜到的結果跟着變化的那種效果,這裏咱們也是能夠作的。監測左邊列表的MoueEnter事件,而後根據當前Enter的點的經緯度建立一個點,而後Foreach右邊搜索結果中的點,若是經過point的equals方法,判斷是不是同一個點,若是是則改變當前的Icon便可。Js腳本:

function ReDrawMap(data) {
            if (data.markersLongitude && data.markersDimension) {
var tmpInfo = LoadMakerInfo(data);
                var point = new BMap.Point(data.markersLongitude, data.markersDimension); // 建立點座標
                var mkrs = option.Map.getOverlays();
                var position;
                for (var i = 0; i < mkrs.length; i++) {
                    position = mkrs[i].point;
                    if (position&&position.equals(point)) {
                        mkrs[i].openInfoWindow(tmpInfo);
                    }
                }
            }
        }
View Code

      雲麻點效果展現

      最初沒有用這個雲麻點展現效果是由於一些敏感數據,但是後來發現沒有其餘合適的解決方案的時候,就採用了這個方案。雲麻點效果也就是LBS雲存儲,用戶將數據存放在百度的雲服務器,而後直接從百度雲獲取數據。這個流程是:先在LBS開放平臺建立數據表,而後添加須要的字段,而後就能夠在後臺批量上傳數據。數據上傳至百度服務器後,會生產相應的雲麻點圖層,這些圖層在加載的時候直接被展現出來,這樣能夠很大程度上提升性能。如今假設後臺數據已經準備完畢了,前臺所做的操做:

首先,初始化地圖的數據:

 var map = new BMap.Map("MapContent"); //初始化數據
                map.enableScrollWheelZoom();                            // 啓用滾輪放大縮小 map.enableContinuousZoom();                             // 啓用地圖慣性拖拽,默認禁用 map.enableInertialDragging();                           // 啓用連續縮放效果,默認禁用。 map.addControl(new BMap.NavigationControl());           // 添加平移縮放控件
                map.addControl(new BMap.ScaleControl());                // 添加比例尺控件
                map.addControl(new BMap.OverviewMapControl());          // 添加縮略地圖控件
                map.addControl(new BMap.MapTypeControl());              // 添加地圖類型控件
                map.centerAndZoom(new BMap.Point(116.418261, 39.921984), 5); // 初始化地圖,設置中心點座標和地圖級別
                map.addControl(new BMap.NavigationControl()); // 啓用魚骨頭。
                map.setCurrentCity("北京");                            //因爲有3D圖,須要設置
View Code

而後,設置篩選的條件:

                //檢索模塊相關代碼
                var keyword = "",   //檢索關鍵詞
                        page = 0,    //當前頁碼
                        points = [],   //存儲檢索出來的結果的座標數組
                        customLayer = null; //麻點圖層
                customLayer = new BMap.CustomLayer({
                    geotableId: 00000,//後臺生成表的Id
                    q: '', //檢索關鍵字
                    tags: '', //空格分隔的多字符串
                    filter: '' //過濾條件,參考http://developer.baidu.com/map/lbs-geosearch.htm#.search.nearby
                }); //新建麻點圖圖層對象
                map.addTileLayer(customLayer); //將麻點圖添加到地圖當中
                customLayer.addEventListener('hotspotclick', hotspotclickCallback); //給麻點圖添加點擊麻點回調函數

                /**
                * 麻點圖點擊麻點的回調函數
                * @param 麻點圖點擊事件返回的單條數據
                */
                function hotspotclickCallback(e) {
                if (e.content.phone == "NULL") {
                    e.content.phone = "暫無";
                }
                    var customPoi = e.customPoi,
            str = [];
                    str.push("address = " + customPoi.address);
                    str.push("phoneNumber = " + customPoi.phoneNumber);
                    var content ='<img src="' + e.content.shopPhoto + '"style="width:111px;height:83px;float:left;margin-right:5px;"/>'+ '<p style="width:280px;margin:0;line-height:20px;">地址:' + customPoi.address + '</p>';
                    content += '<p style="width:280px;margin:0;line-height:20px;">電話:' + e.content.phone + '</p>';
                    //建立檢索信息窗口對象
                    var searchInfoWindow = new BMapLib.SearchInfoWindow(map, content, {
                        title: e.content.nickName,  //標題
                        width: 290,              //寬度
                        height: 40,              //高度
                        enableAutoPan: true,    //自動平移
                        enableSendToPhone: true, //是否顯示發送到手機按鈕
                        searchTypes: [
                BMAPLIB_TAB_SEARCH,   //周邊檢索
                BMAPLIB_TAB_TO_HERE,  //到這裏去
                BMAPLIB_TAB_FROM_HERE //從這裏出發
            ]
                    });
                    var point = new BMap.Point(customPoi.point.lng, customPoi.point.lat);
                    searchInfoWindow.open(point); //打開信息窗口
                }
View Code

以後就是最關鍵的一步,請求數據:

                var url = "http://api.map.baidu.com/geosearch/v2/local?callback=?";
                $.getJSON(url, {
                    'q': '', //檢索關鍵字
                    'page_index': page,  //頁碼
                    // 'filter': filter.join('|'),  //過濾條件
                    'region': '131',  //北京的城市id
                    'scope': '2',  //顯示詳細信息
                    'geotable_id': 00000,
                    'page_size': 12,
                    'ak': 'XXXXXXXX'  //用戶ak
                }, function (e) {
                    renderMap(e, page + 1);
                });
View Code

完了以後再調整一下樣式,結果如圖:

      經過LBS雲存儲,能夠很好的解決海量數據加載緩慢的問題,可是這樣作的缺點就是一方面數據必須上傳到百度的雲服務器,另外一方面數據維護仍是比較麻煩的,必須得經過接口來操做。以上是最近作百度接口總結的一些問題,但願對您能有所幫助,若是您遇到了跟我相似的問題尚未解決,歡迎隨時跟我交流。若是您以爲文章對您有一點點做用,必定要頂哦,原創不容易啊!

相關文章
相關標籤/搜索