百度地图 热力图及轨迹图展示

前一段时间研究行车轨迹在地图上的展示,有些收获,这里分享一下。

此为热力图效果:

此为轨迹图效果:

下面分别详细说明:

1.热力图相对简单,只要调用百度地图的js接口即可。

 

<script type="text/javascript"
	src="http://api.map.baidu.com/api?v=2.0&ak="></script>
<script type="text/javascript"
	src="http://api.map.baidu.com/library/Heatmap/2.0/src/Heatmap_min.js"></script>
<script type="text/javascript" src="./js/baidumap.js"></script>

 

js部分代码:

 

<pre name="code" class="html">heatmap : function(dom, datas) {//dom是地图加载的div,datas是后台传入的数据
			var map = zh.baidumap.createMap(dom, datas.center[0],
					datas.center[1], datas.level || 16);

			/** * 基本控件begin ** */
			map.enableScrollWheelZoom();
			map.addControl(new BMap.NavigationControl());
			map.addControl(new BMap.ScaleControl());
			map.addControl(new BMap.OverviewMapControl());
			map.addControl(new BMap.MapTypeControl());
			/** * 基本控件end ** */

			if (!isSupportCanvas()) {
				alert('热力图目前只支持有canvas支持的浏览器,您所使用的浏览器不能使用热力图功能~')
			}
			
			/** * 热力图接口调用begin ** */
			var hmap = zh.baidumap.createHeatMap(map, {
				data : datas.points,
				max : datas.count * 10
			});
			/** * 热力图接口调用end ** */
			hmap.show();

 

 

 

datas数据结构:List<Map>,map里放入经纬度,部分代码:

 

	public List getPointList(Map map_in) {
		List<Map> list = new ArrayList<Map>();
		
		try {
			double[] point;
			List<Map> lists = mapRecordHeatMapper.getPoints(map_in);

			Iterator itor = lists.iterator();
			while (itor.hasNext()) {
				Map m = (Map) itor.next();
				point = GpsToBaidu.wgs2bd(Double.parseDouble(m.get("lng")+""), Double.parseDouble(m.get("lat")+""));
				
				m.clear();
				m.put("lng", point[0]);
				m.put("lat", point[1]);
				list.add(m);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;
	}

2、轨迹图的展示是调用第三方mapv的接口,目前使用的情况还算一般,在数据量太大的情况下地图非常卡慢。因为轨迹的机制是在百度地图上添加覆盖物,轨迹点一旦太多就难免会卡,希望以后百度地图会有更好的解决方案。

 

js部分代码:

 

pathmap : function(dom, datas) {
			var map = zh.baidumap.createMap(dom, datas.center[0],
					datas.center[1], datas.level || 16);

			/** * 基本控件begin ** */
			map.enableScrollWheelZoom();
			map.addControl(new BMap.NavigationControl());
			map.addControl(new BMap.ScaleControl());
			map.addControl(new BMap.OverviewMapControl());
			map.addControl(new BMap.MapTypeControl());
			/** * 基本控件end ** */

			/** * mapv一般轨迹接口begin ** */
			var mapv = new Mapv({
				drawTypeControl : true,
				map : map
			});

			var driveData = datas.points;

			var layer = new Mapv.Layer({
				zIndex : 1,
				mapv : mapv,
				dataType : 'polyline',
				coordType : 'bd09ll',	//这个参数是设置gps坐标类型的
				data : driveData,
				drawType : 'simple',
				drawOptions : {
					lineWidth : 2,	//线条宽度
					strokeStyle : "rgba(255, 50, 50, 0.1)"	//颜色透明度等等
				}
			});
			/** * mapv一般轨迹接口end ** */

		},

datas数据结构:List<Map>,map里再放入经纬数组,部分代码:

 

 

public List getMapvList(Map map_in) {
		long enterTime = System.currentTimeMillis();
		List<Map> list = new ArrayList<Map>();

		try {
			List list_sql = mapRecordPathMapper.getMapv(map_in);
			writeObject(list_sql);

			String[] lngs, lats;
			double[][] geos;
			int i = 0;
			
			Iterator itor = list_sql.iterator();
			while (itor.hasNext()) {
				Map m = (Map) itor.next();
				lngs = ((String)m.get("lngs")).split(",");
				lats = ((String)m.get("lats")).split(",");
				geos = new double[lats.length][2];
				for (i = 0; i < lats.length; i++) {
					geos[i] = GpsToBaidu.wgs2bd(Double.parseDouble(lngs[i]), Double.parseDouble(lats[i]));
				}
				
				m.clear();
				m.put("geo", geos);
				m.put("count", "1");
				list.add(m);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} 

		long leaveTime = System.currentTimeMillis();
		System.err.println("轨迹图数据处理用时:" + (leaveTime - enterTime) / 1000.00 + "秒");
		return list;
	}

 

 

最后说一点,一般行车仪取到的坐标是gps坐标,要在百度地图上比较精确的展示得转为百度坐标,这里提供一个精度较高的转换方法:

 

public class GpsToBaidu {

	public static double pi = 3.1415926535897932384626;
	public static double ee = 0.00669342162296594323;
	public static double a = 6378245.0;
	public static double lon;
	public static double lat;

	public static void gps84_To_Gcj02() {
		double dLat = transformLat(lon - 105.0, lat - 35.0);
		double dLon = transformLon(lon - 105.0, lat - 35.0);
		double radLat = lat / 180.0 * pi;
		double magic = Math.sin(radLat);
		magic = 1 - ee * magic * magic;
		double sqrtMagic = Math.sqrt(magic);
		dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
		dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
		lat = lat + dLat;
		lon = lon + dLon;
	}

	public static void gcj02_To_Bd09() {
		double x = lon, y = lat;
		double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * pi);
		double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * pi);
		lon = z * Math.cos(theta) + 0.0065;
		lat = z * Math.sin(theta) + 0.006;
	}

	// 函数功能:纬度转换
	public static double transformLat(double x, double y) {
		double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
		ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
		ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
		ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
		return ret;
	}

	// 函数功能:经度转换
	public static double transformLon(double x, double y) {
		double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
		ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
		ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
		ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0;
		return ret;
	}

	public static double[] wgs2bd(double in_lon, double in_lat) {
		lon = in_lon;
		lat = in_lat;
		GpsToBaidu.gps84_To_Gcj02();
		GpsToBaidu.gcj02_To_Bd09();
		double[] gcj2bd = { lon, lat };
		return gcj2bd;
	}

	public static void main(String[] args) {
		double in_lon = 118.50918;
		double in_lat = 35.54187;
		double[] aaa = GpsToBaidu.wgs2bd(in_lon, in_lat);
		System.err.println(aaa[0] + "," + aaa[1]);
	}

}

就这些了。

 

补充一下,做海量点的轨迹效果时,网络传输速度会是很大的问题。

比如600W个点,转成json后大小也有十几兆,按照100KB(我测试用的阿里云主机1M网速)的网速算,得100多秒才能完成服务器到js的传输过程。这在客户使用时是难以接受的。而且600万个点仅仅是两个小城市一天的数据,如果是更大范围的数据则更难相像了。

所以目前看来baidu map或者 mapv要处理大量的轨迹还是有难度的,总结一下目前主要的问题:

1、点数量上十万时,调用百度地图展示时就会有明显的缓慢,这应该是覆盖物太多导致的。

2、数据量太大时,存在的网络传输速度问题。

 

 

后话,时间2020-01-08,因为老是要手机验证很久没上csdn,统一回复一下。源码给不了是当初给前公司做的项目,有版权。核心代码、开源技术上文都写了,主要是百度地图的热力图api及mapv插件的轨迹图。

 

现在2020年,技术也在进步了,在这方面我可以提供一些我的经验。对于行车轨迹的处理,热力图及轨迹图的成型技术:

 

1、简单快速开发部署,可以试试echarts,直接兼容baidumap,成型控件。

热力图:https://echarts.apache.org/examples/zh/editor.html?c=heatmap-bmap

轨迹图:https://echarts.apache.org/examples/zh/editor.html?c=lines-bmap-bus

如果链接失效可以去echart2官网找。

2、想自己维护自由度和要求条件更高的热力图及轨迹图,自己研究百度地图热力图及mapv的api,现在mapv也发展了,有了更多的控件选择。但是开发工作量肯定是有的:

mapv项目demo示例:https://mapv.baidu.com/examples/

不过看来性能问题还是没解决,才150万个点就卡死了。我当年测试好歹是拿的600万个点。。。

 

3、对数据量和性能有非常高要求的,要不问问阿里和高德地图有没有成型的解决方案。

无论哪一种,前提都得要自己对map提供api有一定的学习了解,源码只能解决当前的问题。

 

最后,学海无涯,与君共勉。

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值