文章目录
1 插件选择heatmap.js
官网: http://www.patrick-wied.at/static/heatmapjs/
api: http://www.patrick-wied.at/static/heatmapjs/docs.html
官网例子: http://www.patrick-wied.at/static/heatmapjs/examples.html
2 为什么选择heatmap.js
轻便/操作简单/兼容性高,目前发现最好的轮子
3 heatmap.js学习
3.1 helloworld入手
效果图:
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="/heatmap.js-master/build/heatmap.min.js"></script>
</head>
<style>
.heatmap {
width: 500px;
height: 500px;
border: solid 1px red;
}
</style>
<body>
<div class="heatmap">
</div>
</body>
<script>
var heatmapInstance = h337.create({
container: document.querySelector('.heatmap')
});
heatmapInstance.setData({
max: 100,
data: [{
x: 10,
y: 15,
value: 100
}]
});
</script>
</html>
这里基本可以知道:
(1) 引用规则
(2) 显示规则
(3) 数据规则
3.2 最小化配置demo
效果图
这个例子我们可以获得什么?大概就是知道了,卧槽,原来效果差不多是这样的.
3.3 api学习
名称 | 作用 |
---|---|
create(configObject) | 使用h337.create创建热图实例。可以使用configObject自定义热图,configObject参数是必需的 |
heatmapInstance.addData(object | array) |
heatmapInstance.setData(object) | 用数据集初始化一个热图实例 |
heatmapInstance.setDataMax(number) | 更改数据集的上限并触发完全重新渲染 |
heatmapInstance.setDataMin(number) | 更改数据集的下限并触发完全重新渲染 |
heatmapInstance.configure(configObject) | 初始化后重新配置热图实例。触发完全重新渲染 |
heatmapInstance.getValueAt(object) | 返回数据点位置的值 |
heatmapInstance.getData() | 返回一个可持久且可重新导入(带有setData)的JSON对象 |
heatmapInstance.getDataURL() | 热图实例的base64编码的dataURL |
heatmapInstance.repaint() | 返回heatmapInstance,重绘整个heatmap画布 |
贴上初始化options的属性
var heatmapInstance = h337.create({
container: document.querySelector('.heatmap'),
// backgroundColor: "rgba(0,142,0,0.8)", //控制背景颜色
// gradient: {
// '.3': 'rgb(0, 119, 255)',
// '.6': 'rgb(255, 136, 0)',
// '.9': 'rgb(255, 0, 0)'
// }
// radius: 100 //热力点半径
// opacity:0.7 //热力点透明度
// maxOpacity: 0.8,//热图中最大值具有的最大不透明度
// minOpacity:0.2//热图中最小值的最小不透明度
// onExtremaChange:function(data){
// console.log(data);
// }
// blur:0.5//将应用于所有数据点的模糊因子。模糊因子越高,渐变将越平滑
// xField://数据点中x坐标的属性名称
// yField://数据点中y坐标的属性名称
// valueField://数据点中值的名称
});
关于gradient属性解释下:
热力图的值,假设是0–100,如果0用冷色调(蓝色)表示,100用红色表示,那么在这之间,通过gradient设置间断颜色,则可以形成渐变色;
效果图如下:
cesium融合heatmap.js
效果图先行:
诶,看看,差不多了,有内味道了;但是这样肯定是不行的,只是单纯的叠加…那么如果像百度地图啊,那种贴到地球表面的效果呢?而且在webgl中,我们一般拿到的数据也是经纬度数据,比如:
{
longitude:113.215,
latitude:23.256,
value:100
}
所以要思考几个问题:
- 数据转换
-
表现形式
要满足好看,方便,高效的原理
幸好,这一切都有了解决办法
解决方案:
(1) 数据转换
cesium已经提供了屏幕坐标转换为经纬的方法
(2) 表现形式
为了满足热力图的任意性,我们把其贴在多边形的图形范围中,那么我们首先要有一个任意多边形
效果图
代码:
viewer.scene.globe.depthTestAgainstTerrain = false;
var drawType = new Cesium.PolygonOutlineGeometry.fromPositions({
positions: Cesium.Cartesian3.fromDegreesArray([
-95, 37.0,
-95, 32.0,
-90, 33.0,
-90, 31.0,
]),
})
var polyGon = new Cesium.GeometryInstance({
geometry: drawType,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.WHITE)
}
})
var object = new Cesium.Primitive({
geometryInstances: polyGon,
appearance: new Cesium.PerInstanceColorAppearance({
// flat : true,
renderState: {
lineWidth: Math.min(20.0, scene.maximumAliasedLineWidth)
}
})
})
viewer.scene.primitives.add(object);
然后我们要把热力图,贴到多边形中
经过本屌一下午不懈的努力,终于做出来了:
期间踩了一个坑,就是千万不要用PolygonOutlineGeometry去绘制多边形啊,因为它只是边,没办法填充canvas
代码:
//关闭地形检测
viewer.scene.globe.depthTestAgainstTerrain = false;
//得到heatmap.js绘制出的canvas
var canvas = document.querySelector('.heatmap-canvas');
//使用primitive绘制任意多边形
viewer.scene.primitives.add(new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.PolygonGeometry.fromPositions({
positions: Cesium.Cartesian3.fromDegreesArray([
-95, 37.0,
-95, 32.0,
-90, 31.0,
-90, 33.0,
]),
}),
}),
appearance: new Cesium.MaterialAppearance({
flat: true,
translucent: true,
material: new Cesium.Material({
fabric: {
type: 'Image',
uniforms: {
image: canvas,//绑定canvas
},
}
}),
})
}));
继续深挖
至此呢,一个基本的轮廓就已经成型了;但是,这还不能用于生产环境;我们知道,GIS给出的热力图,基本都是经纬度类型的.跟平面坐标关系不大,那么有什么思路能够解决这个问题呢?
1 利用cesium自带的笛卡尔3接口将WGS84经纬度坐标转成平面二维坐标,然后传入heatmap.js的对象绘制出来;但是呢,这样存在一个问题,首先是效率的问题,由于数据量基本都是万,十万级别的,前端进行转换效率会有影响;其次,当转换完成后,绘制出来的热力点由于不支持小数点,会造成精度失真,理论上,这种方法基本被淘汰
2 我们知道,cesium是能够绘制单点的,那么我们能不能根据经纬度,将绘制的单点画出来,然后在将热力点贴上去呢?理论上效率和精度都保证了.但是实现的过程当中由于是leaf插件,和cesium不匹配,就没去研究了.
3 然后去研究了cesium的插件cesium-heatmap…看heatmap.js源码的时候,发现竟然不能实时刷新radius…我的个老天啊…
然后默默的去改源码…竟然还是用的gruntfile进行打包的…emmmm,实属头疼.
默默的去加载cesium-heatmap的情形:
这样算是解决了经纬转换的关系;但是源码作者也是用rectangle进行映射的,感觉这种算法会比较失真,最最关键的是改了heatmap的源码竟然没有办法进行configure刷新.那我用滚轮进行缩放的动态效果怎么实现?而且效率也堪忧…
算了,博主默默的去改heatmap的源码并做坐标转换试试了.