# vue2 使用 cesium 篇

vue2 使用 cesium 篇

今天好好写一篇哈,之前写的半死不活的。首先说明:这篇博文是我边做边写的,小白也是,实现效果会同时发布截图,如果没有实现也会说明,仅仅作为技术积累,选择性分享,不做教学哈。不好别喷。

安装 cesium

这个就很简单,只需要一句简简单单的命令就可以实现在 vue 项目中安装 cesium 了。

npm install cesium --save

然后等待安装完成就可以了兄弟们!!

image.png

这个样子嘞,就是安装完成了,会开发 vue 的都晓得哈。

image.png

看一下依赖包里面,也成功下载了 cesium 的依赖,非常棒!!

接入项目 cesium

接下来就是使用,这个步骤很不好整,cesium 的官方文档写的很不友好,许多新手小白很难入门,甚至是理解都难,查文档都不会,就比如我。但是!这里的步骤我都是自己测试过可以的哈!首先呢,我是自己创建的 vue2 项目,使用的脚手架是 cli3 以上的。

首先第一步,从 node_modules 依赖包里面,找到我们刚刚安装的 cesium ,在文件夹里面有一个 Build 文件夹,里面有一个 Cesium 文件夹,把这个 Cesium 文件夹复制一份。

然后呢,在项目的 public 文件夹下,粘贴出来。

image.png

好的第一步完成!

然后第二步,在项目 index.html 文件中,head 标签里面,引入 cesium 的全局样式。


还是在这个文件中,在 body 最后,引入 cesium 源码。


就是下面这个样子哈。

image.png

好的,完成之后我们重新启动一下项目,记得哈,重启一下项目!其实不重启也可以,啊哈哈哈哈。

使用 cesium

接下来的工作就很简单了嘛,我们写一个页面哈,用来显示蓝星。这个页面就随便写了哈,没有啥技术含量,咱就不啰嗦了。







写一个黑色的页面,so 简单哈!

image.png

非常好,效果出来了,到现在还没有用到一点儿的 cesium 别急,下面开始哈。

我们写一个 init() 方法,然后在 init() 方法里面呢,实现把这个 div 渲染成一个蓝星。

   init() {
      this.viewer = new Cesium.Viewer('my-map', {
        homeButton: false,
        sceneModePicker: false,
        baseLayerPicker: false, // 影像切换
        animation: true, // 是否显示动画控件
        infoBox: false, // 是否显示点击要素之后显示的信息
        selectionIndicator: false, // 要素选中框
        geocoder: false, // 是否显示地名查找控件
        timeline: true, // 是否显示时间线控件
        fullscreenButton: false,
        shouldAnimate: false,
        navigationHelpButton: false, // 是否显示帮助信息控件
      });
    }

完成!蓝星加载出来了!

image.png

这样初始化蓝星就差不多了是吧!好的下面说一些其他的事情。

cesium 相关资料

首先分享一些资料给各位,希望有用:

Cesium 官网:https://cesium.com/
Cesium 官网 API:https://cesium.com/learn/cesiumjs/ref-doc/
Cesium 中文API: http://cesium.xin/cesium/cn/Documentation1.62/
Cesium 官方案例:https://sandcastle.cesium.com/?
Cesium 技能树:https://www.wenjiangs.com/doc/egyaeyav
Cesium 中文社区:http://cesium.xin/
3D 模型下载网站:https://sketchfab.com/feed

上边这部分网站呢,也许对你有用,需要的话可以看一下。

优化上面代码

为了保证代码稍微稍微的整洁一点点,我们把 cesium 有关的代码抽成一个 js 文件哈,统一的放在一起,这样的话呢,方便管理一下,嘿嘿!

首先在组件同级创建一个 js 文件夹,里面放一个 TCesium.js 文件,里面的代码就是下面的样子:

export class TCesium {

  viewer = null;
  scene = null;

