对于初学者来说,引入CesiumJS是最重要的一步,此文章主要说四种引入方式,vue3和vue2的引入方式基本没有什么区别,都可以用这四种方式。
1、vue-cli-plugin-cesium插件引入
2、npm引入vue-cesium
3、CDN引入
4、手动引入
一、vue-cli-plugin-cesium(仅支持vue-cli3.0+)
简单说就是将Cesium通过插件实现零配置,因为每次配置太麻烦,需要用copy-webpack-plugin插件配置webpack,也就是vue-cli版本小于3.0,配置如下:
...
plugins: [
new CopyWebpackPlugin([{
from: path.join(cesiumSource, cesiumWorkers),
to: "Workers"
}, ]),
new CopyWebpackPlugin([{
from: path.join(cesiumSource, "Assets"),
to: "Assets"
}, ]),
new CopyWebpackPlugin([{
from: path.join(cesiumSource, "Widgets"),
to: "Widgets"
}, ]),
new CopyWebpackPlugin([{
from: path.join(cesiumSource, "ThirdParty/Workers"),
to: "ThirdParty/Workers",
}, ]),
new webpack.DefinePlugin({
CESIUM_BASE_URL: JSON.stringify("./"),
}),
// 使Cesium对象实例可在每个js中使用而无须import
new webpack.ProvidePlugin({
Cesium: ["cesium/Source/Cesium"]
})
]
...
CESIUM_BASE_URL是Cesium中内置的全局变量
// cesium-1.96 Source/Core/buildModuleUrl.js
...
const cesiumScriptRegex = /((?:.*\/)|^)Cesium\.js(?:\?|\#|$)/;
function getBaseUrlFromCesiumScript() {
const scripts = document.getElementsByTagName("script");
for (let i = 0, len = scripts.length; i < len; ++i) {
const src = scripts[i].getAttribute("src");
const result = cesiumScriptRegex.exec(src);
if (result !== null) {
return result[1];
}
}
return undefined;
}
...
// 不配置的话,默认是 /Cesium/,所以这也是为什么手动引入是创建一个静态文件夹Cesium
详情参见:vue3.x +Cesium vue3.x中安装使用cesium
vue-cli-plugin-cesium安装完之后,需要使用vue invoke初始化
npm install --save-dev vue-cli-plugin-cesium
vue invoke vue-cli-plugin-cesium
// 可选择是否在main.js中引入Widgets.css
// 可选择是否在compontents/下生成示例文件
详情参见:让GIS三维可视化变得简单-Vue项目中集成Cesium
配置完之后就可以在页面中直接使用Cesium对象
<template>
<div class="cesiumContainer">
<div id="content-map" class="cesiumContainer-map" ref="targetDom"></div>
</div>
</template>
<script>
export default {
mounted() {
// 实例化Cesium对象
window.viewer = new Cesium.Viewer(node, {
// 导航帮助按钮
navigationHelpButton: false,
// Geocoder小部件(搜索)
geocoder: false,
// 时钟尝试延长仿真时间
shouldAnimate: true,
// HomeButton小部件
homeButton: true,
// SceneModePicker小部件(2/3维切换)
sceneModePicker: true,
// 创建动画组件
animation: true,
// 创建图层组件
baseLayerPicker: false,
timeline: true,
vrButton: false,
infoBox: false,
// 相机选中方框
// selectionIndicator: false,
fullscreenButton: true,
// imageryProvider: imgProvider,
// 默认地形,高度为0
// terrainProvider: Cesium.EllipsoidTerrainProvider()
});
// cesium 版本
console.log(Cesium.VERSION);
},
methods: {},
destroyed() {
let gl = viewer.scene.context._originalGLContext;
viewer.destroy();
viewer = null;
gl.getExtension("WEBGL_lose_context").loseContext();
gl = null;
},
};
</script>
<style lang="scss" scoped>
.cesiumContainer {
position: relative;
width: 100%;
height: 100%;
z-index: 0;
background: #000;
&-map {
width: 100%;
height: 100%;
}
}
</style>
这里面有一个问题,是初始化时会发送endPoint请求,因为Cesium默认是请求Cesium Ion的资源,这是国外网站,请求比较慢,长时间连接不上就会处于pendding状态。一般是两种方式处理;1、将地形服务给一个默认的底图
// 第一种,给定一张全球图片,替换默认底图
let layer = {
url: require("@/assets/img/world.jpg"),
name: "地图",
rectangle: [-180, -90, 180, 90],
};
let imgProvider = new Cesium.SingleTileImageryProvider({
url: layer.url,
credit: layer.name,
rectangle: Cesium.Rectangle.fromDegrees(
layer.rectangle[0],
layer.rectangle[1],
layer.rectangle[2],
layer.rectangle[3]
),
});
// 第二种,设置一个纯色canvas
let imgProvider = new Cesium.SingleTileImageryProvider({
url: createColorCanvas("#FFF"),
rectangle: Cesium.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0)
})
window.viewer = new Cesium.Viewer({
...
baseLayerPicker: false,//隐藏默认底图选择控件
imageryProvider: imgProvider,
...
});
// cesium 版本
console.log(Cesium.VERSION);
function createColorCanvas(color) {
var width = 1, height = 1;
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d');
ctx.fillStyle = color;
ctx.fillRect(0, 0, width, height);
return canvas.toDataURL();
}
2、cesium ion官网申请token配置defaultAccessToken
// 尽量使用自己申请的token,别人的token容易改变,会导致一些错误
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI1Mzk1NjEyMS03YzU2LTRiODgtOGU5NC05NmFhZmY4MjEzYWUiLCJpZCI6NzY0NDMsImlhdCI6MTYzOTQ1OTg5Nn0.2MTeUJoeMx_j3Auv9agF_sT4k73RAJWz9xt2VmFikdw';
window.viewer = new Cesium.Viewer({
...
baseLayerPicker: false,//隐藏默认底图选择控件
imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
name: "img_arcgis",
url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"
}),
...
});
// 这个请求的是一个在线底图
详情参加: Cesium避免endPoint请求
二、npm引入vue-cesium
1、安装vue-cesium
npm i vue-cesium@2.3.4
全局配置:main.js中配置
import lang from 'vue-cesium/lang/zh-hans'
import VueCesium from 'vue-cesium'
Vue.use(VueCesium, {
// cesiumPath 是指引用的Cesium.js路径,如
// 项目本地的Cesium Build包,vue项目需要将Cesium Build包放static目录:
// cesiumPath: /static/Cesium/Cesium.js
// 个人在线Cesium Build包:
// cesiumPath: 'https://zouyaoji.top/vue-cesium/statics/Cesium/Cesium.js'
// 个人在线SuperMap Cesium Build包(在官方基础上二次开发出来的):
// cesiumPath: 'https://zouyaoji.top/vue-cesium/statics/SuperMapCesium/Cesium.js'
// 官方在线Cesium Build包,有CDN加速,推荐用这个:
cesiumPath: 'https://unpkg.com/cesium@1.100/Build/Cesium/Cesium.js',
// 指定Cesium.Ion.defaultAccessToken,使用Cesium ion的数据源需要到https://cesium.com/ion/申请一个账户,获取Access Token。不指定的话可能导致 Cesium 在线影像加载不了
accessToken: 'Your Cesium Ion defaultAccessToken',
baseLayerPicker: false,
lang
})
如果不配置cesiumPath的话,也可以将Cesium源码包拷贝到static/public中,在index.html中通过script引入,适配离线开发
用法如下:
<template>
<vc-viewer class="viewer" :animation="animation" :timeline="timeline" :camera.sync="camera" @ready="ready">
<vc-layer-imagery>
<vc-provider-imagery-openstreetmap></vc-provider-imagery-openstreetmap>
</vc-layer-imagery>
</vc-viewer>
</template>
<script>
export default {
data() {
return {
animation: true,
timeline: true,
camera: {
position: {
lng: 104.06,
lat: 30.67,
height: 100000
},
heading: 360,
pitch: -90,
roll: 0
}
}
},
methods: {
ready(cesiumInstance) {
const { Cesium, viewer } = cesiumInstance
viewer.entities.add({
id: '成都欢迎你',
position: Cesium.Cartesian3.fromDegrees(104.06, 30.67, 100),
billboard: new Cesium.BillboardGraphics({
image: 'https://www.qianduange.cn/upload/article/favicon.png',
scale: 0.1
}),
label: new Cesium.LabelGraphics({
text: 'Hello Word',
fillColor: Cesium.Color.GOLD,
font: '24px sans-serif',
horizontalOrigin: 1,
outlineColor: new Cesium.Color(0, 0, 0, 1),
outlineWidth: 2,
pixelOffset: new Cesium.Cartesian2(17, -5),
style: Cesium.LabelStyle.FILL
})
})
}
}
}
</script>
<style>
.viewer {
width: 100%;
height: 400px;
}
</style>
vue-cesium对vue2.x和3.x有区别,更多的配置和用法可以参见API:Vue Cesium
三、CDN引入
在html中头部引入
<script src="https://cesium.com/downloads/cesiumjs/releases/1.83/Build/Cesium/Cesium.js"></script>
<link rel="stylesheet" href="https://cesium.com/downloads/cesiumjs/releases/1.83/Build/Cesium/Widgets/widgets.css">
创建应用
import * as Cesium from 'Cesium'
window.viewer = new Cesium.Viewer('dom', {
...
})
参见详情 :【一文带你cesium入门】
四、手动引入(离线开发)
1、在static/public下创建Cesium文件夹,原因在上面已经说过了,也可以自由创建,然后对应配置CESIUM_BASE_URL,将node_modules中的cesium/Build/CesiumUnminifed/未压缩的文件夹全部拷贝到新建文件夹下,即Assets、Widgets、Workers、ThirdParty
补充一点,如何更改天空盒
// Cesium/Assets/Textures/SkyBox ,这是打包之后本来就有的文件夹,所以下面的/startmap_2020_16k是再这下面创建文件夹
let groundSkybox = new Cesium.SkyBox({
sources: {
positiveX: "/starmap_2020_16k/starmap_2020_16k_px.jpg",
negativeX: "/starmap_2020_16k/starmap_2020_16k_mx.jpg",
positiveY: "/starmap_2020_16k/starmap_2020_16k_py.jpg",
negativeY: "/starmap_2020_16k/starmap_2020_16k_my.jpg",
positiveZ: "/starmap_2020_16k/starmap_2020_16k_pz.jpg",
negativeZ: "/starmap_2020_16k/starmap_2020_16k_mz.jpg",
},
});
viewer.scene.skyBox = groundSkybox;
2、在index.html中引入
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="/favicon.ico">
<script type="text/javascript" src="/config/settings.js"></script>
<title></title>
</head>
<body>
<div id="app">
</div>
<script type="module" src="/src/main.js"></script>
<script src="/Cesium/Cesium.js"></script>
</body>
</html>
css直接从Cesium中引入import 'Cesium/Source/Widgets/widgets.css';可能会报错,参见详情:解决cesium widgets.css is not exported from package
所以一般是将Cesium/Widgets/widgets.css拷贝一份出来,再在main.js中引入
// main.js
import '@/assets/styles/cesium-widgets.css'
一些cesium的样式更改就在这个文件里改就行了
其实这会可以不用再安装Cesium了,也就是node_modules中不需要cesium源码包了,程序也是可以正常运行的
五、总结
这篇文章并没有从优化、打包、最优引入方面来分析,仅仅是列出了几种引入方式,主要是在平常开发中,这些也确实够了,最近又看了一位博主的文章,已经说的很明白了,从Cesium前置知识、到打包优化、再到选择最优引入,这一篇文章已经够用了。
参见详情:教程 - 在 Vue3+Ts 中引入 CesiumJS 的最佳实践@2023