分享:vue3+OpenTiny UI+cesium 实现三维地球

news2024/11/19 16:46:26

效果图

使用vue3 + OpenTiny UI + cesium 实现三维地球

  1. node.js >= v16.0

  2. opentiny vue3 ui安装指南 https://opentiny.design/tiny-vue/zh-CN/os-theme/docs/installation yarn add @opentiny/vue@3

项目依赖

"dependencies": {

    "@opentiny/vue": "3",

    "core-js": "^3.8.3",

    "vue": "^3.2.13",

    "vue-router": "4",

    "cesium": "^1.99.0",

    "cesium-navigation-es6": "^3.0.8"

  }

模块化代码

main.js

import { createApp } from 'vue'
import App from './App.vue'
// 引入 @opentiny/vue 组件
import TinyVue from '@opentiny/vue'
import Cesium from 'cesium'

// 创建并挂载根实例
const app = createApp(App)
// 注册 @opentiny/vue 组件
app.use(TinyVue)
app.use(Cesium)
app.mount('#app')

App.vue

<template>
  <gis></gis>
</template>

<script>
import gis from './components/EarthGis.vue'

export default {
  name: 'App',
  components: {
    gis
  },
  data() {
    return {
    }
  },
  mounted(){
    // 在“about:blank”中阻止脚本执行,因为文档的框架已被沙盒化并且未设置“allow-scripts”权限。
    let iframe = document.getElementsByClassName('cesium-infoBox-iframe')[0];
    iframe.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-popups allow-forms');
    iframe.setAttribute('src', ''); // 必须设置src为空 否则不会生效。
  }
}
</script>

<style>
body {
  margin: 0;
  padding: 0;
  background-color: #e9edfa;
}
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  background-color: transparent;
}
#loading {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%);
  z-index: 1;
}
.progressText {
  text-align: center;
}
</style>

EarthGis.vue

<template>
  <div class="content">
      <tiny-layout :cols="12">
        <tiny-row :gutter="10">
          <tiny-col :span="12">
            <div class="col" style="position: relative;">
                <div class="select-menu">
                  <tiny-dropdown title="影像来源"  size="medium" split-button @item-click="selectChange">
                    <template #dropdown>
                      <tiny-dropdown-menu popper-class="select-item">
                        <tiny-dropdown-item
                          v-for="(item, index) in imageryLayersOptions"
                          :key="index"
                          :label="item.label"
                          :item-data="item.value"
                        ></tiny-dropdown-item>
                      </tiny-dropdown-menu>
                    </template>
                  </tiny-dropdown>
                </div>
                <div id="cesium-container"></div>
            </div>
          </tiny-col>
        </tiny-row>
      </tiny-layout>
  </div>
</template>

