debut d'une timeline

This commit is contained in:
2024-10-09 12:04:54 +02:00
parent 6292b640bd
commit 143bc9c796
3 changed files with 174 additions and 16 deletions

View File

@@ -61,3 +61,32 @@ canvas {
.clear-button:hover {
background-color: #ff1a1a; /* couleur plus foncée au survol */
}
.timeline-container {
width: 100%;
margin-top: 20px;
}
.player-timeline {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.timeline {
position: relative;
width: 100%;
height: 40px;
background-color: #f0f0f0;
border: 1px solid #ccc;
display: flex;
align-items: center;
}
.timeline-block {
position: absolute;
height: 30px;
background-color: blue;
border: 1px solid black;
cursor: move;
}

View File

@@ -55,11 +55,27 @@
(mouseup)="stopDragging()">
Votre navigateur ne supporte pas l'élément canvas.
</canvas> -->
<canvas #canvas width="800" height="600"
(mousedown)="onCanvasMouseDown($event)"
(mousemove)="onCanvasMouseMove($event)"
(mouseup)="onCanvasMouseUp($event)">
</canvas>
<div class="canvas-and-timeline-container">
<canvas #canvas width="800" height="600"
(mousedown)="onCanvasMouseDown($event)"
(mousemove)="onCanvasMouseMove($event)"
(mouseup)="onCanvasMouseUp($event)">
</canvas>
<div class="timeline-container">
<div *ngFor="let player of players" class="player-timeline">
<span>{{ player.id }}</span>
<div class="timeline" (mousedown)="onTimelineMouseDown($event, player)">
<div *ngFor="let step of player.timeline; let i = index"
class="timeline-block"
[style.left]="calculateLeftPosition(step)"
[style.width]="calculateBlockWidth(step)"
(mousedown)="onTimelineBlockMouseDown($event, player, i)">
</div>
</div>
</div>
</div>
</div>
<div class="timeline">
<h3>Timeline du joueur sélectionné</h3>
<div *ngIf="selectedPlayer">

View File

@@ -3,18 +3,21 @@ import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
interface TimelineStep {
startX: number;
startY: number;
endX: number;
endY: number;
startTime: number; // Le temps de début en millisecondes
endTime: number; // Le temps de fin en millisecondes
startX: number; // Position de départ de l'élément sur l'axe X
startY: number; // Position de départ de l'élément sur l'axe Y
endX: number; // Position de fin de l'élément sur l'axe X
endY: number; // Position de fin de l'élément sur l'axe Y
duration: number; // Temps d'animation (en secondes ou ticks)
}
interface Circle {
x: number;
y: number;
id: number; // Identifiant unique de l'élément
x: number; // Position X du centre du cercle de l'élément
y: number; // Position Y du centre du cercle de l'élément
number: number;
radius: number;
radius: number; // Rayon du cercle de l'élément
isDragging: boolean;
vx: number; // vitesse en X
vy: number; // vitesse en Y
@@ -26,7 +29,7 @@ interface Circle {
progress: number; // Paramètre de progression sur la courbe
startX: number;
startY: number;
timeline: TimelineStep[]; // Nouvelle propriété pour stocker les étapes d'aniion
timeline: TimelineStep[]; // Stockage des étapes d'animation
currentStepIndex: number; // Suivre l'étape actuelle dans la timeline
}
@@ -90,7 +93,8 @@ export class FootballFieldComponent {
public players: Circle[] = [];
public plots: Circle[] = [];
public piquets: Rectangle[] = [];
public ball: Circle = { x:400,
public ball: Circle = { id: 0,
x:400,
y:300,
number:1,
radius:10,
@@ -112,6 +116,17 @@ export class FootballFieldComponent {
public vectorType: 'linear' | 'curved' = 'linear'; // Type de vecteur sélectionné
public interactionMode: 'move' | 'animate' = 'move'; // Mode d'interaction sélectionné
public isTimelineDragging: boolean = false;
public draggedTimelinePlayer: Circle | null = null;
public draggedTimelineIndex: number = -1;
// La largeur totale de la timeline en pixels.
// Cela représente la taille visuelle de la timeline dans laquelle
// les différents étapes de mouvement d'un élément sont affichés.
public timelineWidth: number = 800;
// Décalage horizontal en pixels utilisé lorsque vous commencez à déplacer
// un bloc sur la timeline.
public dragOffsetX: number = 0;
ngOnInit() {
this.ctx = this.canvas.nativeElement.getContext('2d')!;
this.drawField();
@@ -233,6 +248,8 @@ export class FootballFieldComponent {
const step = player.timeline[player.currentStepIndex];
// Avancer le joueur sur la ligne avec un LERP (Linear Interpolation)
player.progress += this.animationSpeed;
// Temps actuel
const currentTime = performance.now();
if (player.progress >= 1) {
player.progress = 0; // Réinitialiser la progression
@@ -270,7 +287,8 @@ export class FootballFieldComponent {
for (let i = 0; i < this.playerCount; i++) {
const x = i * (2 * radius) + radius;
const y = radius;
this.players.push({ x,
this.players.push({ id: i + 1,
x,
y,
number: i + 1,
radius,
@@ -295,7 +313,8 @@ export class FootballFieldComponent {
for (let i = 0; i < this.plotCount; i++) {
const x = (this.canvas.nativeElement.width - radius) - (i) * (2 * radius);
const y = radius;
this.plots.push({ x,
this.plots.push({ id: i + 1,
x,
y,
number: i + 1,
radius,
@@ -476,6 +495,8 @@ export class FootballFieldComponent {
// Ajouter l'étape dans la timeline du joueur
console.log("timeline:", this.selectedPlayer.timeline);
this.selectedPlayer.timeline.push({
startTime: 0,
endTime: 1000,
startX: this.startX,
startY: this.startY,
endX: this.endX,
@@ -873,4 +894,96 @@ export class FootballFieldComponent {
});
this.isAnimating = true; // Redémarrer l'animation
}
/* GESTION DE LA TIMELINE */
getMousePosOnTimeline(event: MouseEvent): { x: number } {
const timelineRect = (event.target as HTMLElement).getBoundingClientRect();
return {
x: event.clientX - timelineRect.left // Position X par rapport à la timeline
};
}
calculateBlockPixelPosition(time: number): number {
// La durée totale de la timeline
const totalDuration = this.getTotalTimelineDuration();
// La largeur de la timeline en pixels (par exemple, 1000px)
const timelineWidth = this.timelineWidth;
// La durée totale de l'animation en millisecondes
return (time / totalDuration) * timelineWidth;
}
onTimelineMouseDown(event: MouseEvent, player: Circle) {
// Récupérer la position de la souris lors du clic
const { x } = this.getMousePosOnTimeline(event);
// Chercher si un bloc (une étape du joueur) a été cliqué
for (let i = 0; i < player.timeline.length; i++) {
const step = player.timeline[i];
// Calculer la position du bloc en pixels sur la timeline
const blockStartX = this.calculateBlockPixelPosition(step.startTime);
const blockEndX = this.calculateBlockPixelPosition(step.endTime);
// Si la souris clique dans un bloc
if (x >= blockStartX && x <= blockEndX) {
// Début du déplacement du bloc
this.isTimelineDragging = true;
this.draggedTimelinePlayer = player;
this.draggedTimelineIndex = i;
// Garder une référence pour un déplacement fluide
this.dragOffsetX = x - blockStartX;
break;
}
}
}
onTimelineBlockMouseDown(event: MouseEvent, player: Circle, index: number) {
this.isTimelineDragging = true;
this.draggedTimelinePlayer = player;
this.draggedTimelineIndex = index;
}
onMouseMove(event: MouseEvent) {
if (this.isTimelineDragging && this.draggedTimelinePlayer) {
const { x } = this.getMousePos(event);
const totalDuration = this.getTotalTimelineDuration();
const newStartTime = (x / this.canvas.nativeElement.width) * totalDuration;
// Mettre à jour l'étape avec la nouvelle position
const step = this.draggedTimelinePlayer.timeline[this.draggedTimelineIndex];
step.startTime = Math.max(0, newStartTime); // Ne pas permettre les valeurs négatives
// Ajuster la position de fin si nécessaire
if (this.draggedTimelineIndex > 0) {
const previousStep = this.draggedTimelinePlayer.timeline[this.draggedTimelineIndex - 1];
previousStep.endTime = step.startTime;
}
}
}
onMouseUp() {
if (this.isTimelineDragging) {
this.isTimelineDragging = false;
this.draggedTimelinePlayer = null;
this.draggedTimelineIndex = -1;
}
}
calculateLeftPosition(step: TimelineStep): string {
const totalDuration = this.getTotalTimelineDuration();
const left = (step.startTime / totalDuration) * 100;
return `${left}%`;
}
calculateBlockWidth(step: TimelineStep): string {
const totalDuration = this.getTotalTimelineDuration();
const width = ((step.endTime - step.startTime) / totalDuration) * 100;
return `${width}%`;
}
getTotalTimelineDuration(): number {
// Calculer la durée totale de la timeline, par exemple basée sur la durée totale de l'animation
return 10000; // Par exemple, 10 000 ms pour une timeline de 10 secondes
}
}