返回 导航

Vue.js

hangge.com

Vue.js - 集成Cesium构建三维可视化场景教程9(使用天地图底图)

作者:hangge | 2026-07-15 09:07
    在 Cesium 中,如果我们直接创建 Viewer 而不做任何额外配置,默认使用的是 Cesium Ion 提供的全球影像底图(通常为 Bing MapsCesium 官方整合的影像服务)。这种默认底图在全球范围内效果良好,但国内访问速度不稳定,存在加载缓慢甚至失败的情况。并且地名、道路等中文标注不够友好,难以满足本地化展示需求。
    本文将演示如何使用国家测绘地理信息局提供的天地图(Tianditu)作为基础底图。天地图覆盖全国范围,提供影像、矢量及中文注记等多种图层形式,访问稳定、合规性高,非常适合电力、能源、自然资源、智慧城市等行业应用场景。

九、使用天地图作为底图

1,申请 Token

(1)在使用天地图服务前,我们需要先注册并申请密钥。首先访问天地图官网(点击访问)注册账号并登录。

(2)然后在服务中心控制台中根据下图所示创建一个应用,得到该应用的密钥(token)。
提示:应用类型选择“浏览器端”

2,使用样例

    下面代码关闭 Cesium 默认底图并接入天地图 Web Mercator 服务,同时实现影像地图与矢量地图(含中文注记)的加载与切换。
<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="switchBase('img')">影像地图</button>
            <button @click="switchBase('vec')">矢量地图(带注记)</button>
        </div>
    </div>
</template>

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

export default {
    name: 'CesiumViewer',

    data() {
        return {
            viewer: null,
            loading: true,
            terrainEnabled: true,
            layers: {
                img: null,
                vec: null,
                cva: null
            },
            // 替换为你的天地图 TOKEN(测试可以直接写,生产请通过后端注入或代理)
            tk: '65d9e8e0eae895407c564b7336c123cs'
        }
    },

    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.defaultAccessToken = ''

                // 创建 Viewer 实例
                this.viewer = new Cesium.Viewer(this.$refs.cesiumContainer, {
                    imageryProvider: false, // 是否显示默认底图
                    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.viewer.scene.globe.depthTestAgainstTerrain = true;

                // 创建并添加影像(默认选中第一个)
                const imgProv = this.createTdtProvider('img');
                this.layers.img = this.viewer.imageryLayers.addImageryProvider(imgProv);

                // 创建矢量与注记(但默认不显示注记以便切换)
                const vecProv = this.createTdtProvider('vec');
                const cvaProv = this.createTdtProvider('cva'); // 注记
                this.layers.vec = this.viewer.imageryLayers.addImageryProvider(vecProv);
                this.layers.cva = this.viewer.imageryLayers.addImageryProvider(cvaProv);

                // 默认显示:只显示影像,隐藏矢量和注记 
                this.layers.img.show = true;
                this.layers.vec.show = false;
                this.layers.cva.show = false;

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

                // 加载完成
                this.loading = false

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

        // 创建 UrlTemplateImageryProvider 的通用函数
        createTdtProvider(type) {
            // type: 'img' | 'vec' | 'cva' (cva = 注记)
            const subdomains = ['0', '1', '2', '3', '4', '5', '6', '7'];
            // WMTS 请求模板(使用 WebMercator 瓦片系),注意 {x},{y},{z} 对应 TileCol、TileRow、TileMatrix
            const urlTemplate = `https://t{s}.tianditu.gov.cn/${type}_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=${type}&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${this.tk}`;
            return new Cesium.UrlTemplateImageryProvider({
                url: urlTemplate,
                subdomains: subdomains,
                maximumLevel: 18,
                credit: new Cesium.Credit('天地图')
            });
        },

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

        // 切换底图类型
        switchBase(type) {
            if (!this.viewer) return;
            if (type === 'img') {
                this.layers.img.show = true;
                this.layers.vec.show = false;
                this.layers.cva.show = false;
            } else if (type === 'vec') {
                // 显示矢量 + 注记(矢量一般为底色,注记放上面)
                this.layers.img.show = false;
                this.layers.vec.show = true;
                this.layers.cva.show = true;
                // 确保注记图层在最上面
                this.viewer.imageryLayers.raiseToTop(this.layers.cva);
            }
        },

        // 销毁 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);
}
</style>

3,运行效果

(1)页面打开后默认会展示天地图影像底图。

(2)通过点击顶部的工具栏按钮,可以在在天地图影像地图与矢量地图(叠加中文注记)之间实时切换。
评论

全部评论(0)

回到顶部