返回 导航

Vue.js

hangge.com

Vue.js - 集成Cesium构建三维可视化场景教程1(安装配置、基本用法)

作者:hangge | 2026-07-02 09:24
    Cesium 是一个功能强大的 WebGL 地球/三维可视化库,它不仅能处理海量的地形数据、3D Tiles(建筑群),还能模拟真实的大气、光影和物理效果。下面我将介绍如何在 Vue 2 项目中集成 Cesium,构建三维可视化场景。

一、安装配置与基本用法

1,安装配置

(1)进入 Vue 项目目录,执行如下命令安装 Cesium 库。
npm install cesium --save

(2)接着我们在项目的 node_modules 中找到 cesium 目录,复制其 build 文件夹下 Cesium 文件夹到 public 文件夹下。
提示Cesium 包含 WorkersAssetsThirdPartyWidgets 等大量静态资源,必须在构建时把这些资源拷贝到最终静态目录,并告诉 Cesium 这些资源的基准 URLCESIUM_BASE_URL)。

(3)最后,在项目入口文件 main.js 中显式声明 CESIUM_BASE_URL 这个环境变量,告诉 Cesium 静态资源在哪里。
// 定义环境变量,告诉 Cesium 静态资源在哪里
window.CESIUM_BASE_URL = "/Cesium/";

2,基本用法

(1)下面时一个简单的 Cesium 三维可视化样例代码,具体包括初始化三维地球场景、设置初始视图、添加示例点、重置视图、相机监听等功能。
<template>
    <div class="layer-container">
        <div ref="cesiumContainer" class="cesium-container"></div>

        <!-- 加载状态 -->
        <div v-if="loading" class="loading-overlay">
            <div class="loading-spinner"></div>
            <p>加载三维场景中...</p>
        </div>

        <!-- 工具栏 -->
        <div class="toolbar" v-if="!loading">
            <button @click="addSamplePoint">添加示例点</button>
            <button @click="resetView">重置视图</button>
            <div class="info">
                当前相机位置:经度 {{ longitude }},纬度 {{ latitude }},高度 {{ height }}米
            </div>
        </div>
    </div>
</template>

<script>
// 引入 Cesium 核心类
import * as Cesium from "cesium";

