Add particle type selection, size control, and enhance particle property handling

This commit is contained in:
Teriuihi 2025-06-23 00:23:03 +02:00
parent 1e5862bae6
commit d4363b3a8a
4 changed files with 175 additions and 27 deletions

View File

@ -1,12 +1,36 @@
<div class="card-div">
<mat-card class="color-picker-card">
<mat-card class="particle-card">
<mat-card-header>
<mat-card-title>Particle Color</mat-card-title>
<mat-card-title>Particle Properties</mat-card-title>
</mat-card-header>
<mat-card-content>
<div class="particle-properties">
<div class="property-row">
<div class="color-picker">
<input type="color" [(ngModel)]="selectedColor">
<span>Selected Color: {{ selectedColor }}</span>
<span>Current color: {{ selectedColor }}</span>
</div>
<mat-form-field appearance="fill" class="type-field">
<mat-label>Select Particle Type</mat-label>
<input type="text"
placeholder="Search for a particle type"
matInput
[formControl]="particleTypeControl"
[matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
<mat-option *ngFor="let type of filteredParticleTypes | async" [value]="type">
{{ type }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
<div class="size-slider">
<mat-slider min="0.1" max="4" step="0.1" class="full-width">
<input matSliderThumb [(ngModel)]="selectedSize">
</mat-slider>
<span>Size: {{ selectedSize }}</span>
</div>
</div>
</mat-card-content>
</mat-card>

View File

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

View File

@ -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<string[]>;
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;
}
}

View File

@ -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
*/