1. Cesium 在 Vue 项目中的简单初始化配置

上一篇文章简单聊了为什么项目里会选择 Cesium。这一篇不展开太多原理,只记录一下 Cesium 在 Vue 项目里是如何引入和初始化的,适合当成一篇简单的配置展示文章来看。

本文重点只有三个:

  • Cesium 静态资源怎么引入。
  • Cesium.Viewer 怎么初始化。
  • 常见初始化配置项大概是什么意思。

1. 引入 Cesium 静态资源

项目里没有通过:

js 复制代码
import * as Cesium from "cesium"

这种方式把 Cesium 交给 webpack 打包,而是把 Cesium 放在:

text 复制代码
public/cesium

构建后会被复制到:

text 复制代码
dist/cesium

然后在 public/index.html 中直接引入:

html 复制代码
<link rel="stylesheet" href="/cesium/Widgets/widgets.css" />
<script src="/cesium/Cesium.js"></script>

这样页面运行后,Cesium 会挂载到全局:

js 复制代码
window.Cesium

所以在业务代码中可以直接使用:

js 复制代码
Cesium.Viewer
Cesium.Cartesian3
Cesium.WebMapTileServiceImageryProvider

这种方式的好处是简单稳定,尤其适合 Vue CLI 老项目。Cesium 自身包含 WorkersAssetsWidgetsThirdParty 等资源,如果全部交给 webpack 处理,需要额外配置资源路径和 Worker 路径,成本会高一些。

2. 准备地图容器

在 Vue 组件里,先准备一个容器:

vue 复制代码
<template>
  <div ref="mapContainer" class="cesium-map"></div>
</template>

样式上需要给容器明确宽高,否则地图可能显示不出来:

scss 复制代码
.cesium-map {
  width: 100%;
  height: 100%;
}

Cesium 初始化时需要一个 DOM 容器,可以传 DOM,也可以传元素 id。

例如传 DOM:

js 复制代码
const container = this.$refs.mapContainer

或者传 id:

js 复制代码
new Cesium.Viewer("CkMap", options)

3. 初始化 Cesium Viewer

项目中的核心初始化逻辑大概是这样:

js 复制代码
async initCesium() {
  const container = this.$refs.mapContainer

  if (!container) {
    return
  }

  Cesium.Ion.defaultAccessToken = "你的 Cesium Ion Token"

  const viewer = new Cesium.Viewer(container, {
    timeline: false,
    geocoder: false,
    homeButton: false,
    sceneModePicker: false,
    baseLayerPicker: false,
    navigationHelpButton: false,
    animation: false,
    fullscreenButton: false,
    imageryProvider: undefined,
    selectionIndicator: false,
    infoBox: false,
    navigationInstructionsInitiallyVisible: false,
  })
}

这里最关键的是:

js 复制代码
new Cesium.Viewer(container, options)

Viewer 是 Cesium 里最常用的入口对象。创建 Viewer 后,Cesium 会帮我们创建场景、相机、图层集合、实体集合、事件系统等基础能力。

后续添加底图、打点、画线、相机定位,基本都是基于这个 viewer 实例完成。

4. 常见配置项说明

项目里初始化时关闭了很多默认控件,主要是为了让地图界面更干净,把 UI 交给业务页面自己控制。

例如:

js 复制代码
timeline: false

关闭底部时间轴。

js 复制代码
animation: false

关闭左下角动画控件。

js 复制代码
geocoder: false

关闭搜索框。

js 复制代码
homeButton: false

关闭 Home 按钮。

js 复制代码
sceneModePicker: false

关闭 2D、2.5D、3D 场景切换按钮。

js 复制代码
baseLayerPicker: false

关闭默认底图选择器。

js 复制代码
navigationHelpButton: false

关闭导航帮助按钮。

js 复制代码
fullscreenButton: false

关闭全屏按钮。

js 复制代码
selectionIndicator: false

关闭选中实体时默认出现的选择框。

js 复制代码
infoBox: false

关闭点击实体后默认弹出的信息框。

js 复制代码
imageryProvider: undefined

不使用 Cesium 默认影像底图,后面自己手动添加业务需要的底图。

