Vue3.x 项目中如何使用Cesium构建三维地图项目

本文列举两种常用使用方法:

1、使用vue-cli-plugin-cesium 插件安装cesium(配置较为简单)

2、安装cesium 手动配置webpack

一、使用vue-cli-plugin-cesium 插件安装cesium

使用vuecli创建vue3.x的项目,因为插件基于webpack的,当前插件只支持 VueCLI3.0+ 版本哦

1. 创建项目

vue create vue3-cesium

2. 安装 vue-cli-plugin-cesium

vue add vue-cli-plugin-cesium
 
// 非全局安装的vue-cli可以
npx vue add vue-cli-plugin-cesium

或npm安装

// npm
npm install --save-dev vue-cli-plugin-cesium
 
// yarn
yarn add vue-cli-plugin-cesium

安装完成后我们要使用 vue invoke 来初始化这个插件

vue invoke vue-cli-plugin-cesium
 
// 非全局安装的vue-cli可以
npx vue invoke vue-cli-plugin-cesium

安装过程会有询问:

在 vue invoke 或 vue add 的过程中会有三个询问

询问一

Please choose a version of 'cesium' from this list

请在列表中选择 cesium 的版本

在此选择想使用的 Cesium 版本

询问二

Whether to import styles globally. 

This operation will automatically import widgets.css in main.js

是否全局引入样式,该操作将自动在main.js引入widgets.css?

此项默认为 yes,该操作将自动在 main.js 引入 widgets.css,即全局引入 Cesium 的 css 样式

如果此项设置为 no,那么开发时我们要手动引入widgets.css样式文件,引入命令如下

import "cesium/Widgets/widgets.css"

询问三
Whether to add sample components to the project components directory
是否添加示例组件到项目components目录?

此选项默认为 yes,该操作会自动在 src/components 文件夹下生成 CesiumExample 文件夹,此文件夹中包含一些 Cesium 的使用示例供参考

如果此项设置为 no,则不生成示例文件

 如果安装完成启动项目时报错 

Error:Cesium is no-undef

请检查配置一下eslint  "no-undef": 0,

module.exports = {
  root: true,
  env: {
    node: true
  },
  'extends': [
    'plugin:vue/vue3-essential',
    'eslint:recommended'
  ],
  parserOptions: {
    parser: 'babel-eslint'
  },
  rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    "no-undef": 0,
    'prefer-const': 'off',
    "no-irregular-whitespace": "off", //这禁止掉 空格报错检查
    'no-unused-vars': 'off', //禁止定义变量未使用报错
    "no-empty": 0
  }
}

安装完成后的main.js

import {
  createApp
} from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import 'cesium/Widgets/widgets.css'


Cesium.Ion.defaultAccessToken = '在cesium官网申请的token'

createApp(App).use(store).use(router).mount('#app')

Cesium.Ion.defaultAccessToken 用户配置我们自己的cesium token的,下面详细说

在vue组件中使用:

<template>
  <div class="map-box">
    <div id="cesiumContainer"></div>
  </div>
</template>

<script>
import { onMounted } from "vue";

