第02章 - 环境搭建与快速开始

第02章:环境搭建与快速开始

2.1 开发环境准备

2.1.1 基础环境要求

在开始 CesiumJS 开发之前,需要准备以下基础环境:

环境 要求 推荐版本
Node.js 16.x 或更高 18.x LTS
npm/yarn/pnpm 包管理器 npm 8.x+
现代浏览器 支持 WebGL 2.0 Chrome 90+
代码编辑器 支持 JavaScript/TypeScript VS Code

2.1.2 检查 Node.js 环境

# 检查 Node.js 版本
node -v
# 应输出:v18.x.x 或更高

# 检查 npm 版本
npm -v
# 应输出:8.x.x 或更高

2.1.3 安装 Node.js

如果尚未安装 Node.js,可以通过以下方式安装:

Windows/macOS:

  1. 访问 https://nodejs.org
  2. 下载 LTS 版本
  3. 运行安装程序

使用 nvm 管理版本(推荐):

# 安装 nvm (Linux/macOS)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash

# 安装 Node.js
nvm install 18
nvm use 18

2.2 项目创建方式

2.2.1 方式一:直接引入 CDN(最简单)

这是最快速的入门方式,适合学习和原型开发:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CesiumJS 快速开始</title>
    
    <!-- 引入 Cesium 样式 -->
    <link href="https://cesium.com/downloads/cesiumjs/releases/1.120/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
    
    <style>
        html, body, #cesiumContainer {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
    <div id="cesiumContainer"></div>
    
    <!-- 引入 Cesium 库 -->
    <script src="https://cesium.com/downloads/cesiumjs/releases/1.120/Build/Cesium/Cesium.js"></script>
    
    <script>
        // 设置 Cesium ion 访问令牌
        Cesium.Ion.defaultAccessToken = 'your_access_token';
        
        // 创建 Viewer
        const viewer = new Cesium.Viewer('cesiumContainer', {
            terrainProvider: Cesium.createWorldTerrain()
        });
        
        // 飞到北京
        viewer.camera.flyTo({
            destination: Cesium.Cartesian3.fromDegrees(116.4, 39.9, 15000)
        });
    </script>
</body>
</html>

2.2.2 方式二:使用 npm 创建(推荐)

这是生产环境推荐的方式:

# 创建项目目录
mkdir cesium-project
cd cesium-project

# 初始化 npm 项目
npm init -y

# 安装 CesiumJS
npm install cesium

# 安装开发依赖(可选,用于构建)
npm install --save-dev vite

项目结构:

cesium-project/
├── node_modules/
├── public/
│   └── index.html
├── src/
│   └── main.js
├── package.json
└── vite.config.js

2.2.3 方式三:使用 Vite 快速创建

# 使用 Vite 创建项目
npm create vite@latest cesium-app -- --template vanilla

cd cesium-app

# 安装依赖
npm install
npm install cesium
npm install --save-dev vite-plugin-cesium

配置 vite.config.js:

import { defineConfig } from 'vite';
import cesium from 'vite-plugin-cesium';

export default defineConfig({
    plugins: [cesium()]
});

修改 main.js:

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

// 设置访问令牌
Cesium.Ion.defaultAccessToken = 'your_access_token';

// 创建 Viewer
const viewer = new Cesium.Viewer('app', {
    terrainProvider: Cesium.createWorldTerrain()
});

修改 index.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CesiumJS Vite 项目</title>
    <style>
        html, body, #app {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>
    <div id="app"></div>
    <script type="module" src="/main.js"></script>
</body>
</html>

2.2.4 方式四:Vue 3 + CesiumJS

# 创建 Vue 3 项目
npm create vue@latest cesium-vue-app

cd cesium-vue-app

# 安装依赖
npm install
npm install cesium
npm install --save-dev vite-plugin-cesium

配置 vite.config.js:

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import cesium from 'vite-plugin-cesium';

export default defineConfig({
    plugins: [vue(), cesium()]
});

创建 CesiumViewer.vue 组件:

<template>
    <div ref="cesiumContainer" class="cesium-container"></div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import * as Cesium from 'cesium';
import 'cesium/Build/Cesium/Widgets/widgets.css';

const cesiumContainer = ref(null);
let viewer = null;

onMounted(() => {
    Cesium.Ion.defaultAccessToken = 'your_access_token';
    
    viewer = new Cesium.Viewer(cesiumContainer.value, {
        terrainProvider: Cesium.createWorldTerrain()
    });
    
    // 飞到初始位置
    viewer.camera.flyTo({
        destination: Cesium.Cartesian3.fromDegrees(116.4, 39.9, 15000)
    });
});

onUnmounted(() => {
    if (viewer) {
        viewer.destroy();
    }
});
</script>

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

