首页 前端知识 Cesium 在vue中如何引入

Cesium 在vue中如何引入

2024-05-30 10:05:22 前端知识 前端哥 834 607 我要收藏

对于初学者来说,引入CesiumJS是最重要的一步,此文章主要说四种引入方式,vue3和vue2的引入方式基本没有什么区别,都可以用这四种方式。

1、vue-cli-plugin-cesium插件引入

2、npm引入vue-cesium

3、CDN引入

4、手动引入

一、vue-cli-plugin-cesium(仅支持vue-cli3.0+)

简单说就是将Cesium通过插件实现零配置,因为每次配置太麻烦,需要用copy-webpack-plugin插件配置webpack,也就是vue-cli版本小于3.0,配置如下:

...
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("./"),
      }),
      // 使Cesium对象实例可在每个js中使用而无须import
      new webpack.ProvidePlugin({
        Cesium: ["cesium/Source/Cesium"]
      })
    ]
...

 CESIUM_BASE_URL是Cesium中内置的全局变量

// cesium-1.96 Source/Core/buildModuleUrl.js
...
const cesiumScriptRegex = /((?:.*\/)|^)Cesium\.js(?:\?|\#|$)/;
function getBaseUrlFromCesiumScript() {
  const scripts = document.getElementsByTagName("script");
  for (let i = 0, len = scripts.length; i < len; ++i) {
    const src = scripts[i].getAttribute("src");
    const result = cesiumScriptRegex.exec(src);
    if (result !== null) {
      return result[1];
    }
  }
  return undefined;
}
...
// 不配置的话,默认是 /Cesium/,所以这也是为什么手动引入是创建一个静态文件夹Cesium

 详情参见:vue3.x +Cesium vue3.x中安装使用cesium

vue-cli-plugin-cesium安装完之后,需要使用vue invoke初始化

npm install --save-dev vue-cli-plugin-cesium
vue invoke vue-cli-plugin-cesium
// 可选择是否在main.js中引入Widgets.css
// 可选择是否在compontents/下生成示例文件

详情参见:让GIS三维可视化变得简单-Vue项目中集成Cesium 

配置完之后就可以在页面中直接使用Cesium对象

<template>
  <div class="cesiumContainer">
    <div id="content-map" class="cesiumContainer-map" ref="targetDom"></div>
  </div>
</template>

<script>
export default {
  mounted() {

    // 实例化Cesium对象
    window.viewer = new Cesium.Viewer(node, {
      // 导航帮助按钮
      navigationHelpButton: false,
      // Geocoder小部件(搜索)
      geocoder: false,
      // 时钟尝试延长仿真时间
      shouldAnimate: true,
      // HomeButton小部件
      homeButton: true,
      // SceneModePicker小部件(2/3维切换)
      sceneModePicker: true,
      // 创建动画组件
      animation: true,
      // 创建图层组件
      baseLayerPicker: false,
      timeline: true,
      vrButton: false,
      infoBox: false,
      // 相机选中方框
      // selectionIndicator: false,
      fullscreenButton: true,
      // imageryProvider: imgProvider,
      // 默认地形,高度为0
      // terrainProvider: Cesium.EllipsoidTerrainProvider()
    });
    // cesium 版本
    console.log(Cesium.VERSION);
  },

  methods: {},
  destroyed() {
    let gl = viewer.scene.context._originalGLContext;
    viewer.destroy();
    viewer = null;
    gl.getExtension("WEBGL_lose_context").loseContext();
    gl = null;
  },
};
</script>

<style lang="scss" scoped>
.cesiumContainer {
  position: relative;
  width: 100%;
  height: 100%;
  z-index: 0;
  background: #000;
  &-map {
    width: 100%;
    height: 100%;
  }
}
</style>

这里面有一个问题,是初始化时会发送endPoint请求,因为Cesium默认是请求Cesium Ion的资源,这是国外网站,请求比较慢,长时间连接不上就会处于pendding状态。一般是两种方式处理;1、将地形服务给一个默认的底图

// 第一种,给定一张全球图片,替换默认底图
let layer = {
    url: require("@/assets/img/world.jpg"),
    name: "地图",
    rectangle: [-180, -90, 180, 90],
};
let imgProvider = new Cesium.SingleTileImageryProvider({
    url: layer.url,
    credit: layer.name,
    rectangle: Cesium.Rectangle.fromDegrees(
        layer.rectangle[0],
        layer.rectangle[1],
        layer.rectangle[2],
        layer.rectangle[3]
    ),
 });

// 第二种,设置一个纯色canvas
let imgProvider =  new Cesium.SingleTileImageryProvider({
    url: createColorCanvas("#FFF"),
    rectangle: Cesium.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0)
})



 window.viewer = new Cesium.Viewer({
    ...
    baseLayerPicker: false,//隐藏默认底图选择控件
    imageryProvider: imgProvider,
    ...
 });