export default {
  name: "",
  mounted() {
    // var viewer = new Cesium.CesiumWidget('cesiumContainer')

    // var viewer = new Cesium.Viewer("cesiumContainer", {
    //   animation: false, //是否显示动画控件
    //   homeButton: true, //是否显示home键
    //   geocoder: false, //是否显示地名查找控件        如果设置为true,则无法查询
    //   baseLayerPicker: false, //是否显示图层选择控件
    //   timeline: false, //是否显示时间线控件
    //   fullscreenButton: true, //是否全屏显示
    //   scene3DOnly: false, //如果设置为true,则所有几何图形以3D模式绘制以节约GPU资源
    //   infoBox: false, //是否显示点击要素之后显示的信息
    //   sceneModePicker: false, //是否显示投影方式控件  三维/二维
    //   navigationInstructionsInitiallyVisible: true,
    //   navigationHelpButton: false, //是否显示帮助信息控件
    //   selectionIndicator: false, //是否显示指示器组件
    //   // 地形
    //   terrainProvider:new Cesium.createWorldTerrain({
    //     requestVertexNormals:true,
    //     requestWaterMask:true
    //   }),
    //   //1 加载天地图
    //   imageryProvider: new Cesium.WebMapTileServiceImageryProvider({
    //     url:
    //       "http://t0.tianditu.com/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=你的天地图申请的key",
    //     layer: "tdtBasicLayer",
    //     style: "default",
    //     format: "image/jpeg",
    //     tileMatrixSetID: "GoogleMapsCompatible",
    //     show: false,
    //     mininumLevel: 0,
    //     maximumLevel: 16
    //   })
    // });

    // console.log(viewer)
  },
  setup() {
    onMounted(() => {
      Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(80, 22, 130, 55)// 默认定位到中国上空,home定位到中国范围
      var viewer = new Cesium.Viewer("cesiumContainer", {
        animation: false, //是否显示动画控件
        homeButton: true, //是否显示home键
        geocoder: false, //是否显示地名查找控件        如果设置为true,则无法查询
        baseLayerPicker: false, //是否显示图层选择控件
        timeline: false, //是否显示时间线控件
        fullscreenButton: true, //是否全屏显示
        scene3DOnly: false, //如果设置为true,则所有几何图形以3D模式绘制以节约GPU资源
        infoBox: false, //是否显示点击要素之后显示的信息
        sceneModePicker: true, //是否显示投影方式控件  三维/二维
        navigationInstructionsInitiallyVisible: true,
        navigationHelpButton: false, //是否显示帮助信息控件
        selectionIndicator: false, //是否显示指示器组件
        // 地形
        terrainProvider: new Cesium.createWorldTerrain({
          requestVertexNormals: true,
          requestWaterMask: true
        }),
        //1 加载天地图
        imageryProvider: new Cesium.WebMapTileServiceImageryProvider({
          url:
            "http://t0.tianditu.com/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=你的天地图申请的key",
          layer: "tdtBasicLayer",
          style: "default",
          format: "image/jpeg",
          tileMatrixSetID: "GoogleMapsCompatible",
          show: false,
          mininumLevel: 0,
          maximumLevel: 16
        })
      });
      //调用影响中文注记服务
      viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({
        url: "http://{s}.tianditu.gov.cn/cia_c/wmts?service=wmts&request=GetTile&version=1.0.0" +
          "&LAYER=cia&tileMatrixSet=c&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}" +
          "&style=default&format=tiles&tk=你的天地图申请的key",
        layer: "tdtImg_c",
        style: "default",
        format: "tiles",
        tileMatrixSetID: "c",
        subdomains: ["t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7"],
        tilingScheme: new Cesium.GeographicTilingScheme(),
        tileMatrixLabels: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19"],
        maximumLevel: 50,
        show: false
      }));
      // 隐藏版权
      viewer._cesiumWidget._creditContainer.style.display = "none";

      // 修改home按钮功能
      viewer.homeButton.viewModel.command.beforeExecute.addEventListener((e) => {
        console.log("click", e)
        e.cancel = true
        // // 方案一:你要飞的位置,根据点来设定
        // viewer.camera.flyTo({
        // 	destination: Cartesian3.fromDegrees(117.16, 32.71, 15000.0)
        // })
        // 返回初始设置位置
        // viewer.camera.flyHome(1)

        // 方案二:你要飞的位置,根据相机的视角来确定

        viewer.camera.flyTo({
          destination: Cesium.Rectangle.fromDegrees(80, 22, 130, 55)// home定位到中国范围
        })
        setTimeout(() => {
          let currentViewRect = viewer.camera.computeViewRectangle(),
            params = []
          params[2] = Cesium.Math.toDegrees(currentViewRect.east);
          params[3] = Cesium.Math.toDegrees(currentViewRect.north);
          params[0] = Cesium.Math.toDegrees(currentViewRect.west);
          params[1] = Cesium.Math.toDegrees(currentViewRect.south);

          console.log("当前视角", params)
        }, 3000)

      })

      console.log("view", viewer)
    })

  }
};
</script> 
<style scoped>
.map-box {
  width: 100%;
  height: 100%;
}

