接上一篇:
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渲染器CSS3DRenderercss3DRenderer = 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 = () => {// 过滤出正常设备的objconst filteredEquipment = state.allDeviceObjList.filter((item: any) => !['AU02', 'AU08', 'AU18'].includes(item.name));let index = state.normalInfo.length - 1;state.intervalId = setInterval(() => {// 移除上一个dialogclearDialog();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