Add an option to highlight particles
This commit is contained in:
parent
fdb57289f8
commit
c3a7be82e9
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -83,4 +83,7 @@ export class FramesComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public highlightParticle(frameId: string, i: number) {
|
||||||
|
this.particleManagerService.highlightParticle(frameId, i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user