在 Cesium 中加载 Heatmap.js 及使用html2canvas转换图片并贴图到地图对象viewer
在本示例中,我们通过 Vue3 和 Cesium 集成了 Heatmap.js 来渲染热力图。通过合理的数据转换、图像生成和地图覆盖技术,成功将热力图叠加到 Cesium 地图上,提供了一个直观的数据可视化方式。通过 html2canvas 的辅助,我们还能够将热力图转换为图像并直接用于 Cesium 的 ImageMaterialProperty 中,从而实现图像叠加。<template>--
·
1. 项目背景与需求
我们希望在一个 Cesium 地图中叠加 Heatmap.js 热力图,热力图的数据来源于一个 JSON 文件。实现过程中,我们利用 Vue3 框架来管理组件,html2canvas 来处理生成的热力图图像,最后通过 Cesium 的 ImageMaterialProperty 将热力图覆盖到地图上。
2. 项目结构与思路
需求完成思路:
- **Cesium 初始化和地图设置:**在 Vue 组件的 mounted 钩子函数中初始化 Cesium,配置底图、标注层等内容。
- **热力图数据处理与转换:**通过 axios 获取热力图数据,并进行必要的数据转换,将经纬度映射到屏幕坐标上。
- **生成热力图并叠加到Cesium 地图:**利用 Heatmap.js 创建热力图,并通过 html2canvas 将其转化为图像,然后使用 Cesium 的 ImageMaterialProperty 将热力图覆盖到地图区域。
3. 代码实现
3.1 HTML 模板结构
<template>
<div id="cesiumContainer" style="width: 100vw; height: 100vh;"></div>
<div id="heatMap" v-show="true"></div>
</template>
- **cesiumContainer:**容器用于显示 Cesium 地图。
- **heatMap:**容器用于显示热力图,将通过 Heatmap.js
渲染。
3.2 Cesium 初始化与地图设置
export default {
name: 'CesiumMap',
async mounted() {
var token = 'your-api-key-here'; // 你的天地图 Token
var tdtUrl = 'https://t{s}.tianditu.gov.cn/'; // 天地图服务 URL
var subdomains = ['0', '1', '2', '3', '4', '5', '6', '7']; // 子域配置
let maximumLevel = 18; // 最大缩放级别
// 初始化 Cesium Viewer
viewer = new Cesium.Viewer('cesiumContainer');
// 叠加天地图的国界服务
var iboMap = new Cesium.UrlTemplateImageryProvider({
url: tdtUrl + 'DataServer?T=ibo_w&x={x}&y={y}&l={z}&tk=' + token,
subdomains,
tilingScheme: new Cesium.WebMercatorTilingScheme(),
maximumLevel,
});
viewer.imageryLayers.addImageryProvider(iboMap);
// 叠加天地图的注记服务
var labelMap = new Cesium.UrlTemplateImageryProvider({
url: tdtUrl + 'DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=' + token,
subdomains,
tilingScheme: new Cesium.WebMercatorTilingScheme(),
maximumLevel,
});
viewer.imageryLayers.addImageryProvider(labelMap);
// 加载热力图
this.loadHeatMap();
}
}
3.3 加载热力图
async loadHeatMap() {
let { data } = await axios("/echarts/examples/data/asset/data/hangzhou-tracks.json"); // 获取热力图数据
//数据格式
// [
// [{
// "coord": [
// 120.14322240845,
// 30.236064370321
// ],
// "elevation": 21
// }, ]
// ]
let heatmapData = data.flat(); // 扁平化数据
let points = [];
let max = 0;
let width = 400, height = 400;
let latMin = 90, latMax = 0;
let lonMin = 180, lonMax = 0;
// 获取最小最大经纬度和最大值
latMin = Math.min(latMin, ...heatmapData.map(point => point.coord[1]));
latMax = Math.max(latMax, ...heatmapData.map(point => point.coord[1]));
lonMin = Math.min(lonMin, ...heatmapData.map(point => point.coord[0]));
lonMax = Math.max(lonMax, ...heatmapData.map(point => point.coord[0]));
max = Math.max(max, ...heatmapData.map(point => point.elevation));
// 数据转换为屏幕坐标
heatmapData.forEach(point => {
points.push({
x: Math.floor((point.coord[1] - latMin) / (latMax - latMin) * width),
y: Math.floor((point.coord[0] - lonMin) / (lonMax - lonMin) * height),
value: Math.floor(point.elevation),
});
});
// 创建热力图实例
let heatMapDom = document.querySelector("#heatMap");
let heatMapInstance = h337.create({
container: heatMapDom,
radius: 3,
blur: 1,
});
// 设置热力图数据
heatMapInstance.setData({
max: max,
data: points,
});
// 使用 html2canvas 生成热力图图像并叠加到 Cesium 地图
let canvasDom = document.querySelector('#heatMap');
html2canvas(canvasDom, {
backgroundColor: null // 确保背景透明
}).then(canvas => {
const imageUrl = canvas.toDataURL('image/png'); // 转为图像 URL
viewer.entities.add({
name: 'heatmap',
rectangle: {
coordinates: Cesium.Rectangle.fromDegrees(lonMin, latMin, lonMax, latMax),
material: new Cesium.ImageMaterialProperty({
image: imageUrl,
transparent: true,
}),
}
});
viewer.zoomTo(viewer.entities);
});
}
- **获取热力图数据:**通过 axios 请求获取热力图数据,数据结构包含经纬度和数值(elevation)。
- **数据处理:**将经纬度映射为屏幕坐标(宽度 400px,高度 400px),并计算最大值来确定热力图强度。
- **热力图实例化:**使用 h337.create() 方法创建热力图实例,并将数据传入。
- **渲染到 Cesium:**通过 html2canvas 将热力图生成图像,并使用 Cesium.ImageMaterialProperty 将其叠加到 Cesium 地图上。
4. 样式与布局
#cesiumContainer {
width: 100vw;
height: 100vh;
}
#heatMap {
width: 400px;
height: 400px;
z-index: 10000;
}
5. 重要一点
h337对象 要这么引入,路径要写全,指定到你修改的那个文件
import * as h337 from "heatmapjs/heatmap.min.js";
6. 总结
在本示例中,我们通过 Vue3 和 Cesium 集成了 Heatmap.js 来渲染热力图。通过合理的数据转换、图像生成和地图覆盖技术,成功将热力图叠加到 Cesium 地图上,提供了一个直观的数据可视化方式。通过 html2canvas 的辅助,我们还能够将热力图转换为图像并直接用于 Cesium 的 ImageMaterialProperty 中,从而实现图像叠加。
最后附上源码
<template>
<!-- Cesium 容器,占满整个屏幕 -->
<div id="cesiumContainer" style="width: 100vw; height: 100vh;"></div>
<!-- 热力图容器,初始可见 -->
<div id="heatMap" v-show="true"></div>
</template>
<script>
// 导入需要的库和工具
import axios from "axios"; // 用于发送 HTTP 请求
import * as h337 from "heatmapjs/heatmap.min.js"; // 导入 Heatmap.js
import html2canvas from 'html2canvas'; // 用于将 HTML 转换为 Canvas
// 定义一个全局变量来存储热力图 DOM 元素
var heatMapDom
// 定义一个全局变量来保存 Cesium Viewer 实例
window.viewer = null
export default {
name: 'CesiumMap', // 组件名称
async mounted() {
// 初始化变量和配置项
var token = 'your-api-key-here'; // 这里需要替换为天地图的 Token
var tdtUrl = 'https://t{s}.tianditu.gov.cn/'; // 天地图服务的基础 URL
var subdomains = ['0', '1', '2', '3', '4', '5', '6', '7']; // 天地图子域
let maximumLevel = 18; // 最大缩放级别
// 初始化 Cesium Viewer(地图显示容器)
viewer = new Cesium.Viewer('cesiumContainer');
// 设置天地图的国界服务图层
var iboMap = new Cesium.UrlTemplateImageryProvider({
url: tdtUrl + 'DataServer?T=ibo_w&x={x}&y={y}&l={z}&tk=' + token, // 配置图层 URL,包含 Token
subdomains, // 设置子域配置
tilingScheme: new Cesium.WebMercatorTilingScheme(), // 使用 WebMercator 瓦片坐标系统
maximumLevel, // 最大缩放级别
});
viewer.imageryLayers.addImageryProvider(iboMap); // 将图层添加到 Cesium 中
// 设置天地图的标注服务图层
var labelMap = new Cesium.UrlTemplateImageryProvider({
url: tdtUrl + 'DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=' + token, // 配置标注图层 URL,包含 Token
subdomains, // 设置子域配置
tilingScheme: new Cesium.WebMercatorTilingScheme(), // 使用 WebMercator 瓦片坐标系统
maximumLevel, // 最大缩放级别
});
viewer.imageryLayers.addImageryProvider(labelMap); // 将标注图层添加到 Cesium 中
// 调用加载热力图的方法
this.loadHeatMap();
},
methods: {
// 加载热力图的逻辑
async loadHeatMap() {
// 使用 axios 请求热力图数据(这里的路径需要根据实际情况修改)
let { data } = await axios("/echarts/examples/data/asset/data/hangzhou-tracks.json");
// 将数据进行扁平化处理
let heatmapData = data.flat();
let points = []; // 用于存储热力图的数据点
let max = 0; // 最大值,用于热力图强度
// 设置热力图的宽度和高度
let width = 400;
let height = 400;
// 设置经纬度的最小值和最大值
let latMin = 90;
let latMax = 0;
let lonMin = 180;
let lonMax = 0;
// 遍历热力图数据,计算经纬度范围,并找到最大值
latMin = Math.min(latMin, ...heatmapData.map(point => point.coord[1]));
latMax = Math.max(latMax, ...heatmapData.map(point => point.coord[1]));
lonMin = Math.min(lonMin, ...heatmapData.map(point => point.coord[0]));
lonMax = Math.max(lonMax, ...heatmapData.map(point => point.coord[0]));
max = Math.max(max, ...heatmapData.map(point => point.elevation));
// 将经纬度转换为屏幕坐标
heatmapData.forEach(point => {
points.push({
x: Math.floor((point.coord[1] - latMin) / (latMax - latMin) * width), // 转换纬度
y: Math.floor((point.coord[0] - lonMin) / (lonMax - lonMin) * height), // 转换经度
value: Math.floor(point.elevation) // 计算强度值
});
});
// 获取热力图的 DOM 元素
heatMapDom = document.querySelector("#heatMap");
// 创建 Heatmap.js 实例
let heatMapInstance = h337.create({
container: heatMapDom, // 设置容器为热力图的 DOM 元素
radius: 3, // 热力图的半径
blur: 1, // 模糊程度
});
// 设置热力图的数据
heatMapInstance.setData({
max: max, // 最大强度值
data: points, // 热力图数据点
});
// 使用 html2canvas 将热力图生成 Canvas 图像
let canvasDom = document.querySelector('#heatMap');
html2canvas(canvasDom, {
backgroundColor: null // 确保背景透明
}).then(canvas => {
// 将 Canvas 转换为图像 URL
const imageUrl = canvas.toDataURL('image/png');
console.log(lonMin, latMin, lonMax, latMax); // 打印经纬度范围
// 将热力图图像添加到 Cesium 地图中
viewer.entities.add({
name: 'heatmap',
rectangle: {
coordinates: Cesium.Rectangle.fromDegrees(lonMin, latMin, lonMax, latMax), // 设置热力图的地理范围
material: new Cesium.ImageMaterialProperty({
image: imageUrl, // 使用热力图的图像
transparent: true // 设置透明
}),
}
});
// 视图自动缩放以适应热力图的区域
viewer.zoomTo(viewer.entities);
});
},
}
};
</script>
<style>
/* Cesium 容器样式,确保地图覆盖整个屏幕 */
#cesiumContainer {
width: 100vw;
height: 100vh;
}
/* 热力图容器样式,设置固定大小 */
#heatMap {
width: 400px;
height: 400px;
z-index: 10000; /* 确保热力图在 Cesium 上方显示 */
}
</style>
更多推荐
所有评论(0)