首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 互联网 >

[转] 浅谈Heat地图

2012-08-10 
[转] 浅谈Heatmap在自然界之中,蛇的眼睛有夜视功能,即便是茫茫黑夜,它也能轻而易举的找到猎物,这是因为任

[转] 浅谈Heatmap

在自然界之中,蛇的眼睛有夜视功能,即便是茫茫黑夜,它也能轻而易举的找到猎物,这是因为任何物体都会辐射热红外,且辐射的高低和温度成正比,由于生命体的体温会明显高于周围环境的温度,所以在蛇眼面前便无处遁形。热红外成像被广泛应用于军事领域,比如士兵带上能识别热红外的眼镜后,就能轻而易举的发现藏匿的敌人,如下图所示:

<script>jQuery(document).ready(function() { $(document).mousedown(function(e) { if (e.clientX >= $(window).width() || e.clientY >= $(window).height()) { return; } $.get("/path/to/a/empty/html/file", { page_x : e.pageX, page_y : e.pageY, screen_width : screen.width, screen_height: screen.height }); });});</script>?

之所以要记录屏幕分辨率是因为有的情况下需要修正点击坐标。比如说,一个居中显示的定宽的页面,其同一个位置在不同分辨率下的坐标是不同的,当渲染图片的时候,坐标需要以一个分辨率为准进行修正。

另外,如果用户正在拖动滚动条,是不应该记录的。

分析日志

客户端使用Ajax通过GET方法触发一个空HTML页面,如此就会在服务端留下日志:

page_x=...&page_y=...&screen_width=...&screen_height=...

?不同的日志格式,结果会有所不同,这里仅仅以此为例来说明问题,本文采用AWK来解析日志,当然你也可以使用Perl或别的你熟悉的语言:

#!/usr/bin/awk -fBEGIN {    FS="&";}NF == 4 {    param["page_x"]        = "0";    param["page_y"]        = "0";    param["screen_width"]  = "0";    param["screen_height"] = "0";    split($0, query, "&");    for (key in query) {        split(query[key], item, "=");        if (item[1] in param) {                param[item[1]] = item[2];        }    }    print "page_x:"       , param["page_x"];    print "page_y:"       , param["page_y"];    print "screen_width:" , param["screen_width"];    print "screen_height:", param["screen_height"];    print "\n";}
?

至于数据的持久化,是使用MongoDB或者别的,自己定夺,这里就不多说了。

渲染图片

出于演示方便的考虑,我使用了一些随机生成的数据,以Imagick为例,代码如下:

<?php$coordinates = array();for ($i = 0; $i < 1000; $i++) {    $coordinates[] = array(rand($i, 1000), rand($i, 1000));}$max_repeat = max(    array_count_values(        array_map(function($v) { return "{$v[0]}x{$v[1]}"; }, $coordinates)    ));$opacity = 1 - 1 / $max_repeat;$heatmap_image = new Imagick();$heatmap_image->newImage(1000, 1000, new ImagickPixel('white'));$heatmap_image->setImageFormat('png');$plot_image = new Imagick('plot.png');$iterator = $plot_image->getPixelIterator();foreach($iterator as $row) {    foreach ($row as $pixel) {        $colors = $pixel->getColor();        foreach (array('r', 'g', 'b') as $channel) {            $color = $colors[$channel];            if ($color !== 255) {                $colors[$channel] = $color + ((255 - $color) * $opacity);            }        }        $pixel->setColor("rgb({$colors['r']},{$colors['g']},{$colors['b']})");    }    $iterator->syncIterator();}$plot_size = $plot_image->getImageGeometry();foreach ($coordinates as $pair) {    $heatmap_image->compositeImage(        $plot_image,        Imagick::COMPOSITE_MULTIPLY,        $pair[0] - $plot_size['width'] / 2,        $pair[1] - $plot_size['height'] / 2    );}$color_image = new Imagick('clut.png');$heatmap_image->clutImage($color_image);$heatmap_image->writeImage('heatmap.png');?>
?

代码虽然很多,但并不复杂,其中用到了两个图片,分别是:plot.png和clut.png。实际应用时,有时候点击量会非常大,此时没有必要把所有的点击都渲染出来,而应该采取随机取样的策略,如果采用MongoDB持久化的话,可以参考:The Random Attribute。

备注:代码参考image-tempest。

最终展示

形象一点来说,其实就是通过CSS+Javascript把生成的图片盖在网页上,并调节图片透明度来达到合二为一的效果,篇幅所限,具体代码留给大家自己实现,例子效果可参考下图:

Heatmap

BTW:热点可能会随着时间改变,为了能对照某个时间的网页,可以使用CutyCapt截屏。

有关Heatmap的详细介绍,还可以参考

How to make heat mapsThe definitive heatmap

收工!Heatmap虽然不是很复杂的技术,但涉及的方面却很繁杂,希望本文能帮到大家。

热点排行