编辑器:webstorm
服务:node.js npm
CesiumJS: Cesium-v1.9.1
vue: v 2.9.6
主要参考:
vue项目实现 cesium + heatmap.js 实现在三维地球上绘制热力图
功能
使用heatmap.js
生成随机热力图,然后将图贴到Cesium相应位置
实现
环境搭建与初始化
见同文件夹下vue+cesium环境搭建个人笔记|vue+cesium环境搭建
下载并引入heatmap.js
下载heatmap.js
heatmap.js
github下载地址:github.com
但是没有梯子的时候连接慢得令人叹气🤕
heatmap.js
无梯子用下载地址:heatmap.js · GitCode
好像是个CSDN搞的加速镜像? 好用就完事了
根据官方的README文档,如果装了node.js的话也可以在webstorm内置的Terminal或者CMD里这么下载
npm install heatmap.js
不过目前找到的参考文章都说要下载.zip格式的安装包,解压以后再把build文件夹里的heatmap.js
复制进自己项目的文件夹里
我自己试了一下npm 就 很流畅啊 11秒完事啊 直接就进node_modules里了啊 再把.js文件复制粘贴出来就很简单了啊 费那老大劲下载解压干嘛呢😅
引入heatmap.js
主要参考的博客文章里是在index.html里引入<script src="./static/heatMap/heatmap.js"></script>
,但照做之后终端还是会报错'h337' is not defined
于是改为在vue里引入,程序正常运行
<script>
import * as Cesium from 'cesium/Cesium'
import * as widgets from 'cesium/Widgets/widgets.css'
import h337 from 'heatmap.js'
...
</script>
HTML & CSS相关设置
HTML方面,要给出一个div
用来贴图
<template>
<div id="app">
<div id="cesiumContainer"></div>
<!-- 使用heatmap.js生成热力图,然后将图贴到Cesium相应位置-->
<div id="heatMap" v-show="false"></div>
</div>
</template>
这里的v-show="false"
不是很懂是什么意思捏
但是可以跑出来 很怪
CSS简单写一下
<style>
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
#app,#cesiumContainer {
font-family: "Avenir", Helvetica, Arial, sans-serif;
width: 100%;
height: 100%;
overflow: hidden;
}
#heatMap {
width: 500px;
height: 500px;
}
</style>
这里直接用了参考文章的数据,设置贴图面积是500px * 500px
,但是参考文章里的代码设置热力图的大小其实是600 * 400
,所以跑出来以后可以看到热力图左右和上边很明显的矩形形状,下面则是不规则的。个人理解是在拿CSS这个画框去套heatmap给出来的画,画大框小,画就被框限制;画小框大,框和画之间就还有留白
在完整代码里把CSS里的长宽改成了700 * 700
,能看到生成的热力图里右边和下边是不规则的,左边和上面还能看出矩形边框
说明h337对象的x和y是以左上角为起始点(0,0)
的?
基于vue框架用heatmap.js实现热力图
这里好像要在设置cesium地球之前先设置好热力图 挠头
主要代码
设置热力图部分
/* 初始化热力图设置 */
// 设置随机数据点数量
let len = 300
// 构建随机数据点
let points = []
// 设置最大值
let max = 100
// 设置热力图宽度和高度
let width = 600
let height = 400
// 设置纬度最低点和最高点
let latMin = 28.364807
let latMax = 40.251095
// 设置经度最低点和最高点
let lonMin = 94.389228
let lonMax = 108.666357
// 准备一个装原始数据的数组
let dataRaw = []
// 设置每个点包含的元素(属性)
for (let i = 0; i < len; i++) {
let point = {
// 在设定的经纬度区间选取随机数作为每个点的经纬度
lat: latMin + Math.random() * (latMax - latMin),
lon: lonMin + Math.random() * (lonMax - lonMin),
// 在0到最大值之间向下取整选取随机数作为每个点的值
value: Math.floor(Math.random() * 100)
}
// 将设置好的点加入数组
dataRaw.push(point)
}
// 将每个点的元素(属性?)转换为创建h337对象即热力图实例所需的数据格式
for (let i = 0; i < len; i++) {
// 传进原始数据
let dataItem = dataRaw[i]
let point = {
// 将数据点经纬度等比例设置成矩形中的x y坐标 值为原始数据的值
x: Math.floor((dataItem.lat - latMin) / (latMax - latMin) * width),
y: Math.floor((dataItem.lon - lonMin) / (lonMax - lonMin) * height),
value: Math.floor(dataItem.value)
}
// 比较设置的最大值和原始数据值大小 取两者间的最大值
max = Math.max(max, dataItem.value)
// 将转换好后的数据存入数组
points.push(point)
}
// 创建热力图实例
let heatMapInstance = h337.create({
container: document.querySelector('#heatMap')
})
// 设置传入实例的数据
let data = {
max: max,
data: points
}
// 新建热力图实例并传入设置好的数据
heatMapInstance.setData(data)
初始化地球部分
详见同文件夹下vue+cesium构建航班轨迹个人笔记|vue+Cesium构建航班轨迹
这里要把personal_token
换成自己的token
/* 初始化地球 */
// 引入个人token
Cesium.Ion.defaultAccessToken = 'personal_token'
// 设置取景器
viewer = new Cesium.Viewer('cesiumContainer', {
terrainProvider: Cesium.createWorldTerrain(),
/* selectionIndicator: false, // 不显示指示器小部件
infoBox: false, // 不显示信息框
sceneModePicker: false, // 不显示模式切换选项
baseLayerPicker: false,
navigationHelpButton: false,
animation: false,
shouldAnimate: false,
timeline: false,
geocoder: false,
homeButton: false, */
// 添加ArcGIS在线影像底图
imageryProvider: new Cesium.UrlTemplateImageryProvider({
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
subdomains: ['0', '1', '2', '3'],
tilingScheme: new Cesium.WebMercatorTilingScheme()
})
})
// 若浏览器不支持pickPosition,显示报错信息
if (!viewer.scene.pickPositionSupported) {
window.alert('This browser does not support pickPosition.')
}
// 载入OSM建筑物
// let buildingsTileset = viewer.scene.primitives.add(Cesium.createOsmBuildings()) // eslint-disable-line no-unused-vars
把底图来源改成了ArcGIS在线影像底图,也可以用高德或者腾讯的,主要是因为网速不好,如果用Cesium Ion在线资源的话会加载很慢
您网速快的话,您随意
铺设热力图部分
/* 把热力图铺到地球上 */
// 设置画布为生成的热力图
let canvas = document.getElementsByClassName('heatmap-canvas')
// 控制台输出画布数据
console.log(canvas)
// 添加热力图实例
viewer.entities.add({
name: 'heatmap',
// 设置矩形
rectangle: {
// 指定矩形区域
coordinates: Cesium.Rectangle.fromDegrees(lonMin, latMin, lonMax, latMax),
// 设置矩形图片为据透明度的热力图
material: new Cesium.ImageMaterialProperty({
image: canvas[0],
transparent: true
})
}
})
// 取景器镜头聚焦到热力图实例上
viewer.zoomTo(viewer.entities)
完整代码
事前处理
npm install heatmap.js
vue部分代码
<template>
<div id="app">
<div id="cesiumContainer"></div>
<!-- 使用heatmap.js生成热力图,然后将图贴到Cesium相应位置-->
<div id="heatMap" v-show="false"></div>
</div>
</template>
<script>
import * as Cesium from 'cesium/Cesium'
import * as widgets from 'cesium/Widgets/widgets.css'
// 从heatmap.js引入h337
// h337是heatmap.js全局对象的名称 用于创建热力图实例
import h337 from 'heatmap.js'
export default {
name: 'App',
data () {
return {
viewer: undefined
}
},
mounted () {
this.Init()
},
methods: {
Init () {
let viewer = this.viewer
/* 初始化热力图设置 */
// 设置随机数据点数量
let len = 300
// 构建随机数据点
let points = []
// 设置最大值
let max = 100
// 设置热力图宽度和高度
let width = 600
let height = 400
// 设置纬度最低点和最高点
let latMin = 28.364807
let latMax = 40.251095
// 设置经度最低点和最高点
let lonMin = 94.389228
let lonMax = 108.666357
// 准备一个装原始数据的数组
let dataRaw = []
// 设置每个点包含的元素(属性)
for (let i = 0; i < len; i++) {
let point = {
// 在设定的经纬度区间选取随机数作为每个点的经纬度
lat: latMin + Math.random() * (latMax - latMin),
lon: lonMin + Math.random() * (lonMax - lonMin),
// 在0到最大值之间向下取整选取随机数作为每个点的值
value: Math.floor(Math.random() * 100)
}
// 将设置好的点加入数组
dataRaw.push(point)
}
// 将每个点的元素(属性?)转换为创建h337对象即热力图实例所需的数据格式
for (let i = 0; i < len; i++) {
// 传进原始数据
let dataItem = dataRaw[i]
let point = {
// 将数据点经纬度等比例设置成矩形中的x y坐标 值为原始数据的值
x: Math.floor((dataItem.lat - latMin) / (latMax - latMin) * width),
y: Math.floor((dataItem.lon - lonMin) / (lonMax - lonMin) * height),
value: Math.floor(dataItem.value)
}
// 比较设置的最大值和原始数据值大小 取两者间的最大值
max = Math.max(max, dataItem.value)
// 将转换好后的数据存入数组
points.push(point)
}
// 创建热力图实例
let heatMapInstance = h337.create({
container: document.querySelector('#heatMap')
})
// 设置传入实例的数据
let data = {
max: max,
data: points
}
// 新建热力图实例并传入设置好的数据
heatMapInstance.setData(data)
/* 初始化地球 */
// 引入个人token
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJkYmJkNWQ3Mi0zOGVkLTQ5N2YtYTBmMy0wMDAyODZiMDMyZWYiLCJpZCI6ODQ2NzQsImlhdCI6MTY0NjQ0NTYxNX0.XkHX3rdysM4uUe5VTKDVEV3W2An33zyh4qAkFUac2fk'
// 设置取景器
viewer = new Cesium.Viewer('cesiumContainer', {
terrainProvider: Cesium.createWorldTerrain(),
/* selectionIndicator: false, // 不显示指示器小部件
infoBox: false, // 不显示信息框
sceneModePicker: false, // 不显示模式切换选项
baseLayerPicker: false,
navigationHelpButton: false,
animation: false,
shouldAnimate: false,
timeline: false,
geocoder: false,
homeButton: false, */
// 添加ArcGIS在线影像底图
imageryProvider: new Cesium.UrlTemplateImageryProvider({
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
subdomains: ['0', '1', '2', '3'],
tilingScheme: new Cesium.WebMercatorTilingScheme()
})
})
// 若浏览器不支持pickPosition,显示报错信息
if (!viewer.scene.pickPositionSupported) {
window.alert('This browser does not support pickPosition.')
}
// 载入OSM建筑物
// let buildingsTileset = viewer.scene.primitives.add(Cesium.createOsmBuildings()) // eslint-disable-line no-unused-vars
/* 把热力图铺到地球上 */
// 设置画布为生成的热力图
let canvas = document.getElementsByClassName('heatmap-canvas')
// 控制台输出画布数据
console.log(canvas)
// 添加热力图实例
viewer.entities.add({
name: 'heatmap',
// 设置矩形
rectangle: {
// 指定矩形区域
coordinates: Cesium.Rectangle.fromDegrees(lonMin, latMin, lonMax, latMax),
// 设置矩形图片为据透明度的热力图
material: new Cesium.ImageMaterialProperty({
image: canvas[0],
transparent: true
})
}
})
// 取景器镜头聚焦到热力图实例上
viewer.zoomTo(viewer.entities)
}
}
}
</script>
<style>
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
#app,#cesiumContainer {
font-family: "Avenir", Helvetica, Arial, sans-serif;
width: 100%;
height: 100%;
overflow: hidden;
}
#heatMap {
width: 700px;
height: 700px;
}
</style>