这个配置在项目里很常见,因为后台系统或大屏页面通常会自己设计地图工具栏、弹窗、图层控制,不希望 Cesium 默认 UI 影响页面风格。

5. 添加底图图层

初始化 Viewer 后,需要添加底图。

项目里使用的是 WMTS 图层,示例:

js 复制代码
function addTianDiTuLayers(viewer) {
  const token = "你的地图服务 Token"

  const vec = new Cesium.WebMapTileServiceImageryProvider({
    url:
      "http://t{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=" +
      token,
    layer: "矢量底图",
    style: "default",
    format: "image/jpeg",
    subdomains: ["0", "1", "2", "3", "4", "5", "6", "7"],
    tileMatrixSetID: "GoogleMapsCompatible",
  })

  const label = new Cesium.WebMapTileServiceImageryProvider({
    url:
      "http://t{s}.tianditu.gov.cn/cia_w/wmts?" +
      "service=wmts&request=GetTile&version=1.0.0" +
      "&LAYER=cia&tileMatrixSet=w" +
      "&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}" +
      "&style=default.jpg&tk=" +
      token,
    layer: "中文注记",
    style: "default",
    format: "image/jpeg",
    subdomains: ["0", "1", "2", "3", "4", "5", "6", "7"],
    tileMatrixSetID: "GoogleMapsCompatible",
  })

  viewer.imageryLayers.addImageryProvider(vec)
  viewer.imageryLayers.addImageryProvider(label)
}

这里添加了两层:

text 复制代码
矢量底图
中文注记

底图负责地图背景,注记负责地名、道路名等文字信息。

实际项目中,如果需要内网或离线部署,也可以把这里的 url 换成自己的地图瓦片服务:

js 复制代码
const imageryProvider = new Cesium.UrlTemplateImageryProvider({
  url: "http://你的内网服务/tiles?z={z}&x={x}&y={y}",
})

viewer.imageryLayers.addImageryProvider(imageryProvider)

也就是说,Cesium 只是负责加载和渲染地图数据,底图服务可以是在线服务,也可以是自己部署的离线瓦片服务。

6. 设置初始视角

地图创建后,通常需要设置一个默认视角。

示例:

js 复制代码
viewer.camera.setView({
  destination: Cesium.Cartesian3.fromDegrees(120.15, 30.28, 1000000),
  orientation: {
    heading: Cesium.Math.toRadians(0),
    pitch: Cesium.Math.toRadians(-90),
    roll: 0,
  },
})

其中:

js 复制代码
Cesium.Cartesian3.fromDegrees(lng, lat, height)

用于把经纬度和高度转换成 Cesium 的三维坐标。

参数含义是:

text 复制代码
lng:经度
lat:纬度
height:相机高度

orientation 控制相机朝向:

text 复制代码
heading:方位角
pitch:俯仰角
roll:翻滚角

项目里常见配置是:

js 复制代码
pitch: Cesium.Math.toRadians(-90)

表示相机垂直向下看,更接近普通二维地图视角。

7. 限制最大缩放距离

项目里还有一行:

js 复制代码
viewer.scene.screenSpaceCameraController.maximumZoomDistance = 10000000

它的作用是限制相机最大缩放距离,避免用户无限往外拉。

这类配置一般根据业务场景调整。如果是城市级、区域级项目,可以限制缩放范围,让用户操作更聚焦。

8. 添加点、线、面

初始化完成后,业务数据一般通过 viewer.entities 添加到地图上。

例如添加点:

js 复制代码
viewer.entities.add({
  position: Cesium.Cartesian3.fromDegrees(120.15, 30.28),
  point: {
    pixelSize: 10,
    color: Cesium.Color.RED,
  },
})

添加线:

js 复制代码
viewer.entities.add({
  polyline: {
    positions: Cesium.Cartesian3.fromDegreesArray([
      120.15, 30.28,
      120.18, 30.3,
    ]),
    width: 3,
    material: Cesium.Color.BLUE,
  },
})

添加面:

js 复制代码
viewer.entities.add({
  polygon: {
    hierarchy: Cesium.Cartesian3.fromDegreesArray([
      120.15, 30.28,
      120.18, 30.28,
      120.18, 30.3,
      120.15, 30.3,
    ]),
    material: Cesium.Color.BLUE.withAlpha(0.4),
  },
})