// cesium 版本
console.log(Cesium.VERSION);


function createColorCanvas(color) {
  var width = 1, height = 1;
  var canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;
  var ctx = canvas.getContext('2d');
  ctx.fillStyle = color;
  ctx.fillRect(0, 0, width, height);
  return canvas.toDataURL();
}

2、cesium ion官网申请token配置defaultAccessToken

// 尽量使用自己申请的token,别人的token容易改变,会导致一些错误
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI1Mzk1NjEyMS03YzU2LTRiODgtOGU5NC05NmFhZmY4MjEzYWUiLCJpZCI6NzY0NDMsImlhdCI6MTYzOTQ1OTg5Nn0.2MTeUJoeMx_j3Auv9agF_sT4k73RAJWz9xt2VmFikdw';

window.viewer = new Cesium.Viewer({
    ...
    baseLayerPicker: false,//隐藏默认底图选择控件
    imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
      name: "img_arcgis",
      url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"
    }),
    ...
});

// 这个请求的是一个在线底图

详情参加: Cesium避免endPoint请求

 二、npm引入vue-cesium

1、安装vue-cesium

npm i vue-cesium@2.3.4

全局配置:main.js中配置

import lang from 'vue-cesium/lang/zh-hans'
import VueCesium from 'vue-cesium'

Vue.use(VueCesium, {
// cesiumPath 是指引用的Cesium.js路径,如
  // 项目本地的Cesium Build包,vue项目需要将Cesium Build包放static目录:
  // cesiumPath: /static/Cesium/Cesium.js
  // 个人在线Cesium Build包:
  // cesiumPath: 'https://zouyaoji.top/vue-cesium/statics/Cesium/Cesium.js'
  // 个人在线SuperMap Cesium Build包(在官方基础上二次开发出来的):
  // cesiumPath: 'https://zouyaoji.top/vue-cesium/statics/SuperMapCesium/Cesium.js'
  // 官方在线Cesium Build包,有CDN加速,推荐用这个:
  cesiumPath: 'https://unpkg.com/cesium@1.100/Build/Cesium/Cesium.js',
  // 指定Cesium.Ion.defaultAccessToken,使用Cesium ion的数据源需要到https://cesium.com/ion/申请一个账户,获取Access Token。不指定的话可能导致 Cesium 在线影像加载不了
  accessToken: 'Your Cesium Ion defaultAccessToken',
  baseLayerPicker: false,
  lang
})

如果不配置cesiumPath的话,也可以将Cesium源码包拷贝到static/public中,在index.html中通过script引入,适配离线开发

用法如下:

<template>
  <vc-viewer class="viewer" :animation="animation" :timeline="timeline" :camera.sync="camera" @ready="ready">
    <vc-layer-imagery>
      <vc-provider-imagery-openstreetmap></vc-provider-imagery-openstreetmap>
    </vc-layer-imagery>
  </vc-viewer>
