目录
前言
本文涉及Cesium加载JSON数据、异步操作、Promise对象的知识完成边界数据的加载,后续会以此为基础进行简单的拓展。诸如地图层次下钻以及信息弹窗。
一、加载地球
<template>
<div id="viewerDiv"></div>
</template>
<script setup lang="ts">
import { onMounted } from "vue";
import * as Cesium from "cesium";
import { createBaseViewer } from "../utils/createBaseViewer";
let viewer: Cesium.Viewer;
function createViewer() {
viewer = createBaseViewer(viewer, "viewerDiv", ["vec", "w"]);
}
onMounted(() => {
createViewer();
});
</script>
<style scoped>
#viewerDiv {
position: absolute;
width: 100%;
height: 100%;
}
</style>
对加载地球有疑惑的可以看我之前的文章
二、加载JSON数据
1.获取JSON数据
从上面的链接可以获取到行政区边界的JSON数据
我们先选个不包含子区域的中国边界数据:https://geo.datav.aliyun.com/areas_v3/bound/100000.json
可以直接下载本地加载,这里我们就直接通过url加载
2.加载数据
Cesium提供GeoJsonDataSource.load()这个函数能够读取JSON数据
其中data可以是一个url、或者一个JSON以及Topo数据对象,当然本地文件路径也是可以的。注意的是它返回的是Promise对象,有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。其他Promise对象的知识本文不过多阐述建议参考其他文章。
需要注意的是这是一个异步操作,这意味着执行这个操作不会立即完成。它会先返回一个Promise对象,然后继续执行后面的操作,如果后面紧接着调用数据而Promise对象还处于pending
(进行中)或者rejected
(已失败)会调用数据失败导致报错。后面我会谈到如何处理这个问题。
完成JSON数据的读取,接下来就是加载到viewer中,通过dataSources.add(),它能加载DataSource或者Promise对象封装的DataSource
function loadGeoJson() {
viewer.dataSources.add(
Cesium.GeoJsonDataSource.load(
"https://geo.datav.aliyun.com/areas_v3/bound/100000.json"
)
);
}
这样我们就完成了最简单的JSON数据加载,但这样看太单调,我们可以利用GeoJsonDataSource.load()中的option参数(可选)进行简单的调整
function loadGeoJson() {
viewer.dataSources.add(
Cesium.GeoJsonDataSource.load(
"https://geo.datav.aliyun.com/areas_v3/bound/100000.json", {
stroke: Cesium.Color.RED, //边界线颜色
fill: Cesium.Color.BLUE.withAlpha(0.5), //填充色
strokeWidth: 10 //边界线宽度
}
)
);
}
这只是一个中国边界数据,我们还可以同时加载多个边界数据
https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json
这样我们就能看到中国各个省份的边界数据,但这样太难辨识。我们可以遍历数据中的每一个边界数据进行调整。
async function loadGeoJson(adcode: number) {
// 从指定的URL加载GeoJson数据,参数为adcode
await Cesium.GeoJsonDataSource.load(
`https://geo.datav.aliyun.com/areas_v3/bound/${adcode}_full.json`,
{
}
).then((dataSource: Cesium.GeoJsonDataSource) => {
// 将加载的GeoJson数据添加到viewer中
viewer.dataSources.add(dataSource);
// 获取dataSource中的entities
let entities = dataSource.entities.values;
// 遍历entities中的每一个entity
entities.forEach((entity) => {
// 获取entity的颜色(随机生成颜色,并设置entity的material)
let color: Cesium.Color = Cesium.Color.fromRandom({ alpha: 0.2 }); //透明度调整为0.2
// 设置entity的material
if (entity.polygon) {
entity.polygon.material = new Cesium.ColorMaterialProperty(color);
(entity.polygon.outline as unknown) = false;
(entity.polygon.extrudedHeight as unknown) = 20000; //高度扩大20000倍,便于观察!
}
});
});
//移动视角
viewer.flyTo(viewer.dataSources.get(viewer.dataSources.length - 1));
console.log(viewer.dataSources.get(viewer.dataSources.length - 1));
}
我们一步步来解读这段代码。
1.首先第一步读取JSON数据,当Promise对象状态为fulfilled
(已成功)也就是读取成功时,执行then中的箭头函数,箭头函数传入的参数就是完成读取后的JSON数据。(rejected
(已失败)也可以执行then,但我没有编写失败执行的代码)
2.第二步加载GeoJson数据到viewer中
3.第三步为核心,dataSource中包含了多个entity也就是边界面数据entity,篇幅关系我就不一一在控制台输出展示了。
所以我们利用forEach对dataSource中的每一个entity进行遍历修改。在循环中,随机生成一种透明度为20%的颜色,并修改entity.polygon.material(面要素纹理),这里我们借助Cesium.ColorMaterialProperty构造函数修改成随机生成的颜色。这里不直接设置的原因是ts的类型约束会导致报错
但是程序是能够正确执行的,嫌麻烦可以直接不管或者//@ts-ignore取消报错。当然最好还是查阅一下官方的API解决类型问题,后面两步嫌麻烦我直接as unknown。
4.最后一步移动视角到我们加载的最新dataSources
三.异步操作注意事项
loadGeoJson()中我使用了async、await关键字(详情建议参考其他文章),前面我提到了异步操作的问题,async用于声明一个函数是一个异步函数,而await就是等待Promise对象处理完成返回fulfilled
(已成功)或者rejected
(已失败),再执行后边的操作。如果Promise对象处理完成就会执行then。
加了async、await关键字的执行顺序
不加的情况
如果不加async、await关键字的话,会先执行移动视角,但此时数据还未加载成功,程序就会发生错误
值得一提的是,只有async声明的函数内部会受await的限制等待,外部不会受影响照常执行
完整代码
<template>
<div id="viewerDiv"></div>
</template>
<script setup lang="ts">
import { onMounted } from "vue";
import * as Cesium from "cesium";
import { createBaseViewer } from "../utils/createBaseViewer";
let viewer: Cesium.Viewer;
function createViewer() {
viewer = createBaseViewer(viewer, "viewerDiv", ["vec", "w"]);
}
async function loadGeoJson(adcode: number) {
// 从指定的URL加载GeoJson数据,参数为adcode
await Cesium.GeoJsonDataSource.load(
`https://geo.datav.aliyun.com/areas_v3/bound/${adcode}_full.json`,
{
}
).then((dataSource: Cesium.GeoJsonDataSource) => {
// 将加载的GeoJson数据添加到viewer中
viewer.dataSources.add(dataSource);
// 获取dataSource中的entities
let entities = dataSource.entities.values;
// 遍历entities中的每一个entity
entities.forEach((entity) => {
// 获取entity的颜色(随机生成颜色,并设置entity的material)
let color: Cesium.Color = Cesium.Color.fromRandom({ alpha: 0.2 }); //透明度调整为0.2
// 设置entity的material
if (entity.polygon) {
entity.polygon.material = new Cesium.ColorMaterialProperty(color);
(entity.polygon.outline as unknown) = false;
(entity.polygon.extrudedHeight as unknown) = 20000; //提高高度赋予立体效果
}
});
});
//移动视角
viewer.flyTo(viewer.dataSources.get(viewer.dataSources.length - 1));
console.log(viewer.dataSources.get(viewer.dataSources.length - 1));
}
onMounted(() => {
createViewer();
loadGeoJson(100000);
});
</script>
<style scoped>
#viewerDiv {
position: absolute;
width: 100%;
height: 100%;
}
</style>