import { handleLClick } from "./handleRLclick/handleLclick"; import { handleRClick } from "./handleRLclick/handleRclick"; import { handleDBLClick } from "./handleDBLclick"; import { checkAnimation } from "./checkTag"; import { handleEndChange, handleStartChange, } from "./handleOrbitControlsChange"; import { saveState, resetState } from "./viewBack"; import addFunction from "./addEvent"; import addDev from "./addDev"; import removeDev from "./removeDev"; export default class Demo { // 摄像机看向位置 origin = null; //附着点的模型 points = []; //设备模型数组 deviceModels = []; constructor(three, mountedElement) { // 外部引入匿名函数 this._handleLClick = handleLClick; this._handleRClick = handleRClick; this._handleDBLClick = handleDBLClick; this._checkAnimation = checkAnimation; this._saveSate = saveState; this._resetState = resetState; // 增加设备模型 this.addDev = addDev; // 删除设备模型 this.removeDev = removeDev; // 外部可添加函数 this.addFunction = addFunction; this.THREE = three; this.mountedElement = mountedElement; //初始化场景 this.scene = new this.THREE.Scene(); // 初始化摄像机 this.camera = new this.THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000 ); this.camera.position.z = -60; this.camera.position.y = 20; this.camera.position.x = -30; this.camera.lookAt(0, 0, 1000); // 初始化渲染器 this.renderer = new this.THREE.WebGLRenderer({ // 抗锯齿 antialias: true, }); this.renderer.setSize(window.innerWidth, window.innerHeight); this.renderer.domElement.style.position = "absolute"; this.mountedElement.appendChild(this.renderer.domElement); // 创建渲染帧 this.render = () => { this.__renderScope(); requestAnimationFrame(this.render); }; this.render(); this.canvasResize(); this.addXYZ(); } //渲染函数作用域(这里主要写渲染帧内操作) __renderScope() { this.renderer.render(this.scene, this.camera); // 轨道控制器更新 if (this.orbitControls) { this.orbitControls.update(); // console.log(this.camera.position); } // 摄像头移动动画 if (this.cameraPositionTween) { this.cameraPositionTween.update(); } //html标签渲染 if (this.CSS2Renderer) { this.CSS2Renderer.render(this.scene, this.camera); } // 选中标签动画渲染 if (this.checkAnimationTween) { this.checkAnimationTween.update(); } // 视角重置动画 if (this.resetViewAngleAnimation) { this.resetViewAngleAnimation.update(); } //视角回退动画 if (this.viewSateResetAnimation) { this.viewSateResetAnimation.update(); } // 视角跟随动画 if (this.intoPointAnimation) { this.intoPointAnimation.update(); } } // 添加世界坐标系 addXYZ() { // const axesHelper = new this.THREE.AxesHelper(100); // this.scene.add(axesHelper); } // 屏幕自适应 canvasResize() { window.addEventListener("resize", () => { this.camera.aspect = window.innerWidth / window.innerHeight; this.camera.updateProjectionMatrix(); this.renderer.setSize(window.innerWidth, window.innerHeight); this.CSS2Renderer.setSize(window.innerWidth, window.innerHeight); }); } // 模型加载 /** * @param {Object} GLTFLoader 模型加载器 * @param {String} path 模型资源路径 */ loadModel(GLTFLoader, path) { return new Promise((resolve, reject) => { this.gltfloader = new GLTFLoader(); this.gltfloader.load( "/tunnelModel/chanel.gltf", (gltf) => { gltf.scene.traverse((child) => { this._forModels(child); }); this.scene.add(gltf.scene); // 加载完后可执行函数 this._afterLoaded(gltf.scene); resolve(gltf); }, (xhr) => { console.log((xhr.loaded / xhr.total) * 100 + "% loaded"); }, (error) => { console.log(error); reject(error); } ); }); } // 模型加载完函数 _afterLoaded() { // 可以进行选中 this._hoverModel(this.points); // 可以进行点击 this._ClickModel(this.points); } // 在此方法中对模型批量操作 _forModels(child) { // 匹配附着点(这里不适合对单个模型进行保存,批量对模型进行操作) if (child.isMesh && /^point+/.test(child.name)) { this.points.push(child); // 改变为基础材质 child.material = new this.THREE.MeshBasicMaterial(); // 遍历一个属性是否存在设备 child.hasDevice = false; //初始化 } } // 添加轨道控制器 /** * @param {Object} OrbitControls 轨道控制器 */ addOrbitControls(OrbitControls) { this.orbitControls = new OrbitControls( this.camera, this.renderer.domElement ); //限制轨道控制器的视角变化 this.orbitControls.maxPolarAngle = Math.PI * (3 / 5); // 监听控制器变化 this.orbitControls.addEventListener("end", handleEndChange.bind(this)); this.orbitControls.addEventListener("start", handleStartChange.bind(this)); } /** * @param {Class} Tween 添加补间动画 */ addTween(Tween) { this.TWEEN = Tween; } /*** * 鼠标移入可以高亮的模型 *@param {Array} hoverModels 需要高亮的模型 */ _hoverModel(hoverModels) { this.renderer.domElement.addEventListener("mousemove", (e) => { const mouse = new this.THREE.Vector2(); mouse.x = (e.clientX / window.innerWidth) * 2 - 1; mouse.y = -(e.clientY / window.innerHeight) * 2 + 1; const raycaster = new this.THREE.Raycaster(); raycaster.setFromCamera(mouse, this.camera); const intersects = raycaster.intersectObjects(hoverModels); if (intersects.length > 0) { if (!this.preHover) { this.preHover = intersects[0].object; } else { this.preHover.material.color.set("white"); this.preHover = intersects[0].object; } intersects[0].object.material.color.set("red"); const tagP = intersects[0].object.getWorldPosition( new this.THREE.Vector3() ); this._checkAnimation(tagP); } else { if (!this.preHover) return; this.preHover.material.color.set("white"); } }); } /** * @param {Array} isClickModels 可以进行点击的模型吧 */ _ClickModel(isClickModels) { // 点击两次处理事件 this.renderer.domElement.addEventListener( "dblclick", this.__handleListenerDBLClickEvent.bind(this, isClickModels) //注意这里重新指向this,第一个是修改this指向,第二个是传入函数的参数 ); // 点击一次时处理时间 this.renderer.domElement.addEventListener( "mousedown", this.__handleListenerClickRLEvent.bind(this, isClickModels) //注意这里重新指向this,第一个是修改this指向,第二个是传入函数的参数 ); } // 处理点击2次触发事件事件 __handleListenerDBLClickEvent(isClickModels, e) { // 如果监听到双击则清空单次点击事件 clearTimeout(this.EventTimer); //最后一个是监听器默认参数 const mouse = new this.THREE.Vector2(); mouse.x = (e.clientX / window.innerWidth) * 2 - 1; mouse.y = -(e.clientY / window.innerHeight) * 2 + 1; const raycaster = new this.THREE.Raycaster(); raycaster.setFromCamera(mouse, this.camera); const intersects = raycaster.intersectObjects(isClickModels); // 取消定位的视角返回初始化 if (intersects.length === 0) { this.clearTagsObj(); this._resetState(); return; } // 处理连续双击击事件 this._handleDBLClick(intersects[0].object); } // 处理点击左右键触发的事件 __handleListenerClickRLEvent(isClickModels, e) { clearTimeout(this.EventTimer); this.EventTimer = setTimeout(() => { const mouse = new this.THREE.Vector2(); mouse.x = (e.clientX / window.innerWidth) * 2 - 1; mouse.y = -(e.clientY / window.innerHeight) * 2 + 1; const raycaster = new this.THREE.Raycaster(); raycaster.setFromCamera(mouse, this.camera); const intersects = raycaster.intersectObjects(isClickModels); if (intersects.length === 0) return; //附着点设置方框 this.setBoxHelper(intersects[0].object); // 处理点击左右键事件 if (e.button === 0) { this._handleLClick(intersects[0].object); } else if (e.button === 2) { this._handleRClick(intersects[0].object); } }, 400); } // 添加css3Renderer addCSS3Renderer(CSS2Renderer, CSS2DObject, [infoDom, editDom]) { this.CSS2Renderer = new CSS2Renderer(); this.CSS2Renderer.setSize(window.innerWidth, window.innerHeight); this.CSS2Renderer.render(this.scene, this.camera); this.mountedElement.appendChild(this.CSS2Renderer.domElement); // 初始化html标签 this.tagHtml = infoDom; this.tag2Html = infoDom; this.tag3Html = editDom; this.CSS2DObject = CSS2DObject; // 创建html标签模型 this.tagCSS2DObj = new CSS2DObject(this.tagHtml); this.tag2CSS2DObj = new CSS2DObject(this.tag2Html); this.tag3CSS2DObj = new CSS2DObject(this.tag3Html); // 设置该标签初始化透明 this.tagCSS2DObj.element.style.opacity = "1"; this.tag2CSS2DObj.element.style.opacity = "1"; this.tag3CSS2DObj.element.style.opacity = "1"; this.tagCSS2DObj.element.style.display = "none"; this.tag2CSS2DObj.element.style.display = "none"; this.tag3CSS2DObj.element.style.display = "none"; this.tagCSS2DObj.scale.set(0.1, 0.1, 0.1); this.tag2CSS2DObj.scale.set(0.1, 0.1, 0.1); this.tag3CSS2DObj.scale.set(0.1, 0.1, 0.1); this.tagCSS2DObj.scale.set(3, 3, 3); } clearTagsObj() { if (this.preDBLModel) { this.preDBLModel.remove(this.tagCSS2DObj); } // 所有标签看不见 this.scene.remove(this.tag2CSS2DObj); this.scene.remove(this.tag3CSS2DObj); // 删除标记动画 this.scene.remove(this.group); } // 附着点选中线宽包围 setBoxHelper(obj) { // 判断场景是否纯在该3d对象 if (this.scene.getObjectByName("boxHelper")) { const preModel = this.scene.getObjectByName("boxHelper"); this.scene.remove(preModel); } const boxHelper = new this.THREE.BoxHelper(obj, 0xffff00); boxHelper.name = "boxHelper"; this.scene.add(boxHelper); } /** *@param {Class} DRACOLoader 解压器 * @param {String} dracoPath 解压器路径 */ addDARCOLoder(DRACOLoader, dracoPath) { this.DRAC = new DRACOLoader(); this.DRAC.setDecoderPath(dracoPath); //给模型加载器添解压器 this.gltfloader.setDRACOLoader(this.DRAC); } /** * @param {Meshes} meshes gltf加载过后的模型数组 */ initDevicesModel(meshes) { this.deviceList = []; meshes.forEach((mesh) => { this.deviceList.push(mesh); }); console.log(this.deviceList); } /** * @param {String} devId 删除的设备ID */ removeDevice(devId) { removeDev.bind(this, devId); } /** * * @param {Number} distance 设置锚点之间的间隔距离 */ setDistance(distance = 10) { this.distance = distance; } loadBackground(backColorSet) { this.scene.background = new this.THREE.TextureLoader().load("/images/background/background.png", function (texture) { texture.encoding = backColorSet; }); } }