热力图原理

        最近公司让做一款统计移动APP的热力图插件,好吧百度了下也只是找到了百度统计的一些线索。思考了几天终于开始做了。

首先我说下思路和开发遇到的问题:

一. 数据采集部分:

           1.因为是移动端第一个考虑的便是分辨率的问题。毕竟市场上手机屏幕大小区别还是很大的。
           2. 第二个要考虑的是坐标点的问题一个1980*1080的屏有200万个象素点,好吧我开始蛋疼了,难道为了一个界面保存200万个坐标的信息?
           3. 第三毕竟是手机端啊,我们的考虑流量的问题,不可能一次弄一个长度200万的数组传后台去,想想都不可能。
           4. 那么第四个问题来了,我们多久传一次呢?
           5.第五个问题,手机可以竖着用,还可以横着用,这又怎么算?
           。。。其他问题也是有的目前可以忽略不计。。。
          答案来了:我解决的方法是分块,将一个屏幕分了1200块不就是30*40,我将所有的分辨率都分成30*40;一下将200万变成了1200,好了现在轻松多了,通过JS迭代器去统计点击次数,好嘛,流量的问题就这么解决了。考虑到不同APP使用的时候需要的时间不一样我觉定这个time 让APP的开发者去决定,当然了默认值是10秒,或者当前页面关闭的时候传输一次数据。

二.后台(数据处理部分):

         前端传过来的数据是采用日志的形式写文件,然后呢定时处理入库。这个参考的是百度统计的做法。

三.展示热力图:

      heatmap.js我用的这个开源插件;

实现:

       好吧!看到这里你也应该猜到了我做的数据采集部分。
先给大家看下我写的JS:
<pre name="code" class="javascript">/*
 * yc
 * 1.0
 * 2015/11/11
 */
/*
 * 热力图坐标采集
 */
(function($) {
	/*
	 * MAP构造
	 */
	var Map = function() {
		this.keys = new Array();
		this.data = new Object();
		this.put = function(key, val) {
			if (this.data[key] == null) {
				this.keys.push(key);
			}
			this.data[key] = val;
		};
		this.clear = function() {
			this.keys = [];
			this.data = {};
		}
		this.toString = function() {
			var s = "{";
			for (var i = 0; i < this.keys.length; i++) {
				var k = this.keys[i];
				s += k + ":" + this.data[k];
				i == (this.keys.length - 1) ? '' : (s += ",");
			}
			s += "}";
			return s;
		};
	};
	//算法和初始化方法
	jQuery.utility = {
		getWindowsWH: function() {
			var ret = {};
			ret.width = $(window).width();
			ret.height = $(window).height();
			console.log(ret.width + "px," + ret.height + "px");
			return ret;
		},
		setPoint: function(x, y, a, cx, cy) {
			return Math.floor(y / cy) * a + Math.floor(x / cx);
		},
		PointArray: function() {
			console.log("初始化  PointArray");
			return new Array();
		},
		PointMap: function() {
			console.log("初始化  PointMap");
			return new Map();
		},
		getImg: function() {
			return new Image(1, 1);
		}
	};
	//参数配置
	var defaults = {
		a: 30,
		b: 39,
		time: 10,
		url: '', //get请求URL
		pluginID: '', //插件ID
		pageNum: 1 //页面编号
	};
	$.fn.extend({
		RLT: function(options) {
			var opts = $.extend(defaults, options);
			var wh = $.utility.getWindowsWH();
			var pointArray = $.utility.PointArray();
			var pointMap = $.utility.PointMap();
			var cx = Math.floor(wh.width / opts.a); //分块大小
			var cy = Math.floor(wh.height / opts.b);
			//数据清空
			var DataClear = function() {
				pointArray = [];
				pointMap.clear();
				console.log("---清空数据---");
			};
			//通过Image对象请求后端脚本
			var url_ = defaults.url + "?pluginID=" + defaults.pluginID + "&pageNum=" + defaults.pageNum + "&data=";
			var Post_ = function(u, data) {
				var img = $.utility.getImg();
				img.src = u + data;
			};
			//整理数据
			var getData = function() {
				if (pointArray.length == 0) {
					return null;
				};
				for (var i = 0; i < pointArray.length; i++) {
					var val = 0;
					for (var j = 0; j < pointArray.length; j++) {
						if (pointArray[i] == pointArray[j]) {
							val++;
						}
					}
					pointMap.put(pointArray[i], val);
				}
				console.log("data:" + pointMap.toString());
				return pointMap.toString();
			}
			return this.each(function() {
				//主体函数
				$(this).on('mousedown', function() {
					var scrollTop = $(this).scrollTop();
					var x = window.event.clientX;
					var y = window.event.clientY + scrollTop;
					var index = $.utility.setPoint(x, y, defaults.a, cx, cy);
					pointArray.push(index);
					console.log(index + ":(" + x + "," + y + ")  pointArray.size-->" + pointArray.length);
				});
				//定时发送数据
				setInterval(function() {
					var data = getData();
					if (data != null) {
						Post_(url_, data); //发送数据
						DataClear(); //清空数据
					}
				}, defaults.time * 1000);
				//页面关闭时发送数据
				window.onbeforeunload = function() {
					var data = getData();
					if (data != null) {
						Post_(url_, data); //发送数据
						DataClear(); //清空数据
					}
				};
			});
		}
	});
	//解析配置文件执行方法
	if (config_) {
		for (var i in config_.dom) {
			$(config_.dom[i]).RLT({ //执行方法
				time: config_.time,
				pluginID: config_.pluginID, //插件ID
				//pageNum: i //页面编号
			});
		}
	} else {
		return null;
	}
})(jQuery);


 
页面引用部分:
<script type="text/javascript">
var config_ = {
dom: ['body'],
time: 10,
pluginID: '12AC89F', //插件ID
pageNum: 1211 //页面编号
};
(function(){
var f = document.createElement('script');
f.type = 'text/javascript';
f.src = 'js/relitu2.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(f, s);
})();
</script>



结果图:
 

    好了这个请求就是我们需要的数据
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值