Files
AltitudeWeb/frontend/src/app/pages/particles/services/renderer.service.ts
T

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