コントローラUIの設計
<video>要素を使用した場合、表示されるコントローラはWebブラウザによって異なる。
再生、一時停止、シークなどあらゆる機能/ボタンはMedia elements APIをとおして、JavaScriptでアクセス/操作することが可能だ。これらのコントローラUIは、HTML/CSS/SVGなどで自由に組みたてられる。
コントローラのマークアップ
まず最初にこれらコントローラをマークアップする必要がある。さきほどのWebブラウザ別ネイティブビデオコントローラを見て分かるとおり、プレーヤには次の機能が求められる。
- 再生/一時停止ボタン
- シークバー
- タイマー
- ボリューム調節ボタン/スライダ
これらを構成するマークアップは次のとおり。
<div class="ghinda-video-controls">
<a class="ghinda-video-play" title="Play/Pause"></a>
<div class="ghinda-video-seek"></div>
<div class="ghinda-video-timer">00:00</div>
<div class="ghinda-volume-box">
<div class="ghinda-volume-slider"></div>
<a class="ghinda-volume-button" title="Mute/Unmute"></a>
</div>
</div>
それぞれのクラス名は次の機能に対応している。
- ghinda-video-controls: コントローラ全体
- ghinda-video-play: 再生/一時停止
- ghinda-video-seek: シーク
- ghinda-video-timer: タイマー
- ghinda-volume-box: ボリューム調節のボタン。オンマウスでスライダとミュート切替を表示
- ghinda-volume-slider: ボリューム調節スライダ
- ghinda-volume-button: ミュート切替
JavaScriptを用いてこのマークアップ(controls wraper)を<video>要素の後に挿入、<div class="hinda-video-player">(main wrapper)で<video>要素をラップする。
作成したプレーヤをjQueryプラグインとしてパッケージ
JavaScriptによるマークアップが完了したら、これらをjQueryプラグインとしてパッケージする。jQueryプラグインにしておくことで、簡単に再利用することが可能になる。AUTHOR'S NOTEによると、jQueryプラグインを作成してみたい場合はSitePointのHow To Develop a jQuery PluginやOpera Developer Communityの39: Programming - the real basics!もチェックしてほしいとのことだ。
次に紹介するコードは、同氏の成果物である「jquery.ghindaVideoPlayer.js」の一部。実装を追いながら確認したい方は、さきに記事最下部の「download the source code (8.5mb, ZIP file)」からソースコードをダウンロードしておくことをおすすめする。
JavaScriptでおこなっている処理の順番は次のとおり。
- デフォルトのオプション定義
- <video>の前後にmain/controlsそれぞれの要素を挿入
- 再生/一時停止のコントローラを作成
- シークの作成
- タイマーの作成
- ボリュームコントローラを作成
- <video>からcontrols属性を削除
JavaScriptを無効にしている場合でもコントロールが無効になることがないように、スクリプトロードが完了し、コントローラの描画に成功した時点でコントロール属性を削除。JavaScriptが無効の環境や、なんらかの理由で1~6が実行できなかった場合は、Webブラウザデフォルトのコントローラがそのまま表示されるというわけだ。
$.fn.gVideo = function(options) {
// build main options before element iteration
var defaults = {
theme: 'simpledark',
childtheme: ''
};
var options = $.extend(defaults, options);
// iterate and reformat each matched element
return this.each(function() {
var $gVideo = $(this);
//create html structure
//main wrapper
var $video_wrap = $('<div></div>').addClass('ghinda-video-player').addClass(options.theme).addClass(options.childtheme);
//controls wraper
var $video_controls = $('<div class="ghinda-video-controls"><a class="ghinda-video-play" title="Play/Pause"></a><div class="ghinda-video-seek"></div><div class="ghinda-video-timer">00:00</div><div class="ghinda-volume-box"><div class="ghinda-volume-slider"></div><a class="ghinda-volume-button" title="Mute/Unmute"></a></div></div>');
$gVideo.wrap($video_wrap);
$gVideo.after($video_controls);
さきほどのマークアップを<video>要素の前後に挿入する。
続いて、コントローラUIを構築する各要素を紐づける。
//get newly created elements
var $video_container = $gVideo.parent('.ghinda-video-player');
var $video_controls = $('.ghinda-video-controls', $video_container);
var $ghinda_play_btn = $('.ghinda-video-play', $video_container);
var $ghinda_video_seek = $('.ghinda-video-seek', $video_container);
var $ghinda_video_timer = $('.ghinda-video-timer', $video_container);
var $ghinda_volume = $('.ghinda-volume-slider', $video_container);
var $ghinda_volume_btn = $('.ghinda-volume-button', $video_container);
$video_controls.hide(); // keep the controls hidden
$video_controls.hide();でいったんコントローラを非表示にしている。これは動作を再生する準備ができるまで、コントローラを非表示にしておきたいため。
続いて、再生/一時停止のコントロールを作成する。
var gPlay = function() {
if($gVideo.attr('paused') == false) {
$gVideo[0].pause();
} else {
$gVideo[0].play();
}
};
$ghinda_play_btn.click(gPlay);
$gVideo.click(gPlay);
$gVideo.bind('play', function() {
$ghinda_play_btn.addClass('ghinda-paused-button');
});
$gVideo.bind('pause', function() {
$ghinda_play_btn.removeClass('ghinda-paused-button');
});
$gVideo.bind('ended', function() {
$ghinda_play_btn.removeClass('ghinda-paused-button');
});
<video>をサポートするほとんどのWebブラウザは、プレーヤを右クリックするとコンテキストメニューに再生や一時停止といったコントロールのためのメニューを表示する。コンテキストメニューから操作されても自前で用意したコントローラUIが連動して動作するように、ここでは「ボタンに機能を紐づける」のとは別に、「<video>の各種イベント(play, pause, ended)時に、ボタンのクラスを操作」している。
再生/一時停止のコントロールの後、シークの作成にうつる。
var createSeek = function() {
if($gVideo.attr('readyState')) {
var video_duration = $gVideo.attr('duration');
$ghinda_video_seek.slider({
value: 0,
step: 0.01,
orientation: "horizontal",
range: "min",
max: video_duration,
animate: true,
slide: function(){
seeksliding = true;
},
stop:function(e,ui){
seeksliding = false;
$gVideo.attr("currentTime",ui.value);
}
});
$video_controls.show();
} else {
setTimeout(createSeek, 150);
}
};
createSeek();
createSeek()は再帰関数。readyState属性の有無をチェックし、再生準備ができたらjQuery UI Sliderを使ってスライダを描画。スライダ描画後、非表示にしていたコントロールを再表示する。
続いてタイマーを作成し、timeupdateイベントリスナにアタッチする。
var gTimeFormat=function(seconds){
var m=Math.floor(seconds/60)<10?"0"+Math.floor(seconds/60):Math.floor(seconds/60);
var s=Math.floor(seconds-(m*60))<10?"0"+Math.floor(seconds-(m*60)):Math.floor(seconds-(m*60));
return m+":"+s;
};
var seekUpdate = function() {
var currenttime = $gVideo.attr('currentTime');
if(!seeksliding) $ghinda_video_seek.slider('value', currenttime);
$ghinda_video_timer.text(gTimeFormat(currenttime));
};
$gVideo.bind('timeupdate', seekUpdate);
gTimeFormatは時間の書式を整形するための関数。seekUpdateはさきほど作成したスライダの値を取得し、現在再生している動画の時間を得るための関数。timeupdateイベントリスナにseekUpdateをアタッチし、スライダを移動させてcurrentTimeの値が変動したときに再生時間を取得。gTimeFormatで時間書式を変換し、タイマー部分に表示する。
ここまできたらコントローラ最後のUI、ボリュームコントローラを作成する。
$ghinda_volume.slider({
value: 1,
orientation: "vertical",
range: "min",
max: 1,
step: 0.05,
animate: true,
slide:function(e,ui){
$gVideo.attr('muted',false);
video_volume = ui.value;
$gVideo.attr('volume',ui.value);
}
});
var muteVolume = function() {
if($gVideo.attr('muted')==true) {
$gVideo.attr('muted', false);
$ghinda_volume.slider('value', video_volume);
$ghinda_volume_btn.removeClass('ghinda-volume-mute');
} else {
$gVideo.attr('muted', true);
$ghinda_volume.slider('value', '0');
$ghinda_volume_btn.addClass('ghinda-volume-mute');
};
};
$ghinda_volume_btn.click(muteVolume);
シーク同様、jQuery UI Sliderでボリュームコントローラを実装している。スライダが動いた場合はvolumeをリアルタイムに変更。またmuteVolumeでミュートのOn/Offを切り替えられるようになっている。
最後にWebブラウザのデフォルトコントローラの代わりに、カスタマイズしたコントローラが使用されるように、<video>からcontrols属性を削除する。
$gVideo.removeAttr('controls');
プラグインの実装はここまで。あとはカスタマイズしたプレーヤを使用したい場面で
$('video').gVideo();
の1行を追加すればOKだ。
なおJavaScriptからプレーヤのコントローラを操作するコードを書いてみたい場合は、「【特集】詳解! HTML 5と関連APIの最新動向 - 新タグ&API編 (3) Video/Audio要素とそのAPI」においても詳細なサンプルが掲載されているので、こちらも参考にされたい。