在使用基于Cesium的Mars3D第三方库做开发的时候,碰到了这么一个需求:“实现两个模型之间的连线,这个直线可以随着模型的移动而移动”。
Mars3D中提供了一个标绘功能,简单来说就是可以通过拖动鼠标改变模型在图层上的位置。所以提出的需求就简化成了————“鼠标拖动模型,模型间的连线随着模型移动而移动”。
这里模型的移动方式对于后续的方案处理有很大的影响。首先我来讲讲第一种方案失败的可能原因。
方案一(失败)
model的position使用PositionProperty, polyline的position使用PositionPropertyArray,array数组里面是ReferenceProperty, 这里是为了让polyline两端的位置依赖于模型的位置。
这种方案是可以成功显示出连线的,但是问题出在标绘上。
调用提供的标绘函数的时候,会出现如图的错误
在ReferenceProperty的api文档中提到了只有引用的属性是PositionProperty是这个函数才有效。
但是我们在最初设定模型position的时候确实是使用的PositionProperty,这里我猜想应该是标绘函数使用了一个CallbackProperty,回调的Object不再是PositionProperty类型了,因此会出错。Mars3D的api并没有开源,具体原因也无从得知了。
方案二(成功)
既然我们想用Mars3D的api实现我们的需求,就需要另辟蹊径。
第二种方案使用了czml数据格式,czml数据配置项中的polyline/position属性有一个references选项, 使用它也可以实现位置依赖。
"polyline":{
"positions":{
"references":[
"model1#position",
"model2#position"
]
}
}
新的问题便是:怎么引入这个czml数据?
Mars3D中提供了很多图层,这些图层都具有不同的功能。我们上文中提到的标绘功能,是基于graphicLayer的,但是graphicLayer并不支持导入czml,Mars3D单独提供了czmlLayer可以导入czml配置文件。
因此采用“双图层同步”的解决方案:graphicLayer上的标绘改变模型位置后,使用监听事件获取改变后的模型坐标,同步更新czml配置文件的相应模型的position属性内容,并更新czmlLayer图层。
graphicLayer显示模型,czmlLayer中的配置项中仅仅记录模型的位置,不显示模型,只显示polyline。简单来说,graphicLayer上的模型和czmlLayer的模型实际上是两个单独的实体,只是通过监听事件让这它们的位置时刻保持一致。
//模型绑定监听事件
this.graphicLayer.getGraphicById("Firecar").on(mars3d.EventType.updatePosition,function (event){
//console.log("位置发生了变化!",event)
console.log(event.position.getValue(Cesium.JulianDate.fromDate(new Date('2022-06-16 08:00:00'))))
that.czml.forEach(function(value,index,array){
if(value.id ==='Firecar')
value.position = {
"cartographicDegrees": (mars3d.LngLatPoint.fromCartesian(event.position.getValue(Cesium.JulianDate.fromDate(new Date('2022-06-16 08:00:00'))))).toArray(false)
}
});
//更新czml图层
that.czmlLayer.load()
console.log(that.czmlLayer)
})
需要注意的点:监听事件返回的是一个event,event里面有监听的position属性,这个属性是一个callbackProperty,使用getValue方法传入随便一个时间值得到变化后的坐标,注意得到的这个坐标是cartesian3,更新czml时候要将cartesian3换成array,这样直线才会正常显示。
这里的代码只是示意,目的还是为了分享解决思路。如果有更好更简单的思路欢迎一起讨论。