  /**
   * 构造器函数:实例化cesium
   * @param {*} dom 节点id
   */
  constructor(dom) {
    this.viewer = new Cesium.Viewer(dom, {
      homeButton: false,
      sceneModePicker: false,
      baseLayerPicker: false, // 影像切换
      animation: true, // 是否显示动画控件
      infoBox: false, // 是否显示点击要素之后显示的信息
      selectionIndicator: false, // 要素选中框
      geocoder: false, // 是否显示地名查找控件
      timeline: true, // 是否显示时间线控件
      fullscreenButton: false,
      shouldAnimate: false,
      navigationHelpButton: false, // 是否显示帮助信息控件
    });
    this.scene = this.viewer.scene
  }
}

然后在组件中呢,引入一下这个文件。

import { TCesium } from './js/TCesium'

然后嘞,init() 方法就可以直接实例化了。

    init() {
      this.mapObject = new TCesium('my-map')  // 注意,这个my-map就是我们div的id
    }

然后呢,效果是一样的。

image.png

很棒!

cesium token 申请和设置

接下来我们说一下 cesium 的 token。使用cesium需要申请一个token值,这个地方就和百度地图或者是高德地图一样,需要一个 token 秘钥来进行操作,确保在使用 cesium 的过程中不会出现 token 过期造成地图加载不出来的问题。当然了,现在看我们是一点问题没有,蓝星地球可以正常加载,但是随着我们测试编写的时间增长,调用 cesium 图层次数过多,就会出现图层加载不出来,就是超次数,这个是时候,我们地球可能就白了,因为没有实时图层返回了,这个时候就需要 token,所以说我们现在就设置上 token,防止这种事情的发生。

首先我们需要去 cesium 官网去申请一个 token,方法很简单:

cesium申请token请点击 这里

image.png

然后嘞,输入用户名、密码登录一下子。没有用户名密码的可以创建一个新的账号来完成操作哟~!

然后就可以创建一个新的 token 来玩。

image.png

然后我们就成功的获取到了一个 cesium 的秘钥,太棒了亲们!

然后我们在 TCesium.js 文件中的构造器函数中,加载这个 token 就可以了。

Cesium.Ion.defaultAccessToken = '你申请的cesium的token'

就像下面这个样子:

好的,这样子的话, token 就申请使用完成了。

cesium 基础配置

相关API

我们在上面的代码配置了一些基本的设置项,稍微过一下子哈。

    this.viewer = new Cesium.Viewer(dom, {
      homeButton: false,
      sceneModePicker: false,
      baseLayerPicker: false, // 影像切换
      animation: false, // 是否显示动画控件
      infoBox: false, // 是否显示点击要素之后显示的信息
      selectionIndicator: false, // 要素选中框
      geocoder: false, // 是否显示地名查找控件
      timeline: false, // 是否显示时间线控件
      fullscreenButton: false,
      shouldAnimate: false,
      navigationHelpButton: false, // 是否显示帮助信息控件
    });

就是上面这一块,我写了几个常用的,先全部设置为 false,就是不使用,我们稍微说几个常用的看一下哈。

homeButton

我们先看 homeButton 参数,我们如果设置为 true。这个是主页按钮,啥意思呢,就是我们加载出蓝星之后,我们可以鼠标转动嘛、放大缩小啥的。如果我们设置 homeButton 为 true 之后,在页面的右上角就会出现一个主页按钮,当我们改变过蓝星之后,点击这个按钮,会回到我们最开始的视角。

image.png

sceneModePicker

sceneModePicker 是地图显示的维度控制,他提供 二维平面 和 三维球体 两种方式。当设置为 true 的时候,右上角会提供一个维度切换的按钮,帮助我们进行蓝星维度的展示切换功能。

image.png

baseLayerPicker

Cesium 为我们提供了一些底图,这个 baseLayerPicker 设置为 true 的时候,右上角会有一个图层切换的按钮,但是我觉得没用,不是没用,不好用,一般都是自己写,不用他默认提供的。

image.png

animation 和 timeline

这两个是时间轴相关的,一般用不到,但是不保险,需要的时候没有还真不行,这两个要同时设置,true 的时候都 true,false 的时候都是 false。当然也不绝对哈,就是 timeline 的时候呢,就开始时间轴功能,animation 就是显示时间轴的控件,可以直观的控制时间轴的进度、速度之类的。

