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 的首屏加载改成按地图页面动态加载,这样能减少非地图页面的首屏压力。

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

相关推荐
Fluxart.ai1 小时前
GPT Image 2 国内怎么用?在 Flux Art 完成图片生成与编辑
前端·javascript·gpt
tanzongbiao1 小时前
Dorado7文件上传 解决HttpServletResponse返回值中文乱码的问题
java·服务器·前端
郑州光合科技余经理5 小时前
本地生活服务系统:成品模块和定制接口怎么划界
java·前端·人工智能·后端·系统架构·php·ai编程
平头哥~9 小时前
Day 07 _ 那条 1px 的线,为什么在手机上忽粗忽细
前端·css·样式·学习资料
小江的记录本9 小时前
【CSS】CSS 动画:transition、animation、transform、CSS3 新特性(附《思维导图》)
前端·css·安全·spring·前端框架·css3·动画
circuitsosk9 小时前
任务规划器的三种范式对比:ReAct、Plan-and-Execute 与 Tree-of-Thought 在真实业务中的取舍
前端·javascript·python·react.js·llm·ai agent
hzxpaipai11 小时前
企业官网技术架构拆解:前端、后台、数据库、服务器如何协同
前端·数据库·架构
深念Y13 小时前
Lenovo XiaoXinAir 14 — 性能模式切换
前端·网络
计算机魔术师13 小时前
Meta突然杀进第一梯队:一个新模型,把AI推理成本打下来8倍
前端