项目里的航线、任务区域、事件点位,本质上也是基于这些能力做业务封装。

9. 组件销毁时释放地图实例

Cesium 比普通 DOM 组件更重,页面销毁时最好释放资源。

示例:

js 复制代码
beforeDestroy() {
  if (this.viewer && !this.viewer.isDestroyed()) {
    this.viewer.destroy()
    this.viewer = null
  }
}

如果是 Vue3,可以写在:

js 复制代码
beforeUnmount()

这样可以避免页面切换后地图实例、事件监听、WebGL 上下文没有释放,导致内存占用越来越高。

10. 一个简单完整示例

把上面的内容合起来,一个简单版本大概是这样:

vue 复制代码
<template>
  <div ref="mapContainer" class="cesium-map"></div>
</template>

<script>
export default {
  name: "SimpleCesiumMap",

  data() {
    return {
      viewer: null,
    }
  },

  mounted() {
    this.initCesium()
  },

  beforeDestroy() {
    if (this.viewer && !this.viewer.isDestroyed()) {
      this.viewer.destroy()
      this.viewer = null
    }
  },

  methods: {
    initCesium() {
      const container = this.$refs.mapContainer

      Cesium.Ion.defaultAccessToken = "你的 Cesium Ion Token"

      this.viewer = new Cesium.Viewer(container, {
        timeline: false,
        geocoder: false,
        homeButton: false,
        sceneModePicker: false,
        baseLayerPicker: false,
        navigationHelpButton: false,
        animation: false,
        fullscreenButton: false,
        imageryProvider: undefined,
        selectionIndicator: false,
        infoBox: false,
      })

      this.viewer.camera.setView({
        destination: Cesium.Cartesian3.fromDegrees(120.15, 30.28, 1000000),
        orientation: {
          heading: Cesium.Math.toRadians(0),
          pitch: Cesium.Math.toRadians(-90),
          roll: 0,
        },
      })
    },
  },
}
</script>

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

这就是一个最基础的 Cesium 初始化组件。

总结

Cesium 初始化并不复杂,核心就是三步:

text 复制代码
1. 引入 Cesium.js 和 Widgets/widgets.css
2. 准备地图容器
3. new Cesium.Viewer(container, options)

项目里关闭了很多默认控件,是为了保持页面简洁,并且方便用自己的业务 UI 控制地图。

初始化后,再根据业务需要添加:

text 复制代码
底图图层
初始视角
点位
航线
区域面
事件交互
KML/KMZ/GeoJSON 数据

对于简单使用来说,记住一句话就够了:

text 复制代码
Viewer 是 Cesium 的入口,地图上的大部分操作都围绕 viewer 展开。

后续如果要优化,可以把 Cesium 从 index.html 的首屏加载改成按地图页面动态加载,这样能减少非地图页面的首屏压力。

最后放一张缩小图和一张放大图

相关推荐
YIAN3 小时前
从 Hash 底层原理到 React Router v6 实战:我学会了什么?
前端·react.js·vue-router
lv__pf3 小时前
Spring配置类解析 【TL spring 11】
java·前端·spring
AI分享猿4 小时前
UI设计Prompt系列(十三):响应式布局需求怎么写——让设计Prompt更接近前端实现
前端
ClouGence4 小时前
Selenium 写不动了?这个工具录一次就能跑 Web 自动化
前端·selenium·测试
hunterandroid4 小时前
[鸿蒙从零到一] HarmonyOS 地图、定位与传感器能力实战:从位置获取到运动感知
前端
大锅盖14 小时前
Web 工单要调用相机,第一步不是打开取景框,而是建立能力门禁
前端·数码相机·harmonyos
fthux4 小时前
不必下载整个仓库:GitZip Pro 让 GitHub 文件与文件夹批量下载更简单
前端·chrome·ai·edge·开源·github·firefox
奥莱维4 小时前
【无标题】
java·前端·javascript
用户921080262864 小时前
0. 为什么我们的项目选择 Cesium:从三维地图、离线部署到工程代价
前端