2.2.5 方式五:React + CesiumJS

# 创建 React 项目
npm create vite@latest cesium-react-app -- --template react

cd cesium-react-app

# 安装依赖
npm install
npm install cesium resium

使用 Resium(React 封装):

import React from 'react';
import { Viewer, Entity, PointGraphics } from 'resium';
import * as Cesium from 'cesium';
import 'cesium/Build/Cesium/Widgets/widgets.css';

// 设置访问令牌
Cesium.Ion.defaultAccessToken = 'your_access_token';

function App() {
    return (
        <Viewer full>
            <Entity
                name="北京"
                position={Cesium.Cartesian3.fromDegrees(116.4, 39.9, 100)}
            >
                <PointGraphics
                    pixelSize={10}
                    color={Cesium.Color.RED}
                />
            </Entity>
        </Viewer>
    );
}

export default App;

2.3 获取 Cesium ion 访问令牌

2.3.1 注册 Cesium ion 账号

  1. 访问 https://cesium.com/ion/signup
  2. 填写注册信息
  3. 验证邮箱
  4. 登录账户

2.3.2 获取访问令牌

  1. 登录 Cesium ion
  2. 进入 Access Tokens 页面
  3. 创建新的令牌或使用默认令牌
  4. 复制令牌字符串
// 在代码中使用令牌
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';

2.3.3 令牌管理最佳实践

// 方式一:环境变量(推荐)
// .env 文件
// VITE_CESIUM_TOKEN=your_access_token

// 代码中使用
Cesium.Ion.defaultAccessToken = import.meta.env.VITE_CESIUM_TOKEN;

// 方式二:配置文件
// config.js
export const cesiumConfig = {
    accessToken: 'your_access_token'
};

// 使用
import { cesiumConfig } from './config.js';
Cesium.Ion.defaultAccessToken = cesiumConfig.accessToken;

2.4 第一个 CesiumJS 应用

2.4.1 完整示例代码

创建一个包含基本功能的完整示例:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>我的第一个 CesiumJS 应用</title>
    <link href="https://cesium.com/downloads/cesiumjs/releases/1.120/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
    <style>
        html, body, #cesiumContainer {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
        
        #toolbar {
            position: absolute;
            top: 10px;
            left: 10px;
            z-index: 1000;
            background: rgba(42, 42, 42, 0.8);
            padding: 10px;
            border-radius: 4px;
        }
        
        #toolbar button {
            display: block;
            margin: 5px 0;
            padding: 8px 16px;
            cursor: pointer;
            background: #303030;
            color: white;
            border: 1px solid #444;
            border-radius: 4px;
        }
        
        #toolbar button:hover {
            background: #404040;
        }
    </style>
