最终效果录屏
概述
代码实现
在每一个开关的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;