tubular.js (6974B)
1 /* jQuery tubular plugin 2 |* by Sean McCambridge 3 |* http://www.seanmccambridge.com/tubular 4 |* version: 1.0 5 |* updated: October 1, 2012 6 |* since 2010 7 |* licensed under the MIT License 8 |* Enjoy. 9 |* 10 |* Thanks, 11 |* Sean */ 12 13 ;(function ($, window) { 14 15 // test for feature support and return if failure 16 17 // defaults 18 var defaults = { 19 ratio: 16/9, // usually either 4/3 or 16/9 -- tweak as needed 20 videoId: 'ZCAnLxRvNNc', // toy robot in space is a good default, no? 21 mute: true, 22 repeat: true, 23 width: $(window).width(), 24 wrapperZIndex: 99, 25 playButtonClass: 'tubular-play', 26 pauseButtonClass: 'tubular-pause', 27 muteButtonClass: 'tubular-mute', 28 volumeUpClass: 'tubular-volume-up', 29 volumeDownClass: 'tubular-volume-down', 30 increaseVolumeBy: 10, 31 start: 0 32 }; 33 34 // methods 35 36 var tubular = function(node, options) { // should be called on the wrapper div 37 38 var options = $.extend({}, defaults, options), 39 $body = $('body') // cache body node 40 $node = $(node); // cache wrapper node 41 42 // build container 43 var tubularContainer = '<div id="tubular-container" style="display:none;overflow: hidden; position: fixed; z-index: 1; width: 100%; height: 100%"><div id="tubular-player" style="position: absolute"></div></div><div id="tubular-shield" style="width: 100%; height: 100%; z-index: 2; position: absolute; left: 0; top: 0;"></div>'; 44 var done = false; 45 // set up css prereq's, inject tubular container and set up wrapper defaults 46 $('html,body').css({'width': '100%', 'height': '100%'}); 47 $body.prepend(tubularContainer); 48 $node.css({position: 'relative', 'z-index': options.wrapperZIndex}); 49 50 // set up iframe player, use global scope so YT api can talk 51 window.player; 52 window.onYouTubeIframeAPIReady = function() { 53 player = new YT.Player('tubular-player', { 54 width: options.width, 55 height: Math.ceil(options.width / options.ratio), 56 videoId: options.videoId, 57 58 playerVars: { 59 rel: 0, 60 controls: 0, 61 showinfo: 0, 62 modestbranding: 1, 63 iv_load_policy:3, 64 wmode: 'transparent' 65 }, 66 events: { 67 'onReady': onPlayerReady, 68 'onStateChange': onPlayerStateChange 69 } 70 }); 71 72 } 73 74 window.onPlayerReady = function(e) { 75 76 //player.addEventListener('onStateChange', onPlayerStateChange); 77 resize(); 78 if (options.mute) e.target.mute(); 79 e.target.seekTo(options.start); 80 e.target.playVideo(); 81 $('#tubular-container').fadeIn(); 82 } 83 84 window.onPlayerStateChange = function(state) { 85 //console.log('ready for safair'); 86 if (state.data === 0 && options.repeat) { // video ended and repeat option is set true 87 player.seekTo(options.start); // restart 88 player.playVideo(); 89 } 90 if (state.data === 1){ 91 $('#tubular-container iframe').addClass('active'); 92 } 93 94 if(options.repeat === false){ 95 var videoDuration = player.getDuration(); 96 97 if (state.data == YT.PlayerState.PLAYING && !done) { 98 // pause 0.1 seconds before the end 99 //console.log((videoDuration-0.2)*1000); 100 setTimeout(pauseVideo, (videoDuration-0.2)*1000); 101 done = true; 102 } 103 } 104 } 105 106 window.pauseVideo = function() { 107 player.pauseVideo(); 108 } 109 110 // resize handler updates width, height and offset of player after resize/init 111 var resize = function() { 112 var width = $(window).width(), 113 pWidth, // player width, to be defined 114 height = $(window).height(), 115 pHeight, // player height, tbd 116 $tubularPlayer = $('#tubular-player'); 117 118 // when screen aspect ratio differs from video, video must center and underlay one dimension 119 120 if (width / options.ratio < height) { // if new video height < window height (gap underneath) 121 pWidth = Math.ceil(height * options.ratio); // get new player width 122 $tubularPlayer.width(pWidth).height(height).css({left: (width - pWidth) / 2, top: 0}); // player width is greater, offset left; reset top 123 } else { // new video width < window width (gap to right) 124 pHeight = Math.ceil(width / options.ratio); // get new player height 125 $tubularPlayer.width(width).height(pHeight).css({left: 0, top: (height - pHeight) / 2}); // player height is greater, offset top; reset left 126 } 127 128 } 129 130 // events 131 $(window).on('resize.tubular', function() { 132 resize(); 133 }) 134 135 $('body').on('click','.' + options.playButtonClass, function(e) { // play button 136 e.preventDefault(); 137 player.playVideo(); 138 }).on('click', '.' + options.pauseButtonClass, function(e) { // pause button 139 e.preventDefault(); 140 player.pauseVideo(); 141 }).on('click', '.' + options.muteButtonClass, function(e) { // mute button 142 e.preventDefault(); 143 (player.isMuted()) ? player.unMute() : player.mute(); 144 }).on('click', '.' + options.volumeDownClass, function(e) { // volume down button 145 e.preventDefault(); 146 var currentVolume = player.getVolume(); 147 if (currentVolume < options.increaseVolumeBy) currentVolume = options.increaseVolumeBy; 148 player.setVolume(currentVolume - options.increaseVolumeBy); 149 }).on('click', '.' + options.volumeUpClass, function(e) { // volume up button 150 e.preventDefault(); 151 if (player.isMuted()) player.unMute(); // if mute is on, unmute 152 var currentVolume = player.getVolume(); 153 if (currentVolume > 100 - options.increaseVolumeBy) currentVolume = 100 - options.increaseVolumeBy; 154 player.setVolume(currentVolume + options.increaseVolumeBy); 155 }) 156 } 157 158 // load yt iframe js api 159 160 var tag = document.createElement('script'); 161 tag.src = "https://www.youtube.com/iframe_api"; 162 var firstScriptTag = document.getElementsByTagName('script')[0]; 163 firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 164 165 // create plugin 166 167 $.fn.tubular = function (options) { 168 return this.each(function () { 169 if (!$.data(this, 'tubular_instantiated')) { // let's only run one 170 $.data(this, 'tubular_instantiated', 171 tubular(this, options)); 172 } 173 }); 174 } 175 176 })(jQuery, window);