Dzisiaj kontynuować będziemy temat kontrolek multimedialnych w HTML5. Tym razem przedstawię sterowanie odtwarzaniem obiektów multimedialnych i dźwiękowych. które pojawiają się w przeglądarce gdy osadzimy plik audio lub wideo w dokumencie HTML. Dodamy przycisk ‘Play/Pause’, obsłużymy sterowanie dźwiękiem i paskiem postępu. Ponadto zajmiemy się możliwością tworzenia list odtwarzania.

Na początek przykład osadzenia filmu w dokumencie HTML, na którym będziemy pracować (dla skrócenia posta, skupię się tylko na znaczniku <video> ale dla plików audio, programowanie odtwarzacza odbywa się w sposób analogiczny):

<video id="video" width="320" height="240" controls="controls">
  <source src="filmik.mp4" type="video/mp4" />
  <source src="filmik.webm" type="video/webm" />
  <object id="video"
          width="320"
          height="240"
          classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
          codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0">
    <param name="src" value="http://burczuwordpress.dev/wp-includes/js/tinymce/plugins/media/moxieplayer.swf" />
    <param name="flashvars" value="url=/wp-admin/filmik.mp4&poster=/wp-admin/" />
    <param name="allowfullscreen" value="true" />
    <param name="allowscriptaccess" value="true" />
    <embed id="video"
           width="320"
           height="240"
           type="application/x-shockwave-flash"
           src="http://burczuwordpress.dev/wp-includes/js/tinymce/plugins/media/moxieplayer.swf"
           flashvars="url=/wp-admin/filmik.mp4&poster=/wp-admin/" a
           llowfullscreen="true"
           allowscriptaccess="true" />
  </object>
</video>

Na początek prosta sprawa - wyłączymy wyświetlanie standardowych kontrolek do obsługi pliku wideo (przyciski ‘play’, ‘pause’ itp.):

var video = document.getElementById("video");
video.controls = false;

Myślę, że powyższego kodu JavaScript nie trzeba za bardzo wyjaśniać ;)

Sterowanie odtwarzaniem multimediów

Przejdźmy od razu dalej. Kolejna rzeczą będzie dodanie własnego przycisku play / pause (w zależności czy film jest aktualnie wyświetlany, dostępna będzie tylko jedna z opcji). Poniżej kod HTML:

<div id="buttons">
  <button id="playandpause" title="play" onclick="playOrPause()">Play</button>
</div>

Powyższa definicja przycisku, posiada przypisanie obsługi zdarzenia kliknięcia do funkcji ‘playOrPause()’. Poniżej jej implementacja:

function playOrPause() {
   var video = document.getElementById("video");
   var button = document.getElementById("playandpause");
   if (video.paused || video.ended) {
      button.title = "pause";
      button.innerHTML = "pause";
      video.play();
   }
   else {
      button.title = "play";
      button.innerHTML = "play";
      video.pause();
   }
}

Na początku, w standardowy sposób pobieramy referencje do obiektu elementu ‘video’ oraz do obiektu przycisku. Następnie sprawdzane w jakim stanie znajduje się film - jeśli jest on wstrzymany (właściwość ‘paused’) lub skończył się (właściwość ‘ended’), wówczas zmieniamy napis na naszym przycisku na ‘pause’ oraz włączamy odtwarzanie filmu (funkcja ‘play()’ obiektu ‘video). Jeśli film znajduje się w innym stanie (czyli jest w tym momencie odtwarzany) - kliknięcie przycisku powoduje zmianę tekstu na przycisku na ‘play’, a film zostaje zatrzymany.

Sterowanie odtwarzaniem dźwięku

Ok, kolejną funkcjonalnością, którą posiada każdy odtwarzacz multimedialny jest sterowanie głośnością. Na początek dodajmy więc kontrolkę pozwalającą na zwiększanie lub zmniejszanie natężenia dźwięku - tutaj z pomocą przychodzi nam nowy typ znacznika <input> - ‘range’ - poniżej przykład:

<input id="volume" type="range" max="10" min="0" step="1" onchange="setVolume()" />

Kontrolka, która wyświetli się nam na ekranie wygląda tak (jej wygląd oczywiście zależy od przeglądarki; pokazuję jak wygląda bo to dla mnie nowość…):

Myślę, że znacznia poszczególnych atrybutów dla tego typu znacznika <input> nie trzeba tłumaczyć. Nas najbardziej w tym przykładzie interesuje, że do zdarzenia ‘onchange’ przypisana została, obsługująca je funkcja ‘setVolume()’. Spójrzmy zatem na jej implementację:

function setVolume() {
   var video = document.getElementById("video");
   var volume = document.getElementById("volume");
   video.volume = volume.value;
}

Jak się więc okazuje, zadanie zmiany głośności w naszym filmie to sprawa banalnie prosta - na początku oczywiście pobieramy referencje do obiektu filmu i do obiektu reprezentującego kontrolkę zmiany głośności. Następnie mamy zwykłe przypisanie wartości pobranej z kontrolki do odpowiedniej właściwości obiektu wideo.

Skoro jesteśmy juz przy sterowaniu dźwiękiem, na naszą stronę dodamy jeszcze przycisk pozwalający na wyciszenie dźwięku. Oto przykład:

<button id="mute" onclick="setMute()">Wycisz</button>

A poniżej kod funkcji obsługującej zdarzenie kliknięcia takiego przycisku:

function setMute() {
   var video = document.getElementById("video");
   video.muted = !video.muted;
}

Wielkiej filozofii w tym nie ma - wartość właściwości ‘muted’ obiektu wideo jest ustawiana na wartość przeciwną. Ewentualnie można by jeszcze zmieniać treść przycisku, ale niech to będzie zadanie domowe ;)

Pasek postępu

Za pomocą funkcji i właściwości obiektów multimedialnych możemy stworzyć również własny pasek postępu, informujący w jakim momencie filmu jesteśmy. Wykorzystamy do tego fakt, że API kontrolek multimedialnych w HTML5, rzuca w czasie działania, szereg zdarzeń, które programista może śledzić i reagować na nie. Jednym z nich jest zdarzenie ‘timeUpdate’, które odpalane jest za każdym razem, kiedy właściwość ‘currentTime’ obiektu filmu zmieni się. Zanim zaczniemy omawiać tworzenie paska postępu, poniżej lista wszystkich zdarzeń, które można obsługiwać:

  • playing - zdarzenie uruchamiane jest kiedy odtwarzanie jest w toku
  • ended - zdarzenie ma miejsce, kiedy odtwarzanie dobiegnie końca (ponieważ film lub muzyka się skończyła)
  • timeUpdate - zdarzenie uruchamiane jest za każdym razem kiedy wartość ‘currentTime’ się zmieni
  • play - zdarzenie ma miejsce w momencie gdy odtwarzanie zostanie wznowione (wcześniej było wstrzymane)
  • pause - zdarzenie ma miejsce, kiedy odtwarzanie zostanie wstrzymane (wcześniej miało miejsce odtwarzanie)
  • volumeChanged - zdarzenie uruchamiane jest, gdy wartość głośności się zmieni

Przejdźmy zatem do paska postępu. Jak wspomniałem, nasz “progress bar” opierać się będzie na zdarzeniu ‘timeUpdate’ - za każdym razem, gdy zdarzenie zostanie uruchomione, funkcja obsługująca to zdarzenie odczyta wartość ‘currentTime’ filmu i na tej podstawie przeliczy szerokość paska postępu. Na początek więc, gdzieś w kodzie inicjalizującym, uruchamianym podczas ładowania naszej strony, dodajmy poniższą definicję “nasłuchiwacza” (? - ang. listener):

var video = document.getElementById("video");
video.addEventListener("timeupdate", calculateProgress, false);

Powyższy kod, informuje obiekt ‘video’, że zdarzenie ‘timeUpdate’ jest obsługiwane przez funkcję ‘calculateProgress’. Ostatni parametr funkcji oznacza, czy ma zostać włączone przechwytywanie zdarzeń - informuje, czy zdarzenie ma zostać przechwycone, zanim trafi do innych ‘listenerów’ - po szczegóły zapraszam do dokumentacji.

Tworzymy pasek

Zanim przejdę do opisu implementacji metody ‘calculateProgress’, pokażę jak został zrealizowany sam pasek postępu. Poniżej prosty kod HTML:

<div id="progressBar"></div>

Pasek postępu w naszym przykładzie, to zwykły kontener (reprezentuje 100% długości pliku), wewnątrz którego znajduje się element <span>, który reprezentuje ilość filmu jaka już upłynęła. Oczywiście nie będzie to dobrze działać, bez odpowiedniego ostylowania tych elementów za pomocą CSS. Poniżej przykładowe style:

#progressBar {
   border:1px solid black;
   width:200px;
   height:20px;
}

#progress {
   background-color: red;
   height: 20px;
   display: inline-block;
}

Implementacja przesuwania się paska

Wcześniej wspomniana została funkcja ‘calculateProgress’, odpowiadająca za obsługę zdarzenia ‘timeUpdate’. Poniżej jej implementacja:

function calculateProgress() {
   var video = document.getElementById("video");
   var progress = document.getElementById("progress");
   var progressValue = 0;
   if (video.currentTime > 0) {
      progressValue = Math.floor((100 / video.duration) * video.currentTime);
   }
   progress.style.width = progressValue + "%";
}

W metodzie tej, na początku pobierane są referencje do filmu i do elementu ‘progress’ (o tym jak on wygląda, za chwilę). Następnie obliczana jest procentowa wartość, odpowiadająca temu jak dużo filmu zostało już obejrzane. Na koniec, wartość ta używana jest do zmiany stylu CSS tego elementu (ustawiana jest odpowiednia, procentowa wartość). W ten sposób, w miarę jak film posuwa się naprzód, szerokość wewnętrznego elementu <span> zwiększa się, aż do osiągnięcia wartości 100%.

Listy odtwarzania

Tym sposobem dobrnęliśmy do ostatniego tematu, który dziś poruszę. Dzięki API jakie dostarczając kontrolki multimedialne, możliwe jest stworzenie na naszej stronie list odtwarzania - użytkownik ma możliwość klikania na filmy/utwory na liście, w celu uruchomienia ich w osadzonym na stronie odtwarzaczu. Aby zabrać się od razu do tematu, dodajmy na naszą stronę listę kilku filmów. Mogło by to wyglądać mniej więcej tak:

<ul id="playlist">
  <li class="active"><a href="#">Śmieszny kot</a></li>
  <li>
    <a onclick="play('ptaki.mp4)" href="#">Ptaki</a>
  </li>
</ul>

Jak możemy wywnioskować z powyższego, następny krok to implementacja funkcji ‘play()’, obsługującej zdarzenie kliknięcia w link:

function play(file) {
   var video = document.getElementById("video");

   // restart odtwarzacza
   var playButton = document.getElementById("playandpause");
   playButton.title = "play";
   playButton.innerHTML = "play";
   if (video.currentTime > 0) {
      video.currentTime = 0;
   }
   calculateProgress(); // metoda wcześniej omawiana

   // uruchom plik
   video.src = file;
   video.load();

   return false;
}

A więc po kolei - na początku jak zwykle pobieramy referencję do obiektu ‘video’. Następnie szereg czynności odpowiedzialnych za zresetowanie odtwarzacza - ustawiamy przycisk ‘Play/Pause’ w pozycji ‘Play’, resetujemy wartość ‘currentTime’ obiektu ‘video’ oraz uruchamiamy funkcję ‘calculateProgress()’, która ustawi opisany wcześniej pasek postępu w pozycji 0%.

Na koniec, do właściwości ‘src’ obiektu ‘video’ przypisywana jest nowa ścieżka do pliku, po czym uruchamiana jest metoda ‘load()’ (nie wszystkie przeglądarki wymagają wywołania tej metody, ale lepiej to zrobić dla pewności). I gotowe! Nowy film z playlisty wczytany!

Sterowanie odtwarzaniem - podsumowanie

To już koniec dzisiejszego wpisu. W kolejnej części cyklu przygotowującego do egzaminu MCSD: 70-480 zajmiemy się dynamicznym (za pomocą języków skryptowych) tworzeniem grafiki - obiekt ‘canvas’. Oprócz tego omówiony zostanie sposób na osadzanie w kodzie strony grafiki wektorowej.

Zapraszam! ;)