Heatmap.js 强大的 HTML5 画布 WEB 网页在线热点图插件

发布于 2018-12-13 20:11:19 字数 6278 浏览 4464 评论 0

Heatmap.js 可以用来生成基于用户自定义数据上的 Web 热点图,使用内嵌的 HTML5 Canvas 画布元素,heatmap.js 可以使用 Canvas 画出来一张漂亮的 heatmap。更重要的是它支持数据的动态添加。比如下图的演示就是一个利用 MouseMove 事件生成 heatmap 的例子。它会自动的刷新 Canvas,实时显示鼠标运动的 heatmap。

Heatmap.js 强大的 HTML5 画布 WEB 网页在线热点图插件

Heatmap 是用来呈现一定区域内的统计数量,最常见的网站访问热力图就是以特殊高亮的形式显示访客热衷的页面区域和访客所在的地理区域的图示。Heatmap.js 这个 JavaScript 库可以实现各种动态热力图的网页,帮助您研究和可视化用户的行为。 Heatmap.js V2.0 是目前网络上最先进的热图可视化库。新的2.0版本 Heatmap.js 更快,拥有更强的渲染模块,使用更方便,因此您可以快速掌握和扩展自定义功能。

一个简单的例子

只有几行代码就可以创建自己的交互式网络热图:

var heatmap = h337.create({
  container: domElement
});

heatmap.setData({
  max: 5,
  data: [{ x: 10, y: 15, value: 5}, ...]
});

打开 heatmap.js 发现里面的代码并不多,但是真的很精悍。

代码分析

下面是一份网站的代码,看了那么久了,写下来一方面是自己加深记忆,另一方面就是可以更好的理清思路吧。 code 中包含两个主要的对象,store 和 heatmap。store 是 heatmap 的数据部分,算是 mode l吧。而 heatmap 则是真正绘制图像的对象。heatmap 部分可以被配置,可以自定义很多的内容,尤其是配色也是可以配置的,那么我们除了做出来正真的 heatmap 的效果之外还可以做出来各种各样不错的效果的。 首先看看存储部分吧,比较简单,注释也比较清楚。

// store object constructor
// a heatmap contains a store
// the store has to know about the heatmap
// in order to trigger heatmap updates when
// datapoints get added
function store(hmap){
    var _ = {
        // data is a two dimensional array
        // a datapoint gets saved as data[point-x-value][point-y-value]
        // the value at [point-x-value][point-y-value]
        // is the occurrence of the datapoint
        data: [],
        // tight coupling of the heatmap object
        heatmap: hmap
    };
    // the max occurrence - the heatmaps radial gradient
    // alpha transition is based on it
    this.max = 1;
    this.get = function(key){
        return _[key];
    },
    this.set = function(key, value){
        _[key] = value;
    };
};

在model里面,支持一次添加一个数据点。这也是heatmapjs支持实时绘制的关键。一旦max值有变化就会重新绘制整个canvas。

addDataPoint: function(x, y){
    if(x < 0 || y < 0)
        return;
    var me = this,
        heatmap = me.get("heatmap"),
        data = me.get("data");
    if(!data[x])
        data[x] = [];
    if(!data[x][y])
        data[x][y] = 0;
    // if count parameter is set increment by count otherwise by 1
    data[x][y]+=(arguments.length       me.set("data", data);
    // do we have a new maximum?
    if(me.max < data[x][y]){
        me.max = data[x][y];
        // max changed, we need to redraw all existing(lower) datapoints
        heatmap.get("actx").clearRect(0,0,heatmap.get("width"),heatmap.get("height"));
        for(var one in data)
            for(var two in data[one])
                heatmap.drawAlpha(one, two, data[one][two]);
        // @TODO
        // implement feature
        // heatmap.drawLegend(); ?
        return;
    }
    heatmap.drawAlpha(x, y, data[x][y]);
},

下面就是画的部分了。这里是最重要的两个方法,drawAlpha colorize

drawAlpha: function(x, y, count){
    // storing the variables because they will be often used
    var me = this,
        r1 = me.get("radiusIn"),
        r2 = me.get("radiusOut"),
        ctx = me.get("actx"),
        max = me.get("max"),
        // create a radial gradient with the defined parameters.
        // we want to draw an alphamap
        rgr = ctx.createRadialGradient(x,y,r1,x,y,r2),
        xb = x-r2, yb = y-r2, mul = 2*r2;
    // the center of the radial gradient has .1 alpha value
    rgr.addColorStop(0, 'rgba(0,0,0,'+((count)?(count/me.store.max):'0.1')+')');
    // and it fades out to 0
    rgr.addColorStop(1, 'rgba(0,0,0,0)');
    // drawing the gradient
    ctx.fillStyle = rgr;
    ctx.fillRect(xb,yb,mul,mul);
    // finally colorize the area
    me.colorize(xb,yb);
},

策略很简单

rgr.addColorStop(0, 'rgba(0,0,0,'+((count)?(count/me.store.max):'0.1')+')');
// and it fades out to 0
rgr.addColorStop(1, 'rgba(0,0,0,0)');

利用当前点的count除以最大的count获取的结果做为 alpha 值。然后做一个 RadialGradient 画出来这个图就可以了。那么由于多个相 近的点 aphla 效果的叠加就可以获取想要的效果了。这里就是Canvas 的 nb 之处了,看别的语言实现都是采用将一个这样的 png 图片画到画板上,但是 canvas 就可以直接实现这个效果。

有了这幅 aphla 版本的 heatmap 我们利用一个配送版做着色就大功告成了。 在通常需要一个图片作为配色板的时候 Canvas 可以自己做出来一个缓存起来。

initColorPalette: function(){
    var me = this,
        canvas = document.createElement("canvas");
    canvas.width = "1";
    canvas.height = "256";
    var ctx = canvas.getContext("2d"),
        grad = ctx.createLinearGradient(0,0,1,256),
    gradient = me.get("gradient");
    for(var x in gradient){
        grad.addColorStop(x, gradient[x]);
    }
    ctx.fillStyle = grad;
    ctx.fillRect(0,0,1,256);
    //这里太强大了,缓存了我的画板数据,然后删除了画板
    me.set("gradient", ctx.getImageData(0,0,1,256).data);
    delete canvas;
    delete grad;
    delete ctx;
},

这种方式也给我们实现各种各样的配色提供了方便,我们只需要改变那个 **gradient** 就可以了。

for(var i=3; i < length; i+=4){  // [0] -> r, [1] -> g, [2] -> b, [3] -> alpha
    var alpha = imageData[i],
    offset = alpha*4;
    if(!offset)
        continue;
    // we ve started with i=3
    // set the new r, g and b values
    // 根据透明度选择配色板上的配色
    imageData[i-3]=palette[offset];
    imageData[i-2]=palette[offset+1];
    imageData[i-1]=palette[offset+2];
    // we want the heatmap to have a gradient from transparent to the colors
    // as long as alpha is lower than the defined opacity (maximum),
    // we'll use the alpha value
    imageData[i] = (alpha < opacity)?alpha:opacity;
}

还是很简练的吧,看到 heatmap.js 的风格,真的像是在看一个不错的艺术品一样。

支持浏览器:Firefox 3.6+, Chrome 10, Safari 5, Opera 11 and IE 9+

Github 地址:https://github.com/pa7/heatmap.js

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84960 人气
更多

推荐作者

qq_Yqvrrd

文章 0 评论 0

2503248646

文章 0 评论 0

浮生未歇

文章 0 评论 0

养猫人

文章 0 评论 0

第七度阳光i

文章 0 评论 0

新雨望断虹

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文