</head>
<body>
    <div id="cesiumContainer"></div>
    
    <div id="toolbar">
        <button onclick="flyToBeijing()">飞到北京</button>
        <button onclick="flyToShanghai()">飞到上海</button>
        <button onclick="addPoint()">添加点</button>
        <button onclick="addPolygon()">添加多边形</button>
        <button onclick="clearEntities()">清除实体</button>
        <button onclick="toggleTerrain()">切换地形</button>
    </div>
    
    <script src="https://cesium.com/downloads/cesiumjs/releases/1.120/Build/Cesium/Cesium.js"></script>
    <script>
        // 设置访问令牌
        Cesium.Ion.defaultAccessToken = 'your_access_token';
        
        // 创建 Viewer
        const viewer = new Cesium.Viewer('cesiumContainer', {
            terrainProvider: Cesium.createWorldTerrain(),
            animation: true,
            timeline: true,
            fullscreenButton: true,
            geocoder: true,
            homeButton: true,
            infoBox: true,
            sceneModePicker: true,
            selectionIndicator: true,
            navigationHelpButton: true
        });
        
        // 启用深度测试
        viewer.scene.globe.depthTestAgainstTerrain = true;
        
        // 飞到北京
        function flyToBeijing() {
            viewer.camera.flyTo({
                destination: Cesium.Cartesian3.fromDegrees(116.4, 39.9, 15000),
                orientation: {
                    heading: Cesium.Math.toRadians(0),
                    pitch: Cesium.Math.toRadians(-45),
                    roll: 0
                },
                duration: 2
            });
        }
        
        // 飞到上海
        function flyToShanghai() {
            viewer.camera.flyTo({
                destination: Cesium.Cartesian3.fromDegrees(121.47, 31.23, 15000),
                orientation: {
                    heading: Cesium.Math.toRadians(0),
                    pitch: Cesium.Math.toRadians(-45),
                    roll: 0
                },
                duration: 2
            });
        }
        
        // 添加点
        function addPoint() {
            const longitude = 116.4 + (Math.random() - 0.5) * 2;
            const latitude = 39.9 + (Math.random() - 0.5) * 2;
            
            viewer.entities.add({
                name: '随机点',
                position: Cesium.Cartesian3.fromDegrees(longitude, latitude, 100),
                point: {
                    pixelSize: 12,
                    color: Cesium.Color.fromRandom({ alpha: 1.0 }),
                    outlineColor: Cesium.Color.WHITE,
                    outlineWidth: 2,
                    heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND
                },
                label: {
                    text: `点 (${longitude.toFixed(2)}, ${latitude.toFixed(2)})`,
                    font: '12px sans-serif',
                    fillColor: Cesium.Color.WHITE,
                    style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                    outlineWidth: 2,
                    verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                    pixelOffset: new Cesium.Cartesian2(0, -15)
                }
            });
        }
        
        // 添加多边形
        function addPolygon() {
            const centerLon = 116.4 + (Math.random() - 0.5) * 2;
            const centerLat = 39.9 + (Math.random() - 0.5) * 2;
            const size = 0.1;
            
            viewer.entities.add({
                name: '随机多边形',
                polygon: {
                    hierarchy: Cesium.Cartesian3.fromDegreesArray([
                        centerLon - size, centerLat - size,
                        centerLon + size, centerLat - size,
                        centerLon + size, centerLat + size,
                        centerLon - size, centerLat + size
                    ]),
                    material: Cesium.Color.fromRandom({ alpha: 0.5 }),
                    outline: true,
                    outlineColor: Cesium.Color.BLACK,
                    height: 0,
                    heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
                }
            });
        }
        
        // 清除所有实体
        function clearEntities() {
            viewer.entities.removeAll();
        }
        
        // 切换地形
        let terrainEnabled = true;
        function toggleTerrain() {
            terrainEnabled = !terrainEnabled;
            if (terrainEnabled) {
                viewer.terrainProvider = Cesium.createWorldTerrain();
            } else {
                viewer.terrainProvider = new Cesium.EllipsoidTerrainProvider();
            }
        }
        
        // 初始飞到北京
        flyToBeijing();
    </script>
</body>
</html>

2.4.2 代码解析

1. 初始化配置:

const viewer = new Cesium.Viewer('cesiumContainer', {
    terrainProvider: Cesium.createWorldTerrain(),  // 全球地形
    animation: true,        // 动画控件
    timeline: true,         // 时间轴
    fullscreenButton: true, // 全屏按钮
    geocoder: true,         // 地理编码搜索
    homeButton: true,       // 主页按钮
    infoBox: true,          // 信息框
    sceneModePicker: true,  // 场景模式选择器
    selectionIndicator: true, // 选择指示器
    navigationHelpButton: true // 导航帮助
});

2. 相机飞行:

viewer.camera.flyTo({
    destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, height),
    orientation: {
        heading: Cesium.Math.toRadians(0),   // 朝向角度
        pitch: Cesium.Math.toRadians(-45),   // 俯仰角度
        roll: 0                               // 翻转角度
    },
    duration: 2  // 飞行时间(秒)
});

3. 添加实体:

viewer.entities.add({
    name: '实体名称',
    position: Cesium.Cartesian3.fromDegrees(lon, lat, height),
    point: { /* 点样式 */ },
    label: { /* 标签样式 */ }
});

2.5 项目结构最佳实践

2.5.1 推荐的项目结构

cesium-project/
├── public/
│   ├── index.html
│   └── assets/
│       ├── models/          # 3D 模型文件
│       ├── textures/        # 纹理贴图
│       └── data/            # 数据文件
├── src/
│   ├── main.js              # 入口文件
│   ├── config/
│   │   └── cesium.config.js # Cesium 配置
│   ├── components/
│   │   ├── CesiumViewer.js  # Viewer 组件
│   │   └── controls/        # 控制组件
│   ├── layers/
│   │   ├── ImageryLayers.js # 影像图层
│   │   ├── TerrainLayers.js # 地形图层
│   │   └── EntityLayers.js  # 实体图层
│   ├── utils/
│   │   ├── coordinate.js    # 坐标工具
│   │   └── camera.js        # 相机工具
│   └── styles/
│       └── cesium.css       # 自定义样式
├── package.json
├── vite.config.js
└── .env                     # 环境变量

2.5.2 配置文件示例

cesium.config.js:

export const cesiumConfig = {
    // 访问令牌
    accessToken: import.meta.env.VITE_CESIUM_TOKEN,
    
    // 默认视图配置
    defaultView: {
        longitude: 116.4,
        latitude: 39.9,
        height: 15000
    },
    
    // Viewer 默认选项
    viewerOptions: {
        animation: true,
        timeline: true,
        fullscreenButton: true,
        geocoder: true,
        homeButton: true,
        infoBox: true,
        sceneModePicker: true,
        selectionIndicator: true,
        navigationHelpButton: false
    },
    
    // 地形配置
    terrain: {
        requestWaterMask: true,
        requestVertexNormals: true
    }
};

