关于javascript:Cesium-上手不完全指北

Cesium 上手不齐全指北

将最近学习的 CesiumJS 做一个零碎梳理,从我的项目配置开始,记录罕用 API 的应用。

环境搭建与装置

首先,什么是 CesiumCesium 是一款开源的基于 JavaScript3D 地图框架,即地图可视化框架。产品基于 WebGL 技术,能够应用 CesiumJS 创立虚构场景的 3D 地理信息平台。其指标是用于创立以基于 Web 的地图动态数据可视化。在晋升平台的性能、准确率、虚拟化能力、易用性方面提供各种反对。

更多介绍和信息可通过官网进行学习。

注册

Cesium ion 是一个提供瓦片图和 3D 天文空间数据的平台,Cesium ion 反对把数据增加到用户本人的 CesiumJS 利用中。应用二三维贴图和世界地形都须要 ion 的反对,如果没有本人的数据源须要 cesium 提供的数据源就须要申请 iontoken,具体能够通过以下链接申请 access token。

在创立 Cesium Viewer 的时候,将 access token 填为本人的 access token 即可。

Cesium.Ion.defaultAccessToken = '<YOUR ACCESS TOKEN HERE>';

我的项目搭建

进入我的项目搭建过程,项目选择在 Vue 平台上进行实现,首先创立我的项目装置 cesium 库:

vue create cesium-vue
cd cesium-vue
npm i [email protected] --save

留神:目前应用 webpack 进行配置援用最新版本(1.71) cesium 临时不能导入,实测 [email protected] 版本能够进行 import 导入。

我的项目配置

根目录下新建 vue.config.js 配置文件,对我的项目进行根本配置:

const CopyWebpackPlugin = require('copy-webpack-plugin')
const webpack = require('webpack')
const path = require('path')

const debug = process.env.NODE_ENV !== 'production'
let cesiumSource = './node_modules/cesium/Source'
let cesiumWorkers = '../Build/Cesium/Workers'
module.exports = {
    publicPath: '',
    devServer: {
        port: 9999
    },
    configureWebpack: {
        output: {
            sourcePrefix: ' '
        },
        amd: {
            toUrlUndefined: true
        },
        resolve: {
            alias: {
                'vue$': 'vue/dist/vue.esm.js',
                '@': path.resolve('src'),
                'cesium': path.resolve(__dirname, cesiumSource)
            }
        },
        plugins: [
            new CopyWebpackPlugin([{ from: path.join(cesiumSource, cesiumWorkers), to: 'Workers'}]),
            new CopyWebpackPlugin([{ from: path.join(cesiumSource, 'Assets'), to: 'Assets'}]),
            new CopyWebpackPlugin([{ from: path.join(cesiumSource, 'Widgets'), to: 'Widgets'}]),
            new CopyWebpackPlugin([{ from: path.join(cesiumSource, 'ThirdParty/Workers'), to: 'ThirdParty/Workers'}]),
            new webpack.DefinePlugin({ CESIUM_BASE_URL: JSON.stringify('./') }),
            new CopyWebpackPlugin([{ from: path.join('./static', 'model'), to: 'model3D' }]),
            new CopyWebpackPlugin([{ from: path.join('./static', 'images'), to: 'images' }])
        ]
    }
}

在根目录下创立 static 文件夹用于后续 modelimages 的寄存。

组件实现

src/components/ 下新建 CesiumViewer.vue 进行组件实现:

<template>
  <div id="cesiumContainer"></div>
</template>

<script>
import Cesium from 'cesium/Cesium'
import 'cesium/Widgets/widgets.css'
export default {
    name: 'CesiumViewer',
    mounted () {
        // token
        Cesium.Ion.defaultAccessToken = 'your token';
        let viewer = new Cesium.Viewer('cesiumContainer');
    },
    methods: {}
}
</script>

<style>
#cesiumContainer {
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    border: none;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    overflow: hidden;
}
</style>

能够看到地图在调用 CesiumViewer 时开始构建。ViewerCesium API 的终点,new Viewer 后便能够看见地球对象。

组件申明

App.vue 中援用组件:

<template>
  <div id="app">
    <CesiumViewer></CesiumViewer>
  </div>
</template>

<script>
import CesiumViewer from './components/CesiumViewer'
export default {
  name: 'App',
  components: {
    CesiumViewer
  }
}
</script>

运行查看成果:

npm run serve

此时,曾经能够看见最开始的地球🌏成果,咱们进行一些简略配置和调整:

