AltitudeWeb/frontend/src/app/particles/particles.component.ts

163 lines
4.8 KiB
TypeScript
Raw Normal View History

import {AfterViewInit, Component, ElementRef, OnDestroy, OnInit, ViewChild} from '@angular/core';
import {CommonModule} from '@angular/common';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {MatButtonModule} from '@angular/material/button';
import {MatInputModule} from '@angular/material/input';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatSelectModule} from '@angular/material/select';
import {MatSliderModule} from '@angular/material/slider';
import {MatCheckboxModule} from '@angular/material/checkbox';
import {MatTabsModule} from '@angular/material/tabs';
import {MatCardModule} from '@angular/material/card';
import {MatIconModule} from '@angular/material/icon';
import {HeaderComponent} from '../header/header.component';
// Services
import {RendererService} from './services/renderer.service';
import {PlayerModelService} from './services/player-model.service';
import {IntersectionPlaneService} from './services/intersection-plane.service';
import {ParticleManagerService} from './services/particle-manager.service';
import {InputHandlerService} from './services/input-handler.service';
// Models
import {PropertiesComponent} from './components/properties/properties.component';
import {ParticleComponent} from './components/particle/particle.component';
import {FramesComponent} from './components/frames/frames.component';
import {MatSnackBar} from '@angular/material/snack-bar';
@Component({
selector: 'app-particles',
standalone: true,
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
MatButtonModule,
MatInputModule,
MatFormFieldModule,
MatSelectModule,
MatSliderModule,
MatCheckboxModule,
MatTabsModule,
MatCardModule,
MatIconModule,
HeaderComponent,
PropertiesComponent,
ParticleComponent,
FramesComponent,
],
templateUrl: './particles.component.html',
styleUrl: './particles.component.scss'
})
export class ParticlesComponent implements OnInit, AfterViewInit, OnDestroy {
@ViewChild('rendererContainer') rendererContainer!: ElementRef;
@ViewChild('planeSlider') planeSlider!: ElementRef;
constructor(
private rendererService: RendererService,
private playerModelService: PlayerModelService,
private intersectionPlaneService: IntersectionPlaneService,
private particleManagerService: ParticleManagerService,
private inputHandlerService: InputHandlerService,
private matSnackBar: MatSnackBar,
) {
}
/**
* Initialize component
*/
ngOnInit(): void {
// No initialization needed here
}
/**
* Initialize Three.js scene after view is initialized
*/
ngAfterViewInit(): void {
this.initializeScene();
this.animate();
}
/**
* Clean up resources when component is destroyed
*/
ngOnDestroy(): void {
// Clean up event listeners
if (this.rendererService.renderer) {
this.inputHandlerService.cleanup(this.rendererService.renderer.domElement);
}
}
/**
* Initialize the 3D scene and all related components
*/
private initializeScene(): void {
// Initialize renderer
this.rendererService.initializeRenderer(this.rendererContainer);
// Create player model
this.playerModelService.createPlayerModel();
// Create intersection plane
this.intersectionPlaneService.createIntersectionPlane();
// Initialize input handlers
this.inputHandlerService.initializeInputHandlers(this.rendererService.renderer.domElement);
}
/**
* Update plane position based on slider
*/
public updatePlanePosition(event: Event): void {
const slider = event.target as HTMLInputElement;
const value = Number(slider.value);
this.intersectionPlaneService.updatePlanePosition(value);
}
/**
* Get the current plane position
*/
public get planePosition(): number {
return this.intersectionPlaneService.getPlanePosition();
}
public set planePosition(newPlanePosition: number) {
this.intersectionPlaneService.updatePlanePosition(newPlanePosition);
}
public get maxOffset(): number {
return this.intersectionPlaneService.getMaxOffset();
}
public get minOffset(): number {
return this.intersectionPlaneService.getMinOffset();
}
/**
* Animation loop
*/
private animate(): void {
requestAnimationFrame(this.animate.bind(this));
// Update plane orientation based on camera position
this.intersectionPlaneService.updatePlaneOrientation(this.rendererService.camera);
// Render the scene
this.rendererService.render();
}
/**
* Generate JSON output
*/
public generateJson(): string {
return this.particleManagerService.generateJson();
}
public copyJson() {
navigator.clipboard.writeText(this.generateJson()).then(() => {
this.matSnackBar.open('Copied to clipboard', '', {duration: 2000})
});
}
}