CesiumViewer.js:

import * as Cesium from 'cesium';
import { cesiumConfig } from '../config/cesium.config.js';

export class CesiumViewer {
    constructor(containerId) {
        this.containerId = containerId;
        this.viewer = null;
        this.init();
    }
    
    init() {
        // 设置访问令牌
        Cesium.Ion.defaultAccessToken = cesiumConfig.accessToken;
        
        // 创建 Viewer
        this.viewer = new Cesium.Viewer(this.containerId, {
            ...cesiumConfig.viewerOptions,
            terrainProvider: Cesium.createWorldTerrain(cesiumConfig.terrain)
        });
        
        // 飞到默认位置
        this.flyToDefault();
    }
    
    flyToDefault() {
        const { longitude, latitude, height } = cesiumConfig.defaultView;
        this.viewer.camera.flyTo({
            destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, height)
        });
    }
    
    destroy() {
        if (this.viewer) {
            this.viewer.destroy();
            this.viewer = null;
        }
    }
}

2.6 开发工具与调试

2.6.1 VS Code 扩展推荐

扩展名 用途
ESLint 代码质量检查
Prettier 代码格式化
JavaScript (ES6) code snippets 代码片段
GitLens Git 增强
Live Server 本地服务器

2.6.2 浏览器开发者工具

Chrome DevTools 使用技巧:

// 在控制台访问 viewer
window.viewer = viewer;

// 查看当前相机位置
console.log(viewer.camera.positionCartographic);

// 查看场景帧率
viewer.scene.debugShowFramesPerSecond = true;

// 查看 3D Tiles 调试信息
viewer.extend(Cesium.viewerCesium3DTilesInspectorMixin);

2.6.3 性能监控

// 启用帧率显示
viewer.scene.debugShowFramesPerSecond = true;

// 监控内存使用
setInterval(() => {
    const memory = performance.memory;
    console.log('内存使用:', {
        usedJSHeapSize: (memory.usedJSHeapSize / 1024 / 1024).toFixed(2) + ' MB',
        totalJSHeapSize: (memory.totalJSHeapSize / 1024 / 1024).toFixed(2) + ' MB'
    });
}, 5000);

2.7 常见问题解决

2.7.1 跨域问题

// 如果遇到 CORS 问题,可以配置代理
// vite.config.js
export default defineConfig({
    server: {
        proxy: {
            '/api': {
                target: 'https://your-server.com',
                changeOrigin: true,
                rewrite: (path) => path.replace(/^\/api/, '')
            }
        }
    }
});

2.7.2 资源加载失败

// 检查静态资源路径
// 确保 Cesium 静态资源可访问
window.CESIUM_BASE_URL = '/node_modules/cesium/Build/Cesium/';

// 或者在 Vite 中使用插件自动处理
import cesium from 'vite-plugin-cesium';

2.7.3 WebGL 兼容性

// 检查 WebGL 支持
if (!Cesium.FeatureDetection.supportsWebGL2()) {
    console.warn('您的浏览器不完全支持 WebGL 2.0');
}

// 降级配置
const viewer = new Cesium.Viewer('cesiumContainer', {
    contextOptions: {
        webgl: {
            alpha: false,
            depth: true,
            stencil: false,
            antialias: true,
            premultipliedAlpha: true,
            preserveDrawingBuffer: false,
            powerPreference: 'high-performance'
        }
    }
});

2.8 本章小结

本章介绍了 CesiumJS 的环境搭建和快速开始:

  1. 开发环境:Node.js、npm、现代浏览器
  2. 项目创建方式
    • CDN 直接引入
    • npm + Vite
    • Vue 3 集成
    • React 集成
  3. Cesium ion:注册账号、获取访问令牌
  4. 第一个应用:完整示例代码和解析
  5. 项目结构:推荐的目录组织
  6. 开发工具:VS Code 扩展、浏览器调试

在下一章中,我们将深入了解 CesiumJS 的核心架构与模块设计。

2.9 思考与练习

  1. 尝试使用不同方式创建 CesiumJS 项目,比较各自的优缺点。
  2. 修改示例代码,添加更多按钮和功能。
  3. 尝试在 Vue 或 React 项目中集成 CesiumJS。
  4. 探索 Cesium ion 平台,了解可用的数据资源。
  5. 使用浏览器开发者工具,观察 CesiumJS 的网络请求和性能指标。
posted @ 2026-01-08 11:13  我才是银古  阅读(13)  评论(0)    收藏  举报