export default {
    name: 'CesiumViewer',

    data() {
        return {
            viewer: null,
            loading: true,
            terrainEnabled: true,
            sampleEntities: [],
            longitude: '',
            latitude: '',
            height: '',
        }
    },

    mounted() {
        // 确保 Cesium 已加载
        if (typeof Cesium === 'undefined') {
            console.error('Cesium 未加载,请检查配置')
            this.loading = false
            return
        }

        // 初始化 Cesium 场景
        this.initCesium()
    },

    beforeDestroy() {
        // 组件销毁时清理资源
        this.destroyCesium()
    },

    methods: {
        // 初始化 Cesium
        async initCesium() {
            try {
                // 配置 Cesium 访问令牌(如果需要,从 Cesium Ion 获取)
                //Cesium.Ion.defaultAccessToken = '你的Cesium Ion访问令牌'

                // 创建 Viewer 实例
                this.viewer = new Cesium.Viewer(this.$refs.cesiumContainer, {
                    animation: false, // 是否显示动画控件
                    baseLayerPicker: false, // 是否显示图层选择控件
                    fullscreenButton: false, // 是否显示全屏按钮
                    geocoder: false, // 是否显示地理编码搜索控件
                    homeButton: false, // 是否显示Home按钮
                    infoBox: false, // 是否显示信息框
                    sceneModePicker: false, // 是否显示3D/2D选择器
                    selectionIndicator: false, // 是否显示选取指示器组件
                    timeline: false, // 是否显示时间轴
                    navigationHelpButton: false, // 是否显示帮助按钮
                    scene3DOnly: true, // 每个几何实例仅以3D渲染以节省GPU内存
                    shouldAnimate: true, // 自动播放动画
                    // 地形配置
                    terrainProvider: await Cesium.createWorldTerrainAsync()
                })

                // 强制重新计算画布尺寸
                this.viewer.canvas.width = this.viewer.container.clientWidth;
                this.viewer.canvas.height = this.viewer.container.clientHeight;
                this.viewer.resize(); // 核心方法:告知 Cesium 容器大小已变

                // 设置初始视图
                this.setInitialView()

                // 添加一些基础实体
                this.addBaseEntities()

                // 监听相机变化
                this.setupCameraListeners()

                // 加载完成
                this.loading = false

                console.log('Cesium 场景初始化完成')
            } catch (error) {
                console.error('初始化 Cesium 失败:', error)
                this.loading = false
            }
        },

        // 设置初始视图
        setInitialView() {
            // 设置初始位置(例如:北京天安门)
            const initialPosition = Cesium.Cartesian3.fromDegrees(116.3974, 39.9093, 1500000)
            this.viewer.camera.setView({
                destination: initialPosition,
                orientation: {
                    heading: Cesium.Math.toRadians(0),
                    pitch: Cesium.Math.toRadians(-90),
                    roll: 0
                }
            })
        },

        // 添加基础实体
        addBaseEntities() {
            // 添加一个示例点(北京天安门)
            const beijingPoint = this.viewer.entities.add({
                name: '北京天安门',
                position: Cesium.Cartesian3.fromDegrees(116.3974, 39.9093),
                point: {
                    pixelSize: 10,
                    color: Cesium.Color.RED,
                    outlineColor: Cesium.Color.WHITE,
                    outlineWidth: 2
                },
                label: {
                    text: '北京天安门',
                    font: '14pt sans-serif',
                    style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                    outlineWidth: 2,
                    verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                    pixelOffset: new Cesium.Cartesian2(0, -20)
                }
            })

            this.sampleEntities.push(beijingPoint)
        },

        // 添加示例点
        addSamplePoint() {
            // 随机生成一个经纬度
            const longitude = 100 + Math.random() * 40
            const latitude = 20 + Math.random() * 30

            const entity = this.viewer.entities.add({
                name: `示例点 ${this.sampleEntities.length}`,
                position: Cesium.Cartesian3.fromDegrees(longitude, latitude),
                point: {
                    pixelSize: 8,
                    color: Cesium.Color.fromRandom({ alpha: 1.0 }),
                    outlineColor: Cesium.Color.WHITE,
                    outlineWidth: 2
                },
                label: {
                    text: `点 ${this.sampleEntities.length}`,
                    font: '12pt sans-serif',
                    style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                    outlineWidth: 1,
                    verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                    pixelOffset: new Cesium.Cartesian2(0, -15)
                }
            })

            this.sampleEntities.push(entity)

            // 飞向新添加的点
            this.viewer.flyTo(entity)
        },

        // 重置视图
        resetView() {
            this.setInitialView()
        },

        // 设置相机监听
        setupCameraListeners() {
            this.viewer.camera.moveEnd.addEventListener(() => {
                const position = this.viewer.camera.position
                const cartographic = Cesium.Cartographic.fromCartesian(position)
                this.longitude = Cesium.Math.toDegrees(cartographic.longitude).toFixed(4)
                this.latitude = Cesium.Math.toDegrees(cartographic.latitude).toFixed(4)
                this.height = cartographic.height.toFixed(0)
            })
        },

        // 销毁 Cesium 资源
        destroyCesium() {
            if (this.viewer) {
                this.viewer.destroy()
                this.viewer = null
            }
        }
    }
}
</script>

<style scoped>
.layer-container {
    position: relative;
    width: 100%;
    height: 100%;
}


.cesium-container {
    width: 100%;
    height: 100%;
}

.loading-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.7);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    z-index: 1000;
    color: white;
}

.loading-spinner {
    border: 4px solid rgba(255, 255, 255, 0.3);
    border-radius: 50%;
    border-top: 4px solid #42b983;
    width: 50px;
    height: 50px;
    animation: spin 1s linear infinite;
    margin-bottom: 15px;
}

@keyframes spin {
    0% {
        transform: rotate(0deg);
    }

    100% {
        transform: rotate(360deg);
    }
}

.toolbar {
    position: absolute;
    top: 20px;
    left: 20px;
    z-index: 999;
    display: flex;
    gap: 10px;
}

.toolbar button {
    padding: 8px 15px;
    background: rgba(40, 44, 52, 0.8);
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 14px;
    transition: background 0.3s;
}

.toolbar button:hover {
    background: rgba(66, 185, 131, 0.8);
}

.toolbar .info {
    text-align: right;
    color: white;
    margin-left: 10px;
    padding: 0 5px;
    height: 37px;
    line-height: 37px;
    background: rgba(40, 44, 52, 0.2);
}
</style>

(2)上面代码运行效果如下,可以看到初始时我们将相机定位到北京天安门上空。同时在北京天安门位置添加了一个红色点状标记,并附有标签。

(3)使用鼠标左键可以拖动地图,滚轮可以进行地图缩放。并且当相机停止移动时,会在上方显示当前相机的位置(经纬度、高度)。点击“重置视图”按钮可以回到最初始视图。

(4)按住鼠标中键然后拖动可以旋转三维视角。

(5)双击一个实体(Entity)会将该实体居中并放大的视图(即飞向该实体)

(6)在飞行到实体后,这时相机的旋转就会围绕这个点进行。如果想让相机取消这个目标锁定,双击点外的其它区域即可。

(7)每次点击“添加示例点”按钮则会在随机位置添加一个颜色随机的点状标记,并飞向该标记。
评论

全部评论(0)

回到顶部