Animation canvas

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour, j'essaye de déplacer une image de façon animé, comme dans cette vidéo. Cependant, le code que j'ai écris me permet uniquement de "téléporter l'image" J'aimerais donc pouvoir la déplacer fluidement, mais je ne comprends pas les exemples trouvés sur le web. Le seul moyen trouvé est cette vidéo et l'auteur utilise Jquery, ce qui fais que je ne comprends rien. Si quelqu'un a une idée de comment je pourrais faire, ça me serait utile. Voici mon code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//infos de l'image à déplacer
var player = {
 positionx: 0,
 positiony: 0,
 newx: 0,
 newy: 0,
 userwidth: 100,
 userheigth: 80,
 vitesse: 30,
 moving: false
};
//infos du canvas
var canvasinfos = {
canvaswidth: canvas.width = window.innerWidth - 5,
canvasheigth: canvas.height = window.innerHeight - 5
}
// téléportation au click -- cherche en animation
document.addEventListener('click', function(e) {
    player.newx = e.clientX;
    player.newy = e.clientY;
    player.moving = true;
    if (player.moving == true) {
    player.positionx = player.newx;
    player.positiony = player.newy;
}
    }, false);
//refresh 60 fois par seconde
setInterval(animate, 1000/60);
function animate() {
    context.clearRect(0, 0, canvasinfos.canvaswidth, canvasinfos.canvasheigth);
    context.drawImage(video, player.positionx, player.positiony, player.userwidth, player.userheigth);
    context.shadowColor = '#999';
      context.shadowBlur = 15;
      context.shadowOffsetX = 10;
      context.shadowOffsetY = 10;
      context.fill();
}

Ce code est donc incomplet. J'attends votre aide avec impatience ! Merci d'avance :) !

Édité par anonyme

+0 -0

Cette réponse a aidé l'auteur du sujet

Il est préférable d'utiliser requestAnimationFrame lorsque tu veux faire une animation plutôt que setInterval. La différence est que requestAnimationFrame permet d'exécuter une action avant le prochain affichage. Cela permet à ton animation de suivre le même framerate que le navigateur, ce qui permet bien souvent d'avoir quelque chose de plus fluide et plus performant (aucun appel de fonction inutile et une mise à jour de l'image à chaque affichage).

L'idée, lorsque tu veux commencer ton animation est d'enregistrer les paramètres de l'animation (temps et données de début et fin) puis d'appeler requestAnimationFrame. Dans ta fonction, il faudra que tu calcules à quel point tu te situes par rapport à l'évolution de l'animation et que mette à jour ton image en conséquence.

Voici un exemple qui déplace x de 0 à 100 en 2 secondes :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var x = 0;
document.addEventListener('onclick', function() {
    // on replace x à sa position initiale
    x = 0;
    // on défini les paramètres de début et de fin
    var startX = 0;
    var endX = 100;
    var startAnimation = Date.now();
    var animationDuration = 2000;
    var endAnimation = startAnimation+animationDuration;
    // on lance l'animation
    requestAnimationFrame(function animate() {
        var now = Date.now();
        if(now < endAnimation) {
            // (now-startAnimation)/animationDuration représente l'avancement de l'animation (entre 0 et 1)
            x = startX + (endX-startX)*(now-startAnimation)/animationDuration;
            // il faut rappeler requestAnimationFrame tant que l'on veut continuer l'animation
            requestAnimationFrame(animate);
        } else {
            x = endX;
        }
    });
});

Je te laisse le soin de trouver un moyen pour gérer l'appel d'une animation lorsqu'il y en a déjà une en cours. ;)

+0 -0
Auteur du sujet

Re-Salut ! ton code, marche, j'ai même réussit à l'adapter, mais le problème est que je souhaite afficher dans mon canvas la webcam de l'utilisateur. J'affiche donc grâce au webrtc la webcam dans une balise vidéo, qui est convertie en image puis afficher dans le canvas. Donc maintenant, on ne voit pas la webcam de l'utilisateur mais un "screenshot" de sa webcam. Je peut uniquement voir les mouvement à la webcam quand l'animation est en marche. Comment faire pour que je puisse voir la webcam en permanence ? Voici mon code (pour la webcam):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var canvas = document.querySelector('canvas');
var whatdisplay = document.querySelector('video');
var context = canvas.getContext('2d');
 navigator.getMedia = ( navigator.getUserMedia || 
                         navigator.webkitGetUserMedia ||
                         navigator.mozGetUserMedia ||
                         navigator.msGetUserMedia);
navigator.getMedia(
    { 
      video: true, 
      audio: false 
    },
    function(stream) {
      if (navigator.mozGetUserMedia) { 
        whatdisplay.mozSrcObject = stream;
      } else {
        var vendorURL = window.URL || window.webkitURL;
        whatdisplay.src = vendorURL ? vendorURL.createObjectURL(stream) : stream;
      }
     whatdisplay.play();
    },
    function(err) {
      console.log("An error occured! " + err);
    }
  );

Et je l'affichait de cette façon :

1
2
// se répétait 60 fois par seconde
context.drawImage(whatdisplay, x, y, w, h);

Je précise que tout le bazar avec la webcam fonctionnait avant, ma question est donc lié au nouveau code

Comment reproduire cela à présent ? Merci d'avance pour vos réponses :)

Édité par anonyme

+0 -0

Est-ce que tu aurais, par hasard, oublié de rappeler requestAnimationFrame à la fin de la callback?

C'est la seule chose qui me semble coller avec le problème que tu as. Si ce n'est pas le cas, montre ton code en entier, parce que je ne pense pas que le problème vienne du code que tu as posté.

