内容简介:网上那些炫酷的热力图是如何绘制的? 相信你也很好奇,本文将以 canvas 作为绘图示例来讲解热力图的原理。我们经常遇到透明度的概念,如 CSS 中的opacity 属性、rgba 颜色中的 alpha 变量、canvas 中的globalAlpha 属性等。它们的取值范围一般是 0-1 之间,0 表示完全透明,1 表示不透明,值越小,越透明。
网上那些炫酷的热力图是如何绘制的? 相信你也很好奇,本文将以 canvas 作为绘图示例来讲解热力图的原理。
透明度
我们经常遇到透明度的概念,如 CSS 中的opacity 属性、rgba 颜色中的 alpha 变量、canvas 中的globalAlpha 属性等。
它们的取值范围一般是 0-1 之间,0 表示完全透明,1 表示不透明,值越小,越透明。
透明度叠加
思考一个问题:透明度为 0.2 的矩形跟透明度为 0.6 的矩形叠加后的透明度为多少?
结果可以看以下示例,通过 canvas 的 getImageData 方法输出了叠加后的透明度(值除以 255 即可)
See the Pencanvas-opacity by linghuam (@linghuam) onCodePen.
很多人的第一感觉也许是 0.8,其实这是一种想当然的理解。正确的思路如下:
假设把透明度理解成玻璃的透光性,这样 alpha=0.2 表示一束光照射到玻璃上,有 20% 的光线被反射回来(这一部分光线会进入你的眼睛),80% 穿透过去,这时我们看到的东西就会很模糊。同理,alpha=0 表示光线全部穿透过去,所以我们什么都看不见,alpha=1 表示光线全部被反射,所以我们能看见全部。
那么 alpha=0.2 和 alpha=0.6 的叠加相当于两块玻璃叠加,第一块玻璃有 80% 光线穿透,
第二块在第一块穿透过的光线中,有 40% 光线穿透,这样穿过两块玻璃后被反射多少光线呢,计算方法如下: 1*0.2 + (1-0.2)*0.6 = 0.68
, 所以最后的透明度是 0.68 而不是 0.8。
下面一篇文章总结了其计算公式: 两个半透明颜色色的叠加计算方法
热力图原理
其实热力图就是根据透明度的大小和叠加来渲染的。
首先我们的数据集是一个对象数组,每个元素包含了 { x, y, value } 属性。我们首先从这一组值中找出 value 最大值 max,然后用 value/max 的值来表示透明度,这样我们可以在画布中绘制不同透明度的小圆圈,起初这些圆圈都是黑白的,所以下一步需要根据不同透明度来进行着色处理。
通过查看 mapv 源码发现,它实现了一个 Intensity 类用来对不同透明度实现一个渐变色。
首先他创建了一个 256 * 1 的 canvas ,然后利用 canvas 的createLinearGradient 来将渐变色填充进去,这样一个透明度值就可以对应 canvas 上的一个颜色值,通过 getImageData 方法就可以根据透明度来取对应的颜色值。
截取部分核心代码:
// 创建一个 256*1 的 canvas 并填充渐变色 Intensity.prototype.initPalette = function () { var gradient = this.gradient; var canvas = new Canvas(256, 1); var paletteCtx = this.paletteCtx = canvas.getContext('2d'); var lineGradient = paletteCtx.createLinearGradient(0, 0, 256, 1); for (var key in gradient) { lineGradient.addColorStop(parseFloat(key), gradient[key]); } paletteCtx.fillStyle = lineGradient; paletteCtx.fillRect(0, 0, 256, 1); } // 通过透明度值取到对应的颜色 Intensity.prototype.getImageData = function (value) { var imageData = this.paletteCtx.getImageData(0, 0, 256, 1).data; if (value === undefined) { return imageData; } var max = this.max; var min = this.min; if (value > max) { value = max; } if (value < min) { value = min; } var index = Math.floor((value - min) / (max - min) * (256 - 1)) * 4; return [imageData[index], imageData[index + 1], imageData[index + 2], imageData[index + 3]]; } 复制代码
当然,为了热力图更好看,作者用了 canvas 的shadowBlur 来实现一个边缘模糊效果。
至此,热力图的实现原理就介绍完了,下面是我根据这个原理做的一个小 Demo:
See the Pencanvas-heatmap by linghuam (@linghuam) onCodePen.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 每日一博|Python 数据可视化----绘制各种图形
- iOS可视化动态绘制连通图(Swift版)
- Python绘制六种可视化图表详解(建议收藏)
- Python 数据可视化:DataFrame.plot() 函数绘制数据图
- iOS可视化动态绘制八种排序过程(Swift版)
- Python 可视化(4):WordCloud 中英文词云图绘制方法汇总
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。