您的位置:首页 > Web前端 > JavaScript

d3.js结合Heatmap.js

2018-01-03 18:30 1496 查看
最近一直在跟gis地图打交道,导师给我的任务是画出所有学校里wifi ap的使用热力图.

于是我接入了百度地图的api,费力地标出了所有wifi ap的坐标信息.最后,导师对百度地图的热力图不甚满意,emmmm.....并给我规定了使用d3.js画热力图.

但是d3所有的热力图都是这样的..



虽然这样的热力图也挺好看的,但是放到我们学校的地图上就不太行了.以下是用d3画我们学校热力图的效果.



但是技术栈又定死了要用d3,怎么办呢?于是我就想能不能在svg上加一层canvas,来实现在d3上画传统热力图的效果.于是就形成了d3.js结合heatmap.js的方案.

首先如何获得可以输入d3的json数据格式?这里推荐WOLFMAP地图下载器,用它的免费功能可以在实景地图上加标注并导出,细节就不多说了,最后导出标注的kml或者kmz文件.

然后放到这个链接 http://2geojson.com/ 里把它转换成d3能接收的geoson格式.

{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "Name": "电群1号", "Description": "" }, "geometry":
{ "type": "Polygon", "coordinates": [ [ [ 121.43, 31.02, 0.0 ], [ 121.42, 31.02801, 0.0 ],
 [ 121.43682025, 31.02, 0.0 ], [ 121.43, 31.0278, 0.0 ], [ 121.435785, 31.027632, 0.0 ] ] ] } }
}

json格式大约是这样的

之后就可以用d3画图了

$(document).ready(function() {
var width = 1300;
var height = 900;
var svg = d3.select("#p1").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(0,0)");

projection = d3.geo.mercator().center([121.43, 31.027]).scale(2100000).translate([width/2, height/2]);

var path = d3.geo.path().projection(projection);

var color = d3.scale.category20();

d3.json("/jsonData/test13.json", function(error, root) {
if (error)
return console.error(error);
console.log(root.features);

svg.selectAll("path")
.data( root.features )
.enter()
.append("path")
.attr("stroke","#000")
.attr("stroke-width",0.5)
.attr("fill", function(d,i){
return "#ffffff";
})
.attr("d", path )
.on("click",function(d,i){alert(d['properties']['Name'])})
.on("mouseover",function(d,i){d3.select(this).attr("fill",function(d,i){
return "#17becf";});
})
.on("mouseout",function(d,i){
d3.select(this)
.attr("fill","#ffffff");

});

});这一套就是d3读取geojson的标准操作,没有什么好多说.重点介绍怎么把heatmap.js覆盖到geojson上.
重点是初始化d3时所申明的这个projection变量,他可以将gis数据转化为当前div中的绝对位置坐标.比如我们现在的中心点设在[121.4,31.024]上,容器的长和宽是[1300,900],那么projection[121.4,31.024]得到的结果就是[650,450].所以说只要能活用这个projection()那么得到任意的gis坐标也可以画到当前的网页中.

接下来就是操作heatmap.js的部分了

下面的程序中,用ajax请求到的数据结构是

['lat': 点的经度,

'lng': 点的纬度,

'count': ap的使用人数]

注意当中有三个坑

第一个是我画d3地图时候用的时google地图,服务器返回的数据的经纬度是基于baidu地图,用projection做映射之后有一定的偏移.

x: Math.round(prolocation[0]-405), y:Math.round(prolocation[1]+190)所以x,y要减去或者加上偏移,不断地调试直到两者重合.
第二个坑就是这边的Math.round,这其实是有关heatmap.js的,因为我发现要是输入点的坐标为float类型,有时候heatmap.js无法正常显示,把他们变成整数后才可以避免这个bug.

第三个坑是d3.js本身是有一些点击事件,mouseon事件的,在上面加了一层canvas后这些事件就无法触发了.解决方法是

<style type="text/css">
.heatmap-canvas{
pointer-events:none
}
</style>

这三个坑是我在实践中遇到并解决的.下面是代码

function updateForUtc(){
var targetTime = 1512100800000;
var ACInfo = {
"time": targetTime
};
$.ajax({
url: "/wireless/requestForHeatByTime",
type: "POST",
dataType: "json",
contentType: 'application/json;charset=utf-8',
data: JSON.stringify(ACInfo),
success: function (data) {
var heatmap = h337.create({
container: document.getElementById('p1'),
//gradient: { .1: 'rgba(0,0,0,0)', 0.25: "rgba(0,0,90, .6)", .6: "blue", .9: "cyan", .95: 'rgba(255,255,255,.4)'},
maxOpacity: .6,
radius: 10,
blur: .90
});
var dataList = data['arrayList'];

for(var i=0;i<dataList.length;i++){
var tmp = dataList[i];
var location = [tmp['lng'], tmp['lat']];
var prolocation = projection(location);
heatmap.addData({ x: Math.round(prolocation[0]-405), y:Math.round(prolocation[1]+190), value: Math.round(tmp['count']/10), radius: 20});
}

},
error: function (XMLHttpRequest, textStatus, errorThrown) {
console.log(XMLHttpRequest);
},
});
}最后上一张结果图

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: