Une des grandes nouveautés du HTML5 est l'apparition des
éléments<audio>
et<video>
,
qui permettent de jouer des sons et d'exécuter des vidéos, le tout nativement, c'est-à-dire sans plugins tels que
Flash, QuickTime ou même Windows Media Player. Nous allons donc voir ici comment interagir, via le JavaScript, avec
ces deux éléments !
Les
éléments<audio>
et<video>
se
ressemblent fortement. D'ailleurs, ils sont représentés par le même objet, à
savoirHTMLMediaElement
. Comme ils dérivent du même objet, ils en
possèdent les propriétés et méthodes.
L'insertion d'un élément<audio>
est
très simple.
id="audioPlayer" src="hype_home.mp3"
Ce bout de code suffit à insérer un
lecteur audio qui lira le sonhype_home.mp3
. Mais, nous, nous n'allons pas
utiliser l'attributsrc
, mais plutôt deux
éléments<source>
, comme ceci :
id="audioPlayer"
src="hype_home.ogg"
src="hype_home.mp3"
De cette manière, si le navigateur est capable de lire le format .ogg, il le fera. Sans quoi, il lira le format .mp3. Ça permet une plus grande interopérabilité (compatibilité entre les navigateurs et les plates-formes).
Pour afficher un contrôleur de lecteur, il faut utiliser l'attribut
booléencontrols
, comme ceci :<audio
controls="controls"></audio>
. Mais ici, c'est un cours de JavaScript, donc nous allons créer
notre propre contrôleur de lecture !
Voyons pour commencer comment recréer les boutons « Play », « Pause » et « Stop ». On commence par accéder à l'élément :
var player = document.querySelector('#audioPlayer');
Si on veut lancer la lecture, on
utilise la méthodeplay()
:
player.play();
Si on veut faire une pause, c'est la
méthodepause()
:
player.pause();
Par contre, il n'y a pas de
méthodestop()
. Si on appuie sur un bouton « Stop », la lecture s'arrête et
se remet au début. Pour ce faire, il suffit de faire « Pause » et d'indiquer que la lecture doit se remettre au
début, avec la propriétécurrentTime
, exprimée en secondes :
player.pause();
player.currentTime = 0;
On va créer un petit lecteur, dont voici le code HTML de base :
id="audioPlayer"
src="hype_home.ogg"
src="hype_home.mp3"
class="control" onclick="play('audioPlayer', this)"Play
class="control" onclick="resume('audioPlayer')"Stop
Deux boutons ont été placés : le
premier est un bouton « Play » et « Pause » en même temps (comme sur la plupart des lecteurs modernes), et le second
permet de stopper et de rembobiner la lecture. Voici les
fonctionsplay
etresume
:
function play(idPlayer, control) {
var player = document.querySelector('#' + idPlayer);
if (player.paused) {
player.play();
control.textContent = 'Pause';
} else {
player.pause();
control.textContent = 'Play';
}
}
function resume(idPlayer) {
var player = document.querySelector('#' + idPlayer);
player.currentTime = 0;
player.pause();
}
Le fonctionnement du bouton « Play »
est simple : avec la méthodepaused
, on vérifie si la lecture est en
pause. En fonction de ça, on
faitplay()
oupause()
,
et on change le libellé du bouton.
L'intensité sonore se règle avec la
propriétévolume
sur une échelle allant de 0 à 1. Si le volume est à 0,
il est muet, et s'il est à 1, il est à fond. Pour le diminuer de moitié, on mettra 0,5. On va faire un système très
simple : cinq barres verticales cliquables qui permettent de choisir un niveau sonore prédéfini :
class="volume"
class="stick1" onclick="volume('audioPlayer', 0)"
class="stick2" onclick="volume('audioPlayer', 0.3)"
class="stick3" onclick="volume('audioPlayer', 0.5)"
class="stick4" onclick="volume('audioPlayer', 0.7)"
class="stick5" onclick="volume('audioPlayer', 1)"
Et la fonction associée :
function volume(idPlayer, vol) {
var player = document.querySelector('#' + idPlayer);
player.volume = vol;
}
Un lecteur sans une barre de progression n'est pas un lecteur ! Le
HTML5 introduit un nouvel élément destiné à afficher une progression : l'élément<progress>
.
Il n'est toutefois utilisable qu'avec Firefox et Chrome. Mais nous n'allons pas l'utiliser ici, car cet élément
n'est pas facilement personnalisable avec du CSS. On l'utilisera plus tard dans le chapitre sur l'API File.
Nous allons donc créer une barre de progression « à la main », avec
des<div>
et quelques calculs de pourcentages !
Ajoutons ce code HTML après
l'élément<audio>
:
id="progressBarControl"
id="progressBar"Pas de lecture
Un
élémentHTMLMediaElement
possède toute une série d'événements pour
analyser et agir sur le lecteur. L'événementontimeupdate
va nous être
utile pour détecter quand le média est en train d'être joué par le lecteur. Cet événement est déclenché
continuellement pendant la lecture.
Ajoutons donc cet
événement sur notre élément<audio>
:
id="audioPlayer" ontimeupdate="update(this)"
Et commençons à coder la
fonctionupdate()
:
function update(player) {
var duration = player.duration; // Durée totale
var time = player.currentTime; // Temps écoulé
var fraction = time / duration;
var percent = Math.ceil(fraction * 100);
var progress = document.querySelector('#progressBar');
progress.style.width = percent + '%';
progress.textContent = percent + '%';
}
L'idée est de récupérer le temps écoulé et de calculer un pourcentage de manière à afficher la barre de progression (qui fait 100 % de large). Donc, si la chanson dure dix minutes et qu'on en est à une minute de lecture, on a lu 10 %.
La propriétéduration
sert
à récupérer la durée totale du média. Le calcul est simple : on divise le temps écoulé par la durée totale et on
multiplie par 100. Comme ça ne tombera certainement pas juste, on arrondit
avecMath.ceil()
. Une fois le pourcentage récupéré, on définit la
largeur de la barre de progression, et on affiche le pourcentage à l'intérieur.
Le petit lecteur est désormais terminé !
L'interface réalisée précédemment est fonctionnelle, mais rudimentaire. Deux améliorations principales sont possibles :
Afficher le temps écoulé ;
Rendre la barre de progression cliquable.
Afficher le temps écoulé ? Ce n'est pas compliqué, il suffit
d'utiliser la propriétécurrentTime
. Le souci est
quecurrentTime
retourne le temps écoulé en secondes avec ses
décimales. Il est donc possible de voir s'afficher un temps de lecture de 4,133968 secondes. Il convient donc de
faire quelques opérations pour rendre ce nombre compréhensible. Voici la
fonctionformatTime()
:
function formatTime(time) {
var hours = Math.floor(time / 3600);
var mins = Math.floor((time % 3600) / 60);
var secs = Math.floor(time % 60);
if (secs < 10) {
secs = "0" + secs;
}
if (hours) {
if (mins < 10) {
mins = "0" + mins;
}
return hours + ":" + mins + ":" + secs; // hh:mm:ss
} else {
return mins + ":" + secs; // mm:ss
}
}
On opère quelques divisions et
arrondissements afin d'extraire le nombre d'heures, de minutes et de secondes. Puis on complète avec des 0 pour un
affichage plus joli.
On peut donc ajouter ceci à notre fonctionupdate()
:
document.querySelector('#progressTime').textContent = formatTime(time);
Et modifier la barre de progression
pour y ajouter un<span>
dans lequel s'affichera le temps écoulé :
id="progressBarControl"
id="progressBar"Pas de lecture
id="progressTime"00:00
Ici, ça se corse un peu. Si on clique sur la barre de progression, le
comportement attendu est la lecture du fichier audio à partir de cet endroit. Il va donc falloir calculer l'endroit
où on a cliqué et positionner la lecture en conséquence, avec la propriétécurrentTime
.
Pour savoir où l'on a cliqué au sein d'un élément, il faut connaître deux choses : les coordonnées de la souris et les coordonnées de l'élément. Ces coordonnées sont calculées à partir du coin supérieur gauche de la page. Voici une explication plus imagée :
Pour connaître la distance représentée par la flèche turquoise, il suffit de soustraire la distance représentée par la flèche rouge (la position de la barre sur l'axe des X) à la distance représentée par la flèche bleue (la position X du curseur de la souris). C'est tout simple, mais la récupération des coordonnées n'est pas évidente.
Nous allons créer la fonctiongetMousePosition()
qui
recevra comme paramètre un événement et qui retournera les positions X et Y du curseur :
function getMousePosition(event) {
return {
x: event.pageX,
y: event.pageY
};
}
Les
propriétéspageX
etpageY
de
l'objetevent
permettent respectivement de récupérer les positions sur
l'axe des X et sur l'axe des Y.
Comme l'élément n'est pas positionné de façon absolue, il n'est pas
possible de connaître les coordonnées de son coin supérieur gauche via le CSS. Il va donc falloir calculer le
décalage entre lui et son élément parent, puis le décalage entre cet élément parent et son parent… et ainsi de
suite, jusqu'à arriver à l'élément racine, c'est-à-dire<html>
:
function getPosition(element){
var top = 0, left = 0;
do {
top += element.offsetTop;
left += element.offsetLeft;
} while (element = element.offsetParent);
return { x: left, y: top };
}
Si vous ne connaissez plus le rôle des
propriétés offsetLeft
,offsetTop
etoffsetParent
,
nous vous conseillez
de revenir sur la partie qui aborde le sujet
dans le chapitre sur la manipulation du CSS.
Maintenant que nous avons nos deux
fonctionsgetMousePosition()
etgetPosition()
,
nous pouvons écrire la fonctionclickProgress()
, qui sera exécutée dès
que l'internaute cliquera sur la barre de progression :
function clickProgress(idPlayer, control, event) {
var parent = getPosition(control); // La position absolue de la progressBar
var target = getMousePosition(event); // L'endroit de la progressBar où on a cliqué
var player = document.querySelector('#' + idPlayer);
var x = target.x - parent.x;
var wrapperWidth = document.querySelector('#progressBarControl').offsetWidth;
var percent = Math.ceil((x / wrapperWidth) * 100);
var duration = player.duration;
player.currentTime = (duration * percent) / 100;
}
On récupère la
distancex
, qui est la distance entre le bord gauche de la barre et
l'endroit où on a cliqué. On divisex
par la largeur totale du
conteneur de la barre de progression (avecoffsetWidth
) et on
multiplie par 100 pour obtenir un pourcentage. Ensuite, on calcule lecurrentTime
en
multipliant le temps total de la chanson par le pourcentage, le tout divisé par 100.
Et n'oublions pas de modifier le code HTML en conséquence :
id="progressBar" onclick="clickProgress('audioPlayer', this, event)"Pas de lecture
Et ça marche !
Il
n'y a pas grand-chose à ajouter en ce qui concerne les vidéos. Le principe de fonctionnement est exactement le même
que pour les lectures audio. L'élément<video>
possède toutefois
quelques propriétés en plus :
Propriété |
Description |
---|---|
|
Hauteur de la zone de lecture |
|
Largeur de la zone de lecture |
|
Récupère l'attribut |
|
La hauteur de la vidéo |
|
La largeur de la vidéo |
En dehors de ça, la création et la personnalisation de la lecture d'une vidéo est rigoureusement identique à celle d'une piste audio.
Il peut être utile d'utiliser un framework JavaScript destiné à la
lecture d'éléments<audio>
et<video>
afin
se faciliter la vie. De plus, ce genre de framework propose généralement une solution en Flash si le navigateur
n'est pas à la hauteur du HTML5.
Voici quelques frameworks qu'il peut être intéressant de considérer :
Les
éléments<audio>
et<video>
possèdent
tous les deux de nombreux attributs et méthodes afin que chacun puisse créer un lecteur entièrement
personnalisé.
La différence
entre les deux éléments est minime. Ils sont tous les deux basés sur le même objet,
l'élément<video>
n'apporte que quelques attributs supplémentaires
permettant de gérer l'affichage.
Contrairement au Flash, la protection du contenu n'existe pas (encore) avec ces deux éléments. Réfléchissez donc bien avant d'écarter définitivement toute solution avec Flash !