thingjs 基础案例整理
ThingJS是一套面向物联网应用的3D可视化PaaS开发和运营平台,它以"ThingJS云视PaaS服务"形式面向广大物联网企业提供全生命周期在线3D可视化服务。
相关资料
- 官方网址:www.thingjs.com/;
- 在线开发:www.thingjs.com/guide/?m=sa...;
- 官方文档:docs.thingjs.com/;
- API文档:docs.thingjs.com/cn/apidocs/;
- 在线开发文档:docs.thingjs.com/cn/App_dev/...;
- CampusBuilder使用文档:docs.thingjs.com/cn/Create_s...;
- 工具下载:store.thingjs.com/tools;
创建模型,使用动画
现在用模模搭软件搭建了一个简单的场景,在场景中创建一个叉车模型,这个模型有两个动画,我们执行两个动画。
javascript
// 加载场景后执行
app.on('load', function (ev) {
var campus = ev.campus;
app.level.change(campus);
// 创建一个按钮,关联 createModel 事件
new THING.widget.Button('创建模型', createModel);
});
// 创建模型
function createModel() {
// 创建Thing
var obj = app.create({
type: 'Thing',
id: 'car-004',
name: 'car-004',
url: '/api/models/fea1e799ff4c4ec595fde2f76df12e15/0/gltf/', // 模型地址
position: [0, 0, 0], // 世界坐标系下的位置
complete: function (ev) {
console.log(ev.object.animationNames); // 查看模型动画
app.camera.flyTo({
time: 1 * 1000,
object: ev.object,
xAngle: 20, // 绕物体自身X轴旋转角度
yAngle: 30, // 绕物体自身Y轴旋转角度
radiusFactor: 2, // 物体包围盒半径的倍数
})
// 查询页面所有的按钮
let btnList = document.querySelectorAll("#widget_root input");
btnList.forEach(btn => { btn.remove() }) // 删除所有的按钮,主要是唯一的一个按钮"创建模型"
new THING.widget.Button('铲杆起', function () { // 创建一个"铲杆起"的按钮
let car4 = app.query("car-004")[0]; // 根据名称找到创建的模型
if ($("input[value='铲杆起']").length) { // 如果有"铲杆起"的按钮
car4.playAnimation("起"); // 执行铲杆起动画
$("input[value='铲杆起']").val('铲杆落'); // "铲杆起"按钮文案改为"铲杆落"
} else { // 否则相反
car4.playAnimation({ name: "落" });
$("input[value='铲杆落']").val('铲杆起');
}
});
}
});
}
创建UI界面
点击按钮,在屏幕右上角创建二维UI界面。点击模型,展示模型名称,点击进入层级按钮,切换到展示名称的模型层级。
javascript
// 加载场景后执行
app.on('load', function (ev) {
var campus = ev.campus;
app.level.change(campus);
// 创建UI页面
new THING.widget.Button('创建UI界面', () => {
reset(); // 清除之前的UI页面
new UI(); // 新建UI页面
});
});
// UI界面
class UI {
constructor() {
this.init();
}
// 初始化面板
init() {
var _this = this;
var template =
`<div class="uiPanel" style='position:absolute;right:20px;top:20px;padding: 8px;width:200px;text-align: center;background: rgba(0,0,0,0.5);'>
<p id="p1" style='color:white'>Hello World!</p>
<button id="uiBtn" style='margin:4px;padding:4px'>进入层级</button>
</div>
`;
// 插入到 ThingJS 内置的 2D 界面 div 中
$('#div2d').append($(template));
// 点击按钮的时候,走层级切换方法
$("#uiBtn").on('click', function() {
_this.changeLevel(); // 走场景切换
})
_this.clickEvent(); // 创建点击事件
}
// 添加点击事件
clickEvent() {
var _this = this;
app.on(THING.EventType.SingleClick, function(ev) { // 单击模型
if (ev.picked && ev.object) {
var obj = ev.object; // 获取单击的模型
var name = obj.name; // 获取单击模型的名称
document.getElementById("p1").innerHTML = name; // 给P标签展示出模型的名字
}
})
}
// 进入指定层级
changeLevel() {
var value = document.getElementById("p1").innerHTML; // 获取P标签展示的模型名称
var obj = app.query(value)[0]; // 根据模型名称查询模型
if (obj) { // 如果有模型
app.level.change(obj); // 切换到模型的层级
}
}
}
// 重置
function reset() {
$(".uiPanel").remove(); // 移除UI界面
}
创建Widget面板
创建widget面板,添加输入框、多选框、开关等组件,实现数据双向绑定,监听数据变化。
javascript
// 加载场景后执行
app.on('load', function (ev) {
var campus = ev.campus;
app.level.change(campus);
new THING.widget.Button('创建Widget面板', () => {
reset(); // 删除之前存在的
new Widget(); // 创建 widget 页面
});
});
// Widget面板
class Widget {
constructor() {
this.init();
}
// 初始化面板
init() {
// 界面组件
this.panel = new THING.widget.Panel({
titleText: '<font color="red">面板标题</font>', // 可通过font标签设置标题颜色 例如:'<font color="red">我是红色标题</font>'
closeIcon: true, // 是否有关闭按钮
dragable: true, // 是否可拖拽
retractable: true, // 是否可收缩
opacity: 0.9, // 设置透明度
hasTitle: true, // 设置标题
zIndex: 999 // 设置层级
});
// 面板定位
// 左上角------TL/topleft,左下角------BL/bottomleft
// 右上角------TR/topright,右下角------BR/bottomright
this.panel.position = ['100%', 0];
this.panel.positionOrigin = 'TR';
this.addData(); // 添加数据
}
// 绑定数据
addData() {
var _this = this;
// 创建数据对象
var dataObj = {
pressure: '0.14MPa',
temperature: '21°C',
checkbox: { '设备1': false, '设备2': false, '设备3': true, '设备4': true },
radio: '摄像头01',
open: true,
height: 10,
iframe: 'https://wjw1014.blog.csdn.net/'
};
// 加载字符型组件
var press = _this.panel.addString(dataObj, 'pressure').caption('水压').isChangeValue(true);
// 可通过font标签设置 组件caption颜色
var water = _this.panel.addString(dataObj, 'temperature').caption('<font color="blue">水温</font>').isChangeValue(true);
// 加载复选框组件
var check = _this.panel.addCheckbox(dataObj, 'checkbox').caption({ "设备2": "设备2(rename)" });
// 复选框需逐个添加change事件
check[0].on('change', function(ev) {
console.log(ev);
});
check[1].on('change', function(ev) {
console.log(ev);
})
// 加载单选框组件
var radio = _this.panel.addRadio(dataObj, 'radio', ['摄像头01', '摄像头02']);
radio.on('change', function(ev) {
console.log(ev);
})
// 加载开关组件(适用于Boolean类型数据)
var open1 = _this.panel.addBoolean(dataObj, 'open').caption('开关01');
open1.on('change', function(ev) {
console.log(ev);
})
// 加载数字组件
var height = _this.panel.addNumber(dataObj, 'height').caption('高度');
// 加载iframe组件
var iframe = _this.panel.addIframe(dataObj, 'iframe').caption('视频');
// 设置iframe高度
iframe.setHeight("250px");
// 组件可通过 remove 移除
// _this.panel.remove(height);
}
}
// 重置
function reset() {
$(".ThingJS_wrap").remove(); // 移除面板
}
创建 UIAnchor 界面
创建UIAnchor界面,跟随模型展示模型信息。
javascript
// 加载场景后执行
app.on('load', function (ev) {
var campus = ev.campus;
app.level.change(campus);
new THING.widget.Button('创建UIAnchor', () => {
reset();
uiAnchorPanel = new UIAnchor();
});
});
var uiAnchorPanel = null;
// UIAnchor界面
class UIAnchor {
constructor() {
this.ui = null;
this.init();
}
// 初始化面板
init() {
var _this = this;
if (document.getElementById('board')) {
$('#div3d').find('#board').remove();
}
var template =
`
<div id="board" style="width: 150px;font-size: 12px;padding: 5px 8px;box-sizing: border-box; text-align: center;background-color: rgba(0, 0, 0, .6);border: 3px solid #eeeeee;border-radius: 8px;color: #eee;position: absolute;top: 0;left: 0;z-index: 10;display:none">
<div style="margin: 3px 0;overflow: hidden;display: flex;align-items: center;justify-content: space-between;">
<span style="float: left;font-size: 14px;">详情</span>
<div style="float: right;width: 12px;height: 12px;background-color: #18EB20;border-radius: 50%;"></div>
</div>
<hr style="border: none;height: 1px;background: rgb(133, 133, 133);">
<div style="margin: 3px 0;overflow: hidden;display: flex;align-items: center;justify-content: space-between;">
<span style="float: left;">模型名称:</span>
<span style="float: right;">${app.query('car-002')[0].name}</span>
</div>
<div class="ed-close" style="width: 12px;height: 12px;position: absolute;top:-6px;right:-6px;background-color: #3F6781;width: 8px;height: 8px;border: 2px solid #eee;border-radius: 50%;cursor: pointer""></div>
</div>
`
$('#div3d').append($(template));
this.test_create_ui();
$('#board .ed-close').on('click', function () {
reset()
})
}
// 创建UIAnchor
test_create_ui() {
var _this = this;
_this.ui = app.create({
type: 'UIAnchor',
parent: app.query('car-002')[0],
element: _this.create_element(),
localPosition: [0, 2, 0],
pivot: [0.5, 1] // [0,0]即以界面左上角定位,[1,1]即以界面右下角进行定位
});
}
// 创建dom元素
create_element() {
var srcElem = document.getElementById('board');
var newElem = srcElem.cloneNode(true);
newElem.style.display = "block";
app.domElement.insertBefore(newElem, srcElem);
return newElem;
}
}
// 重置
function reset() {
if (uiAnchorPanel && uiAnchorPanel.ui) {
uiAnchorPanel.ui.destroy(); // 移除UIAnchor
uiAnchorPanel.ui = null;
}
}
创建Panel面板
创建Panel面板
javascript
// 加载场景后执行
app.on('load', function (ev) {
var campus = ev.campus;
app.level.change(campus);
new THING.widget.Button('创建Panel面板', () => {
reset();
new Panel();
});
});
// Panel面板
class Panel {
constructor() {
this.init();
}
// 初始化面板
init() {
var obj = app.query('car-002')[0];
// 创建widget (绑定数据用)
var panel = new THING.widget.Panel({
// 设置面板宽度
width: '150px',
// cornerType 角标样式
// 没有角标 none ,没有线的角标 noline ,折线角标 polyline
cornerType: 'polyline'
})
// 绑定物体身上相应的属性数据
panel.addString(obj, 'name').caption('名称');
// 创建UIAnchor面板
var uiAnchor = app.create({
// 类型
type: 'UIAnchor',
// 父节点设置
parent: obj,
// 要绑定的页面的 element 对象
element: panel.domElement,
// 设置 localPosition 为 [0, 0, 0]
localPosition: [0, -1, 0],
// 相对于Element左上角的偏移像素值
pivotPixel: [-16, 109] // 当前用值是角标的中心点
});
}
}
// 重置
function reset() {
$(".uiPanel").remove(); // 移除UI界面
}
添加纯文本标签
添加纯文本标签
javascript
// 加载场景后执行
app.on('load', function (ev) {
var campus = ev.campus;
app.level.change(campus);
// 添加纯文本标注
new THING.widget.Button('老爷车展示标签', addTagForOld);
new THING.widget.Button('老爷车删除标签', delTagForOld);
});
function addTagForOld() {
delTagForOld();
let car = app.query("car-002")[0];
var textMarkerHtml =
`<div class="textMarker" id="textMarkerTo` + car.id + `" style="position: absolute;">
<div class="text" style="color: #ff0000;font-size: 12px;text-shadow: #ffff00 0px 2px, #ffff00 2px 0px, #ffff00 -2px 0px, #ffff00 0px -2px, #ffff00 -1.4px -1.4px, #ffff00 1.4px 1.4px, #ffff00 1.4px -1.4px, #ffff00 -1.4px 1.4px;">
老爷车标签
</div>
</div>`;
$('#div3d').append($(textMarkerHtml));
car.setAttribute('textMarkerID', $(textMarkerHtml).attr('id'));
let objTopCardEleID = car.getAttribute("textMarkerID");
let anchorCreateJson = {
type: "UIAnchor",
parent: car,
element: $("#" + objTopCardEleID)[0],
localPosition: [0, 1.5, 0],
pivotPixel: [parseFloat($("#" + objTopCardEleID).css("width")) / 2, parseFloat($("#" + objTopCardEleID).css("height"))]
}
let tempTopCard = app.create(anchorCreateJson); // 创建顶牌
tempTopCard.visible = true; // 设置初始顶牌状态
}
function delTagForOld() {
let car = app.query("car-002")[0];
let objTopCardEleID = car.getAttribute("textMarkerID");
$('#' + objTopCardEleID).remove();
}
添加图片+文本标签
添加图片+文本标签
javascript
// 加载场景后执行
app.on('load', function (ev) {
var campus = ev.campus;
app.level.change(campus);
// 添加纯文本标注
new THING.widget.Button('展示图片标签', addTag);
new THING.widget.Button('删除图片标签', delTag);
});
function addTag() {
delTag();
var textAndPictureMarkerHtml =
`<div class="textAndPictureMarker" style="position: absolute;">
<div class="text" style="color: #FF0000;font-size: 12px;text-shadow: white 0px 2px, white 2px 0px, white -2px 0px, white 0px -2px, white -1.4px -1.4px, white 1.4px 1.4px, white 1.4px -1.4px, white -1.4px 1.4px;margin-bottom: 5px;">
测试标签2
</div>
<div class="picture" style="height: 30px;width: 30px;margin: auto;">
<img src="/guide/examples/images/navigation/pointer.png" style="height: 100%;width: 100%;">
</div>
</div>`;
$('#div3d').append($(textAndPictureMarkerHtml));
let anchorCreateJson = {
type: "UIAnchor",
element: $(".pictureMarker")[0],
localPosition: [0, 1, 0],
parent: app.query('car-002')[0],
pivotPixel: [parseFloat($(".textAndPictureMarker").css("width")) / 2, parseFloat($(".textAndPictureMarker").css("height"))]
}
anchorCreateJson.element = $(".textAndPictureMarker")[0];
anchorCreateJson.pivotPixel = [parseFloat($(".textAndPictureMarker").css("width")) / 2, parseFloat($(".textAndPictureMarker").css("height"))];
let tempTopCard = app.create(anchorCreateJson); // 创建顶牌
tempTopCard.visible = true; // 设置初始顶牌状态
}
function delTag() {
$('.textAndPictureMarker').remove();
}
切换场景效果
用下面一段代码,可以讲场景中,设置ID的模型修改为统一的效果。
javascript
// 场景效果,ThingJS版本为1.2.7.14及以上使用此字符串
var themeStr = "{\"version\":\"1.5.0\",\"background\":\"#001326\",\"skybox\":\"None\",\"fog\":{\"type\":\"None\",\"color\":\"#808080\",\"near\":0.1,\"far\":100},\"postEffects\":{\"glow\":{\"strength\":0.28,\"radius\":0.51}},\"class\":{\"Facade\":{\"enable\":false,\"useColormap\":true,\"colormap\":{\"0\":\"#041026\",\"1\":\"#0e0b93\",\"0.72\":\"#1a4aa8\"},\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"opacity\":0.9,\"glow\":true,\"wireframe\":{\"enable\":true,\"color\":\"#217cd1\",\"glow\":true,\"opacity\":0.99},\"reflection\":{\"enable\":false,\"metalness\":0.6,\"roughness\":0.2},\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"FacadeMain\":{\"enable\":false,\"useColormap\":true,\"colormap\":{\"0\":\"#041026\",\"1\":\"#0e0b93\",\"0.72\":\"#1a4aa8\"},\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"opacity\":0.9,\"glow\":true,\"wireframe\":{\"enable\":true,\"color\":\"#217cd1\",\"glow\":true,\"opacity\":0.99},\"reflection\":{\"enable\":false,\"metalness\":0.6,\"roughness\":0.2},\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Ground\":{\"enable\":false,\"useColormap\":true,\"colormap\":{\"0\":\"#041026\",\"1\":\"#0e0b93\",\"0.72\":\"#1a4aa8\"},\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"opacity\":0.9,\"glow\":false,\"wireframe\":{\"enable\":false,\"color\":\"#ffffff\",\"glow\":false,\"opacity\":0.99},\"reflection\":{\"enable\":false,\"metalness\":0.6,\"roughness\":0.2},\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"FloorFloor\":{\"colormap\":{\"0\":\"#183f5c\",\"1\":\"#183f5c\"},\"opacity\":0.65,\"wireframe\":{\"enable\":false,\"color\":\"#0f8bff\",\"glow\":false,\"opacity\":0.78},\"glow\":false,\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"reflection\":{\"enable\":true,\"metalness\":0.63,\"roughness\":0.46},\"enable\":true,\"useColormap\":true,\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"FloorCeiling\":{\"colormap\":{\"1\":\"#0844dd\",\"0.61\":\"#031d7a\"},\"opacity\":0,\"wireframe\":{\"enable\":false,\"color\":\"#0f8bff\",\"glow\":false,\"opacity\":0},\"glow\":false,\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"reflection\":{\"enable\":false,\"metalness\":0.63,\"roughness\":0.46},\"enable\":true,\"useColormap\":false,\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"FloorRoof\":{\"colormap\":{\"1\":\"#0844dd\",\"0.61\":\"#031d7a\"},\"opacity\":0,\"wireframe\":{\"enable\":false,\"color\":\"#0f8bff\",\"glow\":false,\"opacity\":0},\"glow\":false,\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"reflection\":{\"enable\":false,\"metalness\":0.63,\"roughness\":0.46},\"enable\":true,\"useColormap\":false,\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"FloorManualWall\":{\"colormap\":{\"1\":\"#175E93\",\"0.61\":\"#183F5C\"},\"opacity\":0.6,\"wireframe\":{\"enable\":true,\"color\":\"#34CED5\",\"glow\":false,\"opacity\":0.78},\"glow\":false,\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"reflection\":{\"enable\":true,\"metalness\":0.63,\"roughness\":0.46},\"enable\":true,\"useColormap\":true,\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Door\":{\"colormap\":{\"1\":\"#0844dd\",\"0.61\":\"#031d7a\"},\"opacity\":0.3,\"wireframe\":{\"enable\":true,\"color\":\"#34CED5\",\"glow\":true,\"opacity\":0.78},\"glow\":false,\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"reflection\":{\"enable\":true,\"metalness\":0.63,\"roughness\":0.46},\"enable\":true,\"useColormap\":true,\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Objects\":{\"colormap\":{\"1\":\"#0844dd\",\"0.61\":\"#031d7a\"},\"opacity\":0.3,\"wireframe\":{\"enable\":true,\"color\":\"#0f8bff\",\"glow\":true,\"opacity\":0.78},\"glow\":false,\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"reflection\":{\"enable\":true,\"metalness\":0.63,\"roughness\":0.46},\"enable\":true,\"useColormap\":true,\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Thing\":{\"enable\":true,\"useColormap\":true,\"colormap\":{\"0\":\"#175E93\",\"1\":\"#175e93\",\"0.76\":\"#063799\",\"0.45\":\"#006bce\",\"0.23\":\"#0767bf\"},\"opacity\":0.67,\"wireframe\":{\"enable\":false,\"color\":\"#217cd1\",\"glow\":false,\"opacity\":0.85},\"glow\":false,\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"reflection\":{\"enable\":false,\"metalness\":0.76,\"roughness\":0.41000000000000003},\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Tree\":{\"enable\":true,\"useColormap\":true,\"colormap\":{\"0\":\"#040a26\",\"0.99\":\"#135e1f\",\"0.36\":\"#2fb8d6\",\"0.66\":\"#128cd1\"},\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"opacity\":1,\"glow\":true,\"wireframe\":{\"enable\":false,\"color\":\"#26e2d7\",\"glow\":false,\"opacity\":0.99},\"reflection\":{\"enable\":false,\"metalness\":0.6,\"roughness\":0.2},\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"}},\"resourcePrefix\":\"\",\"enviroment\":\"https://www.thingjs.com/static/images/reflect1.jpg\"}";
// ThingJS版本为1.2.7.13及之前的版本使用此字符串
// var themeStr = "{\"version\":\"1.2.1\",\"background\":\"#001326\",\"skybox\":\"None\",\"fog\":{\"type\":\"None\",\"color\":\"#808080\",\"near\":0.1,\"far\":100},\"postEffects\":{\"glow\":{\"strength\":0.28,\"radius\":0.51}},\"class\":{\"Facade\":{\"enable\":false,\"useColormap\":true,\"colormap\":{\"0\":\"#041026\",\"1\":\"#0e0b93\",\"0.72\":\"#1a4aa8\"},\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"opacity\":0.9,\"glow\":true,\"wireframe\":{\"enable\":true,\"color\":\"#217cd1\",\"glow\":true,\"opacity\":0.99},\"reflection\":{\"enable\":false,\"metalness\":0.6,\"roughness\":0.2},\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Facade-主建筑\":{\"enable\":false,\"useColormap\":true,\"colormap\":{\"0\":\"#041026\",\"1\":\"#0e0b93\",\"0.72\":\"#1a4aa8\"},\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"opacity\":0.9,\"glow\":true,\"wireframe\":{\"enable\":true,\"color\":\"#217cd1\",\"glow\":true,\"opacity\":0.99},\"reflection\":{\"enable\":false,\"metalness\":0.6,\"roughness\":0.2},\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Ground\":{\"enable\":false,\"useColormap\":true,\"colormap\":{\"0\":\"#041026\",\"1\":\"#0e0b93\",\"0.72\":\"#1a4aa8\"},\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"opacity\":0.9,\"glow\":false,\"wireframe\":{\"enable\":false,\"color\":\"#ffffff\",\"glow\":false,\"opacity\":0.99},\"reflection\":{\"enable\":false,\"metalness\":0.6,\"roughness\":0.2},\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Floor--floor\":{\"colormap\":{\"0\":\"#183f5c\",\"1\":\"#183f5c\"},\"opacity\":0.65,\"wireframe\":{\"enable\":false,\"color\":\"#0f8bff\",\"glow\":false,\"opacity\":0.78},\"glow\":false,\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"reflection\":{\"enable\":true,\"metalness\":0.63,\"roughness\":0.46},\"enable\":true,\"useColormap\":true,\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Floor--ceiling\":{\"colormap\":{\"1\":\"#0844dd\",\"0.61\":\"#031d7a\"},\"opacity\":0,\"wireframe\":{\"enable\":false,\"color\":\"#0f8bff\",\"glow\":false,\"opacity\":0},\"glow\":false,\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"reflection\":{\"enable\":false,\"metalness\":0.63,\"roughness\":0.46},\"enable\":true,\"useColormap\":false,\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Floor--roof\":{\"colormap\":{\"1\":\"#0844dd\",\"0.61\":\"#031d7a\"},\"opacity\":0,\"wireframe\":{\"enable\":false,\"color\":\"#0f8bff\",\"glow\":false,\"opacity\":0},\"glow\":false,\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"reflection\":{\"enable\":false,\"metalness\":0.63,\"roughness\":0.46},\"enable\":true,\"useColormap\":false,\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Floor--manualWall\":{\"colormap\":{\"1\":\"#175E93\",\"0.61\":\"#183F5C\"},\"opacity\":0.6,\"wireframe\":{\"enable\":true,\"color\":\"#34CED5\",\"glow\":false,\"opacity\":0.78},\"glow\":false,\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"reflection\":{\"enable\":true,\"metalness\":0.63,\"roughness\":0.46},\"enable\":true,\"useColormap\":true,\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Door\":{\"colormap\":{\"1\":\"#0844dd\",\"0.61\":\"#031d7a\"},\"opacity\":0.3,\"wireframe\":{\"enable\":true,\"color\":\"#34CED5\",\"glow\":true,\"opacity\":0.78},\"glow\":false,\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"reflection\":{\"enable\":true,\"metalness\":0.63,\"roughness\":0.46},\"enable\":true,\"useColormap\":true,\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Floor\":{\"colormap\":{\"1\":\"#0844dd\",\"0.61\":\"#031d7a\"},\"opacity\":0.3,\"wireframe\":{\"enable\":true,\"color\":\"#0f8bff\",\"glow\":true,\"opacity\":0.78},\"glow\":false,\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"reflection\":{\"enable\":true,\"metalness\":0.63,\"roughness\":0.46},\"enable\":true,\"useColormap\":true,\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Thing\":{\"enable\":true,\"useColormap\":true,\"colormap\":{\"0\":\"#175E93\",\"1\":\"#175e93\",\"0.76\":\"#063799\",\"0.45\":\"#006bce\",\"0.23\":\"#0767bf\"},\"opacity\":0.67,\"wireframe\":{\"enable\":false,\"color\":\"#217cd1\",\"glow\":false,\"opacity\":0.85},\"glow\":false,\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"reflection\":{\"enable\":false,\"metalness\":0.76,\"roughness\":0.41000000000000003},\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Thing-树\":{\"enable\":true,\"useColormap\":true,\"colormap\":{\"0\":\"#040a26\",\"0.99\":\"#135e1f\",\"0.36\":\"#2fb8d6\",\"0.66\":\"#128cd1\"},\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"opacity\":1,\"glow\":true,\"wireframe\":{\"enable\":false,\"color\":\"#26e2d7\",\"glow\":false,\"opacity\":0.99},\"reflection\":{\"enable\":false,\"metalness\":0.6,\"roughness\":0.2},\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Region\":{\"enable\":true,\"useColormap\":true,\"colormap\":{\"0.08\":\"#0b142b\",\"0.21\":\"#114f40\",\"0.3\":\"#2555b2\",\"0.44\":\"#31a4d6\",\"0.59\":\"#0e285b\"},\"opacity\":1,\"wireframe\":{\"enable\":false,\"color\":\"#ffffff\",\"glow\":false,\"opacity\":0.99},\"glow\":false,\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"reflection\":{\"enable\":false,\"metalness\":0.6,\"roughness\":0.2},\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"},\"Fence\":{\"enable\":true,\"useColormap\":true,\"colormap\":{\"0\":\"#064896\",\"0.68\":\"#24d8f2\",\"0.41\":\"#348aef\"},\"useScrollTex\":false,\"scrollColor\":\"#ffffff\",\"opacity\":0.8,\"glow\":false,\"wireframe\":{\"enable\":false,\"color\":\"#ffffff\",\"glow\":false,\"opacity\":0.99},\"reflection\":{\"enable\":false,\"metalness\":0.6,\"roughness\":0.2},\"scrollTex\":\"https://www.thingjs.com/static/images/scroll.jpg\"}},\"resourcePrefix\":\"\",\"enviroment\":\"https://www.thingjs.com/static/images/reflect1.jpg\"}";
// 加载场景后执行
app.on('load', function (ev) {
var campus = ev.campus;
app.level.change(campus);
useTheme()
});
// 使用场景效果
function useTheme(){
var theme = JSON.parse(themeStr);
THING.ThemeManager.register('theme', theme);
app.root.applyTheme('theme');
app.applyThemeEnvironment('theme');
}
鼠标事件
鼠标单击、双击、滑过、拖拽事件。
javascript
// 加载场景后执行
app.on('load', function (ev) {
var campus = ev.campus;
// app.level.change(campus);
new THING.widget.Button('开启单击事件', click);
new THING.widget.Button('开启双击事件', db);
new THING.widget.Button('开启滑过事件', mousemove);
new THING.widget.Button('开启拖拽事件', drag);
});
function click() {
var posInfo = document.querySelectorAll("#widget_root input");
if (posInfo[0].value == "开启单击事件") {
app.on('click', function (event) {
if (event.button == 0) {
if (event.picked && event.object) {
if (event.object.style.color === '#FF0000') {
event.object.style.color = null;
} else {
event.object.style.color = "#FF0000";
}
}
}
});
posInfo[0].value = "关闭单击事件";
}
else if (posInfo[0].value == "关闭单击事件") {
app.off('click');
posInfo[0].value = "开启单击事件";
}
}
function db() {
var posInfo = document.querySelectorAll("#widget_root input");
if (posInfo[1].value == "开启双击事件") {
app.on('dblclick', function (event) {
if (event.button == 0) {
if (event.picked && event.object) {
app.camera.flyTo({
object: event.object,
xAngle: 35, // 绕物体自身X轴旋转角度
yAngle: 20, // 绕物体自身Y轴旋转角度
radiusFactor: 4, // 物体包围盒半径的倍数
time: 1 * 1000,
complete: function () { }
});
}
}
});
posInfo[1].value = "关闭双击事件";
}
else if (posInfo[1].value == "关闭双击事件") {
app.off('dblclick');
posInfo[1].value = "开启双击事件";
}
}
function mousemove() {
let objs = app.query(/car/);
var posInfo = document.querySelectorAll("#widget_root input"); // 获取按钮value值,进行改变
// 鼠标滑过事件/取消滑过事件切换
if (posInfo[2].value == "开启滑过事件") {
// 改变颜色
objs.on('mouseenter', function (ev) {
ev.object.style.color = '#ff0000';
});
// 还原颜色
objs.on('mouseleave', function (ev) {
ev.object.style.color = null;
});
posInfo[2].value = "关闭滑过事件";
}
else if (posInfo[2].value == "关闭滑过事件") {
objs.on('mouseenter', function (ev) {
ev.object.style.color = null;
});
objs.on('mouseleave', function (ev) {
ev.object.style.color = null;
});
posInfo[2].value = "开启滑过事件";
}
}
function drag() {
let objs1 = app.query(/car/); // 所有名称里包含 car 字段的物体
let posInfo = document.querySelectorAll("#widget_root input"); // 获取按钮value值,进行改变
if (posInfo[3].value == "开启拖拽事件") { // 开启拖拽/关闭拖拽
objs1.draggable = true; // 设置物体可拖拽(默认物体不可拖拽)
objs1.style.outlineColor = '#00ff00'; // 设置勾边颜色
posInfo[3].value = "关闭拖拽事件";
}
else if (posInfo[3].value == "关闭拖拽事件") {
objs1.draggable = false;
objs1.style.outlineColor = null;
posInfo[3].value = "开启拖拽事件";
}
}
相机位置设置
相机位置设置
javascript
// 加载场景后执行
app.on('load', function (ev) {
var campus = ev.campus;
app.level.change(campus);
new THING.widget.Button('直接设置', setCamera);
new THING.widget.Button('聚焦物体', fitCamera);
new THING.widget.Button('飞到位置', flytoPos);
new THING.widget.Button('环绕物体', rotateAroundObj);
new THING.widget.Button('飞到物体左侧', flytoLeft);
});
function setCamera() {
initThingJsTip('相机位置10,10,10;相机面向0,0,0');
app.camera.position = [10, 10, 10];
app.camera.target = [0, 0, 0];
}
function fitCamera() {
app.camera.fit(app.query('car-002')[0]);
}
function flytoPos() {
app.camera.flyTo({
position: [5, 5, 5],
target: [0, 0, 0],
time: 2 * 1000,
});
}
function rotateAroundObj() {
app.camera.rotateAround({
object: app.query('car-002')[0],
yRotateAngle: 360,
time: 5000,
});
}
function flytoLeft() {
app.camera.flyTo({
object: app.query('car-001')[0],
xAngle: 0, // 绕物体自身X轴旋转角度
yAngle: 90, // 绕物体自身Y轴旋转角度
radiusFactor: 2, // 物体包围盒半径的倍数
time: 2 * 1000,
});
}
相机设置
相机设置
javascript
// 加载场景后执行
app.on('load', function (ev) {
var campus = ev.campus;
app.level.change(campus);
new THING.widget.Button('2D/3D 切换', changeView);
new THING.widget.Button('摄像机移动', cameraMove);
new THING.widget.Button('摄像机推进', cameraGo);
new THING.widget.Button('摄像机旋转', cameraRotate);
new THING.widget.Button('禁用旋转', stopRotate);
new THING.widget.Button('禁用平移', stopMove);
new THING.widget.Button('禁用缩放', stopScale);
new THING.widget.Button('限制俯仰范围', limitX);
new THING.widget.Button('限制水平范围', limitY);
new THING.widget.Button('重置', resetFly);
});
function changeView() {
var viewMode = app.camera.viewMode;
if (viewMode == "normal") {
app.camera.viewMode = THING.CameraView.TopView; // 切换为2D视图
} else {
app.camera.viewMode = THING.CameraView.Normal; // 默认为3D视图
}
}
function cameraMove() {
app.camera.move(5, 0); // 设置移动距离(水平移动, 垂直移动),正负代表方向
}
function cameraGo() {
app.camera.zoom(10); // 设置推进距离,正负代表方向
}
function cameraRotate() {
app.camera.rotateAround({
target: app.camera.target,
yRotateAngle: 5, // 环绕Y轴旋转角度(俯仰面(竖直面)内的角度)
xRotateAngle: 5, // 环绕X轴旋转角度(方位面(水平面)内的角度)
time: 1000 // 环绕飞行的时间
});
}
function stopRotate() {
app.camera.enableRotate = false; // 禁用旋转
}
function stopMove() {
app.camera.enablePan = false; // 禁用平移
}
function stopScale() {
app.camera.enableZoom = false; // 禁用缩放
}
// 限制摄像机水平范围
function limitY() {
reset();
initThingJsTip("设置摄像机俯仰角度范围[30, 60],上下移动鼠标查看效果");
app.camera.yAngleLimitRange = [30, 60]; // 设置摄像机水平角度范围[最小值, 最大值]
}
// 限制摄像机俯仰范围
function limitX() {
reset();
initThingJsTip("设置摄像机俯仰角度范围[0, 90],上下移动鼠标查看效果");
app.camera.xAngleLimitRange = [0, 90]; // 设置摄像机俯仰角度范围[最小值, 最大值]
}
function resetFly() {
app.camera.flyTo({
position: [-36.013, 42.67799999999998, 61.72399999999999],
target: [1.646, 7.891, 4.445],
time: 1000,
complete: function () {
reset()
}
});
}
function reset() {
app.camera.viewMode = THING.CameraView.Normal; // 默认为3D视图
app.camera.enableRotate = true; // 启用旋转
app.camera.enablePan = true; // 启用平移
app.camera.enableZoom = true; // 启用缩放
app.camera.xAngleLimitRange = [-90, 90]; // 设置摄像机俯仰角度范围[最小值, 最大值]
app.camera.yAngleLimitRange = [-360, 360]; // 设置摄像机水平角度范围[最小值, 最大值]
}
模型操作
模型操作
javascript
var line = null;
// 加载场景后执行
app.on('load', function (ev) {
var campus = ev.campus;
app.level.change(campus);
new THING.widget.Button('获取当前相机信息', getCameraInfo);
new THING.widget.Button('移动到某位置', moveToPosition);
new THING.widget.Button('沿路径移动', movePath);
new THING.widget.Button('旋转动画', rotateTo);
new THING.widget.Button('缩放动画', scaleTo);
new THING.widget.Button('重置', reset);
});
function getCameraInfo() {
let pos = app.camera.position;
let tag = app.camera.target;
console.log(pos, tag);
}
function moveToPosition() {
let man = app.query('man-002')[0];
app.camera.flyTo({
position: [-1.62, 8.06, 7.19],
target: [-9.21, 0.01, -8.24],
time: 2 * 1000,
complete: function () {
man.moveTo({
position: [-9.21, 0.01, 3.24],
time: 1 * 1000,
})
}
})
}
function movePath() {
let man = app.query("man-002")[0];
man.position = [0, 0, 0];
let path = [[0, 0.01, 0], [8, 0.1, 0], [8, 0.1, 4], [0, 0.1, 4]];
app.camera.flyTo({
position: [10, 10, 10],
target: [0, 0, 0],
time: 2 * 1000,
complete: function () {
line = app.create({
type: 'Line',
dotSize: 2,
dotColor: 0xFF0000,
points: path,
complete: function () {
man.movePath({
"orientToPath": true,
path: path,
time: 3 * 1000,
delayTime: 1000,
"lerpType": null
})
}
})
}
})
}
function rotateTo() {
let man = app.query('man-002')[0];
// 摄像机飞行到某位置
app.camera.flyTo({
position: [-6.35, 3.0, -2.4],
target: [-9.21, 0.01, -8.24],
time: 1000,
complete: function () {
man.rotateTo({
angles: [0, 720, 0],
time: 5000,
lerpType: THING.LerpType.Quadratic.In, // 速度插值
})
}
});
}
function scaleTo() {
let man = app.query('man-002')[0];
app.camera.flyTo({
position: [-6.35, 3.0, -2.4],
target: [-9.21, 0.01, -8.24],
time: 1000,
complete: function () {
man.scaleTo({
scale: [1.5, 1.5, 1.5], // 缩放倍数
time: 1000, // 动画时间
loopType: THING.LoopType.PingPong, // 循环类型 设置循环后 无回调函数
})
}
})
}
function reset() {
let man = app.query('man-002')[0];
man.position = [-8.0319996, 0.009999999999999787, -5.4910002];
man.angles = [0, 0, 0]
man.scale = [1, 1, 1];
man.stopScaling();
if (line !== null) {
line.destroy();
}
app.camera.flyTo({
position: [-62.90200000000001, 29.026, 22.714999999999996],
target: [-9.205, 0.01, -8.237],
time: 2 * 1000,
complete: function () { }
})
}