# thingjs 基础案例整理

thingjs 基础案例整理

ThingJS是一套面向物联网应用的3D可视化PaaS开发和运营平台,它以"ThingJS云视PaaS服务"形式面向广大物联网企业提供全生命周期在线3D可视化服务。

相关资料

创建模型,使用动画

现在用模模搭软件搭建了一个简单的场景,在场景中创建一个叉车模型,这个模型有两个动画,我们执行两个动画。

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 () { }
    })
}
相关推荐
GISer_Jing4 分钟前
前端面试题合集(一)——HTML/CSS/Javascript/ES6
前端·javascript·html
清岚_lxn6 分钟前
es6 字符串每隔几个中间插入一个逗号
前端·javascript·算法
胡西风_foxww9 分钟前
【ES6复习笔记】Map(14)
前端·笔记·es6·map
星就前端叭9 分钟前
【开源】一款基于SpringBoot的智慧小区物业管理系统
java·前端·spring boot·后端·开源
缘友一世11 分钟前
将现有Web 网页封装为macOS应用
前端·macos·策略模式
刺客-Andy27 分钟前
React 第十九节 useLayoutEffect 用途使用技巧注意事项详解
前端·javascript·react.js·typescript·前端框架
谢道韫66632 分钟前
今日总结 2024-12-27
开发语言·前端·javascript
嘤嘤怪呆呆狗43 分钟前
【插件】vscode Todo Tree 简介和使用方法
前端·ide·vue.js·vscode·编辑器
ᥬ 小月亮1 小时前
Js前端模块化规范及其产品
开发语言·前端·javascript
码小瑞1 小时前
某些iphone手机录音获取流stream延迟问题 以及 录音一次第二次不录音问题
前端·javascript·vue.js