uniapp + renderjs + heatmap.js 实现热力图
app项目中需要热力图展示,第一次用uniapp的renderjs操作dom,遇到了一些坑,包括引入组件,请求传参啥的
项目安装heatmap.js热力图插件,插件支持pc app
heatmap api文档
https://www.patrick-wied.at/static/heatmapjs/docs.html#h337-register
heatmap.js官网
https://www.patrick-wied.at/static/heatmapjs/
首先项目安装插件
npm i heatmap
这个插件需要获取到原生的dom元素,然后uniapp提供的方法只能获取元素数据,不支持操作dom,但是提供了另一种方式renderjs
renderjs使用
在需要热力图组件的页面新增一个script为renderjs模式
在新增的script中引入 heatmap
module相当于是这个模块的名字
<script module="map" lang="renderjs">
import Heatmap from "heatmap.js";
export default {
data() {
return {
heapMapIns: null,
}
},
methods: {
//创建热力图
initHotImg(newV) {
this.deleteHotMap();
let config = {
container: document.getElementById("hotMap"),
radius: 35,
maxOpacity: 0.5,
minOpacity: 0,
blur: 0.85,
value: "value",
gradient: {
"0": "rgb(0,0,255)", //value为0的颜色
"0.2": "rgb(0,255,255)", //value为50的颜色
"0.4": "rgb(0,255,0)", //value为200的颜色
"0.6": "yellow", //value为500的颜色
"1": "rgb(255,0,0)" //value为1000的颜色
}
};
// create heatmap with configuration
this.heapMapIns = Heatmap.create(config);
let dataList = {
max: 200,
min: 0,
data: newV
};
this.heapMapIns.setData(dataList);
},
// 删除之前的热力图,每次重载热力图时canvas都会新增一个,所以要删除前一个canvas
deleteHotMap() {
var heatmapBox = document.querySelector("#hotMap");
if (heatmapBox.children.length > 1) {
var oldCanvas = heatmapBox.children[1];
heatmapBox.removeChild(oldCanvas);
}
},
}
}
</script>
renderjs中不支持uni.request,意思就是renderjs中不能发送请求,所以请求后台拿数据的操作得到原有的script中进行,然后监听参数变化,将参数传递过来进行渲染
<script>
export default {
data() {
return {
pointsArr : [],//
h:'',
}
},
methods: {
//获取热力图数据
gethotData() {
//这里的请求是获取热力图数据通过临时变量接收,然后赋值给被监听的需要传给renderjs的热力图数据
Api.floorAreas(this.clientId).then(res => {
if (res.data.code == 200) {
this.areaId = res.data.data[0].listArea[0].areaId;
this.mapParams.areaId = this.areaId;
Api.clientHeatMapArea(this.mapParams).then(resd => {
if (resd.data.code == 200) {
this.imgSrc = resd.data.data.areaMapUrl;
this.url = "url(" + 'http://pic.ccc.com' + resd.data.data.areaMapUrl +
") 0% 0% /100% 100% no-repeat";
let bi = resd.data.data.areaHeight / resd.data.data.areaWidth;
bi = bi.toFixed(0);
this.h = this.screenWidth * bi;
let dataList = resd.data.data.listAreaMap;
let mapData = [];
if (dataList.length !== 0) {
dataList.forEach(item => {
mapData.push({
x: item.x / 3,
y: item.y / 5,
value: item.times
});
})
this.pointsArr = mapData;
}
}
})
}
})
}
},
mounted(){
this.gethotData();
}
}
</script>
h5代码
<view id="hotMap" :style="'width'+':' +screenWidth * 2 + 'upx'+';' + 'height'+':' +h + 'upx' +';' +
'background:'+url + ';'" :prop="pointsArr" :change:prop="map.initHotImg">
</view>
这里监听pointsArr数据变化,只要pointsArr数据改变,就会触发map.initHotImg方法,然后传递参数过去,我这里的高宽和背景图是动态获取的,可以忽略
热力图效果
坑:
1、官方说renderjs中可以操作dom,我实践过来,发现renderjs仅支持获取原生的dom元素
,想通过原生的el.style.height的方式去修改元素的宽高,没有成功,最后是采用的绑定style的方式实现的宽高控制
2、传参方式:我在百度里搜寻了很多从script向renderjs传参的方式,都行不通,最后采用的这个通过监听实现的传参可行
3、开发时一定要用usb连接实机进行调试,pc浏览器模拟的手机窗口和实机展示的会有差别。
**
简单dome示例完整代码
**
<template>
<view>
<view class="detial" style="display: flex;flex-direction: column;">
<view name='热力分析' style="flex: 1; display: flex;flex-direction: column;">
<!-- 死宽度无背景图 -->
<view id="hotMap" :prop="pointsArr" :change:prop="renderMap.initHotImg"
style="margin: 5px auto;width: 400upx;height: 400upx;border: 1px solid #ccc;"
@click="renderMap.initHotImg">
</view>
<!-- 后台数据设定宽度和背景图 -->
<!-- <view id="hotMap" :style="'width'+':' +screenWidth + 'px'+';' + 'height'+':' +h + 'px' +';' +
'background:'+url + ';'" :prop="pointsArr" :change:prop="map.initHotImg" style="margin: 5px auto;">
</view> -->
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
pointsArr: [],
}
},
methods: {
//模拟后端请求,获取热力图数据
getHotData() {
setTimeout(()=>{
this.pointsArr = [{
x: 0,
y: 0,
value: 100
}]
},500)
},
},
created() {},
mounted() {
this.getHotData();
},
}
</script>
<script module="renderMap" lang="renderjs">
import Heatmap from "heatmap.js";
export default {
data() {
return {
heapMapIns: null,
}
},
methods: {
initHotImg(newV) {
let config = {
container: document.getElementById("hotMap"),
radius: 35,
maxOpacity: 0.5,
minOpacity: 0,
blur: 0.85,
value: "value",
gradient: {
"0": "rgb(0,0,255)", //value为0的颜色
"0.2": "rgb(0,255,255)", //value为50的颜色
"0.4": "rgb(0,255,0)", //value为200的颜色
"0.6": "yellow", //value为500的颜色
"1": "rgb(255,0,0)" //value为1000的颜色
}
};
// create heatmap with configuration
this.heapMapIns = Heatmap.create(config);
let dataList = {
max: 50,
min: 0,
data: newV
};
this.heapMapIns.setData(dataList);
},
// 删除之前的热力图,pc端使用,因为插件会在浏览器未清楚缓存,然后开发者通过再次触发请求的方式拿到数据重新渲染热力图,
//就会一直创建canvas画布,所以页面上会出现好几个热力图板块,所以在每次渲染热力图,都需要把上一个删除
deleteHotMap() {
var heatmapBox = document.querySelector("#hotMap");
if (heatmapBox.children.length > 1) {
var oldCanvas = heatmapBox.children[1];
heatmapBox.removeChild(oldCanvas);
}
},
},
}
</script>
<style scoped lang="scss">
.detial {
position: fixed;
width: 100%;
height: 100%;
background: #2c367b;
background-size: 100% 100%;
display: flex;
flex-direction: column;
}
</style>
demo效果