vegas.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. /*!-----------------------------------------------------------------------------
  2. * Vegas - Fullscreen Backgrounds and Slideshows.
  3. * v2.0.4 - built 2015-03-12
  4. * Licensed under the MIT License.
  5. * http://vegas.jaysalvat.com/
  6. * ----------------------------------------------------------------------------
  7. * Copyright (C) 2010-2015 Jay Salvat
  8. * http://jaysalvat.com/
  9. * --------------------------------------------------------------------------*/
  10. /* global jQuery, Zepto */
  11. (function ($) {
  12. 'use strict';
  13. var defaults = {
  14. slide: 0,
  15. delay: 5000,
  16. preload: false,
  17. preloadImage: false,
  18. preloadVideo: false,
  19. timer: true,
  20. overlay: false,
  21. autoplay: true,
  22. shuffle: false,
  23. cover: true,
  24. color: null,
  25. align: 'center',
  26. valign: 'center',
  27. transition: 'fade',
  28. transitionDuration: 1000,
  29. transitionRegister: [],
  30. animation: null,
  31. animationDuration: 'auto',
  32. animationRegister: [],
  33. init: function () {},
  34. play: function () {},
  35. pause: function () {},
  36. walk: function () {},
  37. slides: [
  38. // {
  39. // src: null,
  40. // color: null,
  41. // delay: null,
  42. // align: null,
  43. // valign: null,
  44. // transition: null,
  45. // transitionDuration: null,
  46. // animation: null,
  47. // animationDuration: null,
  48. // cover: true,
  49. // video: {
  50. // src: [],
  51. // mute: true,
  52. // loop: true
  53. // }
  54. // ...
  55. ]
  56. };
  57. var videoCache = {};
  58. var Vegas = function (elmt, options) {
  59. this.elmt = elmt;
  60. this.settings = $.extend({}, defaults, $.vegas.defaults, options);
  61. this.slide = this.settings.slide;
  62. this.total = this.settings.slides.length;
  63. this.noshow = this.total < 2;
  64. this.paused = !this.settings.autoplay || this.noshow;
  65. this.$elmt = $(elmt);
  66. this.$timer = null;
  67. this.$overlay = null;
  68. this.$slide = null;
  69. this.timeout = null;
  70. this.transitions = [
  71. 'fade', 'fade2',
  72. 'blur', 'blur2',
  73. 'flash', 'flash2',
  74. 'negative', 'negative2',
  75. 'burn', 'burn2',
  76. 'slideLeft', 'slideLeft2',
  77. 'slideRight', 'slideRight2',
  78. 'slideUp', 'slideUp2',
  79. 'slideDown', 'slideDown2',
  80. 'zoomIn', 'zoomIn2',
  81. 'zoomOut', 'zoomOut2',
  82. 'swirlLeft', 'swirlLeft2',
  83. 'swirlRight', 'swirlRight2'
  84. ];
  85. this.animations = [
  86. 'kenburns',
  87. 'kenburnsLeft', 'kenburnsRight',
  88. 'kenburnsUp', 'kenburnsUpLeft', 'kenburnsUpRight',
  89. 'kenburnsDown', 'kenburnsDownLeft', 'kenburnsDownRight'
  90. ];
  91. if (this.settings.transitionRegister instanceof Array === false) {
  92. this.settings.transitionRegister = [ this.settings.transitionRegister ];
  93. }
  94. if (this.settings.animationRegister instanceof Array === false) {
  95. this.settings.animationRegister = [ this.settings.animationRegister ];
  96. }
  97. this.transitions = this.transitions.concat(this.settings.transitionRegister);
  98. this.animations = this.animations.concat(this.settings.animationRegister);
  99. this.support = {
  100. objectFit: 'objectFit' in document.body.style,
  101. transition: 'transition' in document.body.style || 'WebkitTransition' in document.body.style,
  102. video: $.vegas.isVideoCompatible()
  103. };
  104. if (this.settings.shuffle === true) {
  105. this.shuffle();
  106. }
  107. this._init();
  108. };
  109. Vegas.prototype = {
  110. _init: function () {
  111. var $wrapper,
  112. $overlay,
  113. $timer,
  114. isBody = this.elmt.tagName === 'BODY',
  115. timer = this.settings.timer,
  116. overlay = this.settings.overlay,
  117. self = this;
  118. // Preloading
  119. this._preload();
  120. // Wrapper with content
  121. if (!isBody) {
  122. this.$elmt.css('height', this.$elmt.css('height'));
  123. $wrapper = $('<div class="vegas-wrapper">')
  124. .css('overflow', this.$elmt.css('overflow'))
  125. .css('padding', this.$elmt.css('padding'));
  126. // Some browsers don't compute padding shorthand
  127. if (!this.$elmt.css('padding')) {
  128. $wrapper
  129. .css('padding-top', this.$elmt.css('padding-top'))
  130. .css('padding-bottom', this.$elmt.css('padding-bottom'))
  131. .css('padding-left', this.$elmt.css('padding-left'))
  132. .css('padding-right', this.$elmt.css('padding-right'));
  133. }
  134. this.$elmt.clone(true).children().appendTo($wrapper);
  135. this.elmt.innerHTML = '';
  136. }
  137. // Timer
  138. if (timer && this.support.transition) {
  139. $timer = $('<div class="vegas-timer"><div class="vegas-timer-progress">');
  140. this.$timer = $timer;
  141. this.$elmt.prepend($timer);
  142. }
  143. // Overlay
  144. if (overlay) {
  145. $overlay = $('<div class="vegas-overlay">');
  146. if (typeof overlay === 'string') {
  147. $overlay.css('background-image', 'url(' + overlay + ')');
  148. }
  149. this.$overlay = $overlay;
  150. this.$elmt.prepend($overlay);
  151. }
  152. // Container
  153. this.$elmt.addClass('vegas-container');
  154. if (!isBody) {
  155. this.$elmt.append($wrapper);
  156. }
  157. setTimeout(function () {
  158. self.trigger('init');
  159. self._goto(self.slide);
  160. if (self.settings.autoplay) {
  161. self.trigger('play');
  162. }
  163. }, 1);
  164. },
  165. _preload: function () {
  166. var video, img, i;
  167. for (i = 0; i < this.settings.slides.length; i++) {
  168. if (this.settings.preload || this.settings.preloadImages) {
  169. if (this.settings.slides[i].src) {
  170. img = new Image();
  171. img.src = this.settings.slides[i].src;
  172. }
  173. }
  174. if (this.settings.preload || this.settings.preloadVideos) {
  175. if (this.support.video && this.settings.slides[i].video) {
  176. video = this._video(this.settings.slides[i].video);
  177. }
  178. }
  179. }
  180. },
  181. _random: function (array) {
  182. return array[Math.floor(Math.random() * (array.length - 1))];
  183. },
  184. _slideShow: function () {
  185. var self = this;
  186. if (this.total > 1 && !this.paused && !this.noshow) {
  187. this.timeout = setTimeout(function () {
  188. self.next();
  189. }, this._options('delay'));
  190. }
  191. },
  192. _timer: function (state) {
  193. var self = this;
  194. clearTimeout(this.timeout);
  195. if (!this.$timer) {
  196. return;
  197. }
  198. this.$timer
  199. .removeClass('vegas-timer-running')
  200. .find('div')
  201. .css('transition-duration', '0ms');
  202. if (this.paused || this.noshow) {
  203. return;
  204. }
  205. if (state) {
  206. setTimeout(function () {
  207. self.$timer
  208. .addClass('vegas-timer-running')
  209. .find('div')
  210. .css('transition-duration', self._options('delay') - 100 + 'ms');
  211. }, 100);
  212. }
  213. },
  214. _video: function (srcs) {
  215. var video,
  216. source,
  217. cacheKey = srcs.toString();
  218. if (videoCache[cacheKey]) {
  219. return videoCache[cacheKey];
  220. }
  221. if (srcs instanceof Array === false) {
  222. srcs = [ srcs ];
  223. }
  224. video = document.createElement('video');
  225. // video.muted = true;
  226. video.preload = true;
  227. srcs.forEach(function (src) {
  228. source = document.createElement('source');
  229. source.src = src;
  230. video.appendChild(source);
  231. });
  232. videoCache[cacheKey] = video;
  233. return video;
  234. },
  235. _fadeOutSound: function (video, duration) {
  236. var self = this,
  237. delay = duration / 10,
  238. volume = video.volume - 0.09;
  239. var src = video.getElementsByTagName('source')[0].src;
  240. if (volume > 0) {
  241. if (src === 'http://localhost/personnel/vegas/dev/videos/bg2.mp4') {
  242. console.log('----', Math.round(volume * 100));
  243. }
  244. video.volume = volume;
  245. setTimeout(function () {
  246. self._fadeOutSound(video, duration);
  247. }, delay);
  248. } else {
  249. video.pause();
  250. }
  251. },
  252. _fadeInSound: function (video, duration) {
  253. var self = this,
  254. delay = duration / 10,
  255. volume = video.volume + 0.09;
  256. var src = video.getElementsByTagName('source')[0].src;
  257. if (volume < 1) {
  258. if (src === 'http://localhost/personnel/vegas/dev/videos/bg2.mp4') {
  259. console.log('++++', Math.round(volume * 100));
  260. }
  261. video.volume = volume;
  262. setTimeout(function () {
  263. self._fadeInSound(video, duration);
  264. }, delay);
  265. }
  266. },
  267. _options: function (key, i) {
  268. if (i === undefined) {
  269. i = this.slide;
  270. }
  271. if (this.settings.slides[i][key] !== undefined) {
  272. return this.settings.slides[i][key];
  273. }
  274. return this.settings[key];
  275. },
  276. _goto: function (nb) {
  277. if (typeof this.settings.slides[nb] === 'undefined') {
  278. nb = 0;
  279. }
  280. this.slide = nb;
  281. var $slide,
  282. $inner,
  283. $video,
  284. $slides = this.$elmt.children('.vegas-slide'),
  285. src = this.settings.slides[nb].src,
  286. videoSettings = this.settings.slides[nb].video,
  287. delay = this._options('delay'),
  288. align = this._options('align'),
  289. valign = this._options('valign'),
  290. color = this._options('color') || this.$elmt.css('background-color'),
  291. cover = this._options('cover') ? 'cover' : 'contain',
  292. self = this,
  293. total = $slides.length,
  294. video,
  295. img;
  296. var transition = this._options('transition'),
  297. transitionDuration = this._options('transitionDuration'),
  298. animation = this._options('animation' ),
  299. animationDuration = this._options('animationDuration');
  300. if (transition === 'random' || transition instanceof Array) {
  301. if (transition instanceof Array) {
  302. transition = this._random(transition);
  303. } else {
  304. transition = this._random(this.transitions);
  305. }
  306. }
  307. if (animation === 'random' || animation instanceof Array) {
  308. if (animation instanceof Array) {
  309. animation = this._random(animation);
  310. } else {
  311. animation = this._random(this.animations);
  312. }
  313. }
  314. if (transitionDuration === 'auto' || transitionDuration > delay) {
  315. transitionDuration = delay;
  316. }
  317. if (animationDuration === 'auto') {
  318. animationDuration = delay;
  319. }
  320. $slide = $('<div class="vegas-slide"></div>');
  321. if (this.support.transition && transition) {
  322. $slide.addClass('vegas-transition-' + transition);
  323. }
  324. // Video
  325. if (this.support.video && videoSettings) {
  326. if (videoSettings instanceof Array) {
  327. video = this._video(videoSettings);
  328. } else {
  329. video = this._video(videoSettings.src);
  330. }
  331. video.loop = videoSettings.loop !== undefined ? videoSettings.loop : true;
  332. video.muted = videoSettings.mute !== undefined ? videoSettings.mute : true;
  333. if (video.muted === false) {
  334. video.volume = 0;
  335. this._fadeInSound(video, transitionDuration);
  336. } else {
  337. video.pause();
  338. }
  339. $video = $(video)
  340. .addClass('vegas-video')
  341. .css('background-color', color);
  342. if (this.support.objectFit) {
  343. $video
  344. .css('object-position', align + ' ' + valign)
  345. .css('object-fit', cover)
  346. .css('width', '100%')
  347. .css('height', '100%');
  348. } else if (cover === 'contain') {
  349. $video
  350. .css('width', '100%')
  351. .css('height', '100%');
  352. }
  353. $slide.append($video);
  354. // Image
  355. } else {
  356. img = new Image();
  357. $inner = $('<div class="vegas-slide-inner"></div>')
  358. .css('background-image', 'url(' + src + ')')
  359. .css('background-color', color)
  360. .css('background-position', align + ' ' + valign)
  361. .css('background-size', cover);
  362. if (this.support.transition && animation) {
  363. $inner
  364. .addClass('vegas-animation-' + animation)
  365. .css('animation-duration', animationDuration + 'ms');
  366. }
  367. $slide.append($inner);
  368. }
  369. if (!this.support.transition) {
  370. $slide.css('display', 'none');
  371. }
  372. if (total) {
  373. $slides.eq(total - 1).after($slide);
  374. } else {
  375. this.$elmt.prepend($slide);
  376. }
  377. self._timer(false);
  378. function go () {
  379. self._timer(true);
  380. setTimeout(function () {
  381. if (transition) {
  382. if (self.support.transition) {
  383. $slides
  384. .css('transition', 'all ' + transitionDuration + 'ms')
  385. .addClass('vegas-transition-' + transition + '-out');
  386. $slides.each(function () {
  387. var video = $slides.find('video').get(0);
  388. if (video) {
  389. video.volume = 1;
  390. self._fadeOutSound(video, transitionDuration);
  391. }
  392. });
  393. $slide
  394. .css('transition', 'all ' + transitionDuration + 'ms')
  395. .addClass('vegas-transition-' + transition + '-in');
  396. } else {
  397. $slide.fadeIn(transitionDuration);
  398. }
  399. }
  400. for (var i = 0; i < $slides.length - 4; i++) {
  401. $slides.eq(i).remove();
  402. }
  403. self.trigger('walk');
  404. self._slideShow();
  405. }, 100);
  406. }
  407. if (video) {
  408. if (video.readyState === 4) {
  409. video.currentTime = 0;
  410. video.play();
  411. go();
  412. } else {
  413. video.oncanplay = function () {
  414. video.play();
  415. if (!video._started) {
  416. video._started = true;
  417. go();
  418. }
  419. };
  420. }
  421. } else {
  422. img.src = src;
  423. img.onload = go;
  424. }
  425. },
  426. shuffle: function () {
  427. var temp,
  428. rand;
  429. for (var i = this.total - 1; i > 0; i--) {
  430. rand = Math.floor(Math.random() * (i + 1));
  431. temp = this.settings.slides[i];
  432. this.settings.slides[i] = this.settings.slides[rand];
  433. this.settings.slides[rand] = temp;
  434. }
  435. },
  436. play: function () {
  437. if (this.paused) {
  438. this.paused = false;
  439. this.next();
  440. this.trigger('play');
  441. }
  442. },
  443. pause: function () {
  444. this._timer(false);
  445. this.paused = true;
  446. this.trigger('pause');
  447. },
  448. toggle: function () {
  449. if (this.paused) {
  450. this.play();
  451. } else {
  452. this.pause();
  453. }
  454. },
  455. playing: function () {
  456. return !this.paused && !this.noshow;
  457. },
  458. current: function (advanced) {
  459. if (advanced) {
  460. return {
  461. slide: this.slide,
  462. data: this.settings.slides[this.slide]
  463. };
  464. }
  465. return this.slide;
  466. },
  467. jump: function (nb) {
  468. if (nb < 0 || nb > this.total - 1 || nb === this.slide) {
  469. return;
  470. }
  471. this.slide = nb;
  472. this._goto(this.slide);
  473. },
  474. next: function () {
  475. this.slide++;
  476. if (this.slide >= this.total) {
  477. this.slide = 0;
  478. }
  479. this._goto(this.slide);
  480. },
  481. previous: function () {
  482. this.slide--;
  483. if (this.slide < 0) {
  484. this.slide = this.total - 1;
  485. }
  486. this._goto(this.slide);
  487. },
  488. trigger: function (fn) {
  489. var params = [];
  490. if (fn === 'init') {
  491. params = [ this.settings ];
  492. } else {
  493. params = [
  494. this.slide,
  495. this.settings.slides[this.slide]
  496. ];
  497. }
  498. this.$elmt.trigger('vegas' + fn, params);
  499. if (typeof this.settings[fn] === 'function') {
  500. this.settings[fn].apply(this.$elmt, params);
  501. }
  502. },
  503. options: function (key, value) {
  504. var oldSlides = this.settings.slides.slice();
  505. if (typeof key === 'object') {
  506. this.settings = $.extend({}, defaults, $.vegas.defaults, key);
  507. } else if (typeof key === 'string') {
  508. if (value === undefined) {
  509. return this.settings[key];
  510. }
  511. this.settings[key] = value;
  512. } else {
  513. return this.settings;
  514. }
  515. // In case slides have changed
  516. if (this.settings.slides !== oldSlides) {
  517. this.total = this.settings.slides.length;
  518. this.noshow = this.total < 2;
  519. this._preload();
  520. }
  521. }
  522. };
  523. $.fn.vegas = function(options) {
  524. var args = arguments,
  525. error = false,
  526. returns;
  527. if (options === undefined || typeof options === 'object') {
  528. return this.each(function () {
  529. if (!this._vegas) {
  530. this._vegas = new Vegas(this, options);
  531. }
  532. });
  533. } else if (typeof options === 'string') {
  534. this.each(function () {
  535. var instance = this._vegas;
  536. if (!instance) {
  537. throw new Error('No Vegas applied to this element.');
  538. }
  539. if (typeof instance[options] === 'function' && options[0] !== '_') {
  540. returns = instance[options].apply(instance, [].slice.call(args, 1));
  541. } else {
  542. error = true;
  543. }
  544. });
  545. if (error) {
  546. throw new Error('No method "' + options + '" in Vegas.');
  547. }
  548. return returns !== undefined ? returns : this;
  549. }
  550. };
  551. $.vegas = {};
  552. $.vegas.defaults = defaults;
  553. $.vegas.isVideoCompatible = function () {
  554. return !/(Android|webOS|Phone|iPad|iPod|BlackBerry|Windows Phone)/i.test(navigator.userAgent);
  555. };
  556. })(window.jQuery || window.Zepto);