这段代码定义了一个名为 Trajectory
的类,用于在 Cesium 中管理和展示轨迹。以下是对代码的详细解析,包括各个方法的功能和作用:
代码解析
-
构造函数:
constructor(options, map)
:接收配置选项和 Cesium 地图对象map
,并初始化各种属性。- 属性包括轨迹坐标、图标地址、缩放倍数、速度、颜色、图层 ID 等。
- 解析轨迹坐标、创建图层和元素。
-
轨迹坐标转换:
parsePath()
:将轨迹的 WKT 格式坐标转换为 Cesium 可用的笛卡尔坐标。- 使用正则表达式处理字符串,去掉多余的括号并转换为数组。
-
初始化图层:
createLayer()
:检查是否已存在指定 ID 的图层,若不存在则创建一个新的Cesium.CustomDataSource
。
-
获取地形高程:
getTerrainHeight(position)
:通过给定的 Cartesian3 坐标获取相应的地形高程,返回调整后的坐标。
-
获取当前点索引:
getCurrentIndex(time)
:根据当前时间获取轨迹坐标中对应的索引。
-
创建元素:
createFeature()
:创建未完成和已完成的轨迹实体。- 使用
Cesium.CallbackProperty
动态更新位置和线条的颜色,形成动画效果。
-
计算飞行路径:
createProperty()
:创建SampledPositionProperty
对象,计算每个轨迹点的时间,并将其添加到属性中。
-
设置速度:
setSpeed(speed)
:根据传入的速度更新播放速率。
-
播放与暂停:
play()
:设置播放状态为true
。paus()
:设置播放状态为false
。
-
移除元素:
remove()
:从图层中移除未完成和已完成的轨迹实体。
总结
Trajectory
类封装了轨迹的加载、展示和管理逻辑。它通过 Cesium 提供的 API,允许开发者创建动态的轨迹动画。- 类中使用
Cesium.CallbackProperty
来动态更新位置,形成实时动画效果。 - 通过设定速度、播放、暂停等方法,用户可以灵活控制轨迹的展示。
这段代码展示了如何利用 Cesium 的强大功能来实现复杂的地理空间可视化。
/**
* 轨迹
*/
class Trajectory{
/**
* 轨迹
* @param {Object} options
* @param {String} options.layerId 图层ID
* @param {String} options.path 轨迹坐标
* @param {String} options.url 图标地址
* @param {Number} options.scale 图标缩放倍数,默认1
* @param {Number} options.speed 图标运动速度,单位m/s 默认10
* @param {String} options.completedColor 已完成的轨迹颜色,默认值:ffff00
* @param {String} options.incompleteColor 未完成的轨迹颜色 默认值:00ff00
* @param {Number} options.lineWidth 轨迹线的颜色
* @param {map} map
* @example
*/
constructor(options,map){
this.path = options.path;
this.url = options.url;
this.scale = options.scale||1;
this.speed = options.speed||10;
this.completedColor = options.completedColor||'#ffff00';
this.incompleteColor = options.incompleteColor||'#00ff00';
this.layerId = options.layerId||'trajectoryLayer';
this.dataType = options.dataType||'wkt';
this.lineWidth = options.lineWidth||3;
this.layer = null;
this.timeConsumed = 0;
this.currentIndex = 0;
// 循环
this.loop = options.loop||false;
this.rate = 1;
this.isPlay = true;
this.map = map;
// wkt坐标转成笛卡尔坐标
this.parsePath()
this.createProperty()
// 创建图层
this.createLayer()
// 创建元素
this.createFeature();
}
/**
* 轨迹坐标转换
*/
parsePath(){
console.log('this.dataType',this.dataType);
let coords = this.map.typeDataChange({
type: this.dataType,
wkt: this.path,
})
// 去掉所有的[]括号,并在最外面添加一个[]
// 使用正则表达式替换所有出现的特定字符 "g" 标志表示全局搜索
var newStr = "[" + String(coords).replace(new RegExp("[" + "|" + "]", "g"), "") + "]"
let newCoords = JSON.parse(newStr)
this.points = Cesium.Cartesian3.fromDegreesArray(newCoords);
}
/**
* 初始化图层
*/
createLayer(){
// 没有图层则创建
let layers = this.map.viewer.dataSources.getByName(this.layerId)
if (layers.length == 0) {
// 未初始化过图层
const dataSource = new Cesium.CustomDataSource(this.layerId);
this.map.viewer.dataSources.add(dataSource);
this.layer = dataSource;
}else{
this.layer = layers[0]
}
}
/**
* 获取地形高程
* @param {*} position
* @returns
*/
getTerrainHeight(position){
let cartographic = Cesium.Cartographic.fromCartesian(position);
let height = this.map.viewer.scene.globe.getHeight(cartographic);
if(height){
let lon = cartographic.longitude;
let lat = cartographic.latitude;
return Cesium.Cartesian3.fromRadians(lon,lat,height)
}else{
return position
}
}
/**
* 获取当前点在的轨迹坐标中索引
* @param {*} time
* @returns
*/
getCurrentIndex(time){
let times = this.property._property._times;
for(let i = this.currentIndex,j = times.length;i<j;i++){
let t = Cesium.JulianDate.compare(time,times[i]);
if(t<0){
return i;
}
};
return 0;
}
/**
* 创建元素
*/
createFeature(){
let incompletePoints = this.points.slice(this.currentIndex);
let completedPoints = [];
let nowT = new Date()
// 未完成的轨迹
let entity = new Cesium.Entity({
position:new Cesium.CallbackProperty(()=>{
// 更新坐标
let t = new Date();
if(this.isPlay){
this.timeConsumed = this.timeConsumed+(t-nowT)*this.rate;
}
nowT = t;
t = Cesium.JulianDate.addSeconds(this.startTime, this.timeConsumed/1000, new Cesium.JulianDate);
let position = this.property.getValue(t,new Cesium.Cartesian3());
let count = this.getCurrentIndex(t);
if(this.currentIndex != count){
this.currentIndex = count;
}
if(position){
incompletePoints = [position].concat(this.points.slice(this.currentIndex));
completedPoints = this.points.slice(0,this.currentIndex).concat(position)
return this.getTerrainHeight(position)
}else{
if(this.loop){
this.timeConsumed = 0;
t = Cesium.JulianDate.addSeconds(this.startTime, this.timeConsumed/1000, new Cesium.JulianDate);
let position = this.property.getValue(t,new Cesium.Cartesian3());
if(position){
incompletePoints = [position].concat(this.points.slice(this.currentIndex));
completedPoints = this.points.slice(0,this.currentIndex).concat(position)
return this.getTerrainHeight(position)
}else{
this.currentIndex = 0;
incompletePoints = this.points.slice(this.currentIndex);
completedPoints = []
return this.getTerrainHeight(this.points[0])
}
}else{
this.currentIndex = this.points.length-1;
incompletePoints = [];
completedPoints = this.points.slice(0)
return this.getTerrainHeight(this.points.at(-1))
}
}
},false),
billboard:{
image:this.url,
scale:this.scale,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
polyline: {
positions: new Cesium.CallbackProperty(function () {
return incompletePoints;
}, false),
// positions:this.points,
width: this.lineWidth,
material:Cesium.Color.fromCssColorString(this.incompleteColor),
clampToGround: true
}
})
this.incompleteEntity = entity;
this.layer.entities.add(this.incompleteEntity);
// 已完成的轨迹
let entity2 = new Cesium.Entity({
polyline: {
positions: new Cesium.CallbackProperty(function () {
return completedPoints;
}, false),
width: this.lineWidth,
material:Cesium.Color.fromCssColorString(this.completedColor),
clampToGround: true
}
})
this.completedEntity = entity2;
this.layer.entities.add(this.completedEntity);
}
/**
* 计算飞行路径
* @param source 数据坐标
* @returns {SampledPositionProperty|*}
*/
createProperty() {
let start = Cesium.JulianDate.fromDate(new Date());
let property = new Cesium.SampledPositionProperty();
property.addSample(start, this.points[0]);
let time = 0;
for(let i=1,j=this.points.length;i<j;i++){
let position = this.points[i];
let dis = Cesium.Cartesian3.distance(this.points[i-1],position);
let t = dis/this.speed;
time+=t;
t = Cesium.JulianDate.addSeconds(start, time, new Cesium.JulianDate);
property.addSample(t, position);
};
this.property = property;
this.startTime = start;
}
/**
* 设置速度
* @param {Number} speed
*/
setSpeed(speed){
if(speed){
this.rate = speed/this.speed;
}
}
/**
* 播放
*/
play(){
this.isPlay= true;
}
/**
* 暂停
*/
paus(){
this.isPlay=false
}
/**
* 移除元素
*/
remove(){
if(this.layer){
this.incompleteEntity&&this.layer.entities.remove(this.incompleteEntity);
this.completedEntity&&this.layer.entities.remove(this.completedEntity);
}
}
}
export default Trajectory;