最终效果录屏
概述
代码实现
在每一个开关的json中添加一个对象”glassDoor”,根据研究院室内实际情况,抽象出开关与门的关系:一个开关对应着两扇门,一扇门有两个路径动画(开门路径动画、关门路径动画),每一个关门动画都有自己的定时器。
将每扇门按照左右位置和开关index编号。
将每个路径动画按照左右位置、开关动作和开关index编号。
在门的json中使用以上编号标记每一扇门和每一个路径动画。
switchJson.js
/** "glassDoor": [{"doorRef": "leftDoor0","pathRef": ["leftOpen0", "leftClose0"],"closeTimer": null},{"doorRef": "rightDoor0","pathRef": ["rightOpen0", "rightClose0"],"closeTimer": null}],*/const switchJson = [{"ref": "switch0","glassDoor": [{"doorRef": "leftDoor0", // 将每扇门按照左右位置和开关index编号"pathRef": ["leftOpen0", "leftClose0"], // 将每个路径动画按照左右位置、开关动作和开关index编号"closeTimer": null},{"doorRef": "rightDoor0","pathRef": ["rightOpen0", "rightClose0"],"closeTimer": null}],"czmObject": {"xbsjType": "Tileset","xbsjGuid": "b7a4c6d4-23f3-474e-a828-f34264e40416","name": "前台-开关","url": "...", // 模型地址"xbsjPosition": [2.0444499593823284,0.6398407227372647,184.3798550556327],"xbsjRotation": [-0.3959951084942439,-0.08726646259971647,0],"xbsjScale": [0.05,0.04,0.048],"xbsjUseOriginTransform": false,"xbsjClippingPlanes": {},"xbsjCustomShader": {}}},{"ref": "switch1","glassDoor": [{"doorRef": "leftDoor1","pathRef": ["leftOpen1", "leftClose1"],"closeTimer": null},{"doorRef": "rightDoor1","pathRef": ["rightOpen1", "rightClose1"],"closeTimer": null}],"czmObject": {"xbsjType": "Tileset","xbsjGuid": "f1e7c69f-dc49-4ae1-a7f4-e06de262b81a","name": "东走廊-北开关","url": "...", // 模型地址"xbsjPosition": [2.0444524982375794,0.6398415783390702,184.60063585634657],"xbsjRotation": [-0.3959951084942439,0.08726646259971647,0],"xbsjScale": [0.05,0.04,0.048],"xbsjUseOriginTransform": false,"xbsjClippingPlanes": {},"xbsjCustomShader": {}}},{"ref": "switch2","glassDoor": [{"doorRef": "leftDoor2","pathRef": ["leftOpen2", "leftClose2"],"closeTimer": null},{"doorRef": "rightDoor2","pathRef": ["rightOpen2", "rightClose2"],"closeTimer": null}],"czmObject": {"xbsjType": "Tileset","xbsjGuid": "a9ff6500-db41-4ac4-b625-ee1d230ca368","name": "东走廊-南开关","url": "...", // 模型地址"xbsjPosition": [2.044453599997902,0.6398394609856203,184.641940963229],"xbsjRotation": [-0.3959951084942439,0.08726646259971647,0],"xbsjScale": [0.05,0.04,0.048],"xbsjUseOriginTransform": false,"xbsjClippingPlanes": {},"xbsjCustomShader": {}}},{"ref": "switch3","glassDoor": [{"doorRef": "leftDoor3","pathRef": ["leftOpen3", "leftClose3"],"closeTimer": null},{"doorRef": "rightDoor3","pathRef": ["rightOpen3", "rightClose3"],"closeTimer": null}],"czmObject": {"xbsjType": "Tileset","xbsjGuid": "788772f1-7700-44fe-b88a-727125fb9574","name": "展厅-开关","url": "...", // 模型地址"xbsjPosition": [2.044452536861528,0.6398421616480751,184.6179881832191],"xbsjRotation": [-0.3959951084942439,0.08726646259971647,0],"xbsjScale": [0.05,0.04,0.048],"xbsjUseOriginTransform": false,"xbsjClippingPlanes": {},"xbsjCustomShader": {}}}];export default switchJson;
glassDoorJson.js
// 前台接待处const reception = [{"ref": "leftDoor0","czmObject": {"xbsjType": "Tileset","xbsjGuid": "73ed68f3-1dc4-40e7-bddb-50a3e7be4bed","name": "前台-左侧门","url": "...", // 模型地址"xbsjPosition": [2.044449816295,0.6398410391053218,181.25],"xbsjRotation": [-0.3969407967416281,0.014846137946110005,0],"xbsjScale": [0.85,0.88,1],"xbsjUseOriginTransform": false,"xbsjClippingPlanes": {},"xbsjCustomShader": {}}},{"ref": "leftOpen0","czmObject": {"xbsjType": "Path","xbsjGuid": "514fa82b-97c2-4c81-b87d-9a01d953ec3e","name": "前台-左侧门-路径动画","positions": [[2.044449816295,0.6398410391053218,181.25],[2.0444497639740824,0.6398411440696372,181.25]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}},{"ref": "leftClose0","czmObject": {"xbsjType": "Path","xbsjGuid": "0a1e9f7e-18fb-4996-bd1a-1303a2fcc6cc","name": "前台-左侧门-路径动画","positions": [[2.0444497639740824,0.6398411440696372,181.25],[2.044449816295,0.6398410391053218,181.25]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}},{"ref": "rightDoor0","czmObject": {"xbsjType": "Tileset","xbsjGuid": "293745c2-4160-488f-b785-549763654784","name": "前台-右侧门","url": "...", // 模型地址"xbsjPosition": [2.044449875336235,0.639840927184629,181.25],"xbsjRotation": [-0.39542618159920906,0.015707963267948967,0],"xbsjScale": [0.85,0.88,1],"xbsjUseOriginTransform": false,"xbsjClippingPlanes": {},"xbsjCustomShader": {}}},{"ref": "rightOpen0","czmObject": {"xbsjType": "Path","xbsjGuid": "791ba4ac-a022-4f04-8e36-66dff64aa24d","name": "前台-右侧门-路径动画","positions": [[2.044449875336235,0.639840927184629,181.25],[2.044449927731744,0.639840822289407,181.25]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}},{"ref": "rightClose0","czmObject": {"xbsjType": "Path","xbsjGuid": "feb278ee-7aea-448d-adf8-95078157a232","name": "路径动画","positions": [[2.044449927731744,0.639840822289407,181.25],[2.044449875336235,0.639840927184629,181.25]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}}];// 走廊北const corridor_north = [{"ref": "leftDoor1","czmObject": {"xbsjType": "Tileset","xbsjGuid": "86b8b0f7-903c-43b0-97f8-658f813b1721","name": "东走廊北-左侧门","url": "...", // 模型地址"xbsjPosition": [2.0444523934162557,0.6398417755615563,181.46],"xbsjRotation": [-0.3957096034349785,0.015707963267948967,0],"xbsjScale": [0.85,0.87,1],"xbsjUseOriginTransform": false,"xbsjClippingPlanes": {},"xbsjCustomShader": {}}},{"ref": "leftOpen1","czmObject": {"xbsjType": "Path","xbsjGuid": "c8ebc7df-47d2-4370-ba7b-7d496ed08ab9","name": "东走廊北-左侧门-路径动画","positions": [[2.0444523934162557,0.6398417755615563,181.46],[2.04445245106097,0.6398416725678746,181.46]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}},{"ref": "leftClose1","czmObject": {"xbsjType": "Path","xbsjGuid": "c8ebc7df-47d2-4370-ba7b-7d496ed08ab9","name": "东走廊北-左侧门-路径动画","positions": [[2.04445245106097,0.6398416725678746,181.46],[2.0444523934162557,0.6398417755615563,181.46]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}},{"ref": "rightDoor1","czmObject": {"xbsjType": "Tileset","xbsjGuid": "13c9e958-d197-47dd-a205-0b8fe1e5bc5a","name": "东走廊北-右侧门","url": "...", // 模型地址"xbsjPosition": [2.044452336345083,0.6398418863587736,181.46],"xbsjRotation": [-0.3968314720420576,0.015707963267948967,0],"xbsjScale": [0.85,0.87,1],"xbsjUseOriginTransform": false,"xbsjClippingPlanes": {},"xbsjCustomShader": {}}},{"ref": "rightOpen1","czmObject": {"xbsjType": "Path","xbsjGuid": "e20b70e4-3e61-4a54-a26f-ab15c3eae867","name": "东走廊北-右侧门-路径动画","positions": [[2.044452336345083,0.6398418863587736,181.46],[2.044452284412869,0.6398419926270578,181.46]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}},{"ref": "rightClose1","czmObject": {"xbsjType": "Path","xbsjGuid": "e20b70e4-3e61-4a54-a26f-ab15c3eae867","name": "东走廊北-右侧门-路径动画","positions": [[2.044452284412869,0.6398419926270578,181.46],[2.044452336345083,0.6398418863587736,181.46]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}}];// 走廊南const corridor_south = [{"ref": "leftDoor2","czmObject": {"xbsjType": "Tileset","xbsjGuid": "bac20974-3f5f-4adb-b67c-5a5f820da2ee","name": "东走廊南-左侧门","url": "...", // 模型地址"xbsjPosition": [2.044453497691577,0.6398396591887818,181.5],"xbsjRotation": [-0.3949680776541822,0.015707963267948967,0],"xbsjScale": [0.85,0.87,1],"xbsjUseOriginTransform": false,"xbsjClippingPlanes": {},"xbsjCustomShader": {}}},{"ref": "leftOpen2","czmObject": {"xbsjType": "Path","xbsjGuid": "8cc71244-4abb-4be3-8964-31c0f48dacf6","name": "东走廊南-左侧门-路径动画","positions": [[2.044453497691577,0.6398396591887818,181.5],[2.044453551574043,0.6398395546758482,181.5]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}},{"ref": "leftClose2","czmObject": {"xbsjType": "Path","xbsjGuid": "8cc71244-4abb-4be3-8964-31c0f48dacf5","name": "东走廊南-左侧门-路径动画","positions": [[2.044453551574043,0.6398395546758482,181.5],[2.044453497691577,0.6398396591887818,181.5]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}},{"ref": "rightDoor2","czmObject": {"xbsjType": "Tileset","xbsjGuid": "4463f2e9-d4a8-4ce2-b8fd-e27385ec90e7","name": "东走廊南-右侧门","url": "...", // 模型地址"xbsjPosition": [2.0444534406343626,0.6398397703102854,181.5],"xbsjRotation": [-0.39681226428802496,0.015707963267948967,0],"xbsjScale": [0.85,0.87,1],"xbsjUseOriginTransform": false,"xbsjClippingPlanes": {},"xbsjCustomShader": {}}},{"ref": "rightOpen2","czmObject": {"xbsjType": "Path","xbsjGuid": "411b4964-1997-4106-a8fc-6d9e4c25040d","name": "东走廊南-右侧门-路径动画","positions": [[2.0444534406343626,0.6398397703102854,181.5],[2.044453386062222,0.6398398751956313,181.5]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}},{"ref": "rightClose2","czmObject": {"xbsjType": "Path","xbsjGuid": "411b4964-1997-4106-a8fc-6d9e4c25040v","name": "东走廊南-右侧门-路径动画","positions": [[2.044453386062222,0.6398398751956313,181.5],[2.0444534406343626,0.6398397703102854,181.5]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}}];// 展厅const showroom = [{"ref": "leftDoor3","czmObject": {"xbsjType": "Tileset","xbsjGuid": "dcead727-1fa2-4cdf-8914-e85e633a60a1","name": "展厅-左侧门","url": "...", // 模型地址"xbsjPosition": [2.04445265845087,0.639841866217198,181.51049512039936],"xbsjRotation": [-0.3967670706393829,0.015707963267948967,0],"xbsjScale": [0.85,0.87,1],"xbsjUseOriginTransform": false,"xbsjClippingPlanes": {},"xbsjCustomShader": {}}},{"ref": "leftOpen3","czmObject": {"xbsjType": "Path","xbsjGuid": "b5352dab-5d4b-41a8-b2fd-304eb936291b","name": "展厅-左侧门-路径动画","positions": [[2.04445265845087,0.639841866217198,181.51049512039936],[2.0444527145178744,0.6398417611322228,181.51049512039936]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}},{"ref": "leftClose3","czmObject": {"xbsjType": "Path","xbsjGuid": "b5352dab-5d4b-41a8-b2fd-304eb936291a","name": "展厅-左侧门-路径动画","positions": [[2.0444527145178744,0.6398417611322228,181.51049512039936],[2.04445265845087,0.639841866217198,181.51049512039936]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}},{"ref": "rightDoor3","czmObject": {"xbsjType": "Tileset","xbsjGuid": "7254984f-eef8-4b32-ab0b-6b1d20b678a8","name": "展厅-右侧门","url": "...", // 模型地址"xbsjPosition": [2.0444526011030795,0.6398419770744627,181.51200448185625],"xbsjRotation": [-0.3960921777795168,0.015707963267948967,0],"xbsjScale": [0.85,0.87,1],"xbsjUseOriginTransform": false,"xbsjClippingPlanes": {},"xbsjCustomShader": {}}},{"ref": "rightOpen3","czmObject": {"xbsjType": "Path","xbsjGuid": "ec90227e-0b62-4867-8f0a-7a888fdb78f3","name": "展厅-右侧门-路径动画","positions": [[2.0444526011030795,0.6398419770744627,181.51200448185625],[2.0444525492357384,0.6398420829344057,181.51200448185625]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}},{"ref": "rightClose3","czmObject": {"xbsjType": "Path","xbsjGuid": "ec90227e-0b62-4867-8f0a-7a888fdb78f5","name": "展厅-右侧门-路径动画","positions": [[2.0444525492357384,0.6398420829344057,181.51200448185625],[2.0444526011030795,0.6398419770744627,181.51200448185625]],"rotations": [[0,0,0],[0,0,0]],"currentSpeed": 1,"playing": false}}];const glassDoorJson = [...reception,...corridor_north,...corridor_south,...showroom];export default glassDoorJson;
deepblue_ani.js
由于角度加减多少度,需要在CesiumLab中尝试将模型移动、旋转后总结规律得出, 如果想所有的开关模型都使用这个方法计算角度,那么在模型制作时,必须保证模型的尺寸一致,缩放一致
import switchJson from '@/constant/switchJson';let openDoor = false;let switchTimer = null;// 室内模型-玻璃门 开门 动画export function openDoorAnimation (earth, modelArr) {modelArr.forEach((item)=>{const model = earth.sceneTree.$refs[item.doorRef].czmObject;const path = earth.sceneTree.$refs[item.pathRef[0]].czmObject;if (model.xbsjPosition[1] !== path.positions[1][1] && openDoor) {path.playing = true;XE.MVVM.watch(path, 'currentPosition', position => {model.xbsjPosition = [...position];});}});}// 室内模型-玻璃门 关门 动画export function closeDoorAnimation (earth, modelArr) {modelArr.forEach((item)=>{const model = earth.sceneTree.$refs[item.doorRef].czmObject;const path = earth.sceneTree.$refs[item.pathRef[1]].czmObject;if(item.closeTimer) {clearTimeout(item.closeTimer)}if (model.xbsjPosition[1] !== path.positions[1][1] && !openDoor) {item.closeTimer = setTimeout(()=>{path.playing = true;XE.MVVM.watch(path, 'currentPosition', position => {model.xbsjPosition = [...position];})}, 5000)}});}// 室内模型-开关 按下动画export function switchAnimation (earth) {const switchObj = [];let switchRef = "";switchJson.forEach((item,index)=>{switchRef = `switch${index}`;switchObj.push({switch: earth.sceneTree.$refs[switchRef].czmObject,door: item.glassDoor});});switchObj.forEach((item)=>{/** 将开关模型变化之前的rotation和position拷贝一份,* 需要将开关模型恢复原位时赋值即可* 使用...解构赋值是因为...是浅拷贝,不受原值变化的影响*/const oldRotation = [...item.switch.xbsjRotation];const oldPosition = [...item.switch.xbsjPosition];// 弧度转角度item.xdegree = Number((oldPosition[0] / Math.PI * 180).toFixed(7));item.ydegree = Number((oldPosition[1] / Math.PI * 180).toFixed(8));item.switch.onclick = () => {if (switchTimer) {clearTimeout(switchTimer)}openDoor = true;item.switch.xbsjRotation[1] = -item.switch.xbsjRotation[1];// 角度加减多少度,需要在CesiumLab中尝试将模型移动、旋转后总结规律得出// 如果想所有的开关模型都使用这个方法计算角度,那么在模型制作时,必须保证模型的尺寸一致,缩放一致if (item.switch.xbsjRotation[1] < 0) {item.xdegree -= 0.0000002;item.ydegree -= 0.00000006;} else {item.xdegree += 0.0000002;item.ydegree += 0.00000007;}// 角度转弧度item.switch.xbsjPosition[0] = item.xdegree / 180 * Math.PI;item.switch.xbsjPosition[1] = item.ydegree / 180 * Math.PI;openDoorAnimation(earth, item.door);switchTimer = setTimeout(()=>{// 开关模型恢复原位时,需要将所有变化的值赋值为初始值item.switch.xbsjRotation = oldRotation;item.switch.xbsjPosition = oldPosition;item.xdegree = Number((oldPosition[0] / Math.PI * 180).toFixed(7));item.ydegree = Number((oldPosition[1] / Math.PI * 180).toFixed(8));openDoor = false;closeDoorAnimation(earth, item.door);}, 500);}});}
index.js
/* index.js */import deepblueLeafJson from '@/constant/deepblueJson'; // 引入路径可根据实际情况调整import switchJson from '@/constant/switchJson'; // 引入路径可根据实际情况调整import glassDoorJson from '@/constant/glassDoorJson'; // 引入路径可根据实际情况调整import { switchAnimation } from '@/pages/DigitalTwin/deepblue_ani'; // 引入路径可根据实际情况调整class animationDemo 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(...deepblueLeafJson, ...switchJson, ...glassDoorJson);switchAnimation(this.earth);}return (<div id="earthContainer"></div>)}export default animationDemo;
