赞
踩
接上一篇:
three.js如何实现简易3D机房?(二)模型加载的过渡动画:http://t.csdnimg.cn/onbWY
目录
完整源码地址:computerRoom-demo: 3d机房源码
不完美的地方还有很多,多多包涵~
默认在模型加载完之后,报警设备的红色信息框持续展示;正常设备的绿色信息框,每3s轮换展示
创建3D信息框的内容是相同的,只需要区分报警设备和正常设备两种情况即可,这里我是通过CSS3DObject来实现的
在threeD/init.js文件中
- // 引入CSS3渲染器CSS3DRenderer
- import { CSS3DRenderer } from 'three/addons/renderers/CSS3DRenderer.js';
- export let scene, camera, renderer, controls, css3DRenderer, width, height
-
- // 创建CSS3D渲染器
- export const createCSS3DRenderer = (dom) => {
- // 创建一个CSS3渲染器CSS3DRenderer
- css3DRenderer = new CSS3DRenderer();
- css3DRenderer.setSize(180, 200);
- // HTML标签<div id="dialog"></div>外面父元素叠加到canvas画布上且重合
- css3DRenderer.domElement.style.position = 'absolute';
- css3DRenderer.domElement.style.top = '0';
- // css3DRenderer.domElement.style.left = '0px';
- //设置.pointerEvents=none,解决HTML元素标签对threejs canvas画布鼠标事件的遮挡
- css3DRenderer.domElement.style.pointerEvents = 'none';
- // threeDemoRef.value.appendChild(css3DRenderer.domElement);
- dom.appendChild(css3DRenderer.domElement);
- };
以下内容都是在index.vue文件中,便于功能交互的实现,我没有单独封装,大项目可以结合情况自行抽离封装
在HTML中准备好需要用的弹框标签和样式(根据实际项目来),需要注意的是一定要用深度选择器 :deep(),不然不生效
- :deep(#myDialog) {
- font-size: 8px;
-
- .box-container {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- animation: moveUpDown 3s infinite;
-
- .title {
- font-family: Source Han Sans CN, Source Han Sans CN;
- font-weight: bold;
- color: #fff;
- }
-
- .label-text {
- font-family: Source Han Sans CN, Source Han Sans CN;
- color: #ccddff;
-
- .label-value-green {
- color: #5cdd2e;
- font-weight: bold;
- }
- .label-value-red {
- color: #ff4a4a;
- font-weight: bold;
- }
- }
-
- .tip-green {
- width: 80px;
- height: 40px;
- padding: 5px;
- display: flex;
- flex-direction: column;
- justify-content: center;
- background-color: rgba(22, 29, 38, 0.5);
- opacity: 0.9;
- border: 1px solid #329550;
- box-shadow: inset 0px 0px 15px 0px #329550;
- }
-
- .tip-red {
- width: 80px;
- height: 40px;
- padding: 5px;
- display: flex;
- flex-direction: column;
- justify-content: center;
- background-color: rgba(22, 29, 38, 0.5);
- opacity: 0.9;
- border: 1px solid #882c2c;
- box-shadow: inset 0px 0px 15px 0px #882c2c;
- }
-
- .line-green {
- width: 1px;
- height: 35px;
- background: linear-gradient(to bottom, rgba(28, 107, 51, 0.3), rgb(20, 195, 93), rgba(1, 165, 75, 0.89));
- }
-
- .line-red {
- width: 1px;
- height: 35px;
- background: linear-gradient(to bottom, rgba(123, 44, 28, 0.3), rgba(255, 82, 82, 1), rgba(255, 48, 48, 0.89));
- }
- }
- }
-
- // 动画
- @keyframes moveUpDown {
- 0% {
- transform: translateY(0);
- }
- 50% {
- transform: translateY(8px);
- }
- 100% {
- transform: translateY(0);
- }
- }
- const insertDialogHtml = (obj: any, item: any) => {
- // 多个标签-需要克隆复制一份
- const div: any = dialogRef.value.cloneNode();
- div.innerHTML = `
- <div class="box-container">
- <div class=${item.status == 0 ? 'tip-green' : 'tip-red'} >
- <div class="title">设备名称 : ${item.name}</div>
- <div class="label-text">
- 温度 :
- <span class="mr5" class=${item.tempState == '0' ? 'label-value-green' : 'label-value-red'}>
- ${item.temperature}
- </span>
- <span class=${item.tempState == '0' ? 'label-value-green' : 'label-value-red'}>
- ${item.tempState == '0' ? '正常' : '报警'}
- </span>
- </div>
- <div class="label-text">
- 漏水 :
- <span class="mr5" class=${item.leakageState == '0' ? 'label-value-green' : 'label-value-red'}>
- ${item.leakage}
- </span>
- <span class=${item.leakageState == '0' ? 'label-value-green' : 'label-value-red'}>
- ${item.leakageState == '0' ? '正常' : '报警'}
- </span>
- </div>
- </div>
- <div class=${item.status == 0 ? 'line-green' : 'line-red'}></div>
- </div>
- `;
- // HTML元素转化为threejs的CSS3对象
- const dialog = new CSS3DObject(div);
- //避免标签遮挡canvas鼠标事件
- div.style.pointerEvents = 'none';
- dialog.name = obj.name + 'dialog';
- dialog.scale.set(0.1, 0.1, 1);
- dialog.position.set(0, 6, 0);
- // 判断是否需要旋转
- // const nameList = ['AU04', 'AU07', 'AU08', 'AU09', 'AU10', 'AU11', 'AU16', 'AU17', 'AU18', 'AU19', 'AU20'];
- // if (nameList.includes(obj.name)) {
- // dialog.rotation.set(0, -Math.PI / 2, 0);
- // }
- obj.add(dialog);
- };
准备好需要用的变量,为了方便展示,我这里简单写了一些假数据,实际需要从后端接口获取
- const state: any = reactive({
- loading: true, // 是否开启加载动画
- progress: 0, // 模型加载进度
- randomObject: null, // 随机正常设备
- selectedDevice: null, // 点击选中的设备
- intervalId: null, // 定时器
- allDeviceObjList: [], // 所有设备obj
- // 报警设备
- alarmInfo: [
- {
- name: 'AU02',
- temperature: '35℃', // 温度
- tempState: '1', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '1', // 漏水报警状态 0正常 1报警
- status: 1,
- },
- {
- name: 'AU08',
- temperature: '38℃', // 温度
- tempState: '1', // 温度报警状态 0正常 1报警
- leakage: '60', // 漏水
- leakageState: '1', // 漏水报警状态 0正常 1报警
- status: 1,
- },
- {
- name: 'AU18',
- temperature: '40℃', // 温度
- tempState: '1', // 温度报警状态 0正常 1报警
- leakage: '72', // 漏水
- leakageState: '1', // 漏水报警状态 0正常 1报警
- status: 1,
- },
- ],
- // 正常设备
- normalInfo: [
- {
- name: 'AU01',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU03',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU04',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU05',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU06',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU07',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU09',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU10',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU11',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU12',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU13',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU14',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU15',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU16',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU17',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU19',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU20',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU21',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- {
- name: 'AU22',
- temperature: '35℃', // 温度
- tempState: '0', // 温度报警状态 0正常 1报警
- leakage: '58', // 漏水
- leakageState: '0', // 漏水报警状态 0正常 1报警
- status: 0,
- },
- ],
- });
- import { createCSS3DRenderer } from './component/threeD/init.js';
-
- onMounted(async () => {
- init(threeDemoRef.value);
- importModel();
- createControls();
- initLight();
- createCSS3DRenderer(threeDemoRef.value);
- watchDom(threeDemoRef.value);
- renderResize(threeDemoRef.value);
- renderLoop();
- });
-
- const createAlarmDialog = () => {
- state.allDeviceObjList = [];
- model.traverse((obj: any) => {
- // 筛选出报警设备
- if (obj.name.includes('AU')) {
- state.allDeviceObjList.push(obj);
- // 报警数据持续展示
- state.alarmInfo.forEach((item: any) => {
- if (item.name == obj.name) {
- insertDialogHtml(obj, item);
- }
- });
- }
- });
- };
- const createNormalDialog = () => {
- // 过滤出正常设备的obj
- const filteredEquipment = state.allDeviceObjList.filter((item: any) => !['AU02', 'AU08', 'AU18'].includes(item.name));
- let index = state.normalInfo.length - 1;
- state.intervalId = setInterval(() => {
- // 移除上一个dialog
- clearDialog();
- index = index == state.normalInfo.length - 1 ? 0 : ++index;
- const randomInfo = state.normalInfo[index];
- const randomObject = filteredEquipment.filter((item: any) => item.name == randomInfo.name);
- state.randomObject = randomObject[0];
- insertDialogHtml(state.randomObject, randomInfo);
- }, 3000);
- };
-
- // 清除前一个随机框
- const clearDialog = () => {
- if (state.randomObject) {
- const currentRandomObject = model.getObjectByName(state.randomObject.name + 'dialog');
- currentRandomObject ? currentRandomObject.parent.remove(currentRandomObject) : '';
- state.randomObject = null;
- }
- };
在模型加载函数中调用
- // 创建3D弹框
- const create3DDialog = () => {
- createAlarmDialog();
- createNormalDialog();
- };
接下一篇:
three.js如何实现简易3D机房?(四)点击事件:http://t.csdnimg.cn/Fzpxk
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。