three.js如何实现简易3D机房?(三)显示信息弹框/标签

接上一篇:

three.js如何实现简易3D机房?(二)模型加载的过渡动画:http://t.csdnimg.cn/onbWY

目录

七、创建信息展示弹框

1.整体思路

(1)需求:

(2)思路:

(3)具体步骤:

创建3D渲染器

弹框标签和样式

创建3D弹框的公共函数

创建常亮(报警设备红色)信息框

创建随机(正常设备绿色)信息框


七、创建信息展示弹框

1.整体思路
(1)需求:

默认在模型加载完之后,报警设备的红色信息框持续展示;正常设备的绿色信息框,每3s轮换展示

(2)思路:

创建3D信息框的内容是相同的,只需要区分报警设备和正常设备两种情况即可,这里我是通过CSS3DObject来实现的

(3)具体步骤:
创建3D渲染器

在threeD/init.js文件中

javascript 复制代码
// 引入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(),不然不生效

css 复制代码
	: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));
				}
			}
		}
创建3D弹框的公共函数
javascript 复制代码
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);
};

准备好需要用的变量,为了方便展示,我这里简单写了一些假数据,实际需要从后端接口获取

javascript 复制代码
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,
		},
	],
});
创建常亮(报警设备红色)信息框
javascript 复制代码
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);
				}
			});
		}
	});
};
创建随机(正常设备绿色)信息框
javascript 复制代码
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;
	}
};

在模型加载函数中调用

javascript 复制代码
// 创建3D弹框
const create3DDialog = () => {
	createAlarmDialog();
	createNormalDialog();
};
相关推荐
weixin199701080163 分钟前
搜好货商品详情页前端性能优化实战
java·前端·python
SuperEugene8 分钟前
NPM Script 实战:常用命令设计与封装|Vue 工程化篇
前端·javascript·vue.js·前端框架·npm
前端进阶之旅12 分钟前
React 18 并发特性实战指南:提升大型应用性能的关键技术
前端·react.js·前端框架
恋猫de小郭14 分钟前
Android 性能迎来提升:内核引入 AutoFDO 普惠所有 15-16 设备
android·前端·flutter
小霍同学17 分钟前
Vue 动态表单(Dynamic Form)
前端·vue.js
Dragon Wu22 分钟前
Taro 小程序开发注意事项(不定期记录更新)
前端·javascript·小程序·typescript·taro
wangfpp24 分钟前
多端统一你真的会了吗?
前端·javascript·架构
小霍同学24 分钟前
Vue 动态组件(Dynamic Components)
前端·vue.js
Chengbei1129 分钟前
AI 自动逆向 JS 加密!自动抓密钥、出报告,彻底解放双手,解决抓包数据包加密难题
开发语言·javascript·人工智能·安全·网络安全·网络攻击模型
代码煮茶32 分钟前
Vue3 组件封装实战 | 从 0 封装一个可复用的表格组件(附插槽 / Props 设计)
前端·vue.js