From d4363b3a8ae00018c21415db19780003d703f2fe Mon Sep 17 00:00:00 2001 From: Teriuihi Date: Mon, 23 Jun 2025 00:23:03 +0200 Subject: [PATCH] Add particle type selection, size control, and enhance particle property handling --- .../particle/particle.component.html | 34 ++++++-- .../particle/particle.component.scss | 41 ++++++++- .../components/particle/particle.component.ts | 83 ++++++++++++++++++- .../services/particle-manager.service.ts | 44 ++++++---- 4 files changed, 175 insertions(+), 27 deletions(-) diff --git a/frontend/src/app/particles/components/particle/particle.component.html b/frontend/src/app/particles/components/particle/particle.component.html index 5f35d24..e101d73 100644 --- a/frontend/src/app/particles/components/particle/particle.component.html +++ b/frontend/src/app/particles/components/particle/particle.component.html @@ -1,12 +1,36 @@
- + - Particle Color + Particle Properties -
- - Selected Color: {{ selectedColor }} +
+
+
+ + Current color: {{ selectedColor }} +
+ + Select Particle Type + + + + {{ type }} + + + +
+ +
+ + + + Size: {{ selectedSize }} +
diff --git a/frontend/src/app/particles/components/particle/particle.component.scss b/frontend/src/app/particles/components/particle/particle.component.scss index c394ef0..1f26a7e 100644 --- a/frontend/src/app/particles/components/particle/particle.component.scss +++ b/frontend/src/app/particles/components/particle/particle.component.scss @@ -1,16 +1,37 @@ -.color-picker-card { +.particle-card { margin-top: 20px; + margin-bottom: 20px; +} + +.particle-properties { + display: flex; + flex-direction: column; + gap: 20px; +} + +.property-row { + display: flex; + align-items: center; + gap: 15px; + width: 100%; +} + +.type-field { + flex: 1; + min-width: 20ch; + max-width: 40ch; } .color-picker { display: flex; + flex: 1; align-items: center; - gap: 15px; + gap: 10px; } .color-picker input[type="color"] { - width: 50px; - height: 50px; + width: 40px; + height: 40px; border: none; border-radius: 4px; cursor: pointer; @@ -23,6 +44,18 @@ } } +.full-width { + width: 100%; +} + +.size-slider { + display: flex; + flex-direction: column; + gap: 10px; + margin-top: 5px; +} + span { color: var(--font-color); + font-size: 0.9rem; } diff --git a/frontend/src/app/particles/components/particle/particle.component.ts b/frontend/src/app/particles/components/particle/particle.component.ts index f2a4413..2f7146e 100644 --- a/frontend/src/app/particles/components/particle/particle.component.ts +++ b/frontend/src/app/particles/components/particle/particle.component.ts @@ -1,7 +1,16 @@ -import {Component} from '@angular/core'; +import {Component, OnInit} from '@angular/core'; import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from '@angular/material/card'; -import {FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; import {ParticleManagerService} from '../../services/particle-manager.service'; +import {Particle} from '../../models/particle.model'; +import {MatSliderModule} from '@angular/material/slider'; +import {MatSelectModule} from '@angular/material/select'; +import {MatFormFieldModule} from '@angular/material/form-field'; +import {MatInputModule} from '@angular/material/input'; +import {MatAutocompleteModule} from '@angular/material/autocomplete'; +import {Observable} from 'rxjs'; +import {map, startWith} from 'rxjs/operators'; +import {AsyncPipe, NgForOf} from '@angular/common'; @Component({ selector: 'app-particle', @@ -11,16 +20,55 @@ import {ParticleManagerService} from '../../services/particle-manager.service'; MatCardHeader, MatCardTitle, ReactiveFormsModule, - FormsModule + FormsModule, + MatSliderModule, + MatSelectModule, + MatFormFieldModule, + MatInputModule, + MatAutocompleteModule, + NgForOf, + AsyncPipe ], templateUrl: './particle.component.html', styleUrl: './particle.component.scss' }) -export class ParticleComponent { +export class ParticleComponent implements OnInit { + // Available particle types from the enum + particleTypes = Object.values(Particle); + + // Form control for the particle type dropdown with filtering + particleTypeControl = new FormControl(); + filteredParticleTypes: Observable; constructor( private particleManagerService: ParticleManagerService, ) { + this.filteredParticleTypes = this.particleTypeControl.valueChanges.pipe( + startWith(''), + map(value => this._filterParticleTypes(value || '')) + ); + } + + ngOnInit() { + // Initialize the particle type control with the current value + this.particleTypeControl.setValue(this.selectedParticle); + + // Update the selected particle when the control value changes + this.particleTypeControl.valueChanges.subscribe(value => { + if (value && Object.values(Particle).includes(value)) { + this.selectedParticle = value; + } + }); + } + + private _filterParticleTypes(value: string): string[] { + const filterValue = value.toLowerCase(); + return this.particleTypes.filter(type => type.toLowerCase().includes(filterValue)); + } + + // Display function for the autocomplete + displayFn(particle: string): string { + return particle ? particle : ''; } /** @@ -37,4 +85,31 @@ export class ParticleComponent { this.particleManagerService.setSelectedColor(color); } + /** + * Get the selected particle type + */ + public get selectedParticle(): Particle { + return this.particleManagerService.particle; + } + + /** + * Set the selected particle type + */ + public set selectedParticle(particle: Particle) { + this.particleManagerService.particle = particle; + } + + /** + * Get the selected particle size + */ + public get selectedSize(): number { + return this.particleManagerService.size; + } + + /** + * Set the selected particle size + */ + public set selectedSize(size: number) { + this.particleManagerService.size = size; + } } diff --git a/frontend/src/app/particles/services/particle-manager.service.ts b/frontend/src/app/particles/services/particle-manager.service.ts index 151bd12..eee13fb 100644 --- a/frontend/src/app/particles/services/particle-manager.service.ts +++ b/frontend/src/app/particles/services/particle-manager.service.ts @@ -42,7 +42,7 @@ export class ParticleManagerService { */ addParticle(x: number, y: number, z: number): void { // Create a visual representation of the particle - const particleGeometry = new THREE.SphereGeometry(0.03, 16, 16); + const particleGeometry = new THREE.SphereGeometry(0.03 * this.selectedSize, 16, 16); const particleMaterial = new THREE.MeshBasicMaterial({color: this.selectedColor}); const particleMesh = new THREE.Mesh(particleGeometry, particleMaterial); @@ -89,7 +89,7 @@ export class ParticleManagerService { if (!this.particleData.frames[frameId]) return; for (const particleInfo of this.particleData.frames[frameId]) { - const particleGeometry = new THREE.SphereGeometry(0.03, 16, 16); + const particleGeometry = new THREE.SphereGeometry(0.03 * (particleInfo.size ?? 1), 16, 16); const color = this.getColor(particleInfo); const particleMaterial = new THREE.MeshBasicMaterial({color}); @@ -123,7 +123,7 @@ export class ParticleManagerService { const particleInfo = this.particleData.frames[frameId][index]; const color = this.getColor(particleInfo); const particleMaterial = new THREE.MeshBasicMaterial({color}); - const particleGeometry = new THREE.SphereGeometry(0.03, 16, 16); + const particleGeometry = new THREE.SphereGeometry(0.03 * (particleInfo.size ?? 1), 16, 16); const particleMesh = new THREE.Mesh(particleGeometry, particleMaterial); particleMesh.position.set(particleInfo.x, particleInfo.y, particleInfo.z); this.rendererService.scene.add(particleMesh); @@ -135,17 +135,6 @@ export class ParticleManagerService { }); } - private getColor(particleInfo: ParticleInfo) { - if (particleInfo.color) { - const r = parseInt(particleInfo.color.substring(0, 2), 16) / 255; - const g = parseInt(particleInfo.color.substring(2, 4), 16) / 255; - const b = parseInt(particleInfo.color.substring(4, 6), 16) / 255; - return new THREE.Color(r, g, b); - } else { - return new THREE.Color(255, 0, 0); - } - } - private animatePulse(mesh: THREE.Mesh, cycles: number, onComplete: () => void): void { const duration = 300; const maxScale = 0.08 / 0.03; @@ -167,6 +156,17 @@ export class ParticleManagerService { requestAnimationFrame(animate); } + private getColor(particleInfo: ParticleInfo) { + if (particleInfo.color) { + const r = parseInt(particleInfo.color.substring(0, 2), 16) / 255; + const g = parseInt(particleInfo.color.substring(2, 4), 16) / 255; + const b = parseInt(particleInfo.color.substring(4, 6), 16) / 255; + return new THREE.Color(r, g, b); + } else { + return new THREE.Color(255, 0, 0); + } + } + /** * Sets the selected color for new particles */ @@ -181,6 +181,22 @@ export class ParticleManagerService { return this.selectedColor; } + public get particle(): Particle { + return this.selectedParticle; + } + + public set particle(selectedParticle: Particle) { + this.selectedParticle = selectedParticle; + } + + public get size(): number { + return this.selectedSize; + } + + public set size(selectedSize: number) { + this.selectedSize = selectedSize; + } + /** * Gets the particle data */