<script>
import Cesium from 'cesium/Cesium'
import 'cesium/Widgets/widgets.css'
export default {
    name: 'CesiumViewer',
    mounted () {
        this.init();
    },
    methods: {
        init () {
            let viewerOption = {
                geocoder: false,                // 地理位置搜寻控件
                homeButton: false,              // 首页跳转控件
                sceneModePicker: false,         // 2D,3D和Columbus View切换控件
                baseLayerPicker: false,         // 三维地图底图切换控件
                navigationHelpButton: false,    // 帮忙提醒控件
                animation: false,               // 视图动画播放速度控件
                timeline: false,                // 时间轴控件
                fullscreenButton: false,        // 全屏控件
                infoBox: false,                 // 点击显示窗口控件
                selectionIndicator: false,      // 实体对象抉择框控件
                scene3DOnly: true               // 仅3D渲染,节俭GPU内存
            }
            // token
            Cesium.Ion.defaultAccessToken = 'your token';
            let viewer = new Cesium.Viewer('cesiumContainer', viewerOption);

            // 暗藏Logo
            viewer.cesiumWidget.creditContainer.style.display = "none";
        }
    }
}
</script>
npm run serve

最终成果如下:

至此,最开始的构建运行就曾经实现了,上面对具体 API 进行学习。

Imagery 图层

开始 API 学习之前,为了不便办法实现,应用 ref 在元素上注册一个援用信息,不便通过 ID 间接拜访一个子组件实例。

批改如下,援用信息将会注册在父组件的 $refs 对象上,子组件通过 this.$viewer 进行拜访。

这里引入图层的概念(Imagery),瓦片图汇合依据不同的投影形式映射到虚构的三维数字地球表面。依赖于相机指向地表的方向和间隔,Cesium 会去申请和渲染不同层级的图层详细信息。

具体代码如下:

<template>
  <div id="cesiumContainer" ref="viewer"></div>
</template>

<script>
import Cesium from 'cesium/Cesium'
import 'cesium/Widgets/widgets.css'

export default {
    name: 'CesiumViewer',
    mounted () {
        // 初始化
        this.init();

        // 增加图层
        this.addLayers();
    },
    methods: {
        // 初始化
        init () {
            let viewerOption = {...}
            // token
            Cesium.Ion.defaultAccessToken = 'your token';

            this.$viewer = new Cesium.Viewer(this.$refs.viewer, viewerOption);

            this.$viewer.cesiumWidget.creditContainer.style.display = "none";
        },
        // 增加 `Imagery` (图层)
        addLayers () {
            // Remove default base layer
            // this.$viewer.imageryLayers.remove(this.$viewer.imageryLayers.get(0));

            // Add grid imagery
            this.$viewer.imageryLayers.addImageryProvider(new Cesium.GridImageryProvider());
        }
    }
}
</script>

原理上和 PS 的图层统一,多个图层能够增加、移除和排序,渲染并适应到 Cesium 中。

Terrain 地形

Cesium 的地形图层反对渐进式加载和渲染寰球高精度地图,并且包含地形地势、水形数据,包含陆地、湖泊、河流、山峰、峡谷等成果。

为了增加地形数据,咱们须要创立一个 CesiumTerrainProvider,通过 createWorldTerrain 函数创立一个由 Cesium ion 提供服务的 Cesium WorldTerrian,同时可提供配置项,申请额定的水和光数据,最终咱们通过 camera 下的函数定位到创立的地位进行查看:

export default {
  name: "CesiumViewer",
  mounted() {
    // 初始化
    this.init();

    // 增加图层
    // this.addLayers();

    // 增加地形
    this.addTerrain();
  },
  methods: {
    // 初始化
    init() {...},
    // 增加图层
    addLayers() {...},
    // 增加地形
    addTerrain() {
      this.$viewer.terrainProvider = Cesium.createWorldTerrain({
        requestWaterMask: true, // required for water effects
        requestVertexNormals: true, // required for terrain lighting
      });

      // Enable depth testing so things behind the terrain disappear.
      this.$viewer.scene.globe.depthTestAgainstTerrain = true;

      this.$viewer.scene.camera.flyTo({
        destination: Cesium.Cartesian3.fromRadians(
          -2.6399828792482234,
          1.0993550795541742,
          5795
        ),
        orientation: {
          heading: 3.8455,
          pitch: -0.4535,
          roll: 0.0,
        },
      });
    },
  }
}

Viewer 控件

