Add modular services for Three.js integration in ParticlesComponent
Implemented dedicated Angular services (e.g., RendererService, InputHandlerService, PlayerModelService) to modularize and simplify Three.js integration within the `ParticlesComponent`. Refactored component logic to delegate rendering, input handling, and model creation to respective services. Updated particle data models and removed redundant logic from the component.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
import { Injectable, ElementRef } from '@angular/core';
|
||||
import * as THREE from 'three';
|
||||
import { RendererService } from './renderer.service';
|
||||
import { IntersectionPlaneService } from './intersection-plane.service';
|
||||
import { ParticleManagerService } from './particle-manager.service';
|
||||
|
||||
/**
|
||||
* Service responsible for handling user input interactions
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class InputHandlerService {
|
||||
private raycaster = new THREE.Raycaster();
|
||||
private mouse = new THREE.Vector2();
|
||||
private isDragging = false;
|
||||
private mouseDownTime = 0;
|
||||
|
||||
constructor(
|
||||
private rendererService: RendererService,
|
||||
private intersectionPlaneService: IntersectionPlaneService,
|
||||
private particleManagerService: ParticleManagerService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Initializes input event listeners
|
||||
*/
|
||||
initializeInputHandlers(rendererElement: HTMLElement): void {
|
||||
rendererElement.addEventListener('mousedown', this.onMouseDown.bind(this));
|
||||
rendererElement.addEventListener('mouseup', this.onMouseUp.bind(this));
|
||||
rendererElement.addEventListener('mousemove', this.onMouseMove.bind(this));
|
||||
window.addEventListener('resize', this.onWindowResize.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles mouse down event
|
||||
*/
|
||||
private onMouseDown(event: MouseEvent): void {
|
||||
this.isDragging = false;
|
||||
this.mouseDownTime = Date.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles mouse up event
|
||||
*/
|
||||
private onMouseUp(event: MouseEvent): void {
|
||||
// If mouse was down for less than 200ms and didn't move much, consider it a click, not a drag
|
||||
if (Date.now() - this.mouseDownTime < 200 && !this.isDragging) {
|
||||
this.handlePlaneClick(event);
|
||||
}
|
||||
this.isDragging = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles mouse move event
|
||||
*/
|
||||
private onMouseMove(event: MouseEvent): void {
|
||||
// If mouse moves while button is pressed, it's a drag
|
||||
if (event.buttons > 0) {
|
||||
this.isDragging = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles mouse click on the plane
|
||||
*/
|
||||
private handlePlaneClick(event: MouseEvent): void {
|
||||
// Calculate mouse position in normalized device coordinates
|
||||
const rect = this.rendererService.renderer.domElement.getBoundingClientRect();
|
||||
this.mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
|
||||
this.mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
|
||||
|
||||
// Update the picking ray with the camera and mouse position
|
||||
this.raycaster.setFromCamera(this.mouse, this.rendererService.camera);
|
||||
|
||||
// Calculate objects intersecting the picking ray
|
||||
const intersects = this.raycaster.intersectObject(this.intersectionPlaneService.getIntersectionPlane());
|
||||
|
||||
if (intersects.length > 0) {
|
||||
const point = intersects[0].point;
|
||||
this.particleManagerService.addParticle(point.x, point.y, point.z);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles window resize event
|
||||
*/
|
||||
private onWindowResize(): void {
|
||||
// This is delegated to the renderer service
|
||||
const container = this.rendererService.renderer.domElement.parentElement;
|
||||
if (container) {
|
||||
this.rendererService.onWindowResize(new ElementRef(container));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes event listeners
|
||||
*/
|
||||
cleanup(rendererElement: HTMLElement): void {
|
||||
rendererElement.removeEventListener('mousedown', this.onMouseDown.bind(this));
|
||||
rendererElement.removeEventListener('mouseup', this.onMouseUp.bind(this));
|
||||
rendererElement.removeEventListener('mousemove', this.onMouseMove.bind(this));
|
||||
window.removeEventListener('resize', this.onWindowResize.bind(this));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user