在高德地图加载热力图时,数据支持jsonp,通过python实现:
1、后台python:
# 通过jsonp格式返回热力图的数据 def heatjsonp(request): funcname = request.GET.get('callback') # print(funcname) content = '%s(%s)' % (funcname, heatdata()) # print(content) return HttpResponse(content)
# 通过jsonp格式返回热力图的数据 def heatjsonp(request): funcname = request.GET.get('callback') # 收取前台的callback函数名:[27/Apr/2018 10:29:15] "GET /jsonpdata?callback=jsonp_490268_ HTTP/1.1" 200 748372 # 这里是通过get方式传入的:callback=jsonp_490268_
content = '%s(%s)' % (funcname, heatdata()) # heatdata函数返回数据字典,直接作为字符串的一部分返回到前台(有点纳闷:数据字典转为字符串是怎么做到的,估计是%s替换时自动转的?) return HttpResponse(content)
# 二级函数,生成热力图基础数据 def heatdata(): lnglat_set = LngLat.objects.all() heatmapdict = {} for lnglat in lnglat_set: celldatausage_set = CellDataUsage.objects.filter(cell__lnglat=lnglat) # 以下语句相当于group by begin sumusage = celldatausage_set.values_list('begin').annotate(Sum('up'), Sum('down')) for eachday in sumusage: updown = int(eachday[1] + eachday[2]) begin = Begin.objects.filter(id=eachday[0]).first().begin.strftime('%Y-%m-%d') onedict = {"lng": float(lnglat.lng), "lat": float(lnglat.lat), "count": updown} if begin in heatmapdict: if type(heatmapdict[begin]) is list: heatmapdict[begin].append(onedict) else: heatmapdict[begin] = [onedict] else: heatmapdict[begin] = [onedict] # 将数据库查询结果另存为site-data.js文件,用于提高初始加载时,站点的显示速度,注意:字符集统一为utf-8 f = codecs.open('static/javascript/data/heatmapdict.js', 'w', 'utf-8') f.write("var heatmapdict = %s" % heatmapdict) f.close() return heatmapdict
2、前台接收jsonp后,必须配合解析
返回给前台的数据为:
jsonp_490268_({'2017-09-18': [{'lng': 125.2875, 'lat': 42.269444, 'count': 18975}, ...]})
这是什么意思呢?
其实时一个函数的调用,函数名为jsonp_490268_,参数为
{'2017-09-18': [{'lng': 125.2875, 'lat': 42.269444, 'count': 18975}, ...]}
参数就是原本想通过json格式返回的数据。
这个函数的函数名jsonp_490268_是前台调用jsonp时自动生成的,但是函数需要在前台定义:
//设置数据集:该数据为北京部分“公园”数据 heatmap.setDataSet({ //data: heatmapData, data:'/jsonpdata', // 通过jsonp格式请求数据 dataParser: function(data){ // 这个函数就是jsonp返回时,执行的函数,它目前没有函数名,但实际执行时,使用的自动生成的函数名jsonp_490268_ console.log(data); // 这个函数的参数data就是{'2017-09-18': [{'lng': 125.2875, 'lat': 42.269444, 'count': 18975}, ...]} return data['2017-09-18'];//返回的对象结果应该与上面例子的data字段结构相同 }, max: 100 });
注意,每次调用时,函数名都会变。
前台代码:
<!doctype html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width"> <title>热力图</title> <link rel="stylesheet" href="http://cache.amap.com/lbs/static/main1119.css"/> <script type="text/javascript" src="/static/javascript/jquery-3.2.1.min.js"></script> <script type="text/javascript" src="/static/javascript/preventCSRF.js"></script> <script src="http://webapi.amap.com/maps?v=1.4.6&key=348e60dba92f158e939c942cf20e3188"></script> <script type="text/javascript" src="http://cache.amap.com/lbs/static/addToolbar.js"></script> <script type="text/javascript" src="http://a.amap.com/jsapi_demos/static/resource/heatmapData.js"></script> </head> <body> <div id="container"></div> <div class="button-group"> <input type="button" class="button" value="显示热力图0" οnclick="on1off2()"/> <input type="button" class="button" value="显示热力图1" οnclick="on2off1()"/> </div> <script> function on1off2() { heatmap.show(); heatmap1.hide(); } function on2off1() { heatmap.hide(); heatmap1.show(); } var map = new AMap.Map("container", { resizeEnable: true, center: [116.418261, 39.921984], zoom: 11 }); if (!isSupportCanvas()) { alert('热力图仅对支持canvas的浏览器适用,您所使用的浏览器不能使用热力图功能,请换个浏览器试试~') } //详细的参数,可以查看heatmap.js的文档 http://www.patrick-wied.at/static/heatmapjs/docs.html //参数说明如下: /* visible 热力图是否显示,默认为true * opacity 热力图的透明度,分别对应heatmap.js的minOpacity和maxOpacity * radius 势力图的每个点的半径大小 * gradient {JSON} 热力图的渐变区间 . gradient如下所示 * { .2:'rgb(0, 255, 255)', .5:'rgb(0, 110, 255)', .8:'rgb(100, 0, 255)' } 其中 key 表示插值的位置, 0-1 value 为颜色值 */ var points =[ {"lng":116.191031,"lat":39.988585,"count":90}, {"lng":116.389275,"lat":39.925818,"count":91}, {"lng":116.287444,"lat":39.810742,"count":92}, {"lng":116.481707,"lat":39.940089,"count":83}, {"lng":116.410588,"lat":39.880172,"count":74}, {"lng":116.394816,"lat":39.91181,"count":85}, {"lng":116.416002,"lat":39.952917,"count":96} ]; var heatmap, heatmap1; /* heatmap = new AMap.Heatmap({map:map}); //在地图对象叠加热力图 heatmap.setDataSet({data:points,max:100}); //设置热力图数据集 heatmapsetMap(map); */ map.plugin(["AMap.Heatmap"], function() { //初始化heatmap对象 heatmap = new AMap.Heatmap(map, { radius: 25, //给定半径 opacity: [0, 0.8] }); heatmap1 = new AMap.Heatmap(map, { radius: 25, //给定半径 opacity: [0, 0.8] /*,gradient:{ 0.5: 'blue', 0.65: 'rgb(117,211,248)', 0.7: 'rgb(0, 255, 0)', 0.9: '#ffea00', 1.0: 'red' }*/ }); /* console.log("a"); $(function() { // 为防止CSRF(Cross-site request forgery)跨站请求伪造,发post请求时需要在cookie中创建随机码 $.ajaxSetup({ headers: { "X-CSRFToken": getCookie("csrftoken") } }); console.log("b"); $.post("/heatmapdata", {arg: "arg"}, function(data, status) { console.log(data, status); heatmap.setDataSet({ data: data['2017-09-18'], max: 100000 }); heatmap1.setDataSet({data:data['2017-09-19'], max: 100000}); }); }); */ //设置数据集:该数据为北京部分“公园”数据 heatmap.setDataSet({ //data: heatmapData, data:'/jsonpdata', dataParser: function(data){ console.log(data); return data['2017-09-18'];//返回的对象结果应该与上面例子的data字段结构相同 }, max: 100 }); //heatmap.setMap(map); //heatmap1 = new AMap.Heatmap({map:map}); //在地图对象叠加热力图 heatmap1.setDataSet({data:points,max:100}); //设置热力图数据集 //heatmap1.setMap(map); }); //判断浏览区是否支持canvas function isSupportCanvas() { var elem = document.createElement('canvas'); return !!(elem.getContext && elem.getContext('2d')); } </script> </body> </html>
setDataSet(dataset:Object) | | 设置热力图展现的数据集,dataset数据集格式为: { max: Number 权重的最大值, data: Array 坐标数据集 }, 其中max不填则取数据集count最大值 例: { max: 100, data: [{lng: 116.405285, lat: 39.904989, count: 65},{}, …] } 也可以通过url来加载数据,格式为 { data:jsonp格式数据的服务地址URL, dataParser: 数据格式转换function//当jsonp返回结果和官方结构不一致的时候,用户可以传递一个函数用来进行数据格式转换; } 例: { data:'http://abc.com/jsonp.js', dataParser:function(data){ return doSomthing(data);//返回的对象结果应该与上面例子的data字段结构相同 } } |