回到最开始的调整配置上,咱们在 viewerOption 中对 Viewer 申明的一系列根本小控件做了移除和优化操作,具体 API 官网给出了如下形容:

  1. Geocoder : A location search tool that flies the camera to queried location. Uses Bing Maps data by default.
  2. HomeButton : Flies the viewer back to a default view.
  3. SceneModePicker : Switches between 3D, 2D and Columbus View (CV) modes.
  4. BaseLayerPicker : Chooses the imagery and terrain to display on the globe.
  5. NavigationHelpButton : Displays the default camera controls.
  6. Animation : Controls the play speed for view animation.
  7. CreditsDisplay : Displays data attributions. Almost always required!
  8. Timeline : Indicates current time and allows users to jump to a specific time using the scrubber.
  9. FullscreenButton : Makes the Viewer fullscreen.

咱们能够依据本身需要抉择是否启用。

官网形容地址

同时咱们还能够对视窗进行配置,达到本人冀望的成果,如开启依据动静工夫激活太阳地位的光照,对实在地球进行模仿:

export default {
  name: "CesiumViewer",
  mounted() {
    // 初始化
    this.init();

    // 增加图层
    // this.addLayers();

    // 增加地形
    // this.addTerrain();

    // 配置视窗
    this.configScene();
  },
  methods: {
    // 初始化
    init() {...},
    // 配置视窗
    configScene() {
      // Enable lighting based on sun/moon positions(激活基于太阳地位的光照)
      this.$viewer.scene.globe.enableLighting = true;
    },
  }
}

更近一步,能够利用上一大节应用的 camera 实现主视窗的定位:

// 配置视窗
configScene() {
    // Enable lighting based on sun/moon positions(激活基于太阳地位的光照)
    this.$viewer.scene.globe.enableLighting = true;

    // Create an initial camera view
    let initialPosition = new Cesium.Cartesian3.fromDegrees(
        -73.998114468289017509,
        40.674512895646692812,
        2631.082799425431
    );
    let initialOrientation = new Cesium.HeadingPitchRoll.fromDegrees(
        7.1077496389876024807,
        -31.987223091598949054,
        0.025883251314954971306
    );
    let homeCameraView = {
        destination: initialPosition,
        orientation: {
            heading: initialOrientation.heading,
            pitch: initialOrientation.pitch,
            roll: initialOrientation.roll,
        },
    };
    // Set the initial view
    this.$viewer.scene.camera.setView(homeCameraView);
},

这里须要介绍的是 Scene 的概念,Scence 虚构场景是所有3D 图形对象和状态的容器,通常不是由开发者间接创立,而是在 Viewer 或者 CesiumWidget 外部隐式创立的。

通过 Scene 场景,咱们能够管制 Globe 地球(包含地形和图层)、Camera 相机、Primitives (默认矢量数据层)和 PostProcessStage (前期解决成果)等。

除了以上配置,当初咱们须要理解的有以下 Cesium 根本类型的 API:

  1. Cartesian3 : 一个三维笛卡尔坐标——当它被用作绝对于地球核心的地位时,应用地球固定框架(ECEF)。
  2. Cartographic : 由经度、纬度(弧度)和 WGS84 椭球面高度确定的地位。
  3. HeadingPitchRoll : 在西南向上的框架中对于部分轴的旋转(弧度)。航向是围绕负 Z 轴的旋转。俯仰是围绕负 Y 轴的旋转。滚动是对于正 X 轴的旋转。
  4. Quaternion :以 4D 坐标示意的 3D 旋转。

Camera 相机

CameraCesium 中罕用的 API,属于 viewer.scene 中的属性,用来管制以后可见的域。能够管制场景的察看视角,例如旋转、缩放、平移以及航行定位。

一些最罕用的办法如下:

  • Camera.setView(options): 在特定地位和方向立刻设置相机。
  • Camera.zoomIn(amount): 沿着视角矢量挪动摄像机。
  • Camera.zoomOut(amount): 沿视角矢量向后挪动摄像机。
  • Camera.flyTo(options): 创立从以后相机地位到新地位的动画相机航行。
  • Camera.lookAt(target, offset): 定位并定位摄像机以给定偏移量瞄准指标点。
  • Camera.move(direction, amount): 朝任何方向挪动摄像机。
  • Camera.rotate(axis, angle): 绕任意轴旋转相机。

例子参考上一大节的视窗定位。

Clock 时钟

应用 viewerClockTimline 能够管制 scene 的工夫进度。