image.png

selectionIndicator

selectionIndicator 是要素选中框,啥意思呢,就比如说我的蓝星上有模型,那么我点击蓝星上模型的时候呢,就会出现一个框框把模型给框住,我觉得没必要。

fullscreenButton

这个是全屏按钮,设置为 true 的时候呢,右下角就会出现一个全屏按钮,点击之后,cesium 就会进行全屏显示。

image.png

infoBox

这个是要素信息框,一般都是 false,啥呢,就是蓝星上面有一个模型,点击模型的时候会显示这个模型的信息之类的,一般不用他自带的,一般是自己写或者是自己改,一般设置 false 就可以。

geocoder

这个是地名查找组件,开启后,右上角会出现一个查询地址的组件,但是不好用,一般情况下,不显示就行。

image.png

navigationHelpButton

这是一个帮助按钮,如果设置为 true 的时候,右上角会有一个帮助的提示,这个关闭就可以。

image.png

好了,这就是常见的几个设置,当然如果需要的话,可以根据官方文档进行相应的设置,这个玩意儿很多设置,这只是其中几个。

多余样式隐藏

我们使用 cesium 的时候发现哈,左下角会有一些版权信息,我们想隐藏的话也很简单。

只需要在 viewer 创建完成之后,把他的版权 DOM 设置为 none 就可以了。

this.viewer._cesiumWidget._creditContainer.style.display = 'none'

这样界面就干净多了,除了蓝星啥都没有了。

image.png

地形数据

我们看到,我们加载的蓝星是三维的,所以说嘞,和百度地图、高德地图不一样,他能体现出一个地区的地形数据,比如说我们找一下四川山区那边看一下子。

image.png

很明显,看到了山地,我们在稍微放大一点儿。

image.png

尽管图层显示有山地,但是还想只是图像有山,但是实际上还是平面的!没关系哈!我们可以向 cesium 中添加一下地形数据,这样,他就是立体的了!

首先说明一下,我们添加的地形数据是公开的,不是私密的,也就是说,他可能不是很详细很具体,但是是有的,比如有的单位需要做山东的 gis,那么人家会提供山东地形数据,这种数据肯定都是涉密的,这个数据相当具体,数据相当庞大,哪里高哪里底都很详细。但是我们没有,所以说呢,我们使用的,只能展示大概的地形。

怎么使用很简单。我们在构造器函数中创建一个地形对象:

   let terrain = new Cesium.createWorldTerrain({
      requestWaterMask: true,
      requestVertexNormals: true
    })

创建完成,然后在 viewer 中把这个地形数据添加进去就可以了。

this.viewer.terrainProvider = terrain // 加入世界地形图

好的,这个时候我们再来看一下山区能不能显示出高度来。

image.png

诶!地形添加出来了! 厉害!

有两个地方需要说一下。

    this.viewer.scene.globe.depthTestAgainstTerrain = true // 地形遮挡
    this.viewer.scene.postProcessStages.fxaa.enabled = true // 开启抗锯齿

首先第一个是地形遮挡,这是啥意思呢,就是说如果我们在蓝星添加一个模型,如果这个模型被山体给挡住的话,那么这个模型就看不到了,不会透视的看到模型。在比如说,如果模型在地下,不在地表或者是地上,这个模型如果符合实际的话,应该不能被看到的,但是加载上发现我们能够看到地底的模型,如果不想看到的话,开启一下地形遮挡,这样的话模型会被地形给挡起来,符合实际。

第二个是抗锯齿,啥是抗锯齿呢,做过 threejs 的应该接触过,我解释不好,意思就是渲染的更精致,当然性能消耗的也会大一些。

这两个设置根据自己的实际情况选择是否开启哈,好了,不多说了。

添加第三方底图

我们到现在使用的底图都是 cesium 默认提供的,如果我们需要用自己的底图也很简单,无论是 geoserve 自己发布的还是 高德底图 、百度底图、天地图底图都是可以的,但是有一点需要说一下哈,就是这个高德、百度、google 底图都是有偏移的,直接放进来可能会有偏差,所以说建议使用天地图的。

