diff --git a/frontend/src/app/particles/components/frames/frames.component.html b/frontend/src/app/particles/components/frames/frames.component.html index b988a6b..4feebde 100644 --- a/frontend/src/app/particles/components/frames/frames.component.html +++ b/frontend/src/app/particles/components/frames/frames.component.html @@ -11,11 +11,16 @@

Particles in {{ frameId }}

- Particle {{ i + 1 }}: ({{ particle.x.toFixed(2) }}, {{ particle.y.toFixed(2) }} - , {{ particle.z.toFixed(2) }}) - +
diff --git a/frontend/src/app/particles/components/frames/frames.component.scss b/frontend/src/app/particles/components/frames/frames.component.scss index 4e9c57b..0d9a8ae 100644 --- a/frontend/src/app/particles/components/frames/frames.component.scss +++ b/frontend/src/app/particles/components/frames/frames.component.scss @@ -17,10 +17,14 @@ .particle-item { display: flex; - justify-content: space-between; align-items: center; padding: 8px; border-bottom: 1px solid #eee; + gap: 10px; +} + +.particle-item-text { + flex-grow: 1; } .particle-item:last-child { diff --git a/frontend/src/app/particles/components/frames/frames.component.ts b/frontend/src/app/particles/components/frames/frames.component.ts index 484ede0..55ac39f 100644 --- a/frontend/src/app/particles/components/frames/frames.component.ts +++ b/frontend/src/app/particles/components/frames/frames.component.ts @@ -83,4 +83,7 @@ export class FramesComponent { } + public highlightParticle(frameId: string, i: number) { + this.particleManagerService.highlightParticle(frameId, i); + } } diff --git a/frontend/src/app/particles/services/particle-manager.service.ts b/frontend/src/app/particles/services/particle-manager.service.ts index 2afabb7..f14c5e8 100644 --- a/frontend/src/app/particles/services/particle-manager.service.ts +++ b/frontend/src/app/particles/services/particle-manager.service.ts @@ -1,7 +1,7 @@ -import { Injectable } from '@angular/core'; +import {Injectable} from '@angular/core'; import * as THREE from 'three'; -import { RendererService } from './renderer.service'; -import { ParticleData, ParticleInfo, ParticleType } from '../models/particle.model'; +import {RendererService} from './renderer.service'; +import {ParticleData, ParticleInfo, ParticleType} from '../models/particle.model'; /** * Service responsible for managing particles in the scene @@ -32,7 +32,8 @@ export class ParticleManagerService { private frames: string[] = ['frame1']; private selectedColor: string = '#ff0000'; - constructor(private rendererService: RendererService) {} + constructor(private rendererService: RendererService) { + } /** * 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 */