+0 -0
Auteur du sujet

Vu que l'animation que tu m'as donné marche, je pense que c'est bon. Voici le code complet: (j'ai ajouté un système de son 3d, n'y fait pas attention)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
//initialisation du canvas
var canvas = document.querySelector('canvas');
var whatdisplay = document.querySelector('video');
var context = canvas.getContext('2d');
//webrtc pour la webcam
 navigator.getMedia = ( navigator.getUserMedia || 
                         navigator.webkitGetUserMedia ||
                         navigator.mozGetUserMedia ||
                         navigator.msGetUserMedia);
navigator.getMedia(
    { 
      video: true, 
      audio: false 
    },
    function(stream) {
      if (navigator.mozGetUserMedia) { 
        whatdisplay.mozSrcObject = stream;
      } else {
        var vendorURL = window.URL || window.webkitURL;
        whatdisplay.src = vendorURL ? vendorURL.createObjectURL(stream) : stream;
      }
     whatdisplay.play();
    },
    function(err) {
      console.log("An error occured! " + err);
    }
  );
//infos du canvas
var canvasinfos = {
width: canvas.width = window.innerWidth - 5,
heigth: canvas.height = window.innerHeight - 5
};
//initialisation des apis sonore et récupération de l'audio
var AudioContext = window.AudioContext || window.webkitAudioContext;
var audioCtx = new AudioContext();
var panner = audioCtx.createPanner();
var listener = audioCtx.listener;
var source;
var soundboxX = 100;
var soundboxY = 100;
function positionPanner() {
panner.setPosition(soundboxX, soundboxY, 290);
}
function getData() {
source = audioCtx.createBufferSource();
var request = new XMLHttpRequest();
    request.open('GET', 'ziik.ogg', true);
    request.responseType = 'arraybuffer';
    request.onload = function() {
        var audioData = request.response;
audioCtx.decodeAudioData(audioData, function(buffer) {
var myBuffer = buffer;
    source.buffer = myBuffer;
    source.connect(panner);
        panner.connect(audioCtx.destination);
        positionPanner();
},
  function(e){"Error with decoding audio data" + e.err});                       
  }
    request.send();
}
//info du player
var player = {
 x: 0,
 y: 0,
 width: 100,
 heigth: 80
};
//animation au click
document.addEventListener('click', function(e) {
    var newx = e.clientX - player.width / 2;
    var newy = e.clientY - player.heigth / 2;
   var animation = {
       startx: player.x,
       endx: newx,
       starty: player.y,
       endy: newy,
       start: Date.now(),
       duration: 1000
   }
    console.log(parseFloat(newx) + "-" + parseFloat(newy));
   var end = animation.start + animation.duration;
requestAnimationFrame(function animate() {
    var now = Date.now();
    if (now < end) {
        context.clearRect(0, 0, canvasinfos.width, canvasinfos.heigth);
        player.x = animation.startx + (animation.endx - animation.startx) * (now - animation.start) / animation.duration;
        player.y = animation.starty + (animation.endy - animation.starty) * (now - animation.start) / animation.duration;
        requestAnimationFrame(animate);
    } else {
        x = animation.endx;
        y = animation.endy;
    }
    context.drawImage(whatdisplay, player.x, player.y, player.width, player.heigth);
    listener.setPosition(player.x, player.y, 300);
    //dessin d'un écouteur sur le speaker 3d
         var speaker = new Image();
speaker.src= "speaker.png";
    context.drawImage(speaker, soundboxX, soundboxY, 60, 60)
});
}, false);
// appel du système audio
getData();
source.loop = true;
source.start(0);
// Voilà.. la webcam est seulement visible quand je fais l'animation. Sinon c'est une image fixe.

Je m'excuse le code est un peu immonde, j'espère tout de même que tu t'en sortira :) ! Merci d'avance !

+0 -0

Cette réponse a aidé l'auteur du sujet

Ah, après relecture de ton post précédent, je me suis rendu compte que j'avais mal compris la question.

En fait, ce qu'il se passe, c'est qu'il faut que mette à jour ton canvas tout le temps, qu'il y ai une animation ou non.

Il faut donc que l'appel se fasse directement sans attendre le click de l'utilisateur et que chaque appel à requestAnimationFrame lance le suivant (qu'il y ai une animation où non).

Il faut ensuite que tu mette l'objet animation au même niveau que la fonction animate (donc hors du click aussi) et que tu y mette la date de fin. Il te suffit ensuite de mettre à jour cet objet à chaque click et que tu utilises ces données dans la fonction animate de la même manière que ce que tu fais maintenant.

Voici le squelette :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
var animation = {
    startX : 0,
    endX : 0,
    start : Date.now(),
    end : Date.now()
};
document.addEventListener('click', function(){
    animation = {
        // nouvelles données
    };
});
requestAnimationFrame(function animate() {
    var now = Date.now();
    if(animation.end < now) {
        // maj tes données
    } else {
        // données de fin
    }
    // draw
    requestAnimationFrame(animate);
});
+0 -0

Pour le coup, il y a des chances pour que ce soit tout simplement dû à la manipulation de flux vidéo en temps réel dans un langage pas forcément prévu pour. D'autant plus que tu utilises des technologies (très) récentes et qui ne sont probablement pas encore bien implémentés/optimisés par les navigateurs.

+0 -0
Auteur du sujet

finalement, j'avais appelé deux fois requestAnimationFrame, ce qui était à l'origine des mauvaises perfs. Sa tourne très bien sous firefox, mais sous chrome, ça marche pas. Je vais m'y pencher ....

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte