controller.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. import utils from './utils';
  2. import Thumbnails from './thumbnails';
  3. import Icons from './icons';
  4. class Controller {
  5. constructor(player) {
  6. this.player = player;
  7. this.autoHideTimer = 0;
  8. if (!utils.isMobile) {
  9. this.player.container.addEventListener('mousemove', () => {
  10. this.setAutoHide();
  11. });
  12. this.player.container.addEventListener('click', () => {
  13. this.setAutoHide();
  14. });
  15. this.player.on('play', () => {
  16. this.setAutoHide();
  17. });
  18. this.player.on('pause', () => {
  19. this.setAutoHide();
  20. });
  21. }
  22. this.initPlayButton();
  23. this.initThumbnails();
  24. this.initPlayedBar();
  25. this.initFullButton();
  26. this.initQualityButton();
  27. this.initScreenshotButton();
  28. this.initSubtitleButton();
  29. this.initHighlights();
  30. if (utils.isSafari) {
  31. this.initAirplayButton();
  32. }
  33. if (!utils.isMobile) {
  34. this.initVolumeButton();
  35. }
  36. }
  37. initPlayButton() {
  38. this.player.template.playButton.addEventListener('click', () => {
  39. this.player.toggle();
  40. });
  41. this.player.template.mobilePlayButton.addEventListener('click', () => {
  42. this.player.toggle();
  43. });
  44. if (!utils.isMobile) {
  45. this.player.template.videoWrap.addEventListener('click', () => {
  46. this.player.toggle();
  47. });
  48. this.player.template.controllerMask.addEventListener('click', () => {
  49. this.player.toggle();
  50. });
  51. } else {
  52. this.player.template.videoWrap.addEventListener('click', () => {
  53. this.toggle();
  54. });
  55. this.player.template.controllerMask.addEventListener('click', () => {
  56. this.toggle();
  57. });
  58. }
  59. }
  60. initHighlights() {
  61. this.player.on('durationchange', () => {
  62. if (this.player.video.duration !== 1 && this.player.video.duration !== Infinity) {
  63. if (this.player.options.highlight) {
  64. const highlights = document.querySelectorAll('.dplayer-highlight');
  65. [].slice.call(highlights, 0).forEach((item) => {
  66. this.player.template.playedBarWrap.removeChild(item);
  67. });
  68. for (let i = 0; i < this.player.options.highlight.length; i++) {
  69. if (!this.player.options.highlight[i].text || !this.player.options.highlight[i].time) {
  70. continue;
  71. }
  72. const p = document.createElement('div');
  73. p.classList.add('dplayer-highlight');
  74. p.style.left = (this.player.options.highlight[i].time / this.player.video.duration) * 100 + '%';
  75. p.innerHTML = '<span class="dplayer-highlight-text">' + this.player.options.highlight[i].text + '</span>';
  76. this.player.template.playedBarWrap.insertBefore(p, this.player.template.playedBarTime);
  77. }
  78. }
  79. }
  80. });
  81. }
  82. initThumbnails() {
  83. if (this.player.options.video.thumbnails) {
  84. this.thumbnails = new Thumbnails({
  85. container: this.player.template.barPreview,
  86. barWidth: this.player.template.barWrap.offsetWidth,
  87. url: this.player.options.video.thumbnails,
  88. events: this.player.events,
  89. });
  90. this.player.on('loadedmetadata', () => {
  91. this.thumbnails.resize(160, (this.player.video.videoHeight / this.player.video.videoWidth) * 160, this.player.template.barWrap.offsetWidth);
  92. });
  93. }
  94. }
  95. initPlayedBar() {
  96. const thumbMove = (e) => {
  97. let percentage = ((e.clientX || e.changedTouches[0].clientX) - utils.getBoundingClientRectViewLeft(this.player.template.playedBarWrap)) / this.player.template.playedBarWrap.clientWidth;
  98. percentage = Math.max(percentage, 0);
  99. percentage = Math.min(percentage, 1);
  100. this.player.bar.set('played', percentage, 'width');
  101. this.player.template.ptime.innerHTML = utils.secondToTime(percentage * this.player.video.duration);
  102. };
  103. const thumbUp = (e) => {
  104. document.removeEventListener(utils.nameMap.dragEnd, thumbUp);
  105. document.removeEventListener(utils.nameMap.dragMove, thumbMove);
  106. let percentage = ((e.clientX || e.changedTouches[0].clientX) - utils.getBoundingClientRectViewLeft(this.player.template.playedBarWrap)) / this.player.template.playedBarWrap.clientWidth;
  107. percentage = Math.max(percentage, 0);
  108. percentage = Math.min(percentage, 1);
  109. this.player.bar.set('played', percentage, 'width');
  110. this.player.seek(this.player.bar.get('played') * this.player.video.duration);
  111. this.player.timer.enable('progress');
  112. };
  113. this.player.template.playedBarWrap.addEventListener(utils.nameMap.dragStart, () => {
  114. this.player.timer.disable('progress');
  115. document.addEventListener(utils.nameMap.dragMove, thumbMove);
  116. document.addEventListener(utils.nameMap.dragEnd, thumbUp);
  117. });
  118. this.player.template.playedBarWrap.addEventListener(utils.nameMap.dragMove, (e) => {
  119. if (this.player.video.duration) {
  120. const px = this.player.template.playedBarWrap.getBoundingClientRect().left;
  121. const tx = (e.clientX || e.changedTouches[0].clientX) - px;
  122. if (tx < 0 || tx > this.player.template.playedBarWrap.offsetWidth) {
  123. return;
  124. }
  125. const time = this.player.video.duration * (tx / this.player.template.playedBarWrap.offsetWidth);
  126. if (utils.isMobile) {
  127. this.thumbnails && this.thumbnails.show();
  128. }
  129. this.thumbnails && this.thumbnails.move(tx);
  130. this.player.template.playedBarTime.style.left = `${tx - (time >= 3600 ? 25 : 20)}px`;
  131. this.player.template.playedBarTime.innerText = utils.secondToTime(time);
  132. this.player.template.playedBarTime.classList.remove('hidden');
  133. }
  134. });
  135. this.player.template.playedBarWrap.addEventListener(utils.nameMap.dragEnd, () => {
  136. if (utils.isMobile) {
  137. this.thumbnails && this.thumbnails.hide();
  138. }
  139. });
  140. if (!utils.isMobile) {
  141. this.player.template.playedBarWrap.addEventListener('mouseenter', () => {
  142. if (this.player.video.duration) {
  143. this.thumbnails && this.thumbnails.show();
  144. this.player.template.playedBarTime.classList.remove('hidden');
  145. }
  146. });
  147. this.player.template.playedBarWrap.addEventListener('mouseleave', () => {
  148. if (this.player.video.duration) {
  149. this.thumbnails && this.thumbnails.hide();
  150. this.player.template.playedBarTime.classList.add('hidden');
  151. }
  152. });
  153. }
  154. }
  155. initFullButton() {
  156. this.player.template.browserFullButton.addEventListener('click', () => {
  157. this.player.fullScreen.toggle('browser');
  158. });
  159. this.player.template.webFullButton.addEventListener('click', () => {
  160. this.player.fullScreen.toggle('web');
  161. });
  162. }
  163. initVolumeButton() {
  164. const vWidth = 35;
  165. const volumeMove = (event) => {
  166. const e = event || window.event;
  167. const percentage = ((e.clientX || e.changedTouches[0].clientX) - utils.getBoundingClientRectViewLeft(this.player.template.volumeBarWrap) - 5.5) / vWidth;
  168. this.player.volume(percentage);
  169. };
  170. const volumeUp = () => {
  171. document.removeEventListener(utils.nameMap.dragEnd, volumeUp);
  172. document.removeEventListener(utils.nameMap.dragMove, volumeMove);
  173. this.player.template.volumeButton.classList.remove('dplayer-volume-active');
  174. };
  175. this.player.template.volumeBarWrapWrap.addEventListener('click', (event) => {
  176. const e = event || window.event;
  177. const percentage = ((e.clientX || e.changedTouches[0].clientX) - utils.getBoundingClientRectViewLeft(this.player.template.volumeBarWrap) - 5.5) / vWidth;
  178. this.player.volume(percentage);
  179. });
  180. this.player.template.volumeBarWrapWrap.addEventListener(utils.nameMap.dragStart, () => {
  181. document.addEventListener(utils.nameMap.dragMove, volumeMove);
  182. document.addEventListener(utils.nameMap.dragEnd, volumeUp);
  183. this.player.template.volumeButton.classList.add('dplayer-volume-active');
  184. });
  185. this.player.template.volumeButtonIcon.addEventListener('click', () => {
  186. if (this.player.video.muted) {
  187. this.player.video.muted = false;
  188. this.player.switchVolumeIcon();
  189. this.player.bar.set('volume', this.player.volume(), 'width');
  190. } else {
  191. this.player.video.muted = true;
  192. this.player.template.volumeIcon.innerHTML = Icons.volumeOff;
  193. this.player.bar.set('volume', 0, 'width');
  194. }
  195. });
  196. }
  197. initQualityButton() {
  198. if (this.player.options.video.quality) {
  199. this.player.template.qualityList.addEventListener('click', (e) => {
  200. if (e.target.classList.contains('dplayer-quality-item')) {
  201. this.player.switchQuality(e.target.dataset.index);
  202. }
  203. });
  204. }
  205. }
  206. initScreenshotButton() {
  207. if (this.player.options.screenshot) {
  208. this.player.template.camareButton.addEventListener('click', () => {
  209. const canvas = document.createElement('canvas');
  210. canvas.width = this.player.video.videoWidth;
  211. canvas.height = this.player.video.videoHeight;
  212. canvas.getContext('2d').drawImage(this.player.video, 0, 0, canvas.width, canvas.height);
  213. let dataURL;
  214. canvas.toBlob((blob) => {
  215. dataURL = URL.createObjectURL(blob);
  216. const link = document.createElement('a');
  217. link.href = dataURL;
  218. link.download = 'DPlayer.png';
  219. link.style.display = 'none';
  220. document.body.appendChild(link);
  221. link.click();
  222. document.body.removeChild(link);
  223. URL.revokeObjectURL(dataURL);
  224. });
  225. this.player.events.trigger('screenshot', dataURL);
  226. });
  227. }
  228. }
  229. initAirplayButton() {
  230. if (this.player.options.airplay) {
  231. if (window.WebKitPlaybackTargetAvailabilityEvent) {
  232. this.player.video.addEventListener(
  233. 'webkitplaybacktargetavailabilitychanged',
  234. function (event) {
  235. switch (event.availability) {
  236. case 'available':
  237. this.template.airplayButton.disable = false;
  238. break;
  239. default:
  240. this.template.airplayButton.disable = true;
  241. }
  242. this.template.airplayButton.addEventListener(
  243. 'click',
  244. function () {
  245. this.video.webkitShowPlaybackTargetPicker();
  246. }.bind(this)
  247. );
  248. }.bind(this.player)
  249. );
  250. } else {
  251. this.player.template.airplayButton.style.display = 'none';
  252. }
  253. }
  254. }
  255. initSubtitleButton() {
  256. if (this.player.options.subtitle) {
  257. this.player.events.on('subtitle_show', () => {
  258. this.player.template.subtitleButton.dataset.balloon = this.player.tran('Hide subtitle');
  259. this.player.template.subtitleButtonInner.style.opacity = '';
  260. this.player.user.set('subtitle', 1);
  261. });
  262. this.player.events.on('subtitle_hide', () => {
  263. this.player.template.subtitleButton.dataset.balloon = this.player.tran('Show subtitle');
  264. this.player.template.subtitleButtonInner.style.opacity = '0.4';
  265. this.player.user.set('subtitle', 0);
  266. });
  267. this.player.template.subtitleButton.addEventListener('click', () => {
  268. this.player.subtitle.toggle();
  269. });
  270. }
  271. }
  272. setAutoHide() {
  273. this.show();
  274. clearTimeout(this.autoHideTimer);
  275. this.autoHideTimer = setTimeout(() => {
  276. if (this.player.video.played.length && !this.player.paused && !this.disableAutoHide) {
  277. this.hide();
  278. }
  279. }, 3000);
  280. }
  281. show() {
  282. this.player.container.classList.remove('dplayer-hide-controller');
  283. }
  284. hide() {
  285. this.player.container.classList.add('dplayer-hide-controller');
  286. this.player.setting.hide();
  287. this.player.comment && this.player.comment.hide();
  288. }
  289. isShow() {
  290. return !this.player.container.classList.contains('dplayer-hide-controller');
  291. }
  292. toggle() {
  293. if (this.isShow()) {
  294. this.hide();
  295. } else {
  296. this.show();
  297. }
  298. }
  299. destroy() {
  300. clearTimeout(this.autoHideTimer);
  301. }
  302. }
  303. export default Controller;