发布于 

Cesium实现加载GIS数字地球

前言

本文主要实现使用vue3 + cesium绘制GIS数字地球,并实现点击事件

前置准备

安装cesium

此处注意,cesium不同版本之间有着差异,并不是最新版本就是最好的,对于项目来说,实用优先。

1
npm install cesium@1.76.0

复制目录

在node_modules中找到cesium,拷贝到项目/public下,保留Build和Source文件夹,其他文件删掉。
20240416132257

找到index.html,引入资源

1
2
<link rel="stylesheet" href="/cesium/Build/Cesium/Widgets/widgets.css" />
<script src="/cesium/Build/Cesium/Cesium.js"></script>

GisMap组件

components中新建文件夹GisMap,目录下新建两个文件,cesium.ts和index.vue

cesium.ts代码逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import * as Cesium from 'cesium';

export default class CesiumTemplate {
public static viewer: Cesium.Viewer;

// 初始化
public static initMap() {
this.viewer = new Cesium.Viewer('map', {
imageryProvider: new Cesium.UrlTemplateImageryProvider({
url: 'http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}', // 瓦片地址
maximumLevel: 18 // 最大缩放等级
}),
// 以下都是cesium配置项,按需配置
animation: false,
shouldAnimate: false,
homeButton: false,
fullscreenButton: false,
baseLayerPicker: false,
geocoder: false,
timeline: false,
shadows: false,
navigationHelpButton: false,
infoBox: false,
requestRenderMode: false,
scene3DOnly: false,
sceneMode: Cesium.SceneMode.SCENE3D,
maximumRenderTimeChange: 1,
sceneModePicker: false,
selectionIndicator: false,

// 设置渲染
orderIndependentTranslucency: false,
contextOptions: {
webgl: {
alpha: true
}
}
});

//隐藏版权信息
(this.viewer.cesiumWidget.creditContainer as HTMLElement).style.display = 'none';

// 相机位置
this.viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(120, 48, 25000000)
});

return this.viewer;
}

// 添加点
public static addPoint(option: any) {
const entity = new Cesium.Entity({
name: option.name,
position: Cesium.Cartesian3.fromDegrees(option.longitude, option.latitude, option.altitude),
point: {
pixelSize: 5,
color: Cesium.Color.BLUE,
outlineColor: Cesium.Color.fromCssColorString('yellow'),
outlineWidth: 1,
show: true
},
// 文字
label: {
text: option.name,
font: '14pt Source Han Sans CN',
fillColor: Cesium.Color.AQUA,
backgroundColor: Cesium.Color.AQUA,
showBackground: false,
outlineColor: Cesium.Color.BLACK,
outlineWidth: 10,
scale: 1,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
verticalOrigin: Cesium.VerticalOrigin.TOP,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
show: true
}
});
this.viewer.entities.add(entity);
return entity;
}
}

index.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<template>
<div id="map"></div>
</template>

<script lang="ts" setup>
import * as Cesium from 'cesium';
import CesiumContainer from "./cesium";
import { ref, unref } from 'vue';

const emit = defineEmits(['point-click']);
const viewer = ref<Cesium.Viewer>();

// 初始化地图
const initGisMap = () => {
viewer.value = CesiumContainer.initMap();
bindClick();
}

// 绑定点击事件
const bindClick = () => {
const handler = new Cesium.ScreenSpaceEventHandler(unref(viewer)?.scene.canvas);
handler.setInputAction((click) => {
const pickedObject = unref(viewer)?.scene.pick(click.position);
// 坐标系转换,点击缩放
if (Cesium.defined(pickedObject)) {
let earthPosition: any = unref(viewer)?.scene.pickPosition(click.position);
let cartographic = Cesium.Cartographic.fromCartesian(earthPosition);
let longitude = Cesium.Math.toDegrees(cartographic.longitude);
let latitude = Cesium.Math.toDegrees(cartographic.latitude);
if (Cesium.defined(earthPosition)) {
unref(viewer)?.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, 2000000)
})
}
emit("point-click", pickedObject.id)
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}

// 添加点
const addPoint = (options?: any) => {
CesiumContainer.addPoint(options)
}

defineExpose({
initGisMap,
addPoint
})
</script>

<style>
html,
body,
#map {
width: 100vw;
height: 100vh;
padding: 0;
margin: 0;
overflow: hidden;
}
</style>

在页面中引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<template>
<div>
<!--...页面其他DOM-->
<Map ref="gisMap" @point-click="onPointClick" class="map-container" />
</div>
</template>
<script setup lang="ts">
import { onMounted, unref, ref } from 'vue';
import Map from '@/components/map/index.vue';

const gisMap = ref();

onMounted(async () => {
await unref(gisMap).initGisMap();
unref(gisMap).addPoint({
name: "A点",
longitude: 120,
latitude: 48,
altitude: 1056,
})
});

const onPointClick = (entity: any) => {
console.log(entity);
alert('点击了' + entity.name);
}
</script>

<style lang="scss" scoped>
.map-container {
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
overflow: hidden;
}
</style>

GIS瓦片资源

高德街道:http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}

高德卫星图:http://webst02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=6&x={x}&y={y}&z={z}

GeoQ彩色:https://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer/tile/{z}/{y}/{x}

GeoQ灰色:http://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetGray/MapServer/tile/{z}/{y}/{x}

OpenStreetMap Mapnick http://tile.openstreetmap.org/{z}/{x}/{y}.png

OSM Cycle Map http://tile.thunderforest.com/cycle/{z}/{x}/{y}.png

OSM Black and White http://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png

Esri Imagery/Satellite https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}

Esri Streets https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}

Esri Topo https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}

World Light Gray Base https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}

Carto Positron https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png

cartocdn light nolabels https://basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png

Stamen Terrain http://a.tile.stamen.com/terrain/{z}/{x}/{y}.png