总结
cesium热力图通过heatmap.js实现,heatmap.js通过颜色和高度直观展示数据分布,生成三维的热力图。
- 首先准备数据点位,包含坐标,值,还有颜色数组
- 安装下载heatmap.js,通过heatmap算法生成三维热力图
- 计算热力图的边界以防分割
- 通过贴图的方式将热力图贴到地图上 热力图效果
一、创建cesium
js
const viewer = new Cesium.Viewer('cesiumContainer');
二、下载安装heatmap.js
js
npm install heatmap.js
下载完之后,还需将源码中一段代码注释掉,或者运行时会报错。在node_modules中找到heatmap.js的文件夹,选择build-》heatmap文件。

img.data在不少浏览器中是只读的,所以运行会报错,要将代码注释掉。

三、创建heatmap工具类
js
import h337 from "heatmap.js";
import * as Cesium from "cesium";
export default class Heatmap {
constructor(viewer, opt) {
this.viewer = viewer;
this.opt = opt || {};
this.dotList = []
this.list = this.opt.list || [];
if (!this.list || this.list.length < 2) {
console.log("热力图点位不得少于3个!");
return;
}
this.dom = undefined;
this.id = Number(
new Date().getTime() + "" + Number(Math.random() * 1000).toFixed(0)
);
this.canvasw = 200;
this.createDom();
//配置参数
let config = {
container: document.getElementById(`easy3d-heatmap-${this.id}`),
radius: this.opt.raduis ||20,
maxOpacity: 0.7,
minOpacity: 0,
blur: 0.75,
gradient: this.opt.gradient || { //颜色范围
".1": "blue",
".5": "green",
".7": "yellow",
".99": "red",
},
};
//创建热力图
this.heatmapInstance = h337.create(config);
this.init();
}
init() {
this.hierarchy = [];
for (let ind = 0; ind < this.list.length; ind++) {
let position = Cesium.Cartesian3.fromDegrees(
this.list[ind].lnglat[0],
this.list[ind].lnglat[1]
);
this.hierarchy.push(position);
let type = this.list[ind].params.type
//在地图上添加实体
let dot = this.viewer.entities.add({
id:type+this.list[ind].id,
name:type,
position: position,
label: {
text: type +':'+ Math.floor(this.list[ind].value)+'°C',
heightReference: 1,
scale: 0.5,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
},
monitoItems: {
...this.list[ind].params
},
show: true // 确保为true
});
this.dotList.push(dot)
}
this.polygon = undefined;
const bound = this.getBound(this.hierarchy);
if (!bound) return;
let points = [];
let x_axios = Cesium.Cartesian3.subtract(
bound.rightTop,
bound.leftTop,
new Cesium.Cartesian3()
);
x_axios = Cesium.Cartesian3.normalize(x_axios, new Cesium.Cartesian3());
let y_axios = Cesium.Cartesian3.subtract(
bound.leftBottom,
bound.leftTop,
new Cesium.Cartesian3()
);
y_axios = Cesium.Cartesian3.normalize(y_axios, new Cesium.Cartesian3());
const girthX = Cesium.Cartesian3.distance(bound.rightTop, bound.leftTop);
const girthY = Cesium.Cartesian3.distance(bound.leftBottom, bound.leftTop);
for (let i = 0; i < this.hierarchy.length; i++) {
const p1 = this.hierarchy[i];
const p_origin = Cesium.Cartesian3.subtract(
p1,
bound.leftTop,
new Cesium.Cartesian3()
);
const diffX = Cesium.Cartesian3.dot(p_origin, x_axios);
const diffY = Cesium.Cartesian3.dot(p_origin, y_axios);
points.push({
x: Number((diffX / girthX) * this.canvasw).toFixed(0),
y: Number((diffY / girthY) * this.canvasw).toFixed(0),
value: this.list[i].value,
});
}
this.heatmapInstance.addData(points);
this.createPolygon([
bound.leftTop,
bound.leftBottom,
bound.rightBottom,
bound.rightTop,
]);
}
// 以面的形式添加
createPolygon(positions) {
this.polygon = this.viewer.entities.add({
polygon: {
hierarchy: new Cesium.PolygonHierarchy(positions),
material: this.heatmapInstance.getDataURL(),
heightReference: 1,
},
});
this.viewer.zoomTo(this.polygon);
}
// 以地图服务的形式添加
createProvider() {}
createDom() {
this.dom = window.document.createElement("div");
this.dom.id = `easy3d-heatmap-${this.id}`;
this.dom.className = `easy3d-heatmap`;
this.dom.style.width = this.canvasw + "px";
this.dom.style.height = this.canvasw + "px";
this.dom.style.position = "absolute";
this.dom.style.display = "none";
let mapDom = window.document.getElementById(this.viewer.container.id);
mapDom.appendChild(this.dom);
}
destory() {
let dom = document.getElementById(`easy3d-heatmap-${this.id}`);
if (dom) dom.remove();
if (this.polygon) {
this.viewer.entities.remove(this.polygon);
this.polygon = undefined;
}
if(this.dotList.length){
for(let i = 0 ; i<this.dotList.length;i++){
this.viewer.entities.remove(this.dotList[i]);
}
}
}
// 扩展边界 防止出现热力图被分割
getBound(positions) {
let rect = this.toRectangle(positions); // 转为正方形
let lnglats = cUtil.cartesiansToLnglats(rect);
let minLat = Number.MAX_VALUE,
maxLat = Number.MIN_VALUE,
minLng = Number.MAX_VALUE,
maxLng = Number.MIN_VALUE;
const length = rect.length;
for (let i = 0; i < length; i++) {
const lnglat = lnglats[i];
if (lnglat[0] < minLng) {
minLng = lnglat[0];
}
if (lnglat[0] > maxLng) {
maxLng = lnglat[0];
}
if (lnglat[1] < minLat) {
minLat = lnglat[1];
}
if (lnglat[1] > maxLat) {
maxLat = lnglat[1];
}
}
const diff_lat = maxLat - minLat;
const diff_lng = maxLng - minLng;
minLat = minLat - diff_lat / length;
maxLat = maxLat + diff_lat / length;
minLng = minLng - diff_lng / length;
maxLng = maxLng + diff_lng / length;
return {
leftTop: Cesium.Cartesian3.fromDegrees(minLng, maxLat),
leftBottom: Cesium.Cartesian3.fromDegrees(minLng, minLat),
rightTop: Cesium.Cartesian3.fromDegrees(maxLng, maxLat),
rightBottom: Cesium.Cartesian3.fromDegrees(maxLng, minLat),
};
}
// 任何图形均转化为正方形
toRectangle(hierarchy) {
if (!hierarchy) return;
let boundingSphere = Cesium.BoundingSphere.fromPoints(
hierarchy,
new Cesium.BoundingSphere()
);
let center = boundingSphere.center;
const radius = boundingSphere.radius;
let modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center.clone());
let modelMatrix_inverse = Cesium.Matrix4.inverse(
modelMatrix.clone(),
new Cesium.Matrix4()
);
let roate_y = new Cesium.Cartesian3(0, 1, 0);
let arr = [];
for (let i = 45; i <= 360; i += 90) {
let roateZ_mtx = Cesium.Matrix3.fromRotationZ(
Cesium.Math.toRadians(i),
new Cesium.Matrix3()
);
let yaix_roate = Cesium.Matrix3.multiplyByVector(
roateZ_mtx,
roate_y,
new Cesium.Cartesian3()
);
yaix_roate = Cesium.Cartesian3.normalize(
yaix_roate,
new Cesium.Cartesian3()
);
let third = Cesium.Cartesian3.multiplyByScalar(
yaix_roate,
radius,
new Cesium.Cartesian3()
);
let poi = Cesium.Matrix4.multiplyByPoint(
modelMatrix,
third.clone(),
new Cesium.Cartesian3()
);
arr.push(poi);
}
return arr;
}
}
const cUtil = {
cartesiansToLnglats: function (cartesians) {
const lnglats = [];
for (let i = 0; i < cartesians.length; i++) {
const cartesian = cartesians[i];
var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
var latitude = Cesium.Math.toDegrees(cartographic.latitude);
var longitude = Cesium.Math.toDegrees(cartographic.longitude);
lnglats.push([longitude, latitude]);
}
return lnglats;
},
};
四、使用
js
//数据示例
let list = oldlist?.map((item) => {
return {
id: item.id,
lnglat: [item.lon, item.lat],
value: item.value,
params: { ...item, type: type },
};
});
//实例化
let hotObj = new Heatmap(window.viewer, {
list: list,
...opt,
});
//销毁热力图
hotObj.destory();