118 lines
3.3 KiB
TypeScript
118 lines
3.3 KiB
TypeScript
import {ElementRef, Injectable} from '@angular/core';
|
|
import * as THREE from 'three';
|
|
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js';
|
|
import {ThemeService} from '@shared-components/theme/theme.service';
|
|
import {THEME_MODE} from '@custom-types/constant';
|
|
|
|
/**
|
|
* Service responsible for managing the Three.js rendering environment
|
|
*/
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class RendererService {
|
|
scene!: THREE.Scene;
|
|
camera!: THREE.PerspectiveCamera;
|
|
renderer!: THREE.WebGLRenderer;
|
|
controls!: OrbitControls;
|
|
private currentTheme: THEME_MODE = THEME_MODE.LIGHT;
|
|
|
|
constructor(private themeService: ThemeService) {
|
|
this.themeService.theme$.subscribe(theme => {
|
|
this.currentTheme = theme;
|
|
if (this.scene) {
|
|
this.setBackgroundColor();
|
|
}
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Initializes the Three.js scene, camera, renderer, and controls
|
|
*/
|
|
initializeRenderer(container: ElementRef): void {
|
|
// Create scene
|
|
this.scene = new THREE.Scene();
|
|
this.setBackgroundColor();
|
|
|
|
// Get container dimensions
|
|
const containerWidth = container.nativeElement.clientWidth;
|
|
const containerHeight = container.nativeElement.clientHeight;
|
|
|
|
// Create camera
|
|
this.camera = new THREE.PerspectiveCamera(75, containerWidth / containerHeight, 0.1, 1000);
|
|
this.camera.position.set(-1, 2, 3);
|
|
this.camera.lookAt(0, 1, 0);
|
|
|
|
// Create renderer
|
|
this.renderer = new THREE.WebGLRenderer({antialias: true});
|
|
this.renderer.setSize(containerWidth, containerHeight);
|
|
|
|
// Center the canvas in the container
|
|
this.renderer.domElement.style.display = 'block';
|
|
this.renderer.domElement.style.margin = 'auto';
|
|
|
|
container.nativeElement.appendChild(this.renderer.domElement);
|
|
|
|
// Initialize orbit controls
|
|
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
|
|
this.controls.enableDamping = true;
|
|
this.controls.dampingFactor = 0.05;
|
|
this.controls.minDistance = 0.5;
|
|
this.controls.maxDistance = 4;
|
|
this.controls.target.set(0, 1, 0);
|
|
this.controls.update();
|
|
|
|
// Add lights
|
|
this.addLights();
|
|
}
|
|
|
|
private setBackgroundColor() {
|
|
this.scene.background = new THREE.Color(this.currentTheme === THEME_MODE.DARK ? 0x242526 : 0xFBFBFE);
|
|
}
|
|
|
|
/**
|
|
* Resets the camera to its default position and orientation.
|
|
*/
|
|
public resetCamera(): void {
|
|
this.camera.position.set(-1, 2, 3);
|
|
this.camera.lookAt(0, 1, 0);
|
|
this.controls.target.set(0, 1, 0);
|
|
this.controls.update();
|
|
}
|
|
|
|
/**
|
|
* Adds lighting to the scene
|
|
*/
|
|
private addLights(): void {
|
|
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
|
|
this.scene.add(ambientLight);
|
|
|
|
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
|
|
directionalLight.position.set(1, 1, 1);
|
|
this.scene.add(directionalLight);
|
|
}
|
|
|
|
/**
|
|
* Handles window resize events
|
|
*/
|
|
onWindowResize(container: ElementRef): void {
|
|
const containerWidth = container.nativeElement.clientWidth;
|
|
const containerHeight = 400; // Fixed height as defined in CSS
|
|
|
|
this.camera.aspect = containerWidth / containerHeight;
|
|
this.camera.updateProjectionMatrix();
|
|
this.renderer.setSize(containerWidth, containerHeight);
|
|
}
|
|
|
|
/**
|
|
* Renders the scene
|
|
*/
|
|
render(): void {
|
|
if (this.controls) {
|
|
this.controls.update();
|
|
}
|
|
|
|
this.renderer.render(this.scene, this.camera);
|
|
}
|
|
}
|