个人笔记|vue+cesium用heatmap.js插件展示热力图

编辑器:webstorm

服务:node.js npm

CesiumJS: Cesium-v1.9.1

vue: v 2.9.6

主要参考:

vue项目实现 cesium + heatmap.js 实现在三维地球上绘制热力图

Vue2+Cesium1.9+热力图开发笔记

功能

使用heatmap.js生成随机热力图,然后将图贴到Cesium相应位置

铺设热力图效果

实现

环境搭建与初始化

见同文件夹下vue+cesium环境搭建个人笔记|vue+cesium环境搭建

下载并引入heatmap.js

下载heatmap.js

heatmap.jsgithub下载地址: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>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容