<script type="allow-scripts">
import 'cesium/Source/Widgets/widgets.css'
import {  Layout, Row, Col, Dropdown, DropdownMenu, DropdownItem } from '@opentiny/vue'
import { World } from './js/World/World.js'
export default {
  name: 'EarthGis',
  props: {
    msg: String
  },
  components: {
    TinyDropdown: Dropdown,
    TinyDropdownMenu: DropdownMenu,
    TinyDropdownItem: DropdownItem,
    TinyLayout: Layout,
    TinyRow: Row,
    TinyCol: Col
  },
  watch: {
    isLoading: function (val) {
      document.getElementById('loading').style.display = val ? 'black' : 'none'
    }
  },
  data() {
    return {
      isLoading: true,
      imageryLayersOptions: [{
        value: 'SingleTile',
        label: 'SingleTileImageryProvider'
      }],
      world: null
    }
  },
  methods: {
    selectChange(data) {
      let item = data.itemData
      switch (item) {
        case 'SingleTile':
          this.world.changeImagery()
          break
        default:
          break
      }
    }
  },
  mounted() {
    // 1. Create an instance of the World app
    this.world = new World('cesium-container');
    this.$nextTick(() => {
      this.selectChange({itemData: 'SingleTile'})
    })
  },
  destroy(){
    this.removeNavigation()
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
#cesium-container{
  width: 100vw;
  height: 100vh;
}
.select-menu{
  position: absolute;
  top: 1rem;
  left: 1rem;
  background: #ffffff66;
  border-radius: 5px;
  padding: 10px;
}
.select-item{
  top: 1rem;
  left: 1rem;
  background: #ffffff66;
  border-radius: 5px;
  padding: 10px;
}
</style>

World.js

import { createViewer } from './components/viewer.js'
import { createImageryLayer } from './components/imageryLayer.js'
import { createTerrain } from './components/terrain.js'
import { createNavigation } from './components/navigation.js'
import { createCamera } from './components/camera.js';
import darkEarth from '@/assets/images/darkEarth.jpg'
import { FeatureDetection, 
    DirectionalLight, 
    Cartesian3, 
    JulianDate, 
    Math, 
    CameraEventType, 
    KeyboardEventModifier, 
    Cesium3DTileset,
    HeadingPitchRange,
    Matrix4,
    Cartographic,
    ScreenSpaceEventType,
    SingleTileImageryProvider,
    WebMercatorTilingScheme,
    ScreenSpaceEventHandler,
    WebMapTileServiceImageryProvider,
    GeographicTilingScheme,
    ImageryLayer, 
    UrlTemplateImageryProvider,
    OpenStreetMapImageryProvider,
    IonImageryProvider,
    createOsmBuildings,
    Rectangle  } from 'cesium'
// These variables are module-scoped: we cannot access them
// from outside the module
let viewer;
// 添加主题图层相关配置
let layerOption = {
  show: true, // 图像层是否可见
  alpha: 0.6, // 透明度
  nightAlpha: 1, // 地球夜晚一侧的透明度
  dayAlpha: 1, // 地球白天一侧的透明度
  brightness: 1, // 亮度
  contrast: 1, // 对比度
  hue: 0, // 色调
  saturation: 1, // 饱和度
  gamma: 1, // 伽马校正
}
class World {
    // 1. Create an instance of the World app
    constructor(id) {
        viewer = createViewer(id)
        viewer.imageryLayers.removeAll(true)
    }
    init(){
      // 修改场景环境,关闭相关特效
      viewer.scene.debugShowFramesPerSecond = true// 显示fps
      viewer.scene.moon.show = true// 月亮
      viewer.scene.fog.enabled = true// 雾
      viewer.scene.sun.show = true// 太阳
      viewer.scene.skyBox.show = true// 天空盒
      viewer.scene.globe.enableLighting = true // 激活基于太阳位置的光照(场景光照)
      viewer.resolutionScale = 1// 画面细度,默认值为1.0

      // 不显示cesium icon版权信息
      viewer._cesiumWidget._creditContainer.style.display="none"
      viewer.geocoder._form.children[0].placeholder = "请输入关键字"

      // DirectionalLight 表示 从无限远的地方向单一方向发射的光。解决模型光照问题
      viewer.scene.light = new DirectionalLight({
          direction: new Cartesian3(0.354925, -0.890918, -0.283358)
      })

      viewer.clock.currentTime = JulianDate.addHours(
          JulianDate.now(new Date()),
          12,
          new JulianDate()
      )
      // 启用深度测试,使地形后面的东西消失。
      viewer.scene.globe.depthTestAgainstTerrain = true
      viewer.scene.fxaa = false
      viewer.scene.postProcessStages.fxaa.enabled = true

      // 水雾特效
      viewer.scene.globe.showGroundAtmosphere = true

      // 设置最大俯仰角,[-90,0]区间内,默认为-30,单位弧度
      viewer.scene.screenSpaceCameraController.constrainedPitch = Math.toRadians(-20)
      viewer.scene.screenSpaceCameraController.autoResetHeadingPitch = false
      viewer.scene.screenSpaceCameraController.inertiaZoom = 0.5
      viewer.scene.screenSpaceCameraController.minimumZoomDistance = 50
      viewer.scene.screenSpaceCameraController.maximumZoomDistance = 20000000

      viewer.scene.screenSpaceCameraController.zoomEventTypes = [
          CameraEventType.RIGHT_DRAG,
          CameraEventType.WHEEL,
          CameraEventType.PINCH
      ]

      viewer.scene.screenSpaceCameraController.tiltEventTypes = [
          CameraEventType.MIDDLE_DRAG,
          CameraEventType.PINCH,
          {
              eventType: CameraEventType.LEFT_DRAG,
              modifier: KeyboardEventModifier.CTRL
          },
          {
              eventType: CameraEventType.RIGHT_DRAG,
              modifier: KeyboardEventModifier.CTRL
          }
      ]

      // 开启抗锯齿
      if (FeatureDetection.supportsImageRenderingPixelated()) {
          // 判断是否支持图像渲染像素化处理
          viewer.resolutionScale = window.devicePixelRatio
      }
      // 添加默认图层
      createImageryLayer()
      // 开启Navigation导航插件
      createNavigation(viewer)
      // 添加cesium自带的地形
      createTerrain(viewer)

      // 将三维球定位到中国
      viewer.camera.flyTo({
          destination: Cartesian3.fromDegrees(103.84, 31.15, 17860000),
          orientation: {
          heading: Math.toRadians(348.4202942851978),
          pitch: Math.toRadians(-89.74026687972041),
          roll: Math.toRadians(0)
          },
          complete: () => {
              // 定位完成之后的回调函数
              console.log('定位完成')
              document.getElementById('loading').style.display = 'none'
          }
      })

      // 设置默认的视角为中国
      createCamera.DEFAULT_VIEW_RECTANGLE = Rectangle.fromDegrees(
          // 西边经度
          89.5,
          // 南边维度
          20.4,
          // 东边经度
          110.4,
          // 北边维度
          61.2
      )

      //this.cion(layerOption)
      //this.osm(layerOption)
      this.hot(layerOption)
      //this.cartoVoyager(layerOption)
      //this.cartoDark(layerOption)
      //this.stamen(layerOption)
      //this.wmtsImages(layerOption)
      //this.osmBuildings()

      // const tilesetOption = {
      //     skipLevelOfDetail: true,
      //     baseScreenSpaceError: 1024,
      //     skipScreenSpaceErrorFactor: 16,
      //     skipLevels: 1,
      //     immediatelyLoadDesiredLevelOfDetail: false,
      //     loadSiblings: false,
      //     cullWithChildrenBounds: true
      // }

      // const modelPromise = this.addThreeDTiles(69380, tilesetOption);
      // modelPromise.then(model => {
      //     console.log('tileset: ', model)
      //     this.setPosition(model, 113.27, 23.13, 10) // 调整位置到,高度10米
      //     this.setPosition(model, undefined, undefined, 500) // 仅修改高度至500米
      //     this.serMatrix(model) // 使用默认变换矩阵(单位向量),实现回到默认位置的效果
      // })
    }
    // 切换图层
    changeImagery() {
      viewer.imageryLayers.removeAll(true)
      this.roaming()
    }
    async addThreeDTiles(url, option) {
      // 开启地形深度检测:
      // 控制在渲染场景时,相机是否进行深度测试以避免将被遮挡的物体绘制在前景
      // true: 相机会根据地形高度信息进行深度测试,避免将低于地面的物体绘制在地面之上
      viewer.scene.globe.depthTestAgainstTerrain = true

      let tileset = {}
      if (typeof url == 'number') {
        tileset = await Cesium3DTileset.fromIonAssetId(url, option);
      } else {
        tileset = await Cesium3DTileset.fromUrl(url, option);
      }

      viewer.scene.primitives.add(tileset);
      // 定位到模型
      viewer.zoomTo(
        tileset,
        new HeadingPitchRange(
          0.0,
          -0.5,
          tileset.boundingSphere.radius * 2.0 // 模型的包围球半径的2倍
        )
      )
      return tileset // 返回模型对象
    }
    setPosition(tileset, lng, lat, h) {
      // 计算出模型包围球的中心点(弧度制),从世界坐标转弧度制
      const cartographic = Cartographic.fromCartesian(
        tileset.boundingSphere.center
      )
      const { longitude, latitude, height } = cartographic

      // 模型包围球的中心点坐标,输出以笛卡尔坐标系表示的三维坐标点
      const current = Cartesian3.fromRadians(
        longitude,
        latitude,
        height
      )
      // 新的位置的中心点坐标,输出以笛卡尔坐标系表示的三维坐标点
      const offset = Cartesian3.fromDegrees(
        lng || Math.toDegrees(longitude),
        lat || Math.toDegrees(latitude),
        h || height
      );

      // 计算差向量:计算tileset的平移量,并将其应用到modelMatrix中
      const translation = Cartesian3.subtract(
        offset,
        current,
        new Cartesian3()
      )

      // 修改模型的变换矩阵,通过四维矩阵
      tileset.modelMatrix = Matrix4.fromTranslation(translation);
      viewer.zoomTo(tileset);
    }
    //Resets the position of a tileset to a specified model matrix or the identity matrix if none is provided.
    serMatrix(tileset, matrix) {
      tileset.modelMatrix = matrix || Matrix4.IDENTITY
      viewer.zoomTo(tileset);
    }
    showAllImagery(boolean = true) {
      // 获取图像图层集合
      const imageryLayers = viewer.imageryLayers;

      // 遍历图像图层并隐藏它们
      let numLayers = imageryLayers.length;
      for (let i = 0; i < numLayers; i++) {
        const layer = imageryLayers.get(i); // 获取图像图层对象
        layer.show = boolean; // 设置图像图层隐藏
      }
    }
    async roaming() {
      let isRoaming = true; // 漫游标志位
      const DEFAULT_LIGHTING = viewer.scene.globe.enableLighting; // 默认光照状态
      const DEFAULT_SKY_ATMOSPHERE = viewer.scene.skyAtmosphere.show; // 默认光照状态
      let bgImglayer; // 地球底图

      this.showAllImagery(false); // 隐藏所有图层
      viewer.clock.multiplier = -2000.0;  // 时间加速

      const provider = await SingleTileImageryProvider.fromUrl(darkEarth);
 
      provider._tilingScheme = new WebMercatorTilingScheme()
      bgImglayer = viewer.imageryLayers.addImageryProvider(provider); // 加载背景底图

      if (!DEFAULT_LIGHTING) {
        viewer.scene.globe.enableLighting = true; // 开启光照
      }
      if (!DEFAULT_SKY_ATMOSPHERE) {
        viewer.scene.skyAtmosphere.show = true; // 开启天空大气,能在一定程度上降低地球轮廓锯齿
      }

      // 添加鼠标事件,触发后停止漫游效果
      const handler = new ScreenSpaceEventHandler(viewer.scene.canvas); // 交互句柄
      handler.setInputAction(() => {
        isRoaming = false // 停止旋转
        this.showAllImagery(true) // 显示图层
        if (!DEFAULT_LIGHTING) {
          viewer.scene.globe.enableLighting = false; // 关闭光照
        }
        if (!DEFAULT_SKY_ATMOSPHERE) {
          viewer.scene.skyAtmosphere.show = false; // 关闭光照
        }
        viewer.imageryLayers.remove(bgImglayer, true); // 移除图层
        viewer.clock.multiplier = 1;  // 正常时间流速

        handler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK); // 移除鼠标事件监听
        this.init()
      }, ScreenSpaceEventType.LEFT_CLICK);

      (function roamingEvent() {
        if (isRoaming) {
          // 控制相机围绕 Z 轴旋转
          viewer.camera.rotate(Cartesian3.UNIT_Z, Math.toRadians(0.1));
          requestAnimationFrame(roamingEvent);
        }
      })()
    }
    // Cesium ION 服務
    cion (layerOption, id = 3812)  {
      const layer = new ImageryLayer(
        new IonImageryProvider({ assetId: id }),
        layerOption
      )
      viewer.imageryLayers.add(layer)
      return layer
    }
    // 加载osm地图
    osm (layerOption)  {
      const layer = new ImageryLayer(
        new OpenStreetMapImageryProvider({ url: 'https://a.tile.openstreetmap.org/' }),
        layerOption
      )
      viewer.imageryLayers.add(layer)
      return layer
    }
    // 加载Humanitarian OpenStreetMap Team style地图
    hot (layerOption)  {
      const layer = new ImageryLayer(
        new UrlTemplateImageryProvider({ url: 'https://tile-{s}.openstreetmap.fr/hot/{z}/{x}/{y}.png', subdomains: ['a', 'b', 'c'] }),
        layerOption
      )
      viewer.imageryLayers.add(layer)
      return layer
    }
    // 加载carto Basemaps 航海风格地图
    cartoVoyager (layerOption)  {
      const layer = new ImageryLayer(
        new UrlTemplateImageryProvider({ url: 'https://basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png' }),
        layerOption
      )
      viewer.imageryLayers.add(layer)
      return layer
    }
    // 加载carto Basemaps 黑暗风格地图
    cartoDark (layerOption)  {
      const layer = new ImageryLayer(
        new UrlTemplateImageryProvider({ url: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png', subdomains: ['a', 'b', 'c', 'd'] }),
        layerOption
      )
      viewer.imageryLayers.add(layer) 
      return layer
    }
    // 加载Stamen地图
    stamen (layerOption) {
      const layer = new ImageryLayer(
        new UrlTemplateImageryProvider({ url: 'https://stamen-tiles.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.png' }),
        layerOption
      )
      viewer.imageryLayers.add(layer)
      return layer
    }
    // 加载WMTS瓦片地图服务
    wmtsImages () {
      // EPSG:900913(标准名为EPSG:3875)网格切分的瓦片。当将tileMatrixSetID设置为 'EPSG:4326',访问常用的EPSG:4326网络的瓦片
      // 访问GeoServer发布的地图瓦片服务 WebMapTileServiceImageryProvider的切片方案tilingScheme默认使用EPSG:3875投影,即伪墨卡托网格访问切片,与EPSG:4326网格的切片方案存在较大差异
      // Tiling是一种椭球体表面上的几何图形或图像的平铺方案。在详细级别为0,即最粗、最不详细的级别上,瓦片的数量是可配置的。在详细级别为1级以上,每个是一级级瓦片经纬两个方向上扩展为两个瓦片,共有四个子瓦片。如此扩展到最大的缩放级别,这也构成了一个图像瓦片的金字塔。TillingScheme有一个参数ellipsoid用来决定切处时使用的椭球,另外两个比较重要的参数numberOfLevelZeroTilesX和numberOfLevelZeroTilesY,用来决定0级瓦片的数量。
      // TilingSchemee有两个子类,为WebMercatorTilingScheme和GeographicTilingScheme。其中WebMercatorTilingScheme对应于EPSG:3857切片方案,常见于谷歌地图、微软必应地图以及大多数的ArcGIS在线地图,也是Cesium中默认的切片方案。
      // GeographicTilingScheme对应于EPSG:4326切片方案,是一个简单的地理投影方案,可直接将经纬度映射为X和Y,这种投影通常被称为地理投影、等矩形投影、等距圆柱形投影等。
      // 由于在X方向上,WebMercatorTilingScheme只有一个0级瓦片,而GeographicTilingScheme却有2个,这就导致了默认的EPSG:3857切片方案不能正确加载EPSG:4326切片方案的瓦片图像。

      let layer = new WebMapTileServiceImageryProvider({
          url : '/map/gwc/service/wmts/rest/xian:satellite/{style}/{TileMatrixSet}/{TileMatrixSet}:{TileMatrix}/{TileRow}/{TileCol}?format=image/png',
          style : 'raster',
          tileMatrixSetID : 'EPSG:4326',
          tilingScheme: new GeographicTilingScheme(),
      });
      viewer.imageryLayers.addImageryProvider(layer);
      return layer
    }
    // 载入OSM建筑物
    osmBuildings = () => {
      // 突出显示所有的商业和住宅建筑,以查看整个城市不同社区的模式
      // Cesium OSM 建筑物通过3D Tiles,它可以在web上高效地流式传输和可视化。
      // 3D Tiles是一个开放的标准,所以Cesium OSM建筑可以在任何兼容它的查看器中使用,不仅仅是开源的Cesium。
      // Cesium全球3.5亿做建筑物,数据来源openStreetMap地图

      //OpenStreetMap(简称OSM,中文是公开地图)是一个网上地图协作计划,目标是创造一个内容自由且能让所有人编辑的世界地图。
      //其包含图层主要有高速公路、铁路、水系、水域、建筑、边界、建筑物等图层。我们不仅能够免费下载城市数据还可以下载全球数据。
      //网址为https://www.openstreetmap.org/
      //Cesium中支持使用OSM在线的建筑矢量三维模型,但目前OSM数据在国外较为细致,国内只支持几个大城市。
      //由于OSM建筑数据量大,加载较慢,用户在使用建筑白膜时,可根据需求,在OSM官网或百度、高德等地图服务商中下载建筑矢量数据,
      //使用ArcGIS等GIS软件和SketchUP等建模软件,生成建筑白膜,并使用建模软件对白膜进行贴图修改等操作,以实现城市建筑的美化,
      //使用CesiumLab等软件对建模的三维建筑数据 进行切片生成3Dtiles等Cesium支持的数据类型,对其进行加载使用。
      const addOSMAsync = () => {
        try {
          // 突出显示所有的商业和住宅建筑,以查看整个城市不同社区的模式
          viewer.scene.primitives.add(createOsmBuildings())
        } catch (error) {
          console.log(`Failed to add world imagery: ${error}`);
        }
      };
      addOSMAsync()
    }
}
    
export { World };

viewer.js

import { Viewer, Ion } from 'cesium'
function createViewer(id) {
    const cesiumToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJmNDVhMjQ0Yi05MDg4LTRlNDYtYTIxMi00YmI4ZWYxOWMyNTgiLCJpZCI6MTQ5MzYwLCJpYXQiOjE2ODc3ODQ0OTh9.KlhT_LCnsEtYyawpEmJ_wx44_qTUbgze-SxGMRavbAM'
    Ion.defaultAccessToken = cesiumToken
    const viewerOption = {
        // 默认隐藏
        infoBox: true, //是否显示信息框
        animation:false,    //左下角的动画仪表盘
        baseLayerPicker:true,  //右上角的图层选择按钮
        geocoder:true,  //搜索框
        homeButton:true,  //home按钮
        sceneModePicker:true, //模式切换按钮
        timeline:true,    //底部的时间轴
        navigationHelpButton:true,  //右上角的帮助按钮
        fullscreenButton:true,   //右下角的全屏按钮
        contextOptions:{
          webgl:{
            alpha:true
          }
        }
    }
    const instance = new Viewer(id, viewerOption);
    return instance;
}

export { createViewer }

imageryLayer.js

import { ImageryLayer, UrlTemplateImageryProvider } from 'cesium'
// 添加主题图层相关配置
let layerOption = {
    show: true, // 图像层是否可见
    alpha: 0.6, // 透明度
    nightAlpha: 1, // 地球夜晚一侧的透明度
    dayAlpha: 1, // 地球白天一侧的透明度
    brightness: 1, // 亮度
    contrast: 1, // 对比度
    hue: 0, // 色调
    saturation: 1, // 饱和度
    gamma: 1, // 伽马校正
}
function createImageryLayer( option=layerOption ) {
    // 添加主题图层相关配置
    const instance = new ImageryLayer(
        new UrlTemplateImageryProvider({ url: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png', subdomains: ['a', 'b', 'c', 'd'] }),
        option
    )
    return instance;
}

export { createImageryLayer }

camera.js

import { Camera } from 'cesium'
function createCamera() {
    const instance = Camera;
    return instance;
}

export { createCamera }

terrain.js

import { createWorldTerrainAsync } from 'cesium'
function createTerrain(viewer) {
    // 添加地形数据
    const addWorldTerrainAsync = async () => {
        try {
          const terrainProvider = await createWorldTerrainAsync({
            requestWaterMask: false, // 水面特效
            requestVertexNormals: true // 地形照明
          });  
          viewer.terrainProvider = terrainProvider;
        } catch (error) {
          console.log(`Failed to add world imagery: ${error}`);
        }
    };
    addWorldTerrainAsync()
}

export { createTerrain }

navigation.js

import CesiumNavigation from 'cesium-navigation-es6'
import { Cartographic } from 'cesium'

let instance;
function createNavigation(viewer) {
    let navigationOptions = {};
    // 用于在使用重置导航重置地图视图时设置默认视图控制。接受的值是Cesium.Cartographic 和Cesium.Rectangle.
    navigationOptions.defaultResetView = Cartographic.fromDegrees(103.84, 31.15, 17860000);
    // 用于启用或禁用罗盘。true是启用罗盘,false是禁用罗盘。默认值为true。如果将选项设置为false,则罗盘将不会添加到地图中。
    navigationOptions.enableCompass= true;
    // 用于启用或禁用缩放控件。true是启用,false是禁用。默认值为true。如果将选项设置为false,则缩放控件 将不会添加到地图中。
    navigationOptions.enableZoomControls= true;
    // 用于启用或禁用距离图例。true是启用,false是禁用。默认值为true。如果将选项设置为false,距离图例将不会添加到地图中。
    navigationOptions.enableDistanceLegend= true;
    // 用于启用或禁用指南针外环。true是启用,false是禁用。默认值为true。如果将选项设置为false,则该环将可见但无效。
    navigationOptions.enableCompassOuterRing= true;
    navigationOptions.resetTooltip = "重置";
    navigationOptions.zoomInTooltip = "放大";
    navigationOptions.zoomOutTooltip = "缩小";
    // 开启Navigation 罗盘、图例、指南针等导航插件
    instance = new CesiumNavigation(viewer, navigationOptions);
    return instance;
}
function removeNavigation(){
    instance.destroy();
}

export { createNavigation, removeNavigation }

夜色中的地球图片

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1540046.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【LabVIEW FPGA入门】FPGA寄存器(Register)

当您需要从多个时钟域或设计的不同部分访问数据&#xff0c;并且需要编写可重复使用的代码时&#xff0c;可使用寄存器项来存储数据。与 FIFO 相比&#xff0c;寄存器项消耗的 FPGA 逻辑资源更少&#xff0c;而且不消耗块存储器&#xff0c;而块存储器是最有限的 FPGA 资源类型…

AbstractQueuedSynchronizer 独占式源码阅读

概述 ● 一个int成员变量 state 表示同步状态 ● 通过内置的FIFO队列来完成资源获取线程的排队工作 属性 AbstractQueuedSynchronizer属性 /*** 同步队列的头节点 */private transient volatile Node head;/*** 同步队列尾节点&#xff0c;enq 加入*/private transient …

水果销售管理网站|jsp+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含java&#xff0c;…

深度学习(二)安装tensorflow深度学习框架

0.前言 速度更新新的一期&#xff0c;快夸奖我。前情提要这是我在window10系统下完成的操作&#xff0c;并不是ubuntu&#xff0c;所以有相应的区别。 1.安装tensorflow和d2l 这里默认大家已经安装好了anconda或者miniconda并且以及创建了虚拟环境。 conda create -n huahuaji…

JavaScript 权威指南第七版(GPT 重译)(六)

第十五章&#xff1a;JavaScript 在 Web 浏览器中 JavaScript 语言是在 1994 年创建的&#xff0c;旨在使 Web 浏览器显示的文档具有动态行为。自那时以来&#xff0c;该语言已经发生了显著的演变&#xff0c;与此同时&#xff0c;Web 平台的范围和功能也迅速增长。今天&#…

浮点数在计算机中的存储

1. 引言 我们知道&#xff0c;整数在计算机中是以二进制补码的形式存储的&#xff0c;那么浮点数呢&#xff1f; 考虑到这个问题&#xff0c;你会感到十分苦恼&#xff0c;因为你并不知道要如何将一个浮点数转化成一段二进制序列。 那我们不妨先来验证一下&#xff0c;整数与…

【Node.js】npx

概述 npx 可以使用户在不安装全局包的情况下&#xff0c;运行已安装在本地项目中的包或者远程仓库中的包。 高版本npm会自带npx命令。 它可以直接运行 node_modules/.bin 下的 exe 可执行文件。而不像之前&#xff0c;我们需要在 scripts 里面配置&#xff0c;然后 npm run …

相交链表:寻找链表的公共节点

目录 一、公共节点 二、题目 三、思路 四、代码 五、代码解析 1.计算长度 2.等长处理 3.判断 六、注意点 1.leetcode的尿性 2.仔细观察样例 3.经验总结 一、公共节点 链表不会像两直线相交一样&#xff0c;相交之后再分开。 由于单链表只有一个next指针&#xff0…

MySQL 8.0-索引- 不可见索引(invisible indexes)

概述 MySQL 8.0引入了不可见索引(invisible index)&#xff0c;这个在实际工作用还是用的到的&#xff0c;我觉得可以了解下。 在介绍不可见索引之前&#xff0c;我先来看下invisible index是个什么或者定义。 我们依然使用拆开来看&#xff0c;然后再把拆出来的词放到MySQL…

Redis高级数结构HyperLogLog

HyperLogLog 概述 概述。 HyperLogLog并不是一种新的数据结构(实际类型为字符串类型),而是一种基数算法&#xff0c;通过HyperLogLog可以利用极小的内存空间完成独立总数的统计&#xff0c;数据集可以是IP、Email、ID等 如果你负责开发维护一个大型的网站&#xff0c;有一天产…

使用 VMWare 安装 Android-x86 系统(小白版)

文章目录 VMWare 介绍Android 系统介绍概述最终效果前置步骤开始安装 VMWare 介绍 VMware Workstation是VMware公司开发的一款桌面虚拟化软件。它允许用户在一台物理计算机上同时运行多个操作系统&#xff0c;每个操作系统都在自己的虚拟机中运行。这使得用户可以在同一台计算…

如何使用swiprt插件

首先可以来到swiper网站看文档(中文) swiper网址地点 可以在这里面去下载swiper版本插件 需要注意的是从Swiper7开始&#xff0c;容器默认类名由’.swiper-container’变更为’.swiper’ 下载后呢 找到swiper-bundle.min.js和swiper-bundle.min.css文件 并放在你的项目中&…

Apollo配置中心

一、介绍 简要介绍 Apollo&#xff08;阿波罗&#xff09;是携程框架部门研发的分布式配置中心&#xff0c;能够集中化管理应用不同环境、不同集群的配置&#xff0c;配置修改后能够实时推送到应用端&#xff0c;并且具备规范的权限、流程治理等特性&#xff0c;适用于微服务…

在Linux中同一个tomcat出现多个进程

第一步&#xff0c;查看服务器所有的启动进程。 命令&#xff1a;top -c 第二步&#xff0c;通过点击“shiftM”&#xff0c;按照内存大小排序&#xff1b;点击“shiftP”&#xff0c;按照CPU大小排序。 在[COMMAND]列找到相同的tomcat进程&#xff0c;可以得到对应的PID。 …

【JavaEE初阶系列】——单例模式 (“饿汉模式“和“懒汉模式“以及解决线程安全问题)

目录 &#x1f6a9;单例模式 &#x1f388;饿汉模式 &#x1f388;懒汉模式 ❗线程安全问题 &#x1f4dd;加锁 &#x1f4dd;执行效率提高 &#x1f4dd;指令重排序 &#x1f36d;总结 单例模式&#xff0c;非常经典的设计模式&#xff0c;也是一个重要的学科&#x…

iStoreOS R4S软路由结合内网穿透实现公网远程本地电脑桌面

文章目录 简介一、配置远程桌面公网地址二、家中使用永久固定地址 访问公司电脑**具体操作方法是&#xff1a;** 简介 软路由是PC的硬件加上路由系统来实现路由器的功能&#xff0c;也可以说是使用软件达成路由功能的路由器。 使用软路由控制局域网内计算机的好处&#xff1a…

(2022级)成都工业学院软件构造实验二:面向对象软件构造

写在前面 1、基于2022级软件工程实验指导书 2、代码仅提供参考 3、如果代码不满足你的要求&#xff0c;请寻求其他的途径 运行环境 window11家庭版 IntelliJ IDEA 2023.2.2 jdk17.0.6 实验要求 任务&#xff1a;在第2章构造任务的基础上用面向对象构造技术&#xff0c…

错误centos docker版本过低导致 is not a valid repository/tag: invalid reference format

文章目录 错误centos docker版本过低导致 is not a valid repository/tag: invalid reference format1、查看免费主机刚才下载的docker版本2、卸载旧版本3、安装yum依赖包4、安装镜像信息5、安装docker CE6、查看docker版本7、再次运行就成功了&#xff01;&#xff01;&#x…

Codeforces Round 930 (Div. 2)(A,B,C,D)

比赛链接 C是个交互&#xff0c;D是个前缀和加二分。D还是很难写的。 A. Shuffle Party 题意&#xff1a; 您将得到一个数组 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1​,a2​,…,an​ 。最初&#xff0c;每个 1 ≤ i ≤ n 1 \le i \le n 1≤i≤n 对应 a i i a_ii…

STM32 使用gcc编译介绍

文章目录 前言1. keil5下的默认编译工具链用的是哪个2. Arm编译工具链和GCC编译工具链有什么区别吗&#xff1f;3. Gcc交叉编译工具链的命名规范4. 怎么下载gcc-arm编译工具链参考资料 前言 我们在STM32上进行开发时&#xff0c;一般都是基于Keil5进行编译下载&#xff0c;Kei…