这段时间须要实现百度地图的一些展现效果,虽然最终效果作出来了,但是这中间也走了不少的弯路,但愿有用到的能够直接拿来用,少走一些弯路。百度地图为开发者提供了一系列的接口,点百度接口去百度接口。本文主要用到了如下几个效果: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); }
我在本地添加了将近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 }); }
这段代码大部分都很简单,只有一个地方作个简单的说明,网上不少人也问到了这里。就是说循环添加点,而后给每个点都绑定了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); } } } }
云麻点效果展现
最初没有用这个云麻点展现效果是由于一些敏感数据,但是后来发现没有其余合适的解决方案的时候,就采用了这个方案。云麻点效果也就是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图,须要设置
而后,设置筛选的条件:
//检索模块相关代码 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); //打开信息窗口 }
以后就是最关键的一步,请求数据:
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); });
完了以后再调整一下样式,结果如图:
经过LBS云存储,能够很好的解决海量数据加载缓慢的问题,可是这样作的缺点就是一方面数据必须上传到百度的云服务器,另外一方面数据维护仍是比较麻烦的,必须得经过接口来操做。以上是最近作百度接口总结的一些问题,但愿对您能有所帮助,若是您遇到了跟我相似的问题尚未解决,欢迎随时跟我交流。若是您以为文章对您有一点点做用,必定要顶哦,原创不容易啊!