参考资料

EarthSDK在线示例:路径-车辆运动
EarthSDK:XE
EarthSDK API:Earth (重点关注 interaction)
EarthSDK API:MVVM(重点关注 MVVM.watch)
EarthSDK API:Path
EarthSDK API:Tree(重点关注 $refs 及 节点创建方法)
EarthSDK API:XbsjCzmObj

概述

实现效果:点击门->播放开门动画->等待数秒后->播放关门动画

最终效果录屏

开、关门动画.mp4

推拉门动画(开、关)

绘制路径

使用“标绘-高级-路径动画”在模型中绘制路径,在“路径属性”面板中可根据实际情况修改相关属性。
image.png

将动画加载至模型中

在线查看路径代码

选中“路径动画”图层,右键,在弹出的选项中选择“查看加载代码”,即可看到路径的代码,重点是获取路径的position数据,在这里获取的路径动画的positions是不精确的,还需要在代码中去调整。
image.png
image.png

通过JS控制动画的执行与结束

在线查看路径代码之后,需要参考EarthSDK API将室内、门的模型加载到场景树中,并控制开关门动画的执行与结束。

项目关键代码示例(React)

  1. const leafJson = [
  2. {
  3. "czmObject": {
  4. "xbsjType": "Tileset",
  5. "xbsjGuid": "a341be0f-d5df-48c3-9c36-8af547e64000",
  6. "name": "室内",
  7. "url": "...", // 此处为 室内模型 3dtiles数据地址
  8. "xbsjPosition": [
  9. 2.044452086968357,
  10. 0.6398399028959787,
  11. 271.22052428840794
  12. ],
  13. "xbsjUseOriginTransform": false,
  14. "xbsjClippingPlanes": {},
  15. "xbsjCustomShader": {}
  16. }
  17. },{
  18. "ref": "leftDoor",
  19. "czmObject": {
  20. "xbsjType": "Tileset",
  21. "xbsjGuid": "8848caa9-7310-4fa3-8f05-959a26605c54",
  22. "name": "入口左侧门",
  23. "url": "...", // 此处为 门模型 3dtiles数据地址
  24. "xbsjPosition": [
  25. 2.04445030673252,
  26. 0.6398409361655967,
  27. 271.5950337444273
  28. ],
  29. "xbsjRotation": [
  30. 1.5707963267948966,
  31. 0,
  32. 1.5707963267948966
  33. ],
  34. "xbsjUseOriginTransform": false,
  35. "xbsjClippingPlanes": {},
  36. "xbsjCustomShader": {}
  37. }
  38. },{
  39. "ref": "openPath",
  40. "czmObject": {
  41. "xbsjType": "Path",
  42. "xbsjGuid": "791ba4ac-a022-4f04-8e36-66dff64aa24d",
  43. "name": "开门路径动画",
  44. "positions": [
  45. [
  46. 2.04445030673252,
  47. 0.6398409361655967,
  48. 271.5950337444273
  49. ],
  50. [
  51. 2.04445030673252,
  52. 0.6398411909207626,
  53. 271.5950337444273
  54. ]
  55. ],
  56. "rotations": [
  57. [
  58. 0,
  59. 0,
  60. 0
  61. ],
  62. [
  63. 0,
  64. 0,
  65. 0
  66. ]
  67. ],
  68. "currentSpeed": 1,
  69. "playing": false
  70. }
  71. },{
  72. "ref": "closePath",
  73. "czmObject": {
  74. "xbsjType": "Path",
  75. "xbsjGuid": "0a1e9f7e-18fb-4996-bd1a-1303a2fcc6cc",
  76. "name": "关门路径动画",
  77. "positions": [
  78. [
  79. 2.04445030673252,
  80. 0.6398411909207626,
  81. 271.5950337444273
  82. ],
  83. [
  84. 2.04445030673252,
  85. 0.6398409361655967,
  86. 271.5950337444273
  87. ]
  88. ],
  89. "rotations": [
  90. [
  91. 0,
  92. 0,
  93. 0
  94. ],
  95. [
  96. 0,
  97. 0,
  98. 0
  99. ]
  100. ],
  101. "currentSpeed": 1,
  102. "playing": false
  103. }
  104. }
  105. ];
  106. export default leafJson;
  1. import leafJson from "./leafJson"; // 引入路径可根据实际情况调整
  2. class pathAnimationDemo extends Component{
  3. constructor(props) {
  4. super(props);
  5. this.earth = null;
  6. },
  7. componentDidMount() {
  8. XE.ready().then(()=>{
  9. // 加载标绘插件 js
  10. ...
  11. }).then(()=>{
  12. this.startUp();
  13. })
  14. },
  15. startUp = ()=>{
  16. // 创建 Earth实例
  17. this.earth = new XE.Earth("earthContainer");
  18. // 开启拾取(鼠标点击事件)
  19. this.earth.interaction.picking.enabled = true;
  20. // 通过JSON配置创建节点
  21. this.earth.sceneTree.root.children.push(...leafJson);
  22. // 获取节点下挂接的对象
  23. const leftDoor = this.earth.sceneTree.$refs.leftDoor.czmObject;
  24. const openPath = this.earth.sceneTree.$refs.leftDoor.openPath;
  25. const closePath = this.earth.sceneTree.$refs.leftDoor.closePath;
  26. // 给对象添加点击事件
  27. leftDoor.onclick = () => {
  28. // 点击门时播放开门动画
  29. openPath.playing = true;
  30. /* MVVM.watch() 对响应式属性对象的监控,需要三个参数。
  31. *第一个参数是监控的对象;
  32. * 第二个参数是该对象的属性,注意要用字符串表示;
  33. *第三个参数是一个回调函数,当属性的值发生变化时,该函数会响应;
  34. */
  35. XE.MVVM.watch(openPath, "currentPosition", openPosition => {
  36. leftDoor.xbsjPosition = [...openPosition];
  37. /*
  38. * 如果已经移动到开门路径的终点,数秒钟后开始执行关门动画
  39. */
  40. if (openPosition[1] === openPath.positions[1][1]) {
  41. // 如果currentPosition 和 开门路径终点相等, 停止播放开门动画
  42. // 有时候openPosition[1]会比openPath.positions[1][1]多几位小数或者稍微大一点,具体原因待考证
  43. // 出现上述问题之后,需要打印一下openPosition[1],将openPath.positions[1][1]的值改成openPosition[1]的值即可
  44. // 如果还不行,就将openPath.positions[1][1]的值往上或往下调一调
  45. openPath.playing = false;
  46. // 5s之后,执行关门动画
  47. setTimeout(()=>{
  48. closePath.playing = true;
  49. XE.MVVM.watch(closePath, "currentPosition", closePosition => {
  50. leftDoor.xbsjPosition = [...closePosition];
  51. if (closePosition[1] === closePath.positions[1][1]) {
  52. // 如果currentPosition 和 关门路径终点相等, 停止播放关门动画
  53. // 有时候closePosition[1]会比closePath.positions[1][1]多几位小数或者稍微大一点,具体原因待考证
  54. // 出现上述问题之后,需要打印一下closePosition[1],将closePath.positions[1][1]的值改成closePosition[1]的值即可
  55. // 如果还不行,就将closePath.positions[1][1]的值往上或往下调一调
  56. closePath.playing = false;
  57. }
  58. })
  59. }, 5000)
  60. }
  61. })
  62. }
  63. }
  64. return (
  65. <div id="earthContainer"></div>
  66. )
  67. }
  68. 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]的值往上或往下调一调试试。