转自原文 Cesium热力图实现

生成热力图的算法我是用的一个热力图插件 heatmap.js。
 
heatmap中热力图生成原理:
heatmap中首先会根据输入的渐进色参数,在内部生成一个0-255色值的调色板。
var _getColorPalette = function(config) {
var gradientConfig = config.gradient || config.defaultGradient;
var paletteCanvas = document.createElement('canvas');
var paletteCtx = paletteCanvas.getContext('2d'); paletteCanvas.width = 256;
paletteCanvas.height = 1; var gradient = paletteCtx.createLinearGradient(0, 0, 256, 1);
for (var key in gradientConfig) {
gradient.addColorStop(key, gradientConfig[key]);
} paletteCtx.fillStyle = gradient;
paletteCtx.fillRect(0, 0, 256, 1); return paletteCtx.getImageData(0, 0, 256, 1).data;
}; 对于输入的点数据,会根据点坐标生成一个黑色圆阴影效果。 //生成一个阴影模板
var _getPointTemplate = function(radius, blurFactor) {
var tplCanvas = document.createElement('canvas');
var tplCtx = tplCanvas.getContext('2d');
var x = radius;
var y = radius;
tplCanvas.width = tplCanvas.height = radius*2; if (blurFactor == 1) {
tplCtx.beginPath();
tplCtx.arc(x, y, radius, 0, 2 * Math.PI, false);
tplCtx.fillStyle = 'rgba(0,0,0,1)';
tplCtx.fill();
} else {
var gradient = tplCtx.createRadialGradient(x, y, radius*blurFactor, x, y, radius);
gradient.addColorStop(0, 'rgba(0,0,0,1)');
gradient.addColorStop(1, 'rgba(0,0,0,0)');
tplCtx.fillStyle = gradient;
tplCtx.fillRect(0, 0, 2*radius, 2*radius);
} var tpl;
if (!this._templates[radius]) {
this._templates[radius] = tpl = _getPointTemplate(radius, blur);
} else {
tpl = this._templates[radius];
}
// value from minimum / value range
// => [0, 1]
//根据value值设置阴影的alpha通道,后面可以通过alpha值获取value值
var templateAlpha = (value-min)/(max-min);
// this fixes #176: small values are not visible because globalAlpha < .01 cannot be read from imageData
shadowCtx.globalAlpha = templateAlpha < .01 ? .01 : templateAlpha; shadowCtx.drawImage(tpl, rectX, rectY); // update renderBoundaries
if (rectX < this._renderBoundaries[0]) {
this._renderBoundaries[0] = rectX;
}
if (rectY < this._renderBoundaries[1]) {
this._renderBoundaries[1] = rectY;
}
if (rectX + 2*radius > this._renderBoundaries[2]) {
this._renderBoundaries[2] = rectX + 2*radius;
}
if (rectY + 2*radius > this._renderBoundaries[3]) {
this._renderBoundaries[3] = rectY + 2*radius;
} }

首先呢,阴影是黑色的,所以接下来heatmap会进行一个像素点重新着色的过程,根据每个点的alpha值*4(rgba步长)得出一个offset,然后从调色板上取颜色。因为上面设置了阴影透明度效果是递减的,所以在获取颜色的时候,就能获得一个平滑的渐变效果。这样就得到了热力图。

_colorize: function() {
var x = this._renderBoundaries[0];
var y = this._renderBoundaries[1];
var width = this._renderBoundaries[2] - x;
var height = this._renderBoundaries[3] - y;
var maxWidth = this._width;
var maxHeight = this._height;
var opacity = this._opacity;
var maxOpacity = this._maxOpacity;
var minOpacity = this._minOpacity;
var useGradientOpacity = this._useGradientOpacity; if (x < 0) {
x = 0;
}
if (y < 0) {
y = 0;
}
if (x + width > maxWidth) {
width = maxWidth - x;
}
if (y + height > maxHeight) {
height = maxHeight - y;
} var img = this.shadowCtx.getImageData(x, y, width, height);
var imgData = img.data;
var len = imgData.length;
var palette = this._palette; for (var i = 3; i < len; i+= 4) {
var alpha = imgData[i];
var offset = alpha * 4; if (!offset) {
continue;
} var finalAlpha;
if (opacity > 0) {
finalAlpha = opacity;
} else {
if (alpha < maxOpacity) {
if (alpha < minOpacity) {
finalAlpha = minOpacity;
} else {
finalAlpha = alpha;
}
} else {
finalAlpha = maxOpacity;
}
} imgData[i-3] = palette[offset];
imgData[i-2] = palette[offset + 1];
imgData[i-1] = palette[offset + 2];
imgData[i] = useGradientOpacity ? palette[offset + 3] : finalAlpha; } img.data = imgData;
this.ctx.putImageData(img, x, y); this._renderBoundaries = [1000, 1000, 0, 0]; },
采用这种利用透明度来对应获取颜色值的好处就是这种渐变的过程比较柔和,渐变的效果更好。
 
so一开始为什么先绘制alpha渐变的黑点呢?是因为在纯色图像上方便计算它的alpha分量,这样两点相交的区域就会根据alpha分量进行叠加,在转成彩图的时候就可以生成相应的值。
为什么不直接用彩色点叠加呢?是因为彩色点的RGBA并不是简单的线性叠加关系。
 
在Cesium上使用的原理比较简单,就是根据输入点的坐标范围计算一个包围盒,创建一个rectangle geometry。然后呢,通过heatmap.js生成热力图,当做纹理贴到rectangle上面。在每一层级设置不同的radius,相当于在相机缩放的时候每一级都会生成一张热力图,然后更换纹理,实现缩放时的聚合离散效果。
 
