import * as THREE from "three"; import Stats from "three/examples/jsm/libs/stats.module.js"; import Player from "./player/Player.js"; import BoxManager from "./box/BoxManager.js"; import { Mitt } from "./mitt.js"; import testData from "./save.json"; import { dataURItoBlob, saveFile } from "./utils/utils.js"; import { screenshotObject } from "./utils/cap.js"; const stats = new Stats(); function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } export default class Scene extends Mitt { constructor(domElement) { super(); this.domElement = domElement; this.scene = null; this.renderer = null; this.orthCamera = null; this.camera = null; this.player = null; this.sceneType = 1; this.width = 0; this.height = 0; this.defaultZoom = 250; this.defaultUseZoom = 250 / window.devicePixelRatio; this.initCamPView = new THREE.Vector3(); this.initCamRView = new THREE.Vector3(); this.blobScreens = []; this.inited = false; this.init = () => { this.scene = new THREE.Scene(); this.scene.background = new THREE.Color(0xf0f2f5); this.renderer = new THREE.WebGLRenderer({ canvas: this.domElement, antialias: true, autoClear: true, preserveDrawingBuffer: true, }); this.width = this.domElement.clientWidth; this.height = this.domElement.clientHeight; this.renderRes = window.devicePixelRatio; this.defaultUseZoom = this.defaultZoom / window.devicePixelRatio; this.renderer.setSize(this.width, this.height); this.renderer.setPixelRatio(this.renderRes); console.log( "init", this.width, this.height, this.renderRes, this.defaultZoom ); this.camera = new THREE.PerspectiveCamera( 70, this.domElement.clientWidth / this.domElement.clientHeight, 0.1, 1000 ); this.orthCamera = new THREE.OrthographicCamera( -this.width / 2, this.width / 2, this.height / 2, -this.height / 2, 0.1, 1000 ); this.orthCamera.zoom = this.defaultUseZoom; // 影响画线 this.orthCamera.position.set(0, 10, 0); this.orthCamera.lookAt(0, 0, 0); // this.orthCamera.setViewOffset(this.width, this.height, 0, 0); this.orthCamera.updateProjectionMatrix(); //player this.player = new Player(this); domElement.parentNode.appendChild(stats.dom); stats.dom.style.pointerEvents = "none"; stats.dom.style.left = "15%"; stats.dom.style.display = "none"; this.onBindEvent(); this.inited = true; this.load(); this.animate(); }; } load = (list, type, data) => { if (!list) return; // console.log("scene: ", list, type, data); //axesHeloer this.clearScene(); this.sceneType = type; // const axesHelper = new THREE.AxesHelper(1); // this.scene.add(axesHelper); this.boxManager = new BoxManager(this); this.boxManager.load(list, type); //light this.loadLight(); this.player.load(type, data || []); this.initCamPView.copy(this.orthCamera.position); this.initCamRView.copy(this.orthCamera.rotation); }; clearScene() { for (var i = this.scene.children.length - 1; i >= 0; i--) { let obj = this.scene.children[i]; this.scene.remove(obj); } } clearDrawScene() { for (var i = this.scene.children.length - 1; i >= 0; i--) { let obj = this.scene.children[i]; if ( String(obj.name).includes("marker_") || String(obj.name).includes("line_") || String(obj.name).includes("line_point_") || String(obj.name).includes("circle_") || String(obj.name).includes("pureText_") ) { this.scene.remove(obj); } } } deleteItemById(uuid, type) { for (var i = this.scene.children.length - 1; i >= 0; i--) { let obj = this.scene.children[i]; if (obj.uuid === uuid) { console.log("deleteItemById-userData", obj.userData); this.player.deleteItemByType(type, obj.userData); this.scene.remove(obj); } } } deleteImageDataByIds(ids) { this.player.deleteImageDataByIds(ids); } loadLight = () => { const light = new THREE.AmbientLight(0xffffff, 1.5); // 柔和的白光 this.scene.add(light); }; setCamera = () => { // const object = this.boxManager.model; // const boundingBox = new THREE.Box3().setFromObject(object); // let size = boundingBox.getSize(new THREE.Vector3()); // const fov = this.camera.fov * (Math.PI / 180); // const fovh = 2 * Math.atan(Math.tan(fov / 2) * this.camera.aspect); // let dx = Math.abs(size.x / 2 / Math.tan(fovh / 2)); // let dz = Math.abs(size.z / 2 / Math.tan(fov / 2)); // this.orthCamera.zoom = this.floorplanZoom; }; toHorizontal = () => {}; toVertical = () => {}; lockView(open) { if (!open) { this.player.floorplanControls.enablePan = true; this.player.floorplanControls.enableZoom = true; } else { this.player.floorplanControls.enablePan = false; this.player.floorplanControls.enableZoom = false; } } setMode(mode) { this.player.setMode(mode); } onResize = (rWidth, rHeight) => { this.width = typeof rWidth === "number" ? rWidth : this.domElement.clientWidth; this.height = typeof rHeight === "height" ? rHeight : this.domElement.clientHeight; const container = document.querySelector("#canvas"); const { width, height } = container.getBoundingClientRect(); if (width !== this.domElement.clientWidth) { this.width = width; } if (height !== this.domElement.clientHeight) { this.height = height; } console.warn("onResize", this.width, this.height); (this.orthCamera.left = -this.width / 2), (this.orthCamera.right = this.width / 2), (this.orthCamera.bottom = -this.height / 2), (this.orthCamera.top = this.height / 2), this.orthCamera.updateProjectionMatrix(); this.renderer.setSize(this.width, this.height); this.renderRes = window.devicePixelRatio; this.defaultUseZoom = this.defaultZoom / this.renderRes; this.renderer.setPixelRatio(this.renderRes); }; render = () => { if (this.player) { this.player.update(); this.renderer.render(this.scene, this.orthCamera); } }; animate = () => { stats.begin(); this.render(); stats.end(); requestAnimationFrame(this.animate); }; resetCameraView() { this.orthCamera.zoom = this.defaultUseZoom; // this.orthCamera.position.set(0, 0, 0); // this.orthCamera.rotation.set(0, 10, 0); this.orthCamera.updateMatrixWorld(); } editing(item) { this.player.editing(item); } endScreenshot() { this.lockView(false); this.blobScreens = []; this.scene.position.x = 0; this.player.floorplanControls.reset(); this.onResize(this.width, this.height); } screenshot(x, zoom, index) { var imgData, imgNode; const times = 4; this.orthCamera.zoom = zoom || this.defaultUseZoom; this.scene.position.x = x || 0; this.renderer.setSize(this.width * times, this.height * times); this.renderer.setPixelRatio(this.renderRes); this.orthCamera.aspect = this.width / this.height; this.orthCamera.updateProjectionMatrix(); this.renderer.render(this.scene, this.orthCamera, null, false); const dataURL = this.renderer.domElement.toDataURL("image/jpeg"); this.blobScreens.push(dataURItoBlob(dataURL)); console.log(this.width, this.height); if (typeof index === "number") { saveFile(dataURL, `${index}.jpg`); } this.renderer.setSize(this.width, this.height); } exportScreenshot(isSaveJpg = true) { if (window.devicePixelRatio !== 1) { this.emit("devicePixelRatio"); return; } this.player.floorplanControls.reset(); this.onResize(); this.lockView(true); this.setMode(0); // await sleep(500); const object = this.boxManager.model; const total = object.children.length; if (total === 0) { return; console.error("没数据"); } object.updateMatrixWorld(); this.orthCamera.updateProjectionMatrix(); const boundingBox = new THREE.Box3().setFromObject(object); // 计算宽度、高度和深度 const width = boundingBox.max.x - boundingBox.min.x; const one = width / total; let slides = Math.floor(total / 3); console.log("slides", slides); if (slides >= 1 && total > 3) { for (var i = 0; i <= slides; i++) { (function (index, that) { setTimeout(function () { const offset = -(one * 3 * index); console.log("Iteration:", one, index, offset, that.defaultUseZoom); that.screenshot(offset, that.defaultUseZoom); console.log(`Width: ${offset}`); if (index === slides) { console.log("last"); that.emit("submitScreenshot", true); } }, index * 500); })(i, this); // 传递当前迭代的索引i给setTimeout的回调函数 } } else { // 只有一个 if (total >= 1) { console.log("total", total); this.player.floorplanControls.reset(); this.screenshot(-0.3, 227); this.emit("submitScreenshot", true); } } } test() { const object = this.boxManager.model; const boundingBox = new THREE.Box3().setFromObject(object); this.lockView(true); // let size = new THREE.Vector3(); // boundingBox.getSize(size); const width = boundingBox.max.x - boundingBox.min.x; const height = boundingBox.max.y - boundingBox.min.y; const z = boundingBox.max.z - boundingBox.min.z; const radio = width / height; // const dynamicWidth = this.height * radio; // (this.orthCamera.left = -dynamicWidth / 2), // (this.orthCamera.right = dynamicWidth / 2), // (this.orthCamera.bottom = -this.height / 2), // (this.orthCamera.top = this.height / 2), // this.orthCamera.updateProjectionMatrix(); // this.renderer.setSize(dynamicWidth, this.height); // this.renderRes = window.devicePixelRatio; // this.defaultUseZoom = this.defaultZoom / this.renderRes; // this.renderer.setPixelRatio(this.renderRes); // console.log("dynamicWidth", dynamicWidth); // console.log("height", height); } onBindEvent = () => { window.addEventListener("resize", this.onResize, false); }; }