参考资料
EarthSDK在线示例:路径-车辆运动
EarthSDK:XE
EarthSDK API:Earth (重点关注 interaction)
EarthSDK API:MVVM(重点关注 MVVM.watch)
EarthSDK API:Path
EarthSDK API:Tree(重点关注 $refs 及 节点创建方法)
EarthSDK API:XbsjCzmObj
概述
实现效果:点击门->播放开门动画->等待数秒后->播放关门动画
最终效果录屏
推拉门动画(开、关)
绘制路径
使用“标绘-高级-路径动画”在模型中绘制路径,在“路径属性”面板中可根据实际情况修改相关属性。
将动画加载至模型中
在线查看路径代码
选中“路径动画”图层,右键,在弹出的选项中选择“查看加载代码”,即可看到路径的代码,重点是获取路径的position数据,在这里获取的路径动画的positions是不精确的,还需要在代码中去调整。
通过JS控制动画的执行与结束
在线查看路径代码之后,需要参考EarthSDK API将室内、门的模型加载到场景树中,并控制开关门动画的执行与结束。
项目关键代码示例(React)
const leafJson = [
{
"czmObject": {
"xbsjType": "Tileset",
"xbsjGuid": "a341be0f-d5df-48c3-9c36-8af547e64000",
"name": "室内",
"url": "...", // 此处为 室内模型 3dtiles数据地址
"xbsjPosition": [
2.044452086968357,
0.6398399028959787,
271.22052428840794
],
"xbsjUseOriginTransform": false,
"xbsjClippingPlanes": {},
"xbsjCustomShader": {}
}
},{
"ref": "leftDoor",
"czmObject": {
"xbsjType": "Tileset",
"xbsjGuid": "8848caa9-7310-4fa3-8f05-959a26605c54",
"name": "入口左侧门",
"url": "...", // 此处为 门模型 3dtiles数据地址
"xbsjPosition": [
2.04445030673252,
0.6398409361655967,
271.5950337444273
],
"xbsjRotation": [
1.5707963267948966,
0,
1.5707963267948966
],
"xbsjUseOriginTransform": false,
"xbsjClippingPlanes": {},
"xbsjCustomShader": {}
}
},{
"ref": "openPath",
"czmObject": {
"xbsjType": "Path",
"xbsjGuid": "791ba4ac-a022-4f04-8e36-66dff64aa24d",
"name": "开门路径动画",
"positions": [
[
2.04445030673252,
0.6398409361655967,
271.5950337444273
],
[
2.04445030673252,
0.6398411909207626,
271.5950337444273
]
],
"rotations": [
[
0,
0,
0
],
[
0,
0,
0
]
],
"currentSpeed": 1,
"playing": false
}
},{
"ref": "closePath",
"czmObject": {
"xbsjType": "Path",
"xbsjGuid": "0a1e9f7e-18fb-4996-bd1a-1303a2fcc6cc",
"name": "关门路径动画",
"positions": [
[
2.04445030673252,
0.6398411909207626,
271.5950337444273
],
[
2.04445030673252,
0.6398409361655967,
271.5950337444273
]
],
"rotations": [
[
0,
0,
0
],
[
0,
0,
0
]
],
"currentSpeed": 1,
"playing": false
}
}
];
export default leafJson;
import leafJson from "./leafJson"; // 引入路径可根据实际情况调整
class pathAnimationDemo extends Component{
constructor(props) {
super(props);
this.earth = null;
},
componentDidMount() {
XE.ready().then(()=>{
// 加载标绘插件 js
...
}).then(()=>{
this.startUp();
})
},
startUp = ()=>{
// 创建 Earth实例
this.earth = new XE.Earth("earthContainer");
// 开启拾取(鼠标点击事件)
this.earth.interaction.picking.enabled = true;
// 通过JSON配置创建节点
this.earth.sceneTree.root.children.push(...leafJson);
// 获取节点下挂接的对象
const leftDoor = this.earth.sceneTree.$refs.leftDoor.czmObject;
const openPath = this.earth.sceneTree.$refs.leftDoor.openPath;
const closePath = this.earth.sceneTree.$refs.leftDoor.closePath;
// 给对象添加点击事件
leftDoor.onclick = () => {
// 点击门时播放开门动画
openPath.playing = true;
/* MVVM.watch() 对响应式属性对象的监控,需要三个参数。
*第一个参数是监控的对象;
* 第二个参数是该对象的属性,注意要用字符串表示;
*第三个参数是一个回调函数,当属性的值发生变化时,该函数会响应;
*/
XE.MVVM.watch(openPath, "currentPosition", openPosition => {
leftDoor.xbsjPosition = [...openPosition];
/*
* 如果已经移动到开门路径的终点,数秒钟后开始执行关门动画
*/
if (openPosition[1] === openPath.positions[1][1]) {
// 如果currentPosition 和 开门路径终点相等, 停止播放开门动画
// 有时候openPosition[1]会比openPath.positions[1][1]多几位小数或者稍微大一点,具体原因待考证
// 出现上述问题之后,需要打印一下openPosition[1],将openPath.positions[1][1]的值改成openPosition[1]的值即可
// 如果还不行,就将openPath.positions[1][1]的值往上或往下调一调
openPath.playing = false;
// 5s之后,执行关门动画
setTimeout(()=>{
closePath.playing = true;
XE.MVVM.watch(closePath, "currentPosition", closePosition => {
leftDoor.xbsjPosition = [...closePosition];
if (closePosition[1] === closePath.positions[1][1]) {
// 如果currentPosition 和 关门路径终点相等, 停止播放关门动画
// 有时候closePosition[1]会比closePath.positions[1][1]多几位小数或者稍微大一点,具体原因待考证
// 出现上述问题之后,需要打印一下closePosition[1],将closePath.positions[1][1]的值改成closePosition[1]的值即可
// 如果还不行,就将closePath.positions[1][1]的值往上或往下调一调
closePath.playing = false;
}
})
}, 5000)
}
})
}
}
return (
<div id="earthContainer"></div>
)
}
export default pathAnimationDemo;
问题记录
判断开门/关门动画是否执行完毕时,position[1]和path.positions[1][1]会出现一点差别:有时候position[1]会比path.positions[1][1]多几位小数或者稍微大一点,具体原因待考证。
出现上述问题之后,需要打印一下position[1],将path.positions[1][1]的值改成position[1]的值即可。如果还不行,就将path.positions[1][1]的值往上或往下调一调试试。