</template>
<script>
  export default {
    data() {
      return {
        animation: true,
        timeline: true,
        camera: {
          position: {
            lng: 104.06,
            lat: 30.67,
            height: 100000
          },
          heading: 360,
          pitch: -90,
          roll: 0
        }
      }
    },
    methods: {
      ready(cesiumInstance) {
        const { Cesium, viewer } = cesiumInstance
        viewer.entities.add({
          id: '成都欢迎你',
          position: Cesium.Cartesian3.fromDegrees(104.06, 30.67, 100),
          billboard: new Cesium.BillboardGraphics({
            image: 'https://www.qianduange.cn/upload/article/favicon.png',
            scale: 0.1
          }),
          label: new Cesium.LabelGraphics({
            text: 'Hello Word',
            fillColor: Cesium.Color.GOLD,
            font: '24px sans-serif',
            horizontalOrigin: 1,
            outlineColor: new Cesium.Color(0, 0, 0, 1),
            outlineWidth: 2,
            pixelOffset: new Cesium.Cartesian2(17, -5),
            style: Cesium.LabelStyle.FILL
          })
        })
      }
    }
  }
</script>
<style>
  .viewer {
    width: 100%;
    height: 400px;
  }
</style>

 vue-cesium对vue2.x和3.x有区别,更多的配置和用法可以参见API:Vue Cesium

 三、CDN引入

在html中头部引入

<script src="https://cesium.com/downloads/cesiumjs/releases/1.83/Build/Cesium/Cesium.js"></script> 
<link rel="stylesheet" href="https://cesium.com/downloads/cesiumjs/releases/1.83/Build/Cesium/Widgets/widgets.css">

创建应用

import * as Cesium from 'Cesium'

window.viewer = new Cesium.Viewer('dom', {
  ...
})

参见详情 :【一文带你cesium入门】

四、手动引入(离线开发)

 1、在static/public下创建Cesium文件夹,原因在上面已经说过了,也可以自由创建,然后对应配置CESIUM_BASE_URL,将node_modules中的cesium/Build/CesiumUnminifed/未压缩的文件夹全部拷贝到新建文件夹下,即Assets、Widgets、Workers、ThirdParty

补充一点,如何更改天空盒

// Cesium/Assets/Textures/SkyBox ,这是打包之后本来就有的文件夹,所以下面的/startmap_2020_16k是再这下面创建文件夹
let groundSkybox = new Cesium.SkyBox({
    sources: {
      positiveX: "/starmap_2020_16k/starmap_2020_16k_px.jpg",
      negativeX: "/starmap_2020_16k/starmap_2020_16k_mx.jpg",
      positiveY: "/starmap_2020_16k/starmap_2020_16k_py.jpg",
      negativeY: "/starmap_2020_16k/starmap_2020_16k_my.jpg",
      positiveZ: "/starmap_2020_16k/starmap_2020_16k_pz.jpg",
      negativeZ: "/starmap_2020_16k/starmap_2020_16k_mz.jpg",
    },
});
viewer.scene.skyBox = groundSkybox;

2、在index.html中引入

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="renderer" content="webkit">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <link rel="icon" href="/favicon.ico">
  
  <script type="text/javascript" src="/config/settings.js"></script>
  <title></title>

</head>

<body>
  <div id="app">
  </div>
  <script type="module" src="/src/main.js"></script>
  <script src="/Cesium/Cesium.js"></script>
</body>

</html>

 css直接从Cesium中引入import 'Cesium/Source/Widgets/widgets.css';可能会报错,参见详情:解决cesium widgets.css is not exported from package

所以一般是将Cesium/Widgets/widgets.css拷贝一份出来,再在main.js中引入

// main.js
import '@/assets/styles/cesium-widgets.css'

一些cesium的样式更改就在这个文件里改就行了 

其实这会可以不用再安装Cesium了,也就是node_modules中不需要cesium源码包了,程序也是可以正常运行的

五、总结

这篇文章并没有从优化、打包、最优引入方面来分析,仅仅是列出了几种引入方式,主要是在平常开发中,这些也确实够了,最近又看了一位博主的文章,已经说的很明白了,从Cesium前置知识、到打包优化、再到选择最优引入,这一篇文章已经够用了。

参见详情:教程 - 在 Vue3+Ts 中引入 CesiumJS 的最佳实践@2023

转载请注明出处或者链接地址:https://www.qianduange.cn//article/10047.html
标签
评论
发布的文章

使用 mapstructure 解析 json

2024-06-05 13:06:03

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!