用户体验

基于Canvas的热力图绘制方法

一. 介绍

最近参与的一个项目Marmot中需要根据点坐标绘制热力图。

热力图

以特殊高亮的形式显示访客热衷的页面区域或访客所在的地理区域

特点为:

1. 可以显示不可点击区域发生的事情。你将发现用户经常会点击那些不是链接的地方,也许你应该在那个地方放置一个资源链接。比如:如果你发现人们总是在点击某 个产品图片,你能想到的是,他们也许想看大图,或者是想了解该产品的更多信息。 同样,他们可能会错误地认为特别的图片就是导航链接。

2. 热力图同时还能告诉你,页面的哪些部分吸引了大多数用户的注意。这对那些对web分析数据没有很多经验的产品人员非常有用。

3. 如果你在一个页面上有多个链接指向同一个URL,例如:如果有不同位置的3个链接指到同一个特定的产品页面 ,那么热力图将会显示你的访客最喜欢点击哪一个链接,这将帮助你提升网页的设计并让它对用户更加友好,不过实现这个功能需要一些设置。

…………

实例如下:

 

需要注意的是上图实例粒度粗,梯度小,容差大。反映了热力图的一个属性:趋势相关。不过,热力图也可以做到粒度细,梯度大,容差小。这完全是依据采样数据的精确性以及分析需求来做的。给个例子(Google的眼动分析[焦点梯度]图):

下面介绍热力图绘制的方法,注意,以下代码并没有检测数据有效性,也没有对数据进行过滤,剔除脏数据,同时没有处理异常。实际使用时请不要忽略此类情况,否则会对最终结果造成干扰……

二. 绘制

问题描述:

假设有一块画布,1200px*2000px尺寸,一组坐标数据,格式为[x,y]二维数组,量级为10000~100000,采样粒度为7*7。依据点坐标的分布密度绘制热力图

方法一

 

思路:使用canvas元素标签将所有点绘制到画布上,每个点给予较低的透明度。然后获取画布每个点的位数据,根据其alpha值(alpha ∈ [0, 255])的大小计算每一位的r,g,b的值,得出所有新的位数据之后,重新绘制。使之呈现为红色↔蓝色渐变。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*假设点坐标为aXY,二维数组*/
var aXY = [[x1, y1], [x2, y2], [x3, y3], [x4, y4]...];
//获取canvas的context
var context = canvas.getContext('2d');
var pi2 = Math.PI * 2;
//设置填充样式,透明度为0.1
context.fillStyle = 'rgba(255,30,0,0.1)';
for (var i = 0, len = aXY.length; i < len; i++) {
    var x = aXY[i][0], y = aXY[i][1];
    context.beginPath();
    //绘制圆点
    context.arc(x, y, 6, 0, pi2, true);
    context.closePath();
    context.fill();
}
//获取这个画布的位数据
var imgd = context.getImageData(0, 0, 1200, 2000);
var pix = imgd.data;
// 循环计算rgb,使之根据alpha值映射到红蓝渐变
for (var i = 0, n = pix.length; i < n; i += 4) {
    //位数据的格式为[rgbargbargba……],每个rgba代表了每个点的rgba四个通道的值
    var a = pix[i+3]; //alpha
    //red
    pix[i  ] = 128 * Math.sin((1 / 256 * a - 0.5 ) * Math.PI ) + 200;
    //green
    pix[i+1] = 128 * Math.sin((1 / 128 * a - 0.5 ) * Math.PI ) + 127;
    //blue,128之后直接衰减为0
    pix[i+2] = 256 * Math.sin((1 / 256 * a + 0.5 ) * Math.PI );
    pix[i+3] = pix[i+3] * 0.8;
}
context.putImageData(imgd, 0, 0);
希望看到您的想法,请您发表评论x