import * as THREE from 'three'; import { CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer'; import { getTextCanvas, setModalCenter } from '/@/utils/threejs/util'; import Smoke from '/@/views/vent/comment/threejs/Smoke'; import gsap from 'gsap'; // 本模型的上下文对象,用于实现本模型的特定功能,代码参考了旧有的 fanLocal.three.ts class ModelContext { model; modelName = 'jbfj-single'; group: THREE.Object3D | null = null; fanType?: string; topSmoke?: Smoke; downSmoke?: Smoke; returnSmoke?: Smoke; topLife?: number; downLife?: number; constructor(model) { this.model = model; } addLight() { // optional implementation } mountedThree() { return new Promise((resolve) => { this.model.setGLTFModel([this.modelName]).then(async (gltf) => { this.group = gltf[0]; if (this.group) { setModalCenter(this.group); this.addLight(); this.initFly(); this.setModalPosition(); resolve(null); } }); }); } destroy() { if (this.model) { this.model.isRender = false; this.clearFly(); this.topSmoke = undefined; this.downSmoke = undefined; this.returnSmoke = undefined; // @ts-ignore this.group = undefined; this.model.destroy(); } } async initFly() { const topCurve = [ { path0: new THREE.Vector3(7.698, 0.398, 0.19), path1: new THREE.Vector3(-0.65, 0.398, 0.19), isSpread: true, spreadDirection: 0, // }, { path0: new THREE.Vector3(-0.65, 0.398, 0.19), path1: new THREE.Vector3(-7.599, 0.398, 0.19), isSpread: true, spreadRang: 1, spreadDirection: 1, // }, ]; if (!this.topSmoke) { this.topSmoke = new Smoke('/model/img/texture-smoke.png', '#ffffff', 2, 0.35, 3.7, 100); this.topSmoke.setPath(topCurve); await this.topSmoke.setPoints(); this.group?.add(this.topSmoke.points); } } playSmoke(selectData) { // debugger; if (selectData['Fan1StartStatus'] == '1') { // 主风机打开 this.setSmokeFrequency('top', 40); this.runFly('top', 'open'); } else { // 备风机关闭 this.runFly('top', 'close'); } if (selectData['Fan1StartStatus'] != '1') { this.runFly('all', 'close'); } } runFly(deviceType, state) { if (state === 'open') { if (deviceType === 'top') { if (this.downSmoke && this.downSmoke.frameId) { this.downSmoke.stopSmoke(); } if (this.topSmoke && !this.topSmoke.frameId) { this.topSmoke.startSmoke(); } } } else { if (deviceType === 'top') { if (this.topSmoke && this.topSmoke.frameId) { this.topSmoke.stopSmoke(); } } } if (deviceType === 'all' && state === 'close') { this.returnSmoke?.stopSmoke(); } } setSmokeFrequency(deviceType, frequency) { const life = (frequency - 30) * 25; let duration = 0; let smoke; if (deviceType === 'top') { if (this.topLife == life) { return; } this.topLife = life; smoke = this.topSmoke; duration = (Math.abs(life - smoke.life) / 500) * 25; } if (smoke) { gsap.to(smoke, { life: life, duration: duration, ease: 'easeInCubic', overwrite: true, }); } } addText(selectData) { if (!this.group) { return; } // @ts-ignore const screenDownText = VENT_PARAM['modalText'] ? // @ts-ignore VENT_PARAM['modalText'] : // @ts-ignore History_Type['type'] == 'remote' ? `国能神东煤炭集团监制` : '煤科通安(北京)智控科技有限公司研制'; const screenDownTextX = 80 - (screenDownText.length - 10) * 6; const textArr = [ { text: `智能局部通风机监测与控制系统`, font: 'normal 30px Arial', color: '#009900', strokeStyle: '#002200', x: 20, y: 108, }, { text: `供风距离(m):`, font: 'normal 30px Arial', color: '#009900', strokeStyle: '#002200', x: 0, y: 152, }, { text: `${ selectData.airSupplyDistence_merge ? selectData.airSupplyDistence_merge : selectData.fchimenylength ? selectData.fchimenylength : selectData.airSupplyDistence_merge ? selectData.airSupplyDistence_merge : '-' }`, font: 'normal 30px Arial', color: '#009900', strokeStyle: '#002200', x: 228, y: 152, }, { text: `风筒直径(mm): `, font: 'normal 30px Arial', color: '#009900', strokeStyle: '#002200', x: 0, y: 200, }, { text: ` ${selectData.fchimenydiamlimit ? selectData.fchimenydiamlimit : selectData.ductDiameter_merge ? selectData.ductDiameter_merge : '-'}`, font: 'normal 30px Arial', color: '#009900', strokeStyle: '#002200', x: 220, y: 200, }, { text: `故障诊断:`, font: 'normal 30px Arial', color: '#009900', strokeStyle: '#002200', x: 0, y: 245, }, { text: `${selectData.warnLevel_str ? selectData.warnLevel_str : '-'}`, font: 'normal 30px Arial', color: '#009900', strokeStyle: '#002200', x: 220, y: 245, }, { text: `型号功率:`, font: 'normal 30px Arial', color: '#009900', strokeStyle: '#002200', x: 0, y: 285, }, { text: `${selectData.model_Power_merge ? selectData.model_Power_merge : '-'}`, font: 'normal 26px Arial', color: '#009900', strokeStyle: '#002200', x: 220, y: 285, }, { text: screenDownText, font: 'normal 28px Arial', color: '#009900', strokeStyle: '#002200', x: screenDownTextX, y: 325, }, ]; getTextCanvas(526, 346, textArr, '').then((canvas: HTMLCanvasElement) => { const textMap = new THREE.CanvasTexture(canvas); // 关键一步 const textMaterial = new THREE.MeshBasicMaterial({ // 关于材质并未讲解 实操即可熟悉 这里是漫反射类似纸张的材质,对应的就有高光类似金属的材质. map: textMap, // 设置纹理贴图 transparent: true, side: THREE.FrontSide, // 这里是双面渲染的意思 }); textMaterial.blending = THREE.CustomBlending; const monitorPlane = this.group?.getObjectByName('monitorText'); if (monitorPlane) { // @ts-ignore-next-line monitorPlane.material = textMaterial; } else { const planeGeometry = new THREE.PlaneGeometry(526, 346); // 平面3维几何体PlaneGeometry const planeMesh = new THREE.Mesh(planeGeometry, textMaterial); planeMesh.name = 'monitorText'; planeMesh.scale.set(0.0135, 0.0135, 0.0135); planeMesh.rotation.y = -Math.PI / 2; planeMesh.position.set(-84.79, 0.82, 17.0); this.group?.add(planeMesh); } }); } addCssText() { if (!this.group) return; if (!this.group.getObjectByName('text1')) { const element = document.getElementById('inputBox') as HTMLElement; if (element) { const fanLocalCSS3D = new CSS3DObject(element); fanLocalCSS3D.name = 'text1'; fanLocalCSS3D.scale.set(0.04, 0.04, 0.04); fanLocalCSS3D.rotation.y = -Math.PI / 2; fanLocalCSS3D.position.set(-85.68, 5.97, -3.39); this.group.add(fanLocalCSS3D); } } if (!this.group.getObjectByName('text2')) { const element = document.getElementById('outBox') as HTMLElement; if (element) { const fanLocalCSS3D = new CSS3DObject(element); fanLocalCSS3D.name = 'text2'; fanLocalCSS3D.scale.set(0.15, 0.15, 0.15); fanLocalCSS3D.rotation.y = -Math.PI / 2; fanLocalCSS3D.position.set(85.62, 17.65, 7.71); this.group.add(fanLocalCSS3D); } } if (!this.group.getObjectByName('text3')) { const element = document.getElementById('returnBox') as HTMLElement; if (element) { const fanLocalCSS3D = new CSS3DObject(element); fanLocalCSS3D.name = 'text3'; fanLocalCSS3D.scale.set(0.07, 0.07, 0.07); fanLocalCSS3D.rotation.y = -Math.PI / 2; fanLocalCSS3D.position.set(-25.97, 9.3, -15.09); this.group.add(fanLocalCSS3D); } } if (!this.group.getObjectByName('text4')) { const element = document.getElementById('gateBox') as HTMLElement; if (element) { // element.innerHTML = ''; const fanLocalCSS3D = new CSS3DObject(element); fanLocalCSS3D.name = 'text4'; fanLocalCSS3D.scale.set(0.04, 0.04, 0.04); fanLocalCSS3D.rotation.y = -Math.PI / 2; fanLocalCSS3D.position.set(-73.13, 8.44, -23.52); this.group.add(fanLocalCSS3D); } } if (!this.group.getObjectByName('text5')) { const element = document.getElementById('windownBox') as HTMLElement; if (element) { // element.innerHTML = ''; const fanLocalCSS3D = new CSS3DObject(element); fanLocalCSS3D.name = 'text5'; fanLocalCSS3D.scale.set(0.07, 0.07, 0.07); fanLocalCSS3D.rotation.y = -Math.PI / 2; fanLocalCSS3D.position.set(-28.44, 9.78, -40.42); this.group.add(fanLocalCSS3D); } } if (!this.group.getObjectByName('text7')) { const element = document.getElementById('inputBox0') as HTMLElement; if (element) { const fanLocalCSS3D = new CSS3DObject(element); fanLocalCSS3D.name = 'text7'; fanLocalCSS3D.scale.set(0.04, 0.04, 0.04); fanLocalCSS3D.rotation.y = -Math.PI / 2; fanLocalCSS3D.position.set(-84.23, 4.97, -18.92); this.group.add(fanLocalCSS3D); } } if (!this.group.getObjectByName('text6')) { const element = document.getElementById('inputBox1') as HTMLElement; if (element) { const fanLocalCSS3D = new CSS3DObject(element); fanLocalCSS3D.name = 'text6'; fanLocalCSS3D.scale.set(0.04, 0.04, 0.04); fanLocalCSS3D.rotation.y = -Math.PI / 2; fanLocalCSS3D.position.set(-84.47, 6.56, -19.47); this.group.add(fanLocalCSS3D); } } if (!this.group.getObjectByName('text8')) { const element = document.getElementById('gasBox3') as HTMLElement; if (element) { const fanLocalCSS3D = new CSS3DObject(element); fanLocalCSS3D.name = 'text8'; fanLocalCSS3D.scale.set(0.03, 0.03, 0.03); fanLocalCSS3D.rotation.y = -Math.PI / 2; fanLocalCSS3D.position.set(-90.04, 6, 5); this.group.add(fanLocalCSS3D); } } if (!this.group.getObjectByName('text9')) { const element = document.getElementById('gasBox2') as HTMLElement; if (element) { const fanLocalCSS3D = new CSS3DObject(element); fanLocalCSS3D.name = 'text9'; fanLocalCSS3D.scale.set(0.07, 0.07, 0.07); fanLocalCSS3D.rotation.y = -Math.PI / 2; fanLocalCSS3D.position.set(-8, 7.46, -35.28); this.group.add(fanLocalCSS3D); } } if (!this.group.getObjectByName('text10')) { const element = document.getElementById('gasBox1') as HTMLElement; if (element) { const fanLocalCSS3D = new CSS3DObject(element); fanLocalCSS3D.name = 'text10'; fanLocalCSS3D.scale.set(0.1, 0.1, 0.1); fanLocalCSS3D.rotation.y = -Math.PI / 2; fanLocalCSS3D.position.set(80, 9, -43); this.group.add(fanLocalCSS3D); } } } clearFly() { if (this.topSmoke) this.topSmoke.clearSmoke(); if (this.downSmoke) this.downSmoke.clearSmoke(); if (this.returnSmoke) this.returnSmoke.clearSmoke(); } // 设置模型位置 setModalPosition() { if (!this.group) return; this.group.scale.set(13, 13, 13); this.group.position.set(0, -10, -50); } } export default ModelContext;