【 可视化】热力图绘制原理

栏目: Html5 · 发布时间: 5年前

内容简介:网上那些炫酷的热力图是如何绘制的? 相信你也很好奇,本文将以 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.


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

创业无畏

创业无畏

彼得· 戴曼迪斯、史蒂芬· 科特勒 / 贾拥民 / 浙江人民出版社 / 2015-8 / 69.90元

 您是否有最大胆的商业梦想?您是否想把一个好主意快速转化为一家市值几百亿甚至几千亿元的公司?《创业无畏》不仅分享了成功创业家的真知灼见,更为我们绘制了一幅激情创业的行动路线图!  创业缺人手怎么办?如何解决钱的问题?把握指数型大众工具,互联网就是你车间,你的仓库。拥有好的创意,自然有人把钱“白白地送给你用”。当你大海捞针的时候,激励性大奖赛会让针自己跑到你的眼前来!  掌握指数级......一起来看看 《创业无畏》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

随机密码生成器
随机密码生成器

多种字符组合密码