事前准备
获取个人token
首先要去Cesium Ion注册页面注册个人账号
注册成功后进入token获取页面,页面右边的Default Token栏 - token框内字符即是要用到的个人token【重要】
一、 配置Cesium并初始化
配置cesium
见同文集下vue+cesium环境搭建
cesium初始化
首先在初始化的地球场景里添加一点地形嗷,这些东西默认配置在Cesium ion账户里
- Cesium World Terrain: 精度可达1米的高分辨率地形库
- Cesium OSM Buildings: 开源地图( Open Street Map, OSM) 的建筑物数据库
- Bing Maps Aerial Imagery: 分辨率高达15cm的全球卫星图像(这个已经用来捏地球了)
官网教程里是加在index.html里的,不过用的是vue+cesium,这里就改成加到App.vue的mounted()生命周期函数里
其实就是在初始化地球代码上面加一行然后下面再加一行的事
原始的初始化地球部分代码:
<script>
export default {
name: 'App',
mounted () {
const viewer = new Cesium.Viewer('cesiumContainer')
}
}
</script>
改了以后:
<script>
export default {
name: 'App',
mounted () {
// 添加个人Token以使应用程序得以访问cesiumIon中的所有资源
Cesium.Ion.defaultAccessToken = 'your_token_here'
// 创建观察器,并附加到id为“cesiumContainer”的div上
// new Cesium.Viewer(container, options) 基本组件,将所有组件组合成可复用包
const viewer = new Cesium.Viewer('cesiumContainer', {
// 增加Cesium世界地形数据
terrainProvider: Cesium.createWorldTerrain()
})
// 将osm建筑物的3D瓦片数据添加进观察器中
const osmBuildings = viewer.scene.primitives.add(Cesium.createOsmBuildings()) // eslint-disable-line no-unused-vars
}
}
</script>
总(人)结(话):在地球仪初始化地球上捏出来相应地形变成凹凸不平的地球仪,然后把建筑物放上去
二、数据坐标可视化
跟着新手教程入门就直接用官网的数据和代码了,官网说其实还可以下载航班的原始数据,或者自己修改代码,从服务器拿数据然后动态显示实时空中交通情况
这部分是在地球上放一个点,然后拉近镜头到那个点上
单击那个点能看到描述信息,比如位置啊时间啊什么的
接在放建筑物后面:
// 从飞机身上收集到的第一个雷达坐标.用经纬度和高度来描述飞机在哪
const dataPoint = { longitude: -122.38985, latitude: 37.61864, height: -27.32 }
// 在地球上把这个坐标用红点标出来.
const pointEntity = viewer.entities.add({
// 给出描述信息【这里要用tab键上的`包起来】
description: `First data point at (${dataPoint.longitude}, ${dataPoint.latitude})`,
// 给出位置信息 要把经纬度和高度转化成地心地固坐标系(Earth-Centered, Earth-Fixed,ECEF),即一种笛卡尔坐标系
position: Cesium.Cartesian3.fromDegrees(dataPoint.longitude, dataPoint.latitude, dataPoint.height),
// 这个点具体有多大,上什么色
point: { pixelSize: 10, color: Cesium.Color.RED }
})
// 让相机镜头拉近到这个点这里.
viewer.flyTo(pointEntity)
画一个点大概就是这样啦
是不是很简单
好 然后我们开始学高数把所有坐标都用点表示出来
//用这个替换上面只画一个点的
// 用JSON.parse方法把从服务器收到的字符串转换为JS对象
const flightData = JSON.parse(
// 数据太多了 麻烦自己去官网复制好吧
'[{"longitude":-122.39053,"latitude":37.61779,"height":-27.32}]'
);
// 根据每个坐标画点.没什么好说的 就是用for函数遍历一遍
for (let i = 0; i < flightData.length; i++) {
const dataPoint = flightData[i];
viewer.entities.add({
description: `Location: (${dataPoint.longitude}, ${dataPoint.latitude}, ${dataPoint.height})`,
position: Cesium.Cartesian3.fromDegrees(dataPoint.longitude, dataPoint.latitude, dataPoint.height),
point: { pixelSize: 10, color: Cesium.Color.RED }
});
}
这步写好之后就能看到从旧金山停机坪一直到哥本哈根的飞行轨迹了
就是先把轨迹用点画出来
拜托 超酷的好吗
三、动态轨迹可视化
好 现在已经画好轨迹了 然后要把飞机放上去让它顺着轨迹跑了
CesiumJS内置了对随时间推移进行插值采样的支持 就很好嗷 就看用户会不会用了
那么问题来了 要咋整呢
就给每个位置配一个时间戳,告诉飞机说好 在这个时间点你该飞到这里了
那么问题又来了 怎么写代码呢
哈哈 这次把除了token到收服务器数据以外的代码都要删掉 惊不惊喜意不意外不是 注掉就行 万一还要排查问题呢
/* 初始化取景器计时器
* 设所有雷达坐标的间隔均为30s,以此计算总的航班持续时间
* 算出航班的开始时间和结束时间,其中开始时间为已知的航班出发时间,结束时间是开始时间和总持续时间的总和
* 通过将航班的开始和结束时间设置为起点和终点来初始化取景器的计时器
* 同时将取景器的当前时间设置为计时器开始时间 */
// 时间间隔30s
const timeStepInSeconds = 30
// 总时长为时间间隔 * (雷达点数 - 1)
const totalSeconds = timeStepInSeconds * (flightData.length - 1)
// 设置开始时间,使用根据国际标准ISO8601时间转换的儒略历时间
const start = Cesium.JulianDate.fromIso8601('2020-03-09T23:10:00Z')
// 新建一个实例并将其设置为结束时间,结束时间为起点加上总时长
const stop = Cesium.JulianDate.addSeconds(start, totalSeconds, new Cesium.JulianDate())
// 生成开始时间的副本,并令其为取景器计时器的起点
viewer.clock.startTime = start.clone()
viewer.clock.stopTime = stop.clone()
// 令取景器的当前时间为开始时间
viewer.clock.currentTime = start.clone()
// 用开始时间和结束时间设置取景器的时间线
viewer.timeline.zoomTo(start, stop)
// 将播放速度设置为50倍
viewer.clock.multiplier = 50
// 允许加速播放
viewer.clock.shouldAnimate = true
// 取样位置 相当于一个集合
const positionProperty = new Cesium.SampledPositionProperty()
// 为每个雷达坐标建立对应时间和位置信息的实体点
for (let i = 0; i < flightData.length; i++) {
const dataPoint = flightData[i]
const time = Cesium.JulianDate.addSeconds(start, i * timeStepInSeconds, new Cesium.JulianDate())
const position = Cesium.Cartesian3.fromDegrees(dataPoint.longitude, dataPoint.latitude, dataPoint.height)
// 添加位置,和时间对应
positionProperty.addSample(time, position)
viewer.entities.add({
description: `Location: (${dataPoint.longitude}, ${dataPoint.latitude}, ${dataPoint.height})`,
position: position,
point: { pixelSize: 10, color: Cesium.Color.RED }
})
}
// 添加飞机实体
const airplaneEntity = viewer.entities.add({
availability: new Cesium.TimeIntervalCollection([ new Cesium.TimeInterval({ start: start, stop: stop }) ]),
position: positionProperty,
point: { pixelSize: 30, color: Cesium.Color.GREEN },
path: new Cesium.PathGraphics({ width: 3 })
});
// 设置镜头跟随飞机实体.
viewer.trackedEntity = airplaneEntity;
这一步完成的就是给轨迹上的点标出先后顺序,起点终点,规定每个点之间要用多少秒跑完,告诉飞机每个点的信息,然后把飞机放到轨迹上让它开始跑,同时镜头跟随飞机
但是还没设置飞行模型,所以现在还看不到飞机,只能看到代表飞机的绿点在跑
不过还是超酷的好吗
四、创建并载入飞机模型
最后一步就是用飞机模型替代绿点了!
首先把绿点那部分的代码删掉或者注掉
网络状况优秀的话这么整
网好的话可以直接下载模型,然后把文件拖进自己的acconut dashboard页面,在下拉框内选3D Model (Convert to glTF),然后点击上传Upload.
上传完以后可以在asset列表里点选模型,在预览preview窗口记住Name框右边(ID:xxxxxx)里的数字 然后用数字替换创建airplaneUri代码部分的your_asset_id
// 设置飞机模型
async function loadModel () {
// 获取模型数据路径
const airplaneUri = await Cesium.IonResource.fromAssetId(your_asset_id)
// 将模型添加到轨迹上
const airplaneEntity = viewer.entities.add({
// 和时间轴关联
availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({start: start, stop: stop})]),
// 设置位置
position: positionProperty,
// 模型数据
model: { uri: airplaneUri },
// 根据所提供的速度计算模型朝向
orientation: new Cesium.VelocityOrientationProperty(positionProperty),
// 飞行路径
path: new Cesium.PathGraphics({width: 3})
})
// 令取景器视角固定跟随飞机
viewer.trackedEntity = airplaneEntity
}
// 上传飞机模型
loadModel()
网络状况不好的话这么整
网不好的话就不容易拿到在线资源对不对
那把它放到本地不就得了!
把下载下来的包解压到项目文件夹 - static文件夹里,然后把模型数据路径改成后缀为.gltf的文件所在的路径
也就是改这行:
const airplaneUri = 'static/xxxx.gltf' // 改成自己放gltf文件的路径
然后就真的完事了!
恭喜你获得一架沿着轨迹从旧金山咻咻咻飞到哥本哈根的小飞机!
五、完整代码
本来是想放的
但是那个数据量太多了
去[官网教程](Build a Flight Tracker – Cesium)那里看Complete source code吧
踩到的坑
-
ESLint: Unexpected template string expression. (no-template-curly-in-string)
-
原因:
const pointEntity = viewer.entities.add({ // eslint-disable-line no-unused-vars description: 'First data point at (${dataPoint.longitude}, $(dataPoint.latitude))',
其中description冒号后应该用tab键上的`括起来,而不是用'
-
办法:
用`替换'
-
-
设置飞机模型的时候无法显示
原因:使用cesium Ion - My assets里的在线资源作为模型,然而网速太慢 卡住了
-
办法:用本地模型替换在线资源
在项目的static文件夹里新建文件夹并导入本地资源,然后修改模型数据路径为相应路径
题外话
今天是国际劳动妇女节,祝所有劳动妇女特别是程序媛们节日快乐:)
春有约 花不误 年年岁岁不相负