iotgateway/3d/3d.html

282 lines
6.8 KiB
HTML
Raw Normal View History

<!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>