热力图常用于展示在某个地理区域内,数据点(如人群密度、交通流量、气象数据等)的分布情况。颜色的变化表示数据强度的变化。例如,红色表示较高的密度,绿色表示较低的密度。
这里我一共使用了两种方式实现热力图方式
第一种:heatmap.js库很久没维护,不建议使用
存在边界问题,对于四至点的坐标,这里笔者以画图为例,只会渲染创建的canvas边界内容导致热力图失真
//创建热力图对象
let heatmapInstance = h337.create({
container: document.querySelector('#cesiumContainer'),
radius: 25, //给定半径
maxOpacity: 0.8,
minOpacity: 0,
});
let heatmapData = [{
"lng": 116.191031,
"lat": 39.988585,
"count": 10
},
...
];
let xMin = 180, yMin = 90, xMax = 0, yMax = 0;
//获取热力图数据的矩形范围
heatmapData.forEach(data => {
xMin = Math.min(data.lng, xMin);
yMin = Math.min(data.lat, yMin);
xMax = Math.max(data.lng, xMax);
yMax = Math.max(data.lat, yMax);
})
//热力图数据矩形范围的长和宽
let w = xMax - xMin;
let h = yMax - yMin;
//定义用于绘制热力图画布的宽高
let canvasWidth = w * 500;
let canvasHeight = h * 500;
//将经纬度数据坐标转换到画布的坐标系上
let convertData = [];
heatmapData.forEach(data => {
let x = (data.lng - xMin) / w * canvasWidth;
let y = -(data.lat - yMax) / h * canvasHeight;
convertData.push({
x: x,
y: y,
value: data.count
})
})
heatmapInstance.setData({
data: convertData,
max:100
});
let eneity = viewer.entities.add({
rectangle: {
coordinates: rect,
material: heatmapInstance._renderer.canvas
}
})
第二种:cesium-heatmap.js(推荐使用)
调用
let arr = [
// { x: 120.30693844543929, y: 37.620287586410306, value: 100 },
// { x: 120.28656436922547, y: 37.57640461112017, value: 120 },
// { x: 120.28488071005563, y: 37.57589062801232, value: 60 },
{ x: 120.28509677734766, y: 37.57769661997805, value: 50 },
{ x: 120.21137298932902, y: 37.58452670037166, value: 70 },
{ x: 120.28711110984104, y: 37.577876694578165, value: 100 },
{ x: 120.20392240925057, y: 37.61653805327714, value: 90 },
{ x: 120.25916108392813, y: 37.53335589495749, value: 40 },
];
//初始化热力图
this.heatMap = new HeatMap(window.$viewer, arr);
//创建热力图
this.heatMap.create();
封装的热力图类,需要安装turf库以及cesium-heatmap.js
/*
viewer:Cesium.Viewer实例
data:热力图数据
数据格式:
let arr = [
{x: 120.30693844543929, y: 37.620287586410306, value: 100},
{x: 120.28656436922547, y: 37.57640461112017, value: 120},
{x: 120.28488071005563, y: 37.57589062801232, value: 60},
{x: 120.28509677734766, y: 37.57769661997805, value: 50},
{x: 120.21137298932902, y: 37.58452670037166, value: 70},
{x: 120.28711110984104, y: 37.577876694578165, value: 100},
{x: 120.20392240925057, y: 37.61653805327714, value: 90},
{x: 120.25916108392813, y: 37.53335589495749, value: 40}
];
options:热力图配置项
maxOpacity:热力图最大透明度
gradient:热力图渐变颜色
*/
//创建热力图类方法
export default class HeatMap {
constructor(viewer, data, options = {
maxOpacity: 0.7,
gradient: {
".3": "#d9e7fc",
".65": "#2a7aed",
".8": "#fbd801",
".95": "#18c3a1",
},
}) {
this.viewer = viewer;
this.options = options;
this.valueMin = null;
this.valueMax = null;
this.data = data
//根据传入数据求出边界范围
const { bounds, valueMin, valueMax } = this.initBounds(data)
this.valueMin = valueMin
this.valueMax = valueMax
this.bounds = bounds
this.heatMap=null
}
initBounds(arr) {
if (!Array.isArray(arr) || arr.length <= 1) {
// console.warn("热力图数据为空或格式不正确,返回默认边界范围");
return {
bounds: { west: -180, east: 180, south: -90, north: 90 },
valueMax: Infinity,
valueMin: -Infinity,
};
}
let xMax = -180;
let xMin = 180;
let yMax = -90;
let yMin = 90;
let valueMax = -Infinity;
let valueMin = Infinity;
for (let i = 0; i < arr.length; i++) {
xMax = Math.max(xMax, arr[i].x);
xMin = Math.min(xMin, arr[i].x);
yMax = Math.max(yMax, arr[i].y);
yMin = Math.min(yMin, arr[i].y);
valueMax = Math.max(valueMax, arr[i].value);
valueMin = Math.min(valueMin, arr[i].value);
}
return {
bounds: { 'west': xMin, 'east': xMax, 'south': yMin, 'north': yMax }, // 边界范围
valueMax,
valueMin,
};
}
//创建热力图层
create() {
this.heatMap = CesiumHeatmap.create(this.viewer, this.bounds, this.options);
this.heatMap.setWGS84Data(this.valueMin, this.valueMax, this.data);
let arr=this.data.map(item=>{
return [item.x,item.y]
})
//飞行到中心点
let centerPos=turf.points(arr);
var center = turf.center(centerPos);
//转成笛卡尔
var centerCartesian = Cesium.Cartesian3.fromDegrees(...center.geometry.coordinates, 2e4);
window.$viewer.camera.flyTo({
destination:centerCartesian,
orientation: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-90.0),
roll: 0.0,
},
});
}
//更新数据
update(data) {
this.heatMap.setWGS84Data(this.valueMin, this.valueMax, data);
}
}