上面通过批改 init 函数实现一个日夜交替成果:

export default {
  name: "CesiumViewer",
  mounted() {
    // 初始化
    this.init();
  },
  methods: {
    // 初始化
    init() {
      let clock = new Cesium.Clock({
        startTime: Cesium.JulianDate.now(),
        currentTime: Cesium.JulianDate.now(),
        stopTime: Cesium.JulianDate.addDays(Cesium.JulianDate.now(), 1, new Cesium.JulianDate()),
        clockRange: Cesium.ClockRange.LOOP_STOP,
        clockStep: Cesium.ClockStep.SYSTEM_CLOCK_MULTIPLIER,
        multiplier: 9000,
        shouldAnimate: true
      });

      let viewerOption = {
        geocoder: false,
        homeButton: false,
        sceneModePicker: false,
        baseLayerPicker: false,
        navigationHelpButton: false,
        animation: false,
        timeline: false,
        fullscreenButton: false,
        infoBox: false,
        selectionIndicator: false,
        scene3DOnly: true,
        shadows: true,
        shouldAnimate: true,
        clockViewModel: new Cesium.ClockViewModel(clock)
      };

      // your token
      Cesium.Ion.defaultAccessToken = "token";

      this.$viewer = new Cesium.Viewer(this.$refs.viewer, viewerOption);

      // 暗藏Logo
      this.$viewer.cesiumWidget.creditContainer.style.display = "none";

      this.$viewer.scene.globe.enableLighting = true;
    },
  }
}

通过定义 clock,设置起始工夫、速率和循环等配置,应用 clockViewModel 在实例中增加时钟视图模型,而后启用光照,实现成果。

注:此成果为演示,init 函数后续复原为开始的创立实例状态,不便之后的例子应用。

Entity 实体

Cesium 中的所有空间数据都应用 Entity API来示意。Entity API 以一种无效提供灵便的可视化的形式,以便对 Cesium 进行渲染。Cesium Entity 是能够与款式化图形示意配对并定位在空间和工夫上的数据对象。

Cesium 中,加载点线面矢量有两种形式:

  • Entity API 是数据驱动的一组高级对象,具备接口统一,容易应用的特点,但性能略低。
  • Primitive API 是面向三维图形开发,更为底层,具备灵便,性能高的特点,但应用简单。

其中,Entity API 的应用通过 viewer.entities.add() 办法增加矢量数据:

export default {
  name: "CesiumViewer",
  mounted() {
    // 初始化
    this.init();
    // 加载实体
    this.loadEntities();
  },
  methods: {
    // 初始化
    init() {...},
    loadEntities() {
        let polygon = this.$viewer.entities.add({
        name: "正方形",
        id: "square",
        polygon: {
          hierarchy: Cesium.Cartesian3.fromDegreesArray([
            -109.080842,
            45.002073,
            -105.91517,
            45.002073,
            -104.058488,
            44.996596,
            -104.053011,
            43.002989,
            -104.053011,
            41.003906,
            -105.728954,
            40.998429,
            -107.919731,
            41.003906,
            -109.04798,
            40.998429,
            -111.047063,
            40.998429,
            -111.047063,
            42.000709,
            -111.047063,
            44.476286,
            -111.05254,
            45.002073,
          ]),
          height: 0,
          material: Cesium.Color.RED.withAlpha(0.5),
          outline: true,
          outlineColor: Cesium.Color.BLACK,
        },
      });

      this.$viewer.zoomTo(polygon);
      // polygon.show = false;
    }
  }
}

成果如下:

除了绘制实体,还能够通过内部加载的形式进行模型导入。

这里咱们在 static 文件夹下放入 J15.glb 文件进行导入:

export default {
  name: "CesiumViewer",
  mounted() {
    // 初始化
    this.init();
    // 增加模型
    this.addEntities();
  },
  methods: {
    // 初始化
    init() {...},
    addEntities() {
        let fighter = this.$viewer.entities.add({
        name: "fighter",
        id: "J15",
        model: {
          uri: "model3D/J15.glb",
          minimumPixelSize: 100,
          maximumScale: 1000,
        },
        position: Cesium.Cartesian3.fromDegrees(-110.345, 30, 70000),
      });
      // this.$viewer.trackedEntity = fighter;
      this.$viewer.zoomTo(fighter, new Cesium.HeadingPitchRange(-1, -0.3, 35));
    }
  }
}

本文由乐趣区整理发布,转载请注明出处,谢谢。

You may also like...

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据