diff --git a/src/app/football-field/football-field.component.css b/src/app/football-field/football-field.component.css index 3ae33b6..7e74b69 100644 --- a/src/app/football-field/football-field.component.css +++ b/src/app/football-field/football-field.component.css @@ -100,3 +100,12 @@ canvas { font-size: 12px; text-align: center; } + +.time-indicator { + position: absolute; + top: 0; + width: 3px; /* Epaisseur du trait */ + height: 100%; /* La hauteur couvre toute la timeline */ + background-color: red; /* Couleur du trait de temps */ + left: 0; /* Point de départ du trait */ +} \ No newline at end of file diff --git a/src/app/football-field/football-field.component.html b/src/app/football-field/football-field.component.html index 8376d7a..811965a 100644 --- a/src/app/football-field/football-field.component.html +++ b/src/app/football-field/football-field.component.html @@ -39,9 +39,11 @@ --> - - - + + + + + diff --git a/src/app/football-field/football-field.component.ts b/src/app/football-field/football-field.component.ts index f10e0bb..c4d52fe 100644 --- a/src/app/football-field/football-field.component.ts +++ b/src/app/football-field/football-field.component.ts @@ -1,6 +1,7 @@ import { Component, ViewChild, ElementRef, HostListener } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; +import { C } from '@angular/cdk/keycodes'; interface TimelineStep { startTime: number; // Le temps de début en millisecondes @@ -226,10 +227,6 @@ export class FootballFieldComponent { } private animate() { - //this.updatePositions(); - //if (this.isAnimating && this.selectedPlayer) { - // this.updatePlayerPosition(this.selectedPlayer); - //} // Effacer le canvas pour redessiner this.ctx.clearRect(0, 0, this.canvas.nativeElement.width, this.canvas.nativeElement.height); @@ -251,11 +248,17 @@ export class FootballFieldComponent { hasAnimation = true; // Indiquer qu'il y a encore de l'animation } }); + // Mettre à jour la position du trait de visualisation du temps + this.updateTimeIndicator(currentTime); } }); this.drawField(); requestAnimationFrame(() => this.animate()); + + if (this.isPlaying === false) { + this.stopTimeline(); + } // Continuer l'animation seulement si au moins un joueur est encore en mouvement //if ((this.isAnimating) || (hasAnimation && this.isPlaying)) { // requestAnimationFrame(() => this.animate()); @@ -269,6 +272,30 @@ export class FootballFieldComponent { this.isPlaying = false; } + // Mise à jour de la position du trait de temps sur la timeline + updateTimeIndicator(currentTime: number) { + //const timeIndicator = document.getElementById('time-indicator'); + const elmnts = document.querySelectorAll('[id=time-indicator]'); + if (elmnts) { + const timeline = document.querySelector('.timeline') as HTMLElement; + const timelineWidth = timeline.offsetWidth; // Largeur totale de la timeline + // Calcul de la position du trait en pixels + let timePosition = (currentTime / this.getTotalTimelineDuration()) * timelineWidth; + // Si l'indicateur est à la fin de la timeline, on arrete l'animation + if(timePosition >= timelineWidth) { + timePosition = timelineWidth; + this.isPlaying = false; + } + // Mettre à jour la position du trait + //timeIndicator.style.left = `${timePosition}px`; + + // Mettre à jour la position du trait + elmnts.forEach(element => + (element as HTMLElement).style.left = `${timePosition}px` + ); + } + } + private updatePlayerPosition(player: Circle) { if (player.timeline.length === 0 || player.currentStepIndex >= player.timeline.length) { return; // Pas d'animation si la timeline est vide @@ -544,12 +571,12 @@ export class FootballFieldComponent { this.selectedPlayer.timeline.push({ startTime: prevStartTime, - endTime: prevStartTime + 200, + endTime: prevStartTime + 1000, startX: this.startX, startY: this.startY, endX: this.endX, endY: this.endY, - duration: 200 // Durée d'animation arbitraire, peut être ajustée + duration: 1000 // Durée d'animation arbitraire, peut être ajustée }); console.log("timeline:", this.selectedPlayer.timeline); this.selectedPlayer.currentStepIndex = 0; // Réinitialiser au début de la timeline @@ -944,6 +971,18 @@ export class FootballFieldComponent { this.isAnimating = true; // Redémarrer l'animation } + reinitPlayers() { + // Réinitialiser la progression et l'étape actuelle + this.players.forEach(player => { + player.progress = 0; + player.currentStepIndex = 0; + this.updatePlayerPosition(player); + }); + + const currentTime = performance.now(); + this.updateTimeIndicator(currentTime); + } + /* GESTION DE LA TIMELINE */ getMousePosOnTimeline(event: MouseEvent): { x: number } { @@ -965,7 +1004,9 @@ export class FootballFieldComponent { // La durée totale de la timeline const totalDuration = this.getTotalTimelineDuration(); // La longueur de la timeline en pixels (par exemple, 1000px) - const timelineWidth = this.timelineWidth; + const timeline = document.querySelector('.timeline') as HTMLElement; + const timelineWidth = timeline.offsetWidth; // Largeur totale de la timeline + //const timelineWidth = this.timelineWidth; // La durée totale de l'animation en millisecondes return (time / totalDuration) * timelineWidth; } @@ -1011,30 +1052,60 @@ export class FootballFieldComponent { onTimelineMouseMove(event: MouseEvent) { if (this.isTimelineDragging && this.draggedTimelinePlayer) { - //const { x } = this.getMousePos(event); const { x } = this.getMousePosOnTimeline(event); // Calculer la nouvelle position du bloc const newStartX = x - this.dragOffsetX; const totalDuration = this.getTotalTimelineDuration(); - //const newStartTime = Math.floor((newStartX / this.canvas.nativeElement.width) * totalDuration); const newStartTime = Math.floor((newStartX / this.timelineWidth) * totalDuration); console.log("[onTimelineMouseMove] - x:",x, + " - dragOffsetX:", this.dragOffsetX, " - newStartX:", newStartX, - " - newStartTime:", newStartTime); + " - newStartTime:", newStartTime, + " - dragged Index:", this.draggedTimelineIndex, + " - timeline len:", this.draggedTimelinePlayer.timeline.length, + ); // Mettre à jour l'étape avec la nouvelle position const step = this.draggedTimelinePlayer.timeline[this.draggedTimelineIndex]; - if (step.endTime < this.getTotalTimelineDuration()) { - step.startTime = Math.max(0, newStartTime); // Ne pas permettre les valeurs négatives + let prevStep:TimelineStep = null; + // Le bloc N ne peut pas dépasser le bloc N+1 si celui-ci existe + // De même, le bloc N ne peut pas dépasser le bloc N-1 si celui-ci existe + if ((this.draggedTimelineIndex + 1) < this.draggedTimelinePlayer.timeline.length) { + const nextStep = this.draggedTimelinePlayer.timeline[this.draggedTimelineIndex + 1]; + if ((this.draggedTimelineIndex - 1) >= 0) { + prevStep = this.draggedTimelinePlayer.timeline[this.draggedTimelineIndex - 1]; + } + if ((((newStartTime + step.duration) < nextStep.startTime) && + prevStep === null) || + (prevStep != null && + ((prevStep.endTime <= newStartTime) && ((newStartTime + step.duration) < nextStep.startTime)))) { + //console.log("PLOP0.1: (",newStartTime + step.duration, "/", nextStep.startTime,")"); + step.startTime = Math.max(0, newStartTime); // Ne pas permettre les valeurs négatives + step.endTime = Math.max(0, step.startTime + step.duration); // Ne pas permettre les valeurs négatives + } + } else if (((this.draggedTimelineIndex - 1) >= 0) && + (this.draggedTimelinePlayer.timeline[this.draggedTimelineIndex - 1])) { + const prevStep = this.draggedTimelinePlayer.timeline[this.draggedTimelineIndex - 1]; + if ((prevStep.endTime <= newStartTime) && + ((newStartTime + step.duration) <= (this.getTotalTimelineDuration()))) { + //console.log("PLOP1.1: (",prevStep.endTime, "/", newStartTime,"),(",newStartTime + step.duration,"/",this.getTotalTimelineDuration(),")"); + step.startTime = Math.max(0, newStartTime); // Ne pas permettre les valeurs négatives + step.endTime = Math.max(0, step.startTime + step.duration); // Ne pas permettre les valeurs négatives + } + + } else { + if (step.endTime < this.getTotalTimelineDuration()) { + step.startTime = Math.max(0, newStartTime); // Ne pas permettre les valeurs négatives + } + step.endTime = Math.max(0, step.startTime + step.duration); // Ne pas permettre les valeurs négatives } - step.endTime = Math.max(0, newStartTime + step.duration); // 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; - } + console.log("PLOP2"); + if (step.endTime < this.getTotalTimelineDuration()) { + step.startTime = Math.max(0, newStartTime); // Ne pas permettre les valeurs négatives + } + step.endTime = Math.max(0, step.startTime + step.duration); // Ne pas permettre les valeurs négatives */ } } @@ -1042,6 +1113,7 @@ export class FootballFieldComponent { onTimelineMouseUp() { console.log("onMouseUp"); if (this.isTimelineDragging) { + console.log("timeline:", this.draggedTimelinePlayer.timeline); this.isTimelineDragging = false; this.draggedTimelinePlayer = null; this.draggedTimelineIndex = -1; @@ -1075,7 +1147,9 @@ export class FootballFieldComponent { } playTimeline() { - if (this.isPlaying) return; // Ne pas relancer si déjà en cours + if (this.isPlaying) { + return; // Ne pas relancer si déjà en cours + } this.isPlaying = true; this.animationStartTime = performance.now(); // Obtenir le timestamp de départ