-
-
Selected Color: {{ selectedColor }}
+
+
+
+
+
+
+
+ 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
*/