import * as THREE from "three"; import {OrbitControls} from "three/addons/controls/OrbitControls.js"; export class ThreeWorld { constructor(container = document.body, onResize = null) { this.container = container; this.onResize = onResize; this.scene = null; this.camera = null; this.renderer = null; this.controls = null; this.width = this.container.clientWidth; this.height = this.container.clientHeight; this.init(); this.onWindowResize = this.onWindowResize.bind(this); window.addEventListener("resize", this.onWindowResize); } init() { this.scene = new THREE.Scene(); this.camera = new THREE.PerspectiveCamera(60, this.width / this.height, 0.01, 1000); this.camera.position.set(0, 10, 20); this.renderer = new THREE.WebGLRenderer({ alpha: true, antialias: false, powerPreference: "high-performance", }); this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); this.renderer.setSize(this.width, this.height); this.container.appendChild(this.renderer.domElement); this.controls = new OrbitControls(this.camera, this.renderer.domElement); this.controls.enableDamping = true; this.controls.dampingFactor = 0.05; this.controls.zoomSpeed = 1.5; this.controls.maxPolarAngle = Math.PI; this.controls.maxDistance = 80; } adjustCamera(gridInfo, fitMargin, offsetY) { const vFovRad = THREE.MathUtils.degToRad(this.camera.fov); const distForWidth = gridInfo.width / this.camera.aspect / (2 * Math.tan(vFovRad / 2)); const distForHeight = gridInfo.height / (2 * Math.tan(vFovRad / 2)); const baseOffset = Math.max(distForWidth, distForHeight) / fitMargin; const targetY = offsetY; const targetZ = baseOffset; this.camera.position.set(0, targetY, targetZ); this.camera.lookAt(0, targetY, 0); this.controls.target.set(0, targetY, 0); this.controls.update(); } onWindowResize() { this.width = this.container.clientWidth; this.height = this.container.clientHeight; this.camera.aspect = this.width / this.height; this.camera.updateProjectionMatrix(); this.renderer.setSize(this.width, this.height); if (this.onResize) { this.onResize(); } } render() { this.controls.update(); this.renderer.render(this.scene, this.camera); } get domElement() { return this.renderer.domElement; } }