Heatmap.js
- 一、简介
- 二、使用
- 2.1 上手
- 2.2 设置点的半径
- 2.3 添加底图
- 2.4 更多
- 三、高级用法
- 3.1 动态热力图
- 3.2 鼠标跟随热力图
- 3.3 显示数值
一、简介
Heatmap.js V2.0 是目前网络上最先进的热图可视化库。新的2.0版本 Heatmap.js 更快,拥有更强的渲染模块,使用更方便,因此您可以快速掌握和扩展自定义功能。
参考链接:
- 官方文档
- 【JS】heatmap.js v2.0,详细参数总结
二、使用
😃 先下载js使用 😃
原文:https://github.com/pa7/heatmap.js/blob/master/build/heatmap.js
或者外链引入!(建议下载,运行速度更快~)
2.1 上手
- 初始化实例,heatmapInstance
- 给实例设置数据(随机点)
简单教程:Minimal Configuration Example
Tips:获取文档中
class="example"
的第一个元素:
document.querySelector(".example");
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>HeadMap.js</title><!--Framework--><script src="js/heatmap.js" type="text/javascript"></script></head><body><h1>HeadMap</h1><div class="heatmap" style="height: 600px;width: 500px;"></div><script type="text/javascript">// minimal heatmap instance configurationvar heatmapInstance = h337.create({// only container is required, the rest will be defaults//只需要一个container,也就是最终要绘制图形的dom节点,其他都默认container: document.querySelector('.heatmap')});// now generate some random datavar points = [];var max = 0;var width = 840;var height = 400;var len = 200;while (len--) {var val = Math.floor(Math.random()*100);max = Math.max(max, val);var point = {//这里可以自定义x: Math.floor(Math.random()*width),y: Math.floor(Math.random()*height),value: val};points.push(point);}// heatmap data formatvar data = {max: max,//所有数据中的最大值data: points//最终要展示的数据};// if you have a set of datapoints always use setData instead of addData// for data initializationheatmapInstance.setData(data);</script></body>
</html>
2.2 设置点的半径
point 配置点的半径:radius: radius
var point = {x: Math.floor(Math.random()*width),y: Math.floor(Math.random()*height),value: val,// radius configuration on point basis 主要是半径的配置,radius: radius};points.push(point);
}
右图是配置了半径:
2.3 添加底图
<div class="heatmap" style=" width:700px; height: 600px;"><img src="img/classroom.png" style="width:100%; height: 100%"></div>
2.4 更多
修改了画布颜色,点大小等:
源码:
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>HeadMap.js</title><!--Framework--><script src="js/jquery-3.4.1.min.js" type="text/javascript"></script><script src="js/heatmap.js" type="text/javascript"></script></head><body><h1>HeadMap</h1><div class="heatmap" style="height: 600px;width: 500px;"></div><script type="text/javascript">// customized heatmap configurationvar heatmapInstance = h337.create({// required containercontainer: document.querySelector('.heatmap'),// backgroundColor to cover transparent areas 背景颜色,可以覆盖透明区域backgroundColor: 'rgba(0,0,0,.95)',// custom gradient colors 这里设置了颜色梯度。键值从0到1gradient: {// enter n keys between 0 and 1 here// for gradient color customization'.5': 'blue','.8': 'red','.95': 'white'},// the maximum opacity (the value with the highest intensity will have it) 最高透明度maxOpacity: .9,// minimum opacity. any value > 0 will produce // no transparent gradient transition minOpacity: .3});// now generate some random datavar points = [];var max = 0;var width = 540;var height = 600;var len = 300;while (len--) {var val = Math.floor(Math.random()*100);var radius = Math.floor(Math.random()*70);max = Math.max(max, val);var point = {x: Math.floor(Math.random()*width),y: Math.floor(Math.random()*height),value: val,radius: radius};points.push(point);}// heatmap data formatvar data = { max: max, data: points };// if you have a set of datapoints always use setData instead of addData// for data initializationheatmapInstance.setData(data);</script></body>
</html>
三、高级用法
参考官方文档,大概如下函数(命名即使用方法),具体使用见example:
官方文档:heatmap.js Documentation
总共有两个对象: h337是heatmap的全局变量, 而heatmapInstance是h337实例化的对象
😃 划重点 😃
官方示例:heatmap.js Examples
根据官方示例,画轮子造车,这里有:
- 动态热力图
- 基础热力图(basic example也就是我们之前说的)
- 鼠标跟随热力图
- 谷歌地图结合热力图
- AngularJS 结合热力图
3.1 动态热力图
这里我以动态热力图
为目标,开始学习:
(多图数据刷新,模拟动态效果,下方可选择倍数查看)
headMap.js用法与前文相同,这里引入了
canvas
画布作为动图演示模块,引入了原文的example-commons.css
样式,效果实现。
源码:
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>HeadMap.js</title><!-- 动图效果样式 --><link rel="stylesheet" href="https://www.patrick-wied.at/static/heatmapjs/assets/css/commons.css"><link rel="stylesheet" href="https://www.patrick-wied.at/static/heatmapjs/assets/css/example-commons.css"><!--Framework--><script src="js/heatmap.js" type="text/javascript"></script><style>.demo-wrapper {position: relative;}/* animation player css */.timeline-wrapper {position: absolute;top: 10px;left: 10px;right: 10px;height: 30px;background: white;transition: 1s ease all;border-radius: 4px;box-shadow: 0 1px 5px rgba(0, 0, 0, .65)}.heatmap-timeline {position: absolute;top: 0;right: 15px;left: 80px;height: 100%;}.heatmap-timeline .line {position: absolute;left: 0;right: 0;top: 15px;height: 2px;background: #d7d7d7;}.heatmap-timeline .time-point.active {background: black;}.heatmap-timeline .time-point {position: absolute;background: white;border: 2px solid #272727;width: 8px;height: 8px;border-radius: 100%;cursor: pointer;top: 15px;transform: translateX(-50%) translateY(-50%);}.heatmap-timeline .time-point:hover {box-shadow: 0 0 5px black;}.timeline-wrapper button {position: absolute;outline: none;color: black;background: #f2f2f2;width: 65px;height: 100%;cursor: pointer;border: none;text-transform: uppercase;border-top-left-radius: 3px;border-bottom-left-radius: 3px;}.heatmap-timeline .time-point.active {background: black;}/* end animation player css */</style></head><body><h1>HeadMap</h1><div class="wrapper"><div class="demo-wrapper"><div class="heatmap" style="position: relative;"><canvas class="heatmap-canvas" width="834" height="400" style="position: absolute; left: 0px; top: 0px;"></canvas></div><div class="timeline-wrapper"><button>play</button><div class="heatmap-timeline"><div class="line"></div><div class="time-point" style="left: 0%;"></div><div class="time-point" style="left: 5.26316%;"></div><div class="time-point" style="left: 10.5263%;"></div><div class="time-point" style="left: 15.7895%;"></div><div class="time-point" style="left: 21.0526%;"></div><div class="time-point active" style="left: 26.3158%;"></div><div class="time-point" style="left: 31.5789%;"></div><div class="time-point" style="left: 36.8421%;"></div><div class="time-point" style="left: 42.1053%;"></div><div class="time-point" style="left: 47.3684%;"></div><div class="time-point" style="left: 52.6316%;"></div><div class="time-point" style="left: 57.8947%;"></div><div class="time-point" style="left: 63.1579%;"></div><div class="time-point" style="left: 68.4211%;"></div><div class="time-point" style="left: 73.6842%;"></div><div class="time-point" style="left: 78.9474%;"></div><div class="time-point" style="left: 84.2105%;"></div><div class="time-point" style="left: 89.4737%;"></div><div class="time-point" style="left: 94.7368%;"></div><div class="time-point" style="left: 100%;"></div></div></div></div><div class="demo-controls"><button class="trigger-refresh btn" data-fps="10">Set speed to 10 frames per second</button><button class="trigger-refresh btn" data-fps="5">Set speed to 5 frames per second</button><button class="trigger-refresh btn" data-fps="1">Set speed to 1 frame per second</button><br style="clear:both"></div></div><script type="text/javascript">window.onload = function() {function generateRandomData(len) {// generate some random datavar points = [];var max = 0;var width = 840;var height = 400;while (len--) {var val = Math.floor(Math.random() * 100);max = Math.max(max, val);var point = {x: Math.floor(Math.random() * width),y: Math.floor(Math.random() * height),value: val};points.push(point);}var data = {max: max,data: points};return data;}function $(selector) {return document.querySelectorAll(selector);}function AnimationPlayer(options) {this.heatmap = options.heatmap;this.data = options.data;this.interval = null;this.animationSpeed = options.animationSpeed || 300;this.wrapperEl = options.wrapperEl;this.isPlaying = false;this.init();};AnimationPlayer.prototype = {init: function() {var dataLen = this.data.length;this.wrapperEl.innerHTML = '';var playButton = this.playButton = document.createElement('button');playButton.onclick = function() {if (this.isPlaying) {this.stop();} else {this.play();}this.isPlaying = !this.isPlaying;}.bind(this);playButton.innerText = 'play';this.wrapperEl.appendChild(playButton);var events = document.createElement('div');events.className = 'heatmap-timeline';events.innerHTML = '<div class="line"></div>';for (var i = 0; i < dataLen; i++) {var xOffset = 100 / (dataLen - 1) * i;var ev = document.createElement('div');ev.className = 'time-point';ev.style.left = xOffset + '%';ev.onclick = (function(i) {return function() {this.isPlaying = false;this.stop();this.setFrame(i);}.bind(this);}.bind(this))(i);events.appendChild(ev);}this.wrapperEl.appendChild(events);this.setFrame(0);},play: function() {var dataLen = this.data.length;this.playButton.innerText = 'pause';this.interval = setInterval(function() {this.setFrame(++this.currentFrame % dataLen);}.bind(this), this.animationSpeed);},stop: function() {clearInterval(this.interval);this.playButton.innerText = 'play';},setFrame: function(frame) {this.currentFrame = frame;var snapshot = this.data[frame];this.heatmap.setData(snapshot);var timePoints = $('.heatmap-timeline .time-point');for (var i = 0; i < timePoints.length; i++) {timePoints[i].classList.remove('active');}timePoints[frame].classList.add('active');},setAnimationData: function(data) {this.isPlaying = false;this.stop();this.data = data;this.init();},setAnimationSpeed: function(speed) {this.isPlaying = false;this.stop();this.animationSpeed = speed;}};var heatmapInstance = h337.create({container: document.querySelector('.heatmap')});// animationData contains an array of heatmap statesvar animationData = [];for (var i = 0; i < 20; i++) {animationData.push(generateRandomData(300));}var player = new AnimationPlayer({heatmap: heatmapInstance,wrapperEl: document.querySelector('.timeline-wrapper'),data: animationData,animationSpeed: 500});var controlButtons = $('.trigger-refresh');for (var i = 0; i < controlButtons.length; i++) {controlButtons[i].onclick = function() {var fps = this.dataset.fps;player.setAnimationSpeed(1 / (+fps) * 1000);};}};</script></body>
</html>
3.2 鼠标跟随热力图
主要是捕捉鼠标移动效果,再绘图:
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>HeadMap.js</title><!-- 动图效果样式 --><link rel="stylesheet" href="https://www.patrick-wied.at/static/heatmapjs/assets/css/commons.css"><link rel="stylesheet" href="https://www.patrick-wied.at/static/heatmapjs/assets/css/example-commons.css"><!--Framework--><script src="js/heatmap.js" type="text/javascript"></script><style>.demo-wrapper { position:relative; background:rgba(0,0,0,.9); }.text-bg { color:rgba(255,255,255,.8); position:absolute; left:0; top:0; right:0; bottom:0; height:40px; width:230px; text-align:center; margin:auto; }</style></head><body><h1>HeadMap</h1><div class="wrapper"><div class="demo-wrapper"><div class="text-bg">much interesting click & move zone here!</div><div class="heatmap" style="position: relative;"><canvas class="heatmap-canvas" width="834" height="400" style="position: absolute; left: 0px; top: 0px;"> </canvas></div></div></div><script type="text/javascript">window.onload = function() {var heatmapContainer = document.querySelector('.heatmap');var heatmapInstance = h337.create({container: heatmapContainer,radius: 50});heatmapContainer.onmousemove = heatmapContainer.ontouchmove = function(e) {// we need preventDefault for the touchmovee.preventDefault();var x = e.layerX;var y = e.layerY;if (e.touches) {x = e.touches[0].pageX;y = e.touches[0].pageY;}heatmapInstance.addData({ x: x, y: y, value: 1 });};heatmapContainer.onclick = function(ev) {heatmapInstance.addData({x: ev.layerX, y: ev.layerY, value:1 });};};</script></body>
</html>
3.3 显示数值
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>HeadMap.js</title><!-- 动图效果样式 --><link rel="stylesheet" href="https://www.patrick-wied.at/static/heatmapjs/assets/css/commons.css"><link rel="stylesheet" href="https://www.patrick-wied.at/static/heatmapjs/assets/css/example-commons.css"><!--Framework--><script src="js/heatmap.js" type="text/javascript"></script><style>.legend-area { position:absolute; bottom:0; right:0; padding:10px; background:white; outline:3px solid black; 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; }</style></head><body><h1>HeadMap</h1><div class="wrapper"><div class="demo-wrapper"><div class="heatmap" style="position: relative;"><canvas class="heatmap-canvas" width="834" height="400" style="position: absolute; left: 0px; top: 0px;"></canvas></div><div class="tooltip" style="display: none; transform: translate(538px, 377px);">633</div><div class="legend-area"><h4>Legend Title</h4><span id="min">0</span><span id="max">1224</span><img id="gradient" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAKCAYAAABCHPt+AAAAx0lEQVRYR+2WwQqDMBBEn2SF6P9/Z9tTFRSULVkIpdC0kBUxgTDZax4zsx1sG7WPrDDMECdXFVkYgAiuKjNwB27AI70L584HyOIKwsCLrK4gDLxMGQQFomAUiN4vcwNSwUF/AUmgGpDaQMwZheoDpF8gpg4ZkzrMGllj+nCNE70ec8gjqxCERZoPELlYhzyzrrDOKFQfIOqQA7asPhxT6uEUQBwi6rVdZZH4KbI81mBRIIVb1fvW1RxSodTP4ZCrRdaPZW6O2gEogeBRRgNVBwAAAABJRU5ErkJggg==" style="width:100%"></div></div><div class="demo-controls"><button class="trigger-refresh btn">re-generate data</button><br style="clear:both"></div></div><script type="text/javascript">window.onload = function() {function generateRandomData(len) {// generate some random datavar points = [];var max = 0;var min = 1234;var width = 840;var height = 400;while (len--) {var val = Math.floor(Math.random()*1234);max = Math.max(max, val);min = Math.min(min, val);var point = {x: Math.floor(Math.random()*width),y: Math.floor(Math.random()*height),value: val};points.push(point);}var data = { max: max, min:min, data: points };return data;};/* legend code */// we want to display the gradient, so we have to draw itvar legendCanvas = document.createElement('canvas');legendCanvas.width = 100;legendCanvas.height = 10;var min = document.querySelector('#min');var max = document.querySelector('#max');var gradientImg = document.querySelector('#gradient');var legendCtx = legendCanvas.getContext('2d');var gradientCfg = {};function updateLegend(data) {// the onExtremaChange callback gives us min, max, and the gradientConfig// so we can update the legendmin.innerHTML = data.min;max.innerHTML = data.max;// regenerate gradient imageif (data.gradient != gradientCfg) {gradientCfg = data.gradient;var gradient = legendCtx.createLinearGradient(0, 0, 100, 1);for (var key in gradientCfg) {gradient.addColorStop(key, gradientCfg[key]);}legendCtx.fillStyle = gradient;legendCtx.fillRect(0, 0, 100, 10);gradientImg.src = legendCanvas.toDataURL();}};/* legend code end */var heatmapInstance = h337.create({container: document.querySelector('.heatmap'),onExtremaChange: function(data) {updateLegend(data);}});// generate 200 random datapointsvar data = generateRandomData(200);heatmapInstance.setData(data);var demoWrapper = document.querySelector('.demo-wrapper');var tooltip = document.querySelector('.tooltip');function updateTooltip(x, y, value) {// + 15 for distance to cursorvar transform = 'translate(' + (x + 15) + 'px, ' + (y + 15) + 'px)';tooltip.style.MozTransform = transform; /* Firefox */tooltip.style.msTransform = transform; /* IE (9+) - note ms is lowercase */tooltip.style.OTransform = transform; /* Opera */tooltip.style.WebkitTransform = transform; /* Safari and Chrome */tooltip.style.transform = transform; /* One day, my pretty */tooltip.innerHTML = value;}demoWrapper.onmousemove = function(ev) {var x = ev.layerX;var y = ev.layerY;var value = heatmapInstance.getValueAt({x: x,y: y});tooltip.style.display = 'block';updateTooltip(x, y, value);};demoWrapper.onmouseout = function() {tooltip.style.display = 'none';};document.querySelector('.trigger-refresh').onclick = function() {heatmapInstance.setData(generateRandomData(200));};};</script></body>
</html>
大致就是这样,今日学习完工! 😃