这个过程需要注意的是以下几点:
1. 如何将经纬度值映射到纹理上对应位置?
首先需要计算生成纹理的宽高像素,这里我仿照了cesiumheatmap的算法,根据rectangle投影后的范围和初始heatmap的设置的canvasSize参数来计算出一个宽高值。
 
2.用heatmap绘出的canvas贴到rectangle上会有黑色背景
这个可以在shader里面将黑色像素过滤掉即可。
 
'vec4 heightValue = texture2D(image, materialInput.st);' +
'if(heightValue.r<1.0/255.0) heightValue.a= 0.0; ' +
 
3.缩放实现聚合离散
上面提到过了,根据几个层级范围设置一个radius数组,相机缩放到哪个层级就相应的改变它的radius进行重绘,然后替换纹理。
 最终实现效果还可以,能够平滑过渡。

在Openlayer中实现热力图起始是很方便的。具体可参考下面的几篇文章。

Openlayers中热力图的实现

openlayers3 ol3热力图 json

进一步学习的参考资料

至于绘制的过程和原理、及完整代码,可以参考
http://www.wangshaoxing.com/blog/how-to-draw-a-heatmap.html
code
https://github.com/wshxbqq/WebGL-HeatMap

 
 
 
 
 
 

Cesium热力图实现的更多相关文章

  1. cesium 热力图

  2. Cesium专栏-热力图(附源码下载)

    Cesium Cesium 是一款面向三维地球和地图的,世界级的JavaScript开源产品.它提供了基于JavaScript语言的开发包,方便用户快速搭建一款零插件的虚拟地球Web应用,并在性能,精 ...

  3. cesium 水面、淹没 效果

    水面效果 参考: http://cesiumcn.org/topic/158.html http://api.rivermap.cn/cesium/rivermap/map.html https:// ...

  4. Cesium学习系列汇总

    内容比较多,完整看完需要大概10分钟,废话不多说,撸起袖子,加油干!!! 1.前言 按照套路,先介绍一下什么是Cesium. Cesium ['siːzɪəm]是JavaScript开源库,通过Ces ...

  5. 将Cesium Tools用于更好的构建管理

    Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ Cesium技术正在给建筑业带来革命性的变化.我们与 partn ...

  6. cesium自定义气泡窗口infoWindow

    一.自定义气泡窗口与cesium默认窗口效果对比: 1.cesium点击弹出气泡窗口显示的位置固定在地图的右上角,默认效果: 2.对于习惯arcgis或者openlayer气泡窗口样式的giser来说 ...

  7. cesium核心类Viewer简介

    1.简单描述Viewer Viewer类是cesium的核心类,是地图可视化展示的主窗口,cesium程序应用的切入口,扮演必不可少的核心角色. 官网的英文解析如下: A base widget fo ...

  8. Cesium简介以及离线部署运行

    Cesium简介 cesium是国外一个基于JavaScript编写的使用WebGL的地图引擎,一款开源3DGIS的js库.cesium支持3D,2D,2.5D形式的地图展示,可以自行绘制图形,高亮区 ...

  9. 基于开源项目SharpMap的热力图(HeatLayer)实现。

    当前公司需要一个用时较少的热力图呈现方案,在避免较底层的GDI开发和比较了多家GIS产品的实际效果之后,团队决定用sharpMap的API来实现,由于之前框架采用的是另外一个开源项目GMap.net, ...

随机推荐

  1. Android后台的linux一直保持唤醒状态,不进入睡眠

    由于要做Android手机的电池续航测试,是不能插usb的,所以把case放到sh文件中,之后push到手机里,执行的. 但是出现个问题,假如case中有很长时间的sleep操作,关闭手机屏幕,这样l ...

  2. Java中对象方法的调用过程&动态绑定(Dynamic Binding)

    Java面向对象的最重要的一个特点就是多态, 而多态当中涉及到了一个重要的机制是动态绑定(Dynamic binding). 之前只有一个大概的概念, 没有深入去了解动态绑定的机理, 直到很多公司都问 ...

  3. luogu2764 最小路径覆盖问题

    最小路径覆盖,看这里 #include <iostream> #include <cstring> #include <cstdio> #include <q ...

  4. jmeter返回的Unicode转换成utf8

    该问题通过查找资料借鉴前辈门的经验得到了解决,记录下来是为了后面能够用到 最近发现有些接口返回的时unicode类型的,如下图所示: 因此只需要在jmeter中添加后置处理器:BeanShell Po ...

  5. Python学习-day5 常用模块

    day5主要是各种常用模块的学习 time &datetime模块 random os sys shutil json & picle shelve xml处理 yaml处理 conf ...

  6. 我的PC必装软件

    我的PC必装软件 TeXLive LaTeX套装 WinEdt LaTeX编辑器 PyCharm Python IDE Inkscape 矢量图制作,我根本不会用,但是常用来把SVG转成*.tex文件 ...

  7. [整理]linux中颜色的含义

    蓝色(Blue): Directory  目录 绿色(Green): Executable or recognized data file  可执行文件,可执行的程序 天蓝(Sky Blue): Sy ...

  8. c++中vector容器的功能及应用。

    vector基本操作:  1.头文件 #include<vector>. 注:一定要加上using namespace std;  2.vector对象的创建: vector<int ...

  9. POJ 1609 Tiling Up Blocks

    Tiling Up Blocks Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 4675   Accepted: 1824 ...

  10. Linux基础之Linux简介

    Linux(英语发音:/ˈlɪnəks/ lin-əks)是一种自由和开放源代码的类UNIX操作系统. Linux简介 Linux(英语发音:/ˈlɪnəks/ lin-əks)是一种自由和开放源代码 ...