Add an option to highlight particles

This commit is contained in:
Teriuihi 2025-06-22 20:46:08 +02:00
parent fdb57289f8
commit c3a7be82e9
4 changed files with 66 additions and 8 deletions

View File

@ -11,11 +11,16 @@
<h3>Particles in {{ frameId }}</h3> <h3>Particles in {{ frameId }}</h3>
<div class="particles-list"> <div class="particles-list">
<div *ngFor="let particle of particleData.frames[frameId]; let i = index" class="particle-item"> <div *ngFor="let particle of particleData.frames[frameId]; let i = index" class="particle-item">
<span>Particle {{ i + 1 }}: ({{ particle.x.toFixed(2) }}, {{ particle.y.toFixed(2) }} <span class="particle-item-text">
, {{ particle.z.toFixed(2) }})</span> Particle {{ i + 1 }}: ({{ particle.x.toFixed(2) }}, {{ particle.y.toFixed(2) }}
<button mat-icon-button color="warn" (click)="removeParticle(frameId, i)"> , {{ particle.z.toFixed(2) }})
</span>
<button mat-icon-button (click)="removeParticle(frameId, i)">
<mat-icon>delete</mat-icon> <mat-icon>delete</mat-icon>
</button> </button>
<button mat-icon-button (click)="highlightParticle(frameId, i)">
<mat-icon>lightbulb</mat-icon>
</button>
</div> </div>
<div *ngIf="!particleData.frames[frameId] || particleData.frames[frameId].length === 0" <div *ngIf="!particleData.frames[frameId] || particleData.frames[frameId].length === 0"
class="no-particles"> class="no-particles">

View File

@ -17,10 +17,14 @@
.particle-item { .particle-item {
display: flex; display: flex;
justify-content: space-between;
align-items: center; align-items: center;
padding: 8px; padding: 8px;
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
gap: 10px;
}
.particle-item-text {
flex-grow: 1;
} }
.particle-item:last-child { .particle-item:last-child {

View File

@ -83,4 +83,7 @@ export class FramesComponent {
} }
public highlightParticle(frameId: string, i: number) {
this.particleManagerService.highlightParticle(frameId, i);
}
} }

View File

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core'; import {Injectable} from '@angular/core';
import * as THREE from 'three'; import * as THREE from 'three';
import { RendererService } from './renderer.service'; import {RendererService} from './renderer.service';
import { ParticleData, ParticleInfo, ParticleType } from '../models/particle.model'; import {ParticleData, ParticleInfo, ParticleType} from '../models/particle.model';
/** /**
* Service responsible for managing particles in the scene * Service responsible for managing particles in the scene
@ -32,7 +32,8 @@ export class ParticleManagerService {
private frames: string[] = ['frame1']; private frames: string[] = ['frame1'];
private selectedColor: string = '#ff0000'; private selectedColor: string = '#ff0000';
constructor(private rendererService: RendererService) {} constructor(private rendererService: RendererService) {
}
/** /**
* Adds a particle at the specified position * Adds a particle at the specified position
@ -120,6 +121,51 @@ export class ParticleManagerService {
} }
} }
highlightParticle(frameId: string, index: number): void {
if (!(this.particleData.frames[frameId] && this.particleData.frames[frameId].length > index)) {
return;
}
const particleInfo = this.particleData.frames[frameId][index];
const colorParts = particleInfo.color.split(',');
const color = new THREE.Color(
parseFloat(colorParts[0]),
parseFloat(colorParts[1]),
parseFloat(colorParts[2])
);
const particleMaterial = new THREE.MeshBasicMaterial({color});
const particleGeometry = new THREE.SphereGeometry(0.03, 16, 16);
const particleMesh = new THREE.Mesh(particleGeometry, particleMaterial);
particleMesh.position.set(particleInfo.x, particleInfo.y, particleInfo.z);
this.rendererService.scene.add(particleMesh);
this.particles.push(particleMesh);
this.animatePulse(particleMesh, 3, () => {
this.rendererService.scene.remove(particleMesh);
this.clearParticleVisuals();
this.renderFrameParticles(this.currentFrame);
});
}
private animatePulse(mesh: THREE.Mesh, cycles: number, onComplete: () => void): void {
const duration = 300;
const maxScale = 0.08 / 0.03;
const startTime = performance.now();
const animate = (time: number) => {
const elapsed = (time - startTime) % duration;
const t = elapsed / (duration / 2);
const scaleFactor = t <= 1 ? 1 + (maxScale - 1) * t : maxScale - (maxScale - 1) * (t - 1);
mesh.scale.setScalar(scaleFactor);
if (time - startTime >= duration * cycles) {
onComplete();
} else {
requestAnimationFrame(animate);
}
};
requestAnimationFrame(animate);
}
/** /**
* Sets the selected color for new particles * Sets the selected color for new particles
*/ */