生成页面热力图是前端需要在大数据环境下进行展示的需求,比如需要看看页面哪些位置用户点击量比较多,哪些位置是用户比较关注的,利用数据分析能够更好的优化用户体验,提升页面转化率。
经过分析,我认为主要有两点需要注意:
1、一般像APP页面或者网页,都是拥有很大的流量,所以点击次数肯定都是百万级的;
2、热力值肯定要根据点击次数做出对应的调整;
所以,问题的关键就是怎么生成对应坐标的热力值?一般的思路是,设定好每次点击的热力值,然后在当重复点击同一坐标时进行累加;错误的思路肯定是不行了,所以上面的pass!为啥不行就留给读者自己探索了~
现在来说下我的思路:
1)首先既然数据都是百万级的所以肯定不能给每一个坐标都进行处理,因此我们要限定要渲染的坐标,以手机移动端为例,我先限定要生成热力图的部分分成50*200=10000个小格子,然后将每个小格子的中心点作为我将要渲染的坐标,这样不管来多少条数据,我最多只需要渲染10000个坐标即可!(注意:这样就说明用户每次点击的坐标如果在某个小格子的范围内都是会被替换成小格子中心点坐标的)
2)那就是热力值的计算了:
(1)首先我设定最大热力值为1000(这个随意,推荐选个好计算的值);
(2)然后所有被点击坐标的点击次数设为:index。其中肯定有最大值,设为:clickMax;
(3)所以热力值计算公式就出来了:
hotNum = index/clickMax*1000;
这样就可以适应到不同点击次数下的热力值了。 有更好的方法,欢迎留言~
话不多说,开始码代码:
页面结构及样式
<style>
body {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#heatmap {
border: 1pxsolid#ccc;
width: 640px;
height: 383px;
}
.legend-area {
position: absolute;
bottom: 0;
right: 0;
padding: 10px;
background: white;
outline: 3pxsolidblack;
line-height: 1em;
}
h4 {
margin: 0;
padding: 0;
margin-bottom: 5px;
}
#min {
float: left;
}
#max {
float: right;
}
span {
font-size: 14px;
margin: 0;
padding: 0;
}
.tooltip {
position: absolute;
left: 0;
top: 0;
background: rgba(0, 0, 0, .8);
color: white;
font-size: 14px;
padding: 5px;
line-height: 18px;
display: none;
}
.demo-wrapper {
position: relative;
height: 400px;
width: 840px;
background: rgba(0, 0, 0, .03);
border: 3 px solidblack;
}
.heatmap {
height: 400px;
width: 840px;
}
</style>
<body>
<buttonid="btn">生成热力图</button>
<divid="heatmap">
<imgsrc="./img/fuchouzhe.png" />
</div>
</body>
脚本部分:
<scriptsrc="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<scriptsrc="js/heatmap.js"></script>
<script>
window.onload=function () {
varheatmapBox=document.getElementById("heatmap");
varwidth=heatmapBox.offsetWidth;
varheight=heatmapBox.offsetHeight;
varpoints= [];
varminWidth=width/50;
varminHeight=height/200;
// 遍历出所有的横坐标
varxList= [];
varxNum=minWidth/2;
varxNumConst=minWidth/2;
for (vari=0; i<50; i++) {
xList.push(xNum);
xNum+=minWidth
}
// 遍历出所有的纵坐标
varyList= [];
varyNum=minHeight/2;
varyNumConst=minHeight/2;
for (vari=0; i<200; i++) {
yList.push(yNum);
yNum+=minHeight
}
// 遍历出所有的小格子坐标
varxyList= [];
for (vara=0; a<xList.length; a++) {
for (varb=0; b<yList.length; b++) {
varxyItem= {
x: xList[a],
y: yList[b]
};
xyList.push(xyItem)
}
}
varclickPointLIst= []; // 用来存储坐标被点击次数
// 当图片被点击时,记录所点击坐标的点击次数
$("#heatmap").on("click", function (e) {
varpageX=e.pageX;
varpageY=e.pageY;
console.log(pageX, pageY);
varclickXY=isNewXY(pageX, pageY);
console.log(clickXY);
if (clickPointLIst.length>0) {
varisflag=0;
clickPointLIst.forEach(function (item, index) {
varx=item.x;
vary=item.y;
if (x==clickXY.x&&y==clickXY.y) {
isflag++;
clickPointLIst[index].index=clickPointLIst[index].index+1
}
});
if (isflag==0) {
clickPointLIst.push({
x: clickXY.x,
y: clickXY.y,
index: 1
})
}
} else {
clickPointLIst.push({
x: clickXY.x,
y: clickXY.y,
index: 1
})
}
});
// 根据点击点坐标,生成实际应该起作用的坐标
functionisNewXY(pageX, pageY) {
varclickXY= {};
xyList.forEach(function (item, index) {
varx1=item.x-xNumConst;
vary1=item.y-yNumConst;
varx2=item.x+xNumConst;
vary2=item.y+yNumConst;
if ((pageX>=x1&&pageX<=x2) && (pageY>=y1&&pageY<=y2)) {
clickXY= {
x: item.x,
y: item.y
}
}
});
returnclickXY
}
// 计算出坐标应该对应的热力值
functioncalcHotNum(clickXY, list) {
varhotNum=0;
varmax=0;
varthisIndex=0;
list.forEach(function (item, index) {
max=Math.max(max, item.index);
varx=item.x;
vary=item.y;
if (x==clickXY.x&&y==clickXY.y) {
thisIndex=item.index
}
});
hotNum=thisIndex/max*1000;
returnhotNum
}
// 点击坐标生成热力图
$("#btn").on("click", function () {
varmax=0;
clickPointLIst.forEach(function (item, index) {
varhotNum=calcHotNum(item, clickPointLIst);
item.value=hotNum
max=Math.max(max, hotNum);
});
// console.log(clickPointLIst);
points=JSON.parse(JSON.stringify(clickPointLIst));
points.forEach(function (item, index) {
deleteitem.index;
item.x=Math.floor(item.x);
item.y=Math.floor(item.y);
// 很诡异,在工作的时候不需要取整,
// 结果回家写博客的时候,发现居然坐标不能是小数????
});
console.log(points);
// heatmap坐标值不能为小数
createHotMap(max, points)
});
// 热力图生成
functioncreateHotMap(max, points) {
varheatmapInstance=h337.create({
container: document.querySelector('#heatmap'),
});
vardata= {
max: max,
data: points
};
console.log(data)
heatmapInstance.setData(data)
};
//鼠标点击位置
$("body").click(function (event) {
varpos=getMousePos(event);
console.log(pos);
});
functiongetMousePos(event) {
vare=eventwindow.event;
varscrollX=document.documentElement.scrollLeftdocument.body.scrollLeft;
varscrollY=document.documentElement.scrollTopdocument.body.scrollTop;
varx=e.pageXe.clientX+scrollX;
vary=e.pageYe.clientY+scrollY;
//alert('x: ' + x + '\ny: ' + y);
return {
'x': x,
'y': y
};
}
}
</script>
在图片对应区域进行点击:
点击生成热力图:
对于需要更多的配置的,如下比如需要生成图例的,鼠标移动到热力区域返回热力值的 。
更多内容请查看附件,以及官网:
http://html2canvas.hertzen.com/
https://www.patrick-wied.at/static/heatmapjs/