423 lines
12 KiB
JavaScript
Executable File

/*
BigVideo - The jQuery Plugin for Big Background Video (and Images)
by John Polacek (@johnpolacek)
Dual licensed under MIT and GPL.
Dependencies: jQuery, jQuery UI (Slider), Video.js, ImagesLoaded
*/
(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
define([
'jquery',
'videojs',
'imagesloaded',
'jquery-ui'
], factory);
} else {
factory(jQuery, videojs);
}
})(function($, videojs) {
$.BigVideo = function(options) {
var defaults = {
// If you want to use a single mp4 source, set as true
useFlashForFirefox:true,
// If you are doing a playlist, the video won't play the first time
// on a touchscreen unless the play event is attached to a user click
forceAutoplay:false,
controls:false,
doLoop:false,
container:$('body'),
shrinkable:false
};
var BigVideo = {},
player,
vidEl = '#big-video-vid',
wrap = $('<div id="big-video-wrap"></div>'),
video = $(''),
mediaAspect = 16/9,
vidDur = 0,
defaultVolume = 0.8,
isInitialized = false,
isSeeking = false,
isPlaying = false,
isQueued = false,
isAmbient = false,
playlist = [],
currMediaIndex,
currMediaType;
var settings = $.extend({}, defaults, options);
function updateSize() {
var containerW = settings.container.outerWidth() < $(window).width() ? settings.container.outerWidth() : $(window).width(),
containerH = settings.container.outerHeight() < $(window).height() ? settings.container.outerHeight() : $(window).height(),
containerAspect = containerW/containerH;
if (settings.container.is($('body'))) {
$('html,body').css('height',$(window).height() > $('body').css('height','auto').height() ? '100%' : 'auto');
}
if (containerAspect < mediaAspect) {
// taller
if (currMediaType == 'video') {
player
.width(containerH*mediaAspect)
.height(containerH);
if (!settings.shrinkable) {
$(vidEl)
.css('top',0)
.css('left',-(containerH*mediaAspect-containerW)/2)
.css('height',containerH);
} else {
$(vidEl)
.css('top',-(containerW/mediaAspect-containerH)/2)
.css('left',0)
.css('height',containerW/mediaAspect);
}
$(vidEl+'_html5_api')
.css('width',containerH*mediaAspect)
.css('height',containerH);
$(vidEl+'_flash_api')
.css('width',containerH*mediaAspect)
.css('height',containerH);
} else {
// is image
$('#big-video-image')
.css({
width: 'auto',
height: containerH,
top:0,
left:-(containerH*mediaAspect-containerW)/2
});
}
} else {
// wider
if (currMediaType == 'video') {
player
.width(containerW)
.height(containerW/mediaAspect);
$(vidEl)
.css('top',-(containerW/mediaAspect-containerH)/2)
.css('left',0)
.css('height',containerW/mediaAspect);
$(vidEl+'_html5_api')
.css('width',$(vidEl+'_html5_api').parent().width()+"px")
.css('height','auto');
$(vidEl+'_flash_api')
.css('width',containerW)
.css('height',containerW/mediaAspect);
} else {
// is image
$('#big-video-image')
.css({
width: containerW,
height: 'auto',
top:-(containerW/mediaAspect-containerH)/2,
left:0
});
}
}
}
function initPlayControl() {
// create video controls
var markup = ''+
'<div id="big-video-control-container">'+
'<div id="big-video-control">'+
'<a href="#" id="big-video-control-play"></a>'+
'<div id="big-video-control-middle">'+
'<div id="big-video-control-bar">'+
'<div id="big-video-control-bound-left"></div>'+
'<div id="big-video-control-progress"></div>'+
'<div id="big-video-control-track"></div>'+
'<div id="big-video-control-bound-right"></div>'+
'</div>'+
'</div>'+
' <div id="big-video-control-timer"></div>'+
'</div>'+
'</div>';
settings.container.append(markup);
// hide until playVideo
$('#big-video-control-container').css('display','none');
$('#big-video-control-timer').css('display','none');
// add events
$('#big-video-control-track').slider({
animate: true,
step: 0.01,
slide: function(e,ui) {
isSeeking = true;
$('#big-video-control-progress').css('width',(ui.value-0.16)+'%');
player.currentTime((ui.value/100)*player.duration());
},
stop:function(e,ui) {
isSeeking = false;
player.currentTime((ui.value/100)*player.duration());
}
});
$('#big-video-control-bar').click(function(e) {
player.currentTime((e.offsetX/$(this).width())*player.duration());
});
$('#big-video-control-play').click(function(e) {
e.preventDefault();
playControl('toggle');
});
player.on('timeupdate', function() {
if (!isSeeking && (player.currentTime()/player.duration())) {
var currTime = player.currentTime();
var minutes = Math.floor(currTime/60);
var seconds = Math.floor(currTime) - (60*minutes);
if (seconds < 10) seconds='0'+seconds;
var progress = player.currentTime()/player.duration()*100;
$('#big-video-control-track').slider('value',progress);
$('#big-video-control-progress').css('width',(progress-0.16)+'%');
$('#big-video-control-timer').text(minutes+':'+seconds+'/'+vidDur);
}
});
}
function playControl(a) {
var action = a || 'toggle';
if (action == 'toggle') action = isPlaying ? 'pause' : 'play';
if (action == 'pause') {
player.pause();
$('#big-video-control-play').css('background-position','-16px');
isPlaying = false;
} else if (action == 'play') {
player.play();
$('#big-video-control-play').css('background-position','0');
isPlaying = true;
} else if (action == 'skip') {
nextMedia();
}
}
function setUpAutoPlay() {
player.play();
settings.container.off('click',setUpAutoPlay);
}
function nextMedia() {
currMediaIndex++;
if (currMediaIndex === playlist.length) currMediaIndex=0;
playVideo(playlist[currMediaIndex]);
}
function playVideo(source) {
// clear image
$(vidEl).css('display','block');
currMediaType = 'video';
player.src(source);
isPlaying = true;
if (isAmbient) {
$('#big-video-control-container').css('display','none');
player.ready(function(){
player.volume(0);
});
doLoop = true;
} else {
$('#big-video-control-container').css('display','block');
player.ready(function(){
player.volume(defaultVolume);
});
doLoop = false;
}
$('#big-video-image').css('display','none');
$(vidEl).css('display','block');
}
function showPoster(source) {
// remove old image
$('#big-video-image').remove();
// hide video
player.pause();
$(vidEl).css('display','none');
$('#big-video-control-container').css('display','none');
// show image
currMediaType = 'image';
var bgImage = $('<img id="big-video-image" src='+source+' />');
wrap.append(bgImage);
$('#big-video-image').imagesLoaded(function() {
mediaAspect = $('#big-video-image').width() / $('#big-video-image').height();
updateSize();
});
}
BigVideo.init = function() {
if (!isInitialized) {
// create player
settings.container.prepend(wrap);
var autoPlayString = settings.forceAutoplay ? 'autoplay' : '';
player = $('<video id="'+vidEl.substr(1)+'" class="video-js vjs-default-skin" height="1" width="1" preload="auto" data-setup="{}" '+autoPlayString+' webkit-playsinline></video>');
player.css('position','absolute');
wrap.append(player);
var videoTechOrder = ['html5','flash'];
// If only using mp4s and on firefox, use flash fallback
var ua = navigator.userAgent.toLowerCase();
var isFirefox = ua.indexOf('firefox') != -1;
if (settings.useFlashForFirefox && (isFirefox)) {
videoTechOrder = ['flash', 'html5'];
}
player = videojs(vidEl.substr(1), {
controls:false,
autoplay:true,
preload:'auto',
techOrder:videoTechOrder
});
// add controls
if (settings.controls) initPlayControl();
// set initial state
updateSize();
isInitialized = true;
isPlaying = false;
if (settings.forceAutoplay) {
$('body').on('click', setUpAutoPlay);
}
$('#big-video-vid_flash_api')
.attr('scale','noborder')
.attr('width','100%')
.attr('height','100%');
// set events
$(window).on('resize.bigvideo', function() {
updateSize();
});
player.on('loadedmetadata', function(data) {
if (document.getElementById('big-video-vid_flash_api')) {
// use flash callback to get mediaAspect ratio
mediaAspect = document.getElementById('big-video-vid_flash_api').vjs_getProperty('videoWidth')/document.getElementById('big-video-vid_flash_api').vjs_getProperty('videoHeight');
} else {
// use html5 player to get mediaAspect
mediaAspect = $('#big-video-vid_html5_api').prop('videoWidth')/$('#big-video-vid_html5_api').prop('videoHeight');
}
updateSize();
var dur = Math.round(player.duration());
var durMinutes = Math.floor(dur/60);
var durSeconds = dur - durMinutes*60;
if (durSeconds < 10) durSeconds='0'+durSeconds;
vidDur = durMinutes+':'+durSeconds;
});
player.on('ended', function() {
if (settings.doLoop) {
player.currentTime(0);
player.play();
}
if (isQueued) {
nextMedia();
}
});
}
};
/**
* Show video or image file
*
* @param source: The file to show, can be:
* - an array with objects for video files types
* - a string to a single video file
* - a string to a image file
* @param options: An object with those possible attributes:
* - boolean "ambient" to set video to loop
* - function onShown
*/
BigVideo.show = function(source,options) {
if (options === undefined) options = {};
isAmbient = options.ambient === true;
if (isAmbient || options.doLoop) settings.doLoop = true;
if (typeof(source) === 'string') {
// if input was a string, try show that image or video
var ext = ( source.lastIndexOf('?') > 0 ) ? source.substring(source.lastIndexOf('.')+1, source.lastIndexOf('?')) : source.substring( source.lastIndexOf('.')+1);
if (ext == 'jpg' || ext == 'gif' || ext == 'png') {
showPoster(source);
} else if (ext == 'mp4' || ext == 'ogg' || ext == 'ogv'|| ext == 'webm') {
playVideo(source);
if (options.onShown) options.onShown();
isQueued = false;
}
} else if ($.isArray(source)) {
// if the input was an array, pass it to videojs
playVideo(source);
} else if (typeof(source) === "object" && source.src && source.type) {
// if the input was an object with valid attributes, wrap it in an
// array and pass it to videojs
playVideo([source]);
} else {
// fail without valid input
throw("BigVideo.show received invalid input for parameter source");
}
};
/**
* Show a playlist of video files
*
* @param files: array of elements to pass to BigVideo.show in sequence
* @param options: An object with those possible attributes:
* - boolean "ambient" to set video to loop
* - function onShown
*/
BigVideo.showPlaylist = function (files, options) {
if (!$.isArray(files)) {
throw("BigVideo.showPlaylist parameter files accepts only arrays");
}
if (options === undefined) options = {};
isAmbient = options.ambient === true;
if (isAmbient || options.doLoop) settings.doLoop = true;
playlist = files;
currMediaIndex = 0;
this.show(playlist[currMediaIndex]);
if (options.onShown) options.onShown();
isQueued = true;
};
// Expose Video.js player
BigVideo.getPlayer = function() {
return player;
};
// Remove/dispose the player
BigVideo.remove = BigVideo.dispose = function() {
isInitialized = false;
wrap.remove();
$(window).off('resize.bigvideo');
if(player) {
player.off('loadedmetadata');
player.off('ended');
player.dispose();
}
};
// Expose BigVideoJS player actions play, pause, skip (if a playlist is available)
// Example: BigVideo.triggerPlayer('skip')
BigVideo.triggerPlayer = function(action){
playControl(action);
};
return BigVideo;
};
});