#cesiumContainer {
  width: 100%;
  height: 100%;
}
</style>

运行效果:

上面我们可以看到运行时候回报出 我们当前使用的是默认的token,需要我们去cesium官网申请一个token,以便后期官方更新内容我们可以使用等,在main.js中设置一下

Cesium.Ion.defaultAccessToken = "你申请的token"  配置后就不会有提示了。

当项目运行出地球说明配置成功了,就可以进行开发了。

资料:vue-cli-plugin-cesium

 

 二、安装cesium 手动配置webpack

1、创建vue-cli项目 

2、在创建完成的项目中安装cesium

npm i cesium --save

3、安装插件 copy-webpack-plugin 版本5.0.1

npm i copy-webpack-plugin@5.0.1 -D

4、创建vue.config.js文件,配置webpack

const CopyWebpackPlugin = require("copy-webpack-plugin");
const webpack = require("webpack");
const path = require("path");

let cesiumSource = "./node_modules/cesium/Source";
let cesiumWorkers = "Workers";
module.exports = {
  configureWebpack: {
    resolve: {
      alias: {
        "@": path.resolve("src"),
      },
    },
    amd: {
      // Cesium源码模块化使用的requireJs
      // 此配置允许webpack友好地在铯中使用require,使webpack打包cesium
      // 告诉Cesium, AMD的webpack版本用来评估要求的声明是不符合标准的toUrl功能
      toUrlUndefined: true
    },
    module: {
      // 解决require引入警告
      unknownContextCritical: false
    },
    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"]
      })
    ],
    module: {
      unknownContextCritical: false,
      unknownContextRegExp: /\/cesium\/cesium\/Source\/Core\/buildModuleUrl\.js/,
    },
  },
};

注意:

(1)配置ProvidePlugin   

通过new webpack.ProvidePlugin  自动加载模块,而不必到处 import 或 require 

   // 使Cesium对象实例可在每个js中使用而无须import
      new webpack.ProvidePlugin({
        Cesium: ["cesium/Source/Cesium"]
      })

 使用:无需导出引入,直接使用

<script>
import { onMounted } from "@vue/runtime-core";
export default{
  setup() {
    onMounted(() => {
      let viewer = new Cesium.Viewer("cesiumContainer");
    });
    return {};
  },
};
</script>

(2)不配置ProvidePlugin 

如果不配置ProvidePlugin,使用cesium变量需要手动配置引入:如下

main.js 引入,使用provide/inject 或 config.globalProperties (自行百度如何使用)

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// import 'cesium/Source/Widgets/widgets.css';
// const Cesium = require("cesium/Source/Cesium");

import * as Cesium from 'cesium/Source/Cesium';
import 'cesium/Source/Widgets/widgets.css'



const Vue = createApp(App)
Vue.provide('Cesium',Cesium)

Vue.use(store).use(router).mount('#app')

使用:

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

使用一:setup() 中使用

<script>
import { defineComponent, inject, onMounted } from "@vue/runtime-core";
export default{
  setup() {
    let Cesium = inject("Cesium");
    onMounted(() => {
      let viewer = new Cesium.Viewer("cesiumContainer");
    });
    return {};
  },
};
</script>

使用二:选项式使用

<script>
export default {
  inject: ['Cesium'],
  mounted() {
    
    const Cesium = this.Cesium
    let viewer = new Cesium.Viewer("cesiumContainer");

  },
  methods: {
    loadMap() {
     
      let viewer = new this.Cesium.Viewer("aboutCesium");
    }
  }
}

</script>

运行项目就可以看到效果:

 

Logo

前往低代码交流专区

更多推荐