我们先创建一个底图对象,使用天地图需要申请 tk 值,这个自己去申请,如果不会的话,看我关于天地图的博文,里面有介绍和步骤。

  // 矢量图
  TDT_SL = new Cesium.WebMapTileServiceImageryProvider({
    url: 'http://{s}.tianditu.gov.cn/vec_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=vec&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=这是你申请的天地图的tk值',
    layer: 'vec',
    style: 'default',
    format: 'tiles',
    tileMatrixSetID: 'w',
    subdomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
    maximumLevel: 18
  })

然后创建完成添加到 cesium 就可以了。

    // 添加天地图矢量图 (底图对象,层级) 返回图层
    this.TDL_YX_LAY = this.viewer.imageryLayers.addImageryProvider(this.TDL_SL, 1)

这样就添加进来了。

image.png

放大看一下哈,当然,天地图是中国的,所以说只有中国的详细信息。

image.png

都是可以的哈。移除的话也很简单的啦。

this.viewer.imageryLayers.remove(this.TDL_YX_LAY) // 移除某个图层(注意传的参数)

或者

this.viewer.imageryLayers.removeAll(true)  // 移除所有图层并销毁

相关文档

好了,这就是关于添加第三方图层相关操作了。

销毁 cesium

创建说完了,现在说一下销毁,销毁的话就很简单了,就是一句话:

this.viewer.destroy()

执行上面这句话就直接销毁了,这个一般是组件注销了,不展示 cesium 的时候使用,防止一直占用资源啥的,具体情况具体分析哈!

地图放大缩小

其实 cesium 的放大缩小和百度地图他们不一样。cesium 的放大缩小其实就是相机高度,相机高度变小就是放大,相机高度变大就是缩小。理解吧?相机高了,视角大了,蓝星上面东西就小了。

首先是放大:

  /**
   * 地图放大
   */
  zoomIn() {
    // viewer 为 Viewer 对象
    let position = this.viewer.camera.position;
    let cameraHeight = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(position).height;
    // 每次缩小 20 倍,参数可改
    let moveRate = cameraHeight / 20.0;
    this.viewer.camera.moveForward(moveRate);
  }

然后是缩小:

  /**
   * 地图缩小
   */
  zoomOut() {
    // viewer 为 Viewer 对象
    let position = this.viewer.camera.position;
    let cameraHeight = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(position).height;
    // 每次缩小 20 倍,参数可改
    let moveRate = cameraHeight / 20.0;
    this.viewer.camera.moveBackward(moveRate);
  }

道理都是一样的!

可以写两个按钮分别是“放大”和“缩小”,点击按钮的时候,执行这两个方法就可以了!

获取可视区域、高度、层级

获取可视区域这个很简单呀,一行代码完事:

let rectangle = this.viewer.camera.computeViewRectangle();

我们可以看一下返回的数据:

image.png

我们看到哈,打印出来的坐标不是地理坐标,转换一下就可以了。

    let rectangle = this.viewer.camera.computeViewRectangle();
    let east = Cesium.Math.toDegrees(rectangle.east).toFixed(6);  // 转地理坐标
    console.log(rectangle, east)
image.png

如果需要的话,挨个转换一下也可以。

获取相机高度的话更简单了。

let height = Math.ceil(this.viewer.camera.positionCartographic.height).toFixed(0);
console.log("相机高度----->> ", height)

直接打印一下看结果:

image.png

这个单位是米哈。

然后是层级,就和百度高德一样,层级显示:

let zoom = this.heightToZoom(height).toFixed(0)
console.log("层级----->> ", zoom)

这是需要用到的一个方法,为啥里面是这样,我也不知道,我也是从网上抄的这个方法:

  heightToZoom(height) {
    let A = 40487.57;
    let B = 0.00007096758;
    let C = 91610.74;
    let D = -40467.74;
    return Math.round(D + (A - D) / (1 + Math.pow(height / C, B)));
  }

然后看一下结果:

image.png

真棒!

你可能感兴趣的:(# vue2 使用 cesium 篇)