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

news2025/6/18 23:44:25

接上一篇:

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文件中

// 引入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);
	}
}
 创建3D弹框的公共函数
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 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1496267.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

猜猜:哪句古诗与古代女子妆容有关?2024.3.8蚂蚁庄园今日答案:金盆水里拨红泥

蚂蚁庄园是一款爱心公益游戏&#xff0c;用户可以通过喂养小鸡&#xff0c;产生鸡蛋&#xff0c;并通过捐赠鸡蛋参与公益项目。用户每日完成答题就可以领取鸡饲料&#xff0c;使用鸡饲料喂鸡之后&#xff0c;会可以获得鸡蛋&#xff0c;可以通过鸡蛋来进行爱心捐赠。其中&#…

Java 中创建线程多种方式介绍

在 Java 中&#xff0c;创建线程有多种方式&#xff0c;以下是最常见的四种&#xff1a; 1. **通过继承 Thread 类** 2. **通过实现 Runnable 接口** 3. **通过实现 Callable 接口** 4. **通过使用 Executor 框架** 每种方式都有其特点和适用场…

ElasticSearch之通过search after和scroll解决深度分页问题

写在前面 通过from&#xff0c;size来进行分页查询时&#xff0c;如下&#xff1a; 当from比较大时会有深度分页问题&#xff0c;问题产生的核心是coordinate node需要从每个分片中获取fromsize条数据&#xff0c;当from比较大&#xff0c;整体需要获取的数据量也会比较大&am…

【Java_JSON】如何从JSON数据中提取value值

如何从JSON数据中提取value值&#xff1f; 首先将JSON数据转成字符串 创建JSONObject 对象 通过kv键值对的特性 使用key值来获取value 值 并输出 结果&#xff1a;

Redis(十七)分布式锁

文章目录 面试题分布式锁锁的种类分布式锁需要具备的条件和刚需分布式锁 案例nginx分布式微服务部署&#xff0c;单机锁问题分布式锁注意事项lock/unlocklua脚本自研版的redis分布式锁搞定lua脚本 可重入锁可重入锁种类可重入锁hset实现&#xff0c;对比setnx&#xff08;重要&…

Jmeter压测分配业务比例

在进行综合场景压测时&#xff0c;由于不同的请求&#xff0c;要求所占比例不同&#xff0c;如何实现呢&#xff1f; 不同的请求&#xff0c;服务器对其处理能力不同&#xff0c;有的处理快&#xff0c;有的处理慢。 真实模拟按比例进行并发&#xff1a; 在使用LR进行过类似…

在winform中如何嵌入第三方软件窗体✨

相关win32api的学习✨ SetParent [DllImport("user32.dll ", EntryPoint "SetParent")] private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); //将外部窗体嵌入程序语法&#xff1a; HWND SetParent([in] H…

windows关闭copilot预览版

如果用户不想在windows系统当中启用Copilot&#xff0c;可以通过以下三种方式禁用。 第一种&#xff1a;隐藏Copilot 按钮 右键点击任务栏&#xff0c;取消勾选“显示 Copilot&#xff08;预览版&#xff09;按钮”&#xff0c;任务栏则不再显示&#xff0c;用户可以通过快捷键…

2024 年 AI 辅助研发趋势:从研发数字化到 AI + 开发工具 2.0,不止于 Copilot

在上一年里&#xff0c;已经有不少的企业在工具链上落地了生成式 AI&#xff0c;结合我们对于这些企业的分析&#xff0c;以及最近在国内的一些 “新技术” 趋势&#xff0c;诸如于鸿蒙原生应用的初步兴起。从这些案例与趋势中&#xff0c;我们也看到了一些新的可能方向。 结合…

【C++】蓝桥杯必备 算法竞赛常用STL万字总结

传送门⏬⏬⏬[方便查表] &#x1f31f;一、什么是STL&#xff1f;&#x1f31f;二、为什么STL重要&#xff1f;✨1、原因✨2、STL的作用 &#x1f31f;三、STL知识点总结✨0.使用说明书✨1、vector 【可变数组】✨2、pair [ x,y ]✨3、string【字符串】✨4、queue【队列】 和pr…

