You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FilmStrip.js 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /* global $, interfaceConfig */
  2. import UIEvents from "../../../service/UI/UIEvents";
  3. import UIUtil from "../util/UIUtil";
  4. const FilmStrip = {
  5. /**
  6. *
  7. * @param eventEmitter the {EventEmitter} through which {FilmStrip} is to
  8. * emit/fire {UIEvents} (such as {UIEvents.TOGGLED_FILM_STRIP}).
  9. */
  10. init (eventEmitter) {
  11. this.filmStrip = $('#remoteVideos');
  12. this.eventEmitter = eventEmitter;
  13. this.filmStripIsVisible = true;
  14. this.renderFilmstripToolbar();
  15. this.activateHideButton();
  16. },
  17. /**
  18. * Attach 'click' listener to "hide filmstrip" button
  19. */
  20. activateHideButton () {
  21. $('#videospace').on('click', '#hideVideoToolbar', () => {
  22. var icon = document.querySelector('#hideVideoToolbar i');
  23. this.filmStripIsVisible = !this.filmStripIsVisible;
  24. this.toggleFilmStrip(this.filmStripIsVisible);
  25. icon.classList.remove(
  26. this.filmStripIsVisible ? 'icon-menu-up' : 'icon-menu-down');
  27. icon.classList.add(
  28. this.filmStripIsVisible ? 'icon-menu-down' : 'icon-menu-up');
  29. });
  30. },
  31. /**
  32. * Shows toolbar on the right of the filmstrip
  33. */
  34. renderFilmstripToolbar () {
  35. // create toolbar
  36. var container = document.createElement('div');
  37. container.className = 'filmstripToolbar';
  38. container.innerHTML = `
  39. <button id="hideVideoToolbar">
  40. <i class="icon-menu-${this.filmStripIsVisible ? 'down' : 'up'}">
  41. </i>
  42. </button>
  43. `;
  44. // show toolbar
  45. document.querySelector('#videospace')
  46. .insertBefore(container, document.querySelector('#remoteVideos'));
  47. },
  48. /**
  49. * Toggles the visibility of the film strip.
  50. *
  51. * @param visible optional {Boolean} which specifies the desired visibility
  52. * of the film strip. If not specified, the visibility will be flipped
  53. * (i.e. toggled); otherwise, the visibility will be set to the specified
  54. * value.
  55. */
  56. toggleFilmStrip (visible) {
  57. if (typeof visible === 'boolean'
  58. && this.isFilmStripVisible() == visible) {
  59. return;
  60. }
  61. this.filmStrip.toggleClass("hidden");
  62. // Emit/fire UIEvents.TOGGLED_FILM_STRIP.
  63. var eventEmitter = this.eventEmitter;
  64. if (eventEmitter) {
  65. eventEmitter.emit(
  66. UIEvents.TOGGLED_FILM_STRIP,
  67. this.isFilmStripVisible());
  68. }
  69. },
  70. isFilmStripVisible () {
  71. return !this.filmStrip.hasClass('hidden');
  72. },
  73. setupFilmStripOnly () {
  74. this.filmStrip.css({
  75. padding: "0px 0px 18px 0px",
  76. right: 0
  77. });
  78. },
  79. getFilmStripHeight () {
  80. if (this.isFilmStripVisible()) {
  81. return this.filmStrip.outerHeight();
  82. } else {
  83. return 0;
  84. }
  85. },
  86. getFilmStripWidth () {
  87. return this.filmStrip.innerWidth()
  88. - parseInt(this.filmStrip.css('paddingLeft'), 10)
  89. - parseInt(this.filmStrip.css('paddingRight'), 10);
  90. },
  91. calculateThumbnailSize() {
  92. let availableSizes = this.calculateAvailableSize();
  93. let width = availableSizes.availableWidth;
  94. let height = availableSizes.availableHeight;
  95. return this.calculateThumbnailSizeFromAvailable(width, height);
  96. },
  97. /**
  98. * Normalizes local and remote thumbnail ratios
  99. */
  100. normalizeThumbnailRatio () {
  101. let remoteHeightRatio = interfaceConfig.REMOTE_THUMBNAIL_RATIO_HEIGHT;
  102. let remoteWidthRatio = interfaceConfig.REMOTE_THUMBNAIL_RATIO_WIDTH;
  103. let localHeightRatio = interfaceConfig.LOCAL_THUMBNAIL_RATIO_HEIGHT;
  104. let localWidthRatio = interfaceConfig.LOCAL_THUMBNAIL_RATIO_WIDTH;
  105. let commonHeightRatio = remoteHeightRatio * localHeightRatio;
  106. let localRatioCoefficient = localWidthRatio / localHeightRatio;
  107. let remoteRatioCoefficient = remoteWidthRatio / remoteHeightRatio;
  108. remoteWidthRatio = commonHeightRatio * remoteRatioCoefficient;
  109. remoteHeightRatio = commonHeightRatio;
  110. localWidthRatio = commonHeightRatio * localRatioCoefficient;
  111. localHeightRatio = commonHeightRatio;
  112. let localRatio = {
  113. widthRatio: localWidthRatio,
  114. heightRatio: localHeightRatio
  115. };
  116. let remoteRatio = {
  117. widthRatio: remoteWidthRatio,
  118. heightRatio: remoteHeightRatio
  119. };
  120. return { localRatio, remoteRatio };
  121. },
  122. calculateAvailableSize() {
  123. let availableHeight = interfaceConfig.FILM_STRIP_MAX_HEIGHT;
  124. let thumbs = this.getThumbs(true);
  125. let numvids = thumbs.remoteThumbs.length;
  126. let localVideoContainer = $("#localVideoContainer");
  127. /**
  128. * If the videoAreaAvailableWidth is set we use this one to calculate
  129. * the filmStrip width, because we're probably in a state where the
  130. * film strip size hasn't been updated yet, but it will be.
  131. */
  132. let videoAreaAvailableWidth
  133. = UIUtil.getAvailableVideoWidth()
  134. - UIUtil.parseCssInt(this.filmStrip.css('right'), 10)
  135. - UIUtil.parseCssInt(this.filmStrip.css('paddingLeft'), 10)
  136. - UIUtil.parseCssInt(this.filmStrip.css('paddingRight'), 10)
  137. - UIUtil.parseCssInt(this.filmStrip.css('borderLeftWidth'), 10)
  138. - UIUtil.parseCssInt(this.filmStrip.css('borderRightWidth'), 10)
  139. - 5;
  140. let availableWidth = videoAreaAvailableWidth;
  141. // If local thumb is not hidden
  142. if(thumbs.localThumb) {
  143. availableWidth = Math.floor(
  144. (videoAreaAvailableWidth - (
  145. UIUtil.parseCssInt(
  146. localVideoContainer.css('borderLeftWidth'), 10)
  147. + UIUtil.parseCssInt(
  148. localVideoContainer.css('borderRightWidth'), 10)
  149. + UIUtil.parseCssInt(
  150. localVideoContainer.css('paddingLeft'), 10)
  151. + UIUtil.parseCssInt(
  152. localVideoContainer.css('paddingRight'), 10)
  153. + UIUtil.parseCssInt(
  154. localVideoContainer.css('marginLeft'), 10)
  155. + UIUtil.parseCssInt(
  156. localVideoContainer.css('marginRight'), 10)))
  157. );
  158. }
  159. // If the number of videos is 0 or undefined we don't need to calculate
  160. // further.
  161. if (numvids) {
  162. let remoteVideoContainer = thumbs.remoteThumbs.eq(0);
  163. availableWidth = Math.floor(
  164. (videoAreaAvailableWidth - numvids * (
  165. UIUtil.parseCssInt(
  166. remoteVideoContainer.css('borderLeftWidth'), 10)
  167. + UIUtil.parseCssInt(
  168. remoteVideoContainer.css('borderRightWidth'), 10)
  169. + UIUtil.parseCssInt(
  170. remoteVideoContainer.css('paddingLeft'), 10)
  171. + UIUtil.parseCssInt(
  172. remoteVideoContainer.css('paddingRight'), 10)
  173. + UIUtil.parseCssInt(
  174. remoteVideoContainer.css('marginLeft'), 10)
  175. + UIUtil.parseCssInt(
  176. remoteVideoContainer.css('marginRight'), 10)))
  177. );
  178. }
  179. let maxHeight
  180. // If the MAX_HEIGHT property hasn't been specified
  181. // we have the static value.
  182. = Math.min(interfaceConfig.FILM_STRIP_MAX_HEIGHT || 120,
  183. availableHeight);
  184. availableHeight
  185. = Math.min(maxHeight, window.innerHeight - 18);
  186. return { availableWidth, availableHeight };
  187. },
  188. calculateThumbnailSizeFromAvailable(availableWidth, availableHeight) {
  189. let { localRatio, remoteRatio } = this.normalizeThumbnailRatio();
  190. let { remoteThumbs } = this.getThumbs(true);
  191. let remoteProportion = remoteRatio.widthRatio * remoteThumbs.length;
  192. let widthProportion = remoteProportion + localRatio.widthRatio;
  193. let heightUnit = availableHeight / localRatio.heightRatio;
  194. let widthUnit = availableWidth / widthProportion;
  195. if (heightUnit < widthUnit) {
  196. widthUnit = heightUnit;
  197. }
  198. else
  199. heightUnit = widthUnit;
  200. let localVideo = {
  201. thumbWidth: widthUnit * localRatio.widthRatio,
  202. thumbHeight: heightUnit * localRatio.heightRatio
  203. };
  204. let remoteVideo = {
  205. thumbWidth: widthUnit * remoteRatio.widthRatio,
  206. thumbHeight: widthUnit * remoteRatio.heightRatio
  207. };
  208. return {
  209. localVideo,
  210. remoteVideo
  211. };
  212. },
  213. resizeThumbnails (local, remote,
  214. animate = false, forceUpdate = false) {
  215. return new Promise(resolve => {
  216. let thumbs = this.getThumbs(!forceUpdate);
  217. if(thumbs.localThumb)
  218. thumbs.localThumb.animate({
  219. height: local.thumbHeight,
  220. width: local.thumbWidth
  221. }, {
  222. queue: false,
  223. duration: animate ? 500 : 0,
  224. complete: resolve
  225. });
  226. if(thumbs.remoteThumbs)
  227. thumbs.remoteThumbs.animate({
  228. height: remote.thumbHeight,
  229. width: remote.thumbWidth
  230. }, {
  231. queue: false,
  232. duration: animate ? 500 : 0,
  233. complete: resolve
  234. });
  235. this.filmStrip.animate({
  236. // adds 2 px because of small video 1px border
  237. height: remote.thumbHeight + 2
  238. }, {
  239. queue: false,
  240. duration: animate ? 500 : 0
  241. });
  242. if (!animate) {
  243. resolve();
  244. }
  245. });
  246. },
  247. getThumbs (only_visible = false) {
  248. let selector = 'span';
  249. if (only_visible) {
  250. selector += ':visible';
  251. }
  252. let localThumb = $("#localVideoContainer");
  253. let remoteThumbs = this.filmStrip.children(selector)
  254. .not("#localVideoContainer");
  255. // Exclude the local video container if it has been hidden.
  256. if (localThumb.hasClass("hidden")) {
  257. return { remoteThumbs };
  258. } else {
  259. return { remoteThumbs, localThumb };
  260. }
  261. }
  262. };
  263. export default FilmStrip;