vegas.js 21 KB

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