1
0

Scene.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. import * as THREE from "three";
  2. import Stats from "three/examples/jsm/libs/stats.module.js";
  3. import Player from "./player/Player.js";
  4. import BoxManager from "./box/BoxManager.js";
  5. import { Mitt } from "./mitt.js";
  6. import testData from "./save.json";
  7. import { dataURItoBlob, saveFile } from "./utils/utils.js";
  8. import { screenshotObject } from "./utils/cap.js";
  9. const stats = new Stats();
  10. function sleep(ms) {
  11. return new Promise((resolve) => setTimeout(resolve, ms));
  12. }
  13. export default class Scene extends Mitt {
  14. constructor(domElement) {
  15. super();
  16. this.domElement = domElement;
  17. this.scene = null;
  18. this.renderer = null;
  19. this.orthCamera = null;
  20. this.camera = null;
  21. this.player = null;
  22. this.sceneType = 1;
  23. this.width = 0;
  24. this.height = 0;
  25. this.defaultZoom = 250;
  26. this.defaultUseZoom = 250 / window.devicePixelRatio;
  27. this.initCamPView = new THREE.Vector3();
  28. this.initCamRView = new THREE.Vector3();
  29. this.blobScreens = [];
  30. this.inited = false;
  31. this.init = () => {
  32. this.scene = new THREE.Scene();
  33. this.scene.background = new THREE.Color(0xf0f2f5);
  34. this.renderer = new THREE.WebGLRenderer({
  35. canvas: this.domElement,
  36. antialias: true,
  37. autoClear: true,
  38. preserveDrawingBuffer: true,
  39. });
  40. this.width = this.domElement.clientWidth;
  41. this.height = this.domElement.clientHeight;
  42. this.renderRes = window.devicePixelRatio;
  43. this.defaultUseZoom = this.defaultZoom / window.devicePixelRatio;
  44. this.renderer.setSize(this.width, this.height);
  45. this.renderer.setPixelRatio(this.renderRes);
  46. console.log(
  47. "init",
  48. this.width,
  49. this.height,
  50. this.renderRes,
  51. this.defaultZoom
  52. );
  53. this.camera = new THREE.PerspectiveCamera(
  54. 70,
  55. this.domElement.clientWidth / this.domElement.clientHeight,
  56. 0.1,
  57. 1000
  58. );
  59. this.orthCamera = new THREE.OrthographicCamera(
  60. -this.width / 2,
  61. this.width / 2,
  62. this.height / 2,
  63. -this.height / 2,
  64. 0.1,
  65. 1000
  66. );
  67. this.orthCamera.zoom = this.defaultUseZoom;
  68. // 影响画线
  69. this.orthCamera.position.set(0, 10, 0);
  70. this.orthCamera.lookAt(0, 0, 0);
  71. // this.orthCamera.setViewOffset(this.width, this.height, 0, 0);
  72. this.orthCamera.updateProjectionMatrix();
  73. //player
  74. this.player = new Player(this);
  75. domElement.parentNode.appendChild(stats.dom);
  76. stats.dom.style.pointerEvents = "none";
  77. stats.dom.style.left = "15%";
  78. stats.dom.style.display = "none";
  79. this.onBindEvent();
  80. this.inited = true;
  81. this.load();
  82. this.animate();
  83. };
  84. }
  85. load = (list, type, data) => {
  86. if (!list) return;
  87. // console.log("scene: ", list, type, data);
  88. //axesHeloer
  89. this.clearScene();
  90. this.sceneType = type;
  91. // const axesHelper = new THREE.AxesHelper(1);
  92. // this.scene.add(axesHelper);
  93. this.boxManager = new BoxManager(this);
  94. this.boxManager.load(list, type);
  95. //light
  96. this.loadLight();
  97. this.player.load(type, data || []);
  98. this.initCamPView.copy(this.orthCamera.position);
  99. this.initCamRView.copy(this.orthCamera.rotation);
  100. };
  101. clearScene() {
  102. for (var i = this.scene.children.length - 1; i >= 0; i--) {
  103. let obj = this.scene.children[i];
  104. this.scene.remove(obj);
  105. }
  106. }
  107. clearDrawScene() {
  108. for (var i = this.scene.children.length - 1; i >= 0; i--) {
  109. let obj = this.scene.children[i];
  110. if (
  111. String(obj.name).includes("marker_") ||
  112. String(obj.name).includes("line_") ||
  113. String(obj.name).includes("line_point_") ||
  114. String(obj.name).includes("circle_") ||
  115. String(obj.name).includes("pureText_")
  116. ) {
  117. this.scene.remove(obj);
  118. }
  119. }
  120. }
  121. deleteItemById(uuid, type) {
  122. for (var i = this.scene.children.length - 1; i >= 0; i--) {
  123. let obj = this.scene.children[i];
  124. if (obj.uuid === uuid) {
  125. console.log("deleteItemById-userData", obj.userData);
  126. this.player.deleteItemByType(type, obj.userData);
  127. this.scene.remove(obj);
  128. }
  129. }
  130. }
  131. deleteImageDataByIds(ids) {
  132. this.player.deleteImageDataByIds(ids);
  133. }
  134. loadLight = () => {
  135. const light = new THREE.AmbientLight(0xffffff, 1.5); // 柔和的白光
  136. this.scene.add(light);
  137. };
  138. setCamera = () => {
  139. // const object = this.boxManager.model;
  140. // const boundingBox = new THREE.Box3().setFromObject(object);
  141. // let size = boundingBox.getSize(new THREE.Vector3());
  142. // const fov = this.camera.fov * (Math.PI / 180);
  143. // const fovh = 2 * Math.atan(Math.tan(fov / 2) * this.camera.aspect);
  144. // let dx = Math.abs(size.x / 2 / Math.tan(fovh / 2));
  145. // let dz = Math.abs(size.z / 2 / Math.tan(fov / 2));
  146. // this.orthCamera.zoom = this.floorplanZoom;
  147. };
  148. toHorizontal = () => {};
  149. toVertical = () => {};
  150. lockView(open) {
  151. if (!open) {
  152. this.player.floorplanControls.enablePan = true;
  153. this.player.floorplanControls.enableZoom = true;
  154. } else {
  155. this.player.floorplanControls.enablePan = false;
  156. this.player.floorplanControls.enableZoom = false;
  157. }
  158. }
  159. setMode(mode) {
  160. this.player.setMode(mode);
  161. }
  162. onResize = (rWidth, rHeight) => {
  163. this.width =
  164. typeof rWidth === "number" ? rWidth : this.domElement.clientWidth;
  165. this.height =
  166. typeof rHeight === "height" ? rHeight : this.domElement.clientHeight;
  167. const container = document.querySelector("#canvas");
  168. const { width, height } = container.getBoundingClientRect();
  169. if (width !== this.domElement.clientWidth) {
  170. this.width = width;
  171. }
  172. if (height !== this.domElement.clientHeight) {
  173. this.height = height;
  174. }
  175. console.warn("onResize", this.width, this.height);
  176. (this.orthCamera.left = -this.width / 2),
  177. (this.orthCamera.right = this.width / 2),
  178. (this.orthCamera.bottom = -this.height / 2),
  179. (this.orthCamera.top = this.height / 2),
  180. this.orthCamera.updateProjectionMatrix();
  181. this.renderer.setSize(this.width, this.height);
  182. this.renderRes = window.devicePixelRatio;
  183. this.defaultUseZoom = this.defaultZoom / this.renderRes;
  184. this.renderer.setPixelRatio(this.renderRes);
  185. };
  186. render = () => {
  187. if (this.player) {
  188. this.player.update();
  189. this.renderer.render(this.scene, this.orthCamera);
  190. }
  191. };
  192. animate = () => {
  193. stats.begin();
  194. this.render();
  195. stats.end();
  196. requestAnimationFrame(this.animate);
  197. };
  198. resetCameraView() {
  199. this.orthCamera.zoom = this.defaultUseZoom;
  200. // this.orthCamera.position.set(0, 0, 0);
  201. // this.orthCamera.rotation.set(0, 10, 0);
  202. this.orthCamera.updateMatrixWorld();
  203. }
  204. editing(item) {
  205. this.player.editing(item);
  206. }
  207. endScreenshot() {
  208. this.lockView(false);
  209. this.blobScreens = [];
  210. this.scene.position.x = 0;
  211. this.player.floorplanControls.reset();
  212. this.onResize(this.width, this.height);
  213. }
  214. screenshot(x, zoom, index) {
  215. var imgData, imgNode;
  216. const times = 4;
  217. this.orthCamera.zoom = zoom || this.defaultUseZoom;
  218. this.scene.position.x = x || 0;
  219. this.renderer.setSize(this.width * times, this.height * times);
  220. this.renderer.setPixelRatio(this.renderRes);
  221. this.orthCamera.aspect = this.width / this.height;
  222. this.orthCamera.updateProjectionMatrix();
  223. this.renderer.render(this.scene, this.orthCamera, null, false);
  224. const dataURL = this.renderer.domElement.toDataURL("image/jpeg");
  225. this.blobScreens.push(dataURItoBlob(dataURL));
  226. console.log(this.width, this.height);
  227. if (typeof index === "number") {
  228. saveFile(dataURL, `${index}.jpg`);
  229. }
  230. this.renderer.setSize(this.width, this.height);
  231. }
  232. exportScreenshot(isSaveJpg = true) {
  233. if (window.devicePixelRatio !== 1) {
  234. this.emit("devicePixelRatio");
  235. return;
  236. }
  237. window.isExportScreenshot = true
  238. this.player.floorplanControls.reset();
  239. this.onResize();
  240. this.lockView(true);
  241. this.setMode(0);
  242. // await sleep(500);
  243. const object = this.boxManager.model;
  244. const total = object.children.length;
  245. if (total === 0) {
  246. return;
  247. console.error("没数据");
  248. }
  249. object.updateMatrixWorld();
  250. this.orthCamera.updateProjectionMatrix();
  251. const boundingBox = new THREE.Box3().setFromObject(object);
  252. // 计算宽度、高度和深度
  253. const width = boundingBox.max.x - boundingBox.min.x;
  254. const one = width / total;
  255. let slides = Math.floor(total / 3);
  256. console.log("slides", slides);
  257. if (slides >= 1 && total > 3) {
  258. for (var i = 0; i <= slides; i++) {
  259. (function (index, that) {
  260. setTimeout(function () {
  261. const offset = -(one * 3 * index);
  262. console.log("Iteration:", one, index, offset, that.defaultUseZoom);
  263. that.screenshot(offset, that.defaultUseZoom);
  264. console.log(`Width: ${offset}`);
  265. if (index === slides) {
  266. console.log("last");
  267. that.emit("submitScreenshot", true);
  268. window.isExportScreenshot = false
  269. }
  270. }, index * 500);
  271. })(i, this); // 传递当前迭代的索引i给setTimeout的回调函数
  272. }
  273. } else {
  274. // 只有一个
  275. if (total >= 1) {
  276. console.log("total", total);
  277. this.player.floorplanControls.reset();
  278. this.screenshot(-0.3, 227);
  279. this.emit("submitScreenshot", true);
  280. window.isExportScreenshot = false
  281. }
  282. }
  283. }
  284. test() {
  285. const object = this.boxManager.model;
  286. const boundingBox = new THREE.Box3().setFromObject(object);
  287. this.lockView(true);
  288. // let size = new THREE.Vector3();
  289. // boundingBox.getSize(size);
  290. const width = boundingBox.max.x - boundingBox.min.x;
  291. const height = boundingBox.max.y - boundingBox.min.y;
  292. const z = boundingBox.max.z - boundingBox.min.z;
  293. const radio = width / height;
  294. // const dynamicWidth = this.height * radio;
  295. // (this.orthCamera.left = -dynamicWidth / 2),
  296. // (this.orthCamera.right = dynamicWidth / 2),
  297. // (this.orthCamera.bottom = -this.height / 2),
  298. // (this.orthCamera.top = this.height / 2),
  299. // this.orthCamera.updateProjectionMatrix();
  300. // this.renderer.setSize(dynamicWidth, this.height);
  301. // this.renderRes = window.devicePixelRatio;
  302. // this.defaultUseZoom = this.defaultZoom / this.renderRes;
  303. // this.renderer.setPixelRatio(this.renderRes);
  304. // console.log("dynamicWidth", dynamicWidth);
  305. // console.log("height", height);
  306. }
  307. onBindEvent = () => {
  308. window.addEventListener("resize", this.onResize, false);
  309. };
  310. }