综合应用
这章节我们将讲解一些快速应用的案例,把往期的重要知识点和项目中常见的需求场景联系起来。
拾取和选择
关于 Pick 和 选择 的讲解,我们在前文已经讲述过,本章不在做过多赘述。
物体对象监控
物体面板显示监控
在 3D 的某些应用需求中,当选中某个物体时,需要展示该物体的详细信息,我们可以创建一个物体面板,来展示这些数据。
有如下几步即可实现让物体面板显示监控:
- query 获取物体对象集合;
- 对物体集合注册单击事件;
- 点击选中的物体 加入Selection中;
- 通过Select DeSelect事件 对物体做相应的操作;
- 如果是接口数据 可通过Ajax或WebSocket进行请求、对接;
- 创建物体面板 双向绑定数据;
示例效果如下图所示:
批量显示监控面板
在某些 3D 可视化应用场景中,需要显示一批物体的某些重要指标,如何实现多个对象批量显示这些数据呢?
我们通过 UIAnchor ,将相应的数据展示面板作为孩子连接到每个对象上即可。
示例效果如下图所示:
动态加载场景
关于动态创建组合场景的讲解,我们在前文已经讲述过,本章不在做过多赘述。
实现思路如下图所示:
视频中代码实现过程的具体迭代版本如下:
版本1如下:
var app = new THING.App({
"url": "https://www.thingjs.com/./uploads/wechat/oLX7p0wh7Ct3Y4sowypU5zinmUKY/scene/%E5%8A%A8%E6%80%81%E5%B1%82%E7%BA%A7%E5%A4%96%E7%AB%8B%E9%9D%A2",
"skyBox": "BlueSky",
});
// 主场景加载完后 删掉楼层
app.on('load', function (ev) {
// 进入层级切换
app.level.change(ev.campus);
console.log('卸载园区建筑下的默认楼层');
// 园区加载完成后,将园区中建筑下的楼层删除(Floor)
for (var i = 0; i < ev.buildings.length; i++) {
ev.buildings[i].floors.destroy();
}
});
var url = 'https://www.thingjs.com/./uploads/wechat/oLX7p0wh7Ct3Y4sowypU5zinmUKY/scene/%E5%95%86%E4%B8%9AE%E6%A5%BC%E5%B1%82%E7%BA%A7';
// 设置进入建筑事件
app.on(THING.EventType.EnterLevel, '.Building', function (ev) {
var buildingMain = ev.object;
console.log('动态加载');
// 动态创建园区
var campusTmp = app.create({
type: 'Campus',
// 动态创建园区的url
url: url,
// 在回调中,将动态创建的园区和园区下的建筑删除 只保留楼层 并添加到相应的建筑中
complete: function () {
var buildingTmp = campusTmp.buildings[0];
//遍历楼层 挂接到当前进入的建筑身上
buildingTmp.floors.forEach(function (floor) {
//将每层Floor作为孩子 挂接到 主建筑上
buildingMain.add({
object: floor,
// 设置相对坐标,楼层相对于建筑的位置保持一致
localPosition: floor.localPosition
});
})
// 楼层添加后,删除园区以及内部的园区建筑
buildingTmp.destroy();
campusTmp.destroy();
console.log('=== 加载完成!===');
}
});
}, '进入建筑创建楼层');
版本2如下:
var app = new THING.App({
"url": "https://www.thingjs.com/./uploads/wechat/oLX7p0wh7Ct3Y4sowypU5zinmUKY/scene/%E5%8A%A8%E6%80%81%E5%B1%82%E7%BA%A7%E5%A4%96%E7%AB%8B%E9%9D%A2",
"skyBox": "BlueSky",
});
// 主场景加载完后 删掉楼层
app.on('load', function (ev) {
// 进入层级切换
app.level.change(ev.campus);
console.log('卸载园区建筑下的默认楼层');
// 园区加载完成后,将园区中建筑下的楼层删除(Floor)
for (var i = 0; i < ev.buildings.length; i++) {
ev.buildings[i].floors.destroy();
}
});
var url = 'https://www.thingjs.com/./uploads/wechat/oLX7p0wh7Ct3Y4sowypU5zinmUKY/scene/%E5%95%86%E4%B8%9AE%E6%A5%BC%E5%B1%82%E7%BA%A7';
// 设置进入建筑事件
app.on(THING.EventType.EnterLevel, '.Building', function (ev) {
console.log('=== 进入了我的事件 === ');
var buildingMain = ev.object;
if (buildingMain._isAlreadyBuildedFloors) {
console.log('=== 建筑已加载!=== ');
return;
}
// 动态创建园区
var campusTmp = app.create({
type: 'Campus',
// 动态创建园区的url
url: url,
// 在回调中,将动态创建的园区和园区下的建筑删除 只保留楼层 并添加到相应的建筑中
complete: function () {
var buildingTmp = campusTmp.buildings[0];
//遍历楼层 挂接到当前进入的建筑身上
buildingTmp.floors.forEach(function (floor) {
buildingMain.add({
object: floor,
// 设置相对坐标,楼层相对于建筑的位置保持一致
localPosition: floor.localPosition
});
})
// 楼层添加后,删除园区以及内部的园区建筑
buildingTmp.destroy();
campusTmp.destroy();
buildingMain._isAlreadyBuildedFloors = true;
console.log('=== 加载完成!===');
}
});
}, '进入建筑创建楼层');
版本3如下:
var app = new THING.App({
"url": "https://www.thingjs.com/./uploads/wechat/oLX7p0wh7Ct3Y4sowypU5zinmUKY/scene/%E5%8A%A8%E6%80%81%E5%B1%82%E7%BA%A7%E5%A4%96%E7%AB%8B%E9%9D%A2",
"skyBox": "BlueSky",
});
// 主场景加载完后 删掉楼层
app.on('load', function (ev) {
// 进入层级切换
app.level.change(ev.campus);
console.log('卸载园区建筑下的默认楼层');
// 园区加载完成后,将园区中建筑下的楼层删除(Floor)
for (var i = 0; i < ev.buildings.length; i++) {
ev.buildings[i].floors.destroy();
}
});
var url = 'https://www.thingjs.com/./uploads/wechat/oLX7p0wh7Ct3Y4sowypU5zinmUKY/scene/%E5%95%86%E4%B8%9AE%E6%A5%BC%E5%B1%82%E7%BA%A7';
// 设置进入建筑事件
app.on(THING.EventType.EnterLevel, '.Building', function (ev) {
var buildingMain = ev.object;
if (buildingMain._isAlreadyBuildedFloors) {
console.log('=== 建筑已加载!=== ');
return;
}
// 停止进入物体层级的默认飞行行为
app.pauseEvent(THING.EventType.EnterLevel, '.Building', THING.EventTag.LevelFly);
// 动态创建园区
var campusTmp = app.create({
type: 'Campus',
// 动态创建园区的url
url: url,
// 在回调中,将动态创建的园区和园区下的建筑删除 只保留楼层 并添加到相应的建筑中
complete: function () {
var buildingTmp = campusTmp.buildings[0];
//遍历楼层 挂接到当前进入的建筑身上
buildingTmp.floors.forEach(function (floor) {
buildingMain.add({
object: floor,
// 设置相对坐标,楼层相对于建筑的位置保持一致
localPosition: floor.localPosition
});
})
// 楼层添加后,删除园区以及内部的园区建筑
buildingTmp.destroy();
campusTmp.destroy();
app.resumeEvent(THING.EventType.EnterLevel, '.Building', THING.EventTag.LevelFly);
buildingMain._isAlreadyBuildedFloors = true;
console.log('=== 加载完成!===');
}
});
// 提升事件响应的优先级
}, '进入建筑创建楼层',51);
版本4如下:
var app = new THING.App({
"url": "https://www.thingjs.com/./uploads/wechat/oLX7p0wh7Ct3Y4sowypU5zinmUKY/scene/%E5%8A%A8%E6%80%81%E5%B1%82%E7%BA%A7%E5%A4%96%E7%AB%8B%E9%9D%A2",
"skyBox": "BlueSky",
});
// 主场景加载完后 删掉楼层
app.on('load', function (ev) {
// 进入层级切换
app.level.change(ev.campus);
console.log('卸载园区建筑下的默认楼层');
// 园区加载完成后,将园区中建筑下的楼层删除(Floor)
for (var i = 0; i < ev.buildings.length; i++) {
ev.buildings[i].floors.destroy();
}
});
var url = 'https://www.thingjs.com/./uploads/wechat/oLX7p0wh7Ct3Y4sowypU5zinmUKY/scene/%E5%95%86%E4%B8%9AE%E6%A5%BC%E5%B1%82%E7%BA%A7';
// 设置进入建筑事件
app.on(THING.EventType.EnterLevel, '.Building', function (ev) {
var buildingMain = ev.object;
if (buildingMain._isAlreadyBuildedFloors) {
console.log('=== 建筑已加载!=== ');
return;
}
// 停止进入物体层级的默认飞行行为
app.pauseEvent(THING.EventType.EnterLevel, '.Building', THING.EventTag.LevelFly);
// 动态创建园区
var campusTmp = app.create({
type: 'Campus',
// 动态创建园区的url
url: url,
// 在回调中,将动态创建的园区和园区下的建筑删除 只保留楼层 并添加到相应的建筑中
complete: function () {
var buildingTmp = campusTmp.buildings[0];
//遍历楼层 挂接到当前进入的建筑身上
buildingTmp.floors.forEach(function (floor) {
buildingMain.add({
object: floor,
// 设置相对坐标,楼层相对于建筑的位置保持一致
localPosition: floor.localPosition
});
})
// 楼层添加后,删除园区以及内部的园区建筑
buildingTmp.destroy();
campusTmp.destroy();
app.resumeEvent(THING.EventType.EnterLevel, '.Building', THING.EventTag.LevelFly);
// 触发层级进入事件前 在该帧内 暂停自定义的 '进入建筑创建楼层' 响应
app.pauseEventInFrame(THING.EventType.EnterLevel,".Building",'进入建筑创建楼层');
// 楼层加载完成后的建筑 触发层级进入事件
buildingMain.trigger(THING.EventType.EnterLevel,ev);
buildingMain._isAlreadyBuildedFloors = true;
console.log('=== 加载完成!===');
}
});
}, '进入建筑创建楼层',51);
相对关系与坐标转换
相对关系
之前的教程中已经讲解过了,当创建对象,管理对象时,我们可以设置该物体的父物体。
指定了对象的父物体后,那么该对象的位移、旋转、缩放以及显示隐藏,默认都跟随父物体的变化而变化。
如果要让子对象不继承父物体的位移、旋转、缩放,可分别设置相应的 inheritPosition 、inheritAngles 、inheritScale 值为 false 实现。
坐标转换
之前的教程中已经讲解过了坐标转换,本章不在做多余赘述。
为了让大家更容易理解与使用相对关系与坐标转化,我们新增了一个 示例。
动态加载管理对象
对于一些有摆放规律或者有位置信息的管理对象(比如书柜里的书、楼层里的烟雾感应器、消防喷淋器),我们可以动态的请求数据来进行批量创建。在这种应用场景下创建管理对象时,建议设置对象的父物体、使用相对坐标,以更方便的进行对象的管理和控制。