Files
tunnel-cloud-web/src/components/content/tunnelScene/sceneClass/demo.js
2023-12-10 17:03:43 +08:00

381 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
});
}
}