mirror of
https://gitee.com/iioter/iotgateway.git
synced 2024-11-29 18:28:09 +08:00
282 lines
6.8 KiB
HTML
282 lines
6.8 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
|
||
<head>
|
||
<title>3D</title>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||
<link type="text/css" rel="stylesheet" href="./css/main.css">
|
||
<style>
|
||
body {
|
||
background-color: #bfe3dd;
|
||
color: #000;
|
||
}
|
||
|
||
a {
|
||
color: #2983ff;
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
|
||
<div id="container"></div>
|
||
<script src="../jquery.min.js"></script>
|
||
<script src="../mqtt.min.js"></script>
|
||
<script type="module">
|
||
import * as THREE from './lib/three.module.js';
|
||
|
||
import Stats from './lib/stats.module.js';
|
||
|
||
import { OrbitControls } from './lib/OrbitControls.js';
|
||
import { RoomEnvironment } from './lib/RoomEnvironment.js';
|
||
|
||
import { GLTFLoader } from './lib/GLTFLoader.js';
|
||
import { DRACOLoader } from './lib/DRACOLoader.js';
|
||
import { CSS3DObject, CSS3DRenderer } from './lib/CSS3DRenderer.js';
|
||
|
||
let W = window.innerWidth;
|
||
let H = window.innerHeight;
|
||
let mixer;
|
||
let labelArr = [];
|
||
|
||
//标签数据
|
||
let modelData = [{
|
||
id: 1,
|
||
cname: "Modbus设备",
|
||
ename: "modbus_01",
|
||
position: {
|
||
x: -0.5,
|
||
y: 0.6,
|
||
z: 1.55,
|
||
},
|
||
param: [{
|
||
name: "温度",
|
||
value: 123,
|
||
},
|
||
{
|
||
name: "湿度",
|
||
value: 123,
|
||
},
|
||
],
|
||
}
|
||
];
|
||
|
||
//定时更新数据
|
||
//setInterval(() => {
|
||
// modelData.forEach((item) => {
|
||
// if (item.id > 0) {
|
||
// item.param[0].value = parseInt(Math.random() * 30 + 150).toFixed(0);
|
||
// item.param[1].value = parseInt(Math.random() * 30 + 150).toFixed(0);
|
||
// }
|
||
// });
|
||
|
||
// updateData();
|
||
|
||
//}, 2000);
|
||
inimqttclient();
|
||
const clock = new THREE.Clock();
|
||
const container = document.getElementById('container');
|
||
|
||
const stats = new Stats();
|
||
container.appendChild(stats.dom);
|
||
|
||
const css3dRenderer = new CSS3DRenderer();
|
||
css3dRenderer.setSize(W, H);
|
||
css3dRenderer.domElement.style.position = 'absolute';
|
||
css3dRenderer.domElement.style.top = 0;
|
||
container.appendChild(css3dRenderer.domElement);
|
||
|
||
const renderer = new THREE.WebGLRenderer({ antialias: true });
|
||
renderer.setPixelRatio(window.devicePixelRatio);
|
||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||
renderer.outputEncoding = THREE.sRGBEncoding;
|
||
container.appendChild(renderer.domElement);
|
||
|
||
const pmremGenerator = new THREE.PMREMGenerator(renderer);
|
||
|
||
const scene = new THREE.Scene();
|
||
scene.background = new THREE.Color(0xbfe3dd);
|
||
scene.environment = pmremGenerator.fromScene(new RoomEnvironment(), 0.04).texture;
|
||
|
||
const camera = new THREE.PerspectiveCamera(40, W / H, .1, 10000);
|
||
camera.position.set(5, 2, 8);
|
||
|
||
const controls = new OrbitControls(camera, container);
|
||
controls.target.set(0, 0.5, 0);
|
||
controls.update();
|
||
controls.enablePan = false;
|
||
controls.enableDamping = true;
|
||
|
||
const dracoLoader = new DRACOLoader();
|
||
dracoLoader.setDecoderPath('./lib/gltf/');
|
||
|
||
const loader = new GLTFLoader();
|
||
loader.setDRACOLoader(dracoLoader);
|
||
loader.load('./model/LittlestTokyo.glb', function (gltf) {
|
||
|
||
const model = gltf.scene;
|
||
model.position.set(1, 1, 0);
|
||
model.scale.set(0.01, 0.01, 0.01);
|
||
scene.add(model);
|
||
|
||
createLableArr();
|
||
|
||
mixer = new THREE.AnimationMixer(model);
|
||
mixer.clipAction(gltf.animations[0]).play();
|
||
|
||
animate();
|
||
|
||
}, undefined, function (e) {
|
||
|
||
console.error(e);
|
||
|
||
});
|
||
|
||
//创建标签
|
||
function createLableArr() {
|
||
let style = "color: #00CED1;cursor:pointer;font-size:30px;padding:5px 15px;"; //background:#43bafe;
|
||
modelData.forEach((item) => {
|
||
let label = createLabel(item.cname, style, item.param);
|
||
label.position.set(item.position.x, item.position.y, item.position.z);
|
||
let scale = 0.003;
|
||
label.scale.set(scale, scale, scale); //缩放比例
|
||
label.name = item.ename;
|
||
//label.visible = true;
|
||
scene.add(label);
|
||
labelArr.push(label);
|
||
|
||
const axesHelper = new THREE.AxesHelper(5);
|
||
label.add(axesHelper);
|
||
});
|
||
}
|
||
|
||
/**销毁模型*/
|
||
function destroyObject(object) {
|
||
if (!object) return;
|
||
object.traverse((item) => {
|
||
if (item.material) {
|
||
if (Array.isArray(item.material)) {
|
||
item.material.forEach(m => m.dispose());
|
||
} else {
|
||
item.material.dispose();
|
||
}
|
||
}
|
||
if (item.geometry) item.geometry.dispose();
|
||
item = null;
|
||
});
|
||
|
||
scene.remove(object);
|
||
object = null;
|
||
}
|
||
|
||
/**信息标注的生成*/
|
||
function createLabel(text, style, param) {
|
||
//创建CSS3D
|
||
let div_label = document.createElement("div");
|
||
div_label.className = "div-label";
|
||
let div_ul = document.createElement("ul");
|
||
let div_li = document.createElement("li");
|
||
|
||
style ? (div_li.style = style) : "";
|
||
div_li.textContent = `设备名称:${text}`;
|
||
div_ul.appendChild(div_li);
|
||
|
||
if (param.length) {
|
||
param.forEach((item) => {
|
||
let param_li = document.createElement("li");
|
||
style ? (param_li.style = style) : "";
|
||
param_li.textContent = `${item.name}:${item.value}`;
|
||
div_ul.appendChild(param_li);
|
||
});
|
||
}
|
||
|
||
div_label.appendChild(div_ul);
|
||
let label = new CSS3DObject(div_label);
|
||
|
||
return label;
|
||
}
|
||
|
||
//更新数据标签
|
||
function updateData() {
|
||
if (labelArr.length) {
|
||
labelArr.forEach(item => {
|
||
destroyObject(item);
|
||
});
|
||
createLableArr();
|
||
}
|
||
}
|
||
|
||
|
||
window.onresize = function () {
|
||
|
||
camera.aspect = window.innerWidth / window.innerHeight;
|
||
camera.updateProjectionMatrix();
|
||
|
||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||
|
||
};
|
||
|
||
|
||
function animate() {
|
||
|
||
requestAnimationFrame(animate);
|
||
|
||
const delta = clock.getDelta();
|
||
|
||
mixer.update(delta);
|
||
|
||
controls.update();
|
||
|
||
//标签
|
||
// if (labelArr.length) {
|
||
// labelArr.forEach((item) => {
|
||
// if (item.visible) {
|
||
// item.quaternion.slerp(camera.quaternion, 1);
|
||
// }
|
||
// });
|
||
// }
|
||
|
||
stats.update();
|
||
|
||
renderer.render(scene, camera);
|
||
css3dRenderer.render(scene, camera);
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
function inimqttclient() {
|
||
var options = {
|
||
//mqtt客户端的id,这里面应该还可以加上其他参数,具体看官方文档
|
||
clientId: 'mqttjs3d_' + (Math.random() * 10000000).toString()
|
||
}
|
||
var client = mqtt.connect('ws://' + window.location.host + '/mqtt', options);
|
||
client.on('connect', function () {
|
||
client.subscribe('internal/v1/gateway/telemetry/+/+', function (err) {
|
||
if (!err) {
|
||
console.log("订阅成功!")
|
||
} else {
|
||
console.log(err)
|
||
}
|
||
})
|
||
})
|
||
|
||
client.on('message', function (topic, message) {
|
||
if (topic == 'internal/v1/gateway/telemetry/Modbus/temperature') {
|
||
var objmsg = $.parseJSON(message.toString());
|
||
modelData[0].param[0].value = objmsg.CookedValue;
|
||
updateData();
|
||
} else if (topic == 'internal/v1/gateway/telemetry/Modbus/humidity') {
|
||
var objmsg = $.parseJSON(message.toString());
|
||
modelData[0].param[1].value = objmsg.CookedValue;
|
||
updateData();
|
||
}
|
||
})
|
||
}
|
||
</script>
|
||
|
||
</body>
|
||
|
||
</html> |