2024年【道路运输企业安全生产管理人员】复审考试及道路运输企业安全生产管理人员模拟考试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年道路运输企业安全生产管理人员复审考试为正在备考道路运输企业安全生产管理人员操作证的学员准备的理论考试专题&#xff0c;每个月更新的道路运输企业安全生产管理人员模拟考试题祝您顺利通过道路运输企业安全…

第三讲 汇编初步 课程随手记

一、寄存器 32位CPU通用寄存器如下图所示&#xff1a; 因为教材依照的是32位CPU寄存器&#xff0c;而我安装的是64位寄存器&#xff0c;所以找了一下64位的寄存器的资料 PS&#xff1a;一般来说&#xff0c;Intel处理器字节存储顺序为小端法存储&#xff0c;是指数据的高字节保…

JavaScript极速入门(1)

初识JavaScript JavaScript是什么 JavaScript(简称JS),是一个脚本语言,解释型或者即时编译型语言.虽然它是作为开发Web页面的脚本语言而著名,但是也应用到了很多非浏览器的环境中. 看似这门语言叫JavaScript,其实在最初发明之初,这门语言的名字其实是在蹭Java的热度,实际上和…

Vue2+ElementUI下拉、Select组件的封装

Vue2ElementUI下拉、Select组件的封装&#xff1a;引言 在 Vue2 项目中&#xff0c;ElementUI 的 el-select 组件是常用的下拉选择框组件。它提供了丰富的功能和样式&#xff0c;可以满足各种需求。但是&#xff0c;在实际开发中&#xff0c;我们经常会遇到一些重复性的需求&a…

男人的玩具系统wordpress外贸网站主题模板

垂钓用品wordpress外贸模板 鱼饵、鱼竿、支架、钓箱、渔线轮、鱼竿等垂钓用品wordpress外贸模板。 https://www.jianzhanpress.com/?p3973 身体清洁wordpress外贸网站模板 浴盐、防蚊液、足部护理、沐浴液、洗手液、泡澡用品wordpress外贸网站模板。 https://www.jianzhan…

【CSP试题回顾】201612-1-中间数

CSP-201612-1-中间数 解题思路 输入和初始化&#xff1a;首先&#xff0c;程序读入一个整数n&#xff0c;表示序列中数的个数。接着&#xff0c;读入n个正整数并存储在numList向量中&#xff0c;这些数依次表示a1, a2, …, an。 排序&#xff1a;使用sort函数对numList进行升…

前端运算符比较与计算中的类型转换,运算规则

题目&#xff1a; 下面表达式的值分别都是什么&#xff08;类型转换&#xff09; 0 0 0 2 true 2 false false false false 0 false undefined false null null undefined\t\r\n 0JS中的原始类型有哪些 原始值类型就是 存储的都是值&#xff0c;没有函数可以调用的。…

【Python时序预测系列】基于LSTM+Attention实现单变量时间序列预测(源码)

这是我的第232篇原创文章。 一、引言 长短期记忆网络&#xff08;LSTM&#xff09;结合注意力机制是一种常用的深度学习模型结构&#xff0c;用于处理序列数据。LSTM是一种循环神经网络&#xff08;RNN&#xff09;的变体&#xff0c;专门设计用来解决长序列数据的梯度消失和…

不知道去哪里找拍抖音的短视频素材?分享几个抖音短视频素材资源网站

嘿嘿&#xff0c;小伙伴们&#xff0c;是不是在抖音创作的路上遇到了素材荒&#xff1f;别担心&#xff0c;我这里有几个超给力的短视频素材网站推荐给大家&#xff0c;保证让你的创作不再为素材发愁 1&#xff0c;蛙学府资源 这个网站简直是短视频素材的大宝库&#xff0c;无…

CSS盒子模型笔记

尚硅谷学习视频链接&#xff1a;117_CSS_盒子模型的组成部分_哔哩哔哩_bilibili 1、盒子组成 盒子组成 content内容 padding border &#xff08;margin不包含在盒子内&#xff09; 2、div样式width、height 当css3属性box-sizingcontent-box&#xff08;默认&#xff0…