Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

LargeVideoBackground.web.js 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. // @flow
  2. import React, { Component } from 'react';
  3. /**
  4. * Constants to describe the dimensions of the video. Landscape videos
  5. * are wider than they are taller and portrait videos are taller than they
  6. * are wider. The dimensions will determine how {@code LargeVideoBackground}
  7. * will strech to fill its container.
  8. *
  9. * @type {Object}
  10. */
  11. export const ORIENTATION = {
  12. LANDSCAPE: 'landscape',
  13. PORTRAIT: 'portrait'
  14. };
  15. /**
  16. * The type of the React {@code Component} props of
  17. * {@link LargeVideoBackgroundCanvas}.
  18. */
  19. type Props = {
  20. /**
  21. * Additional CSS class names to add to the root of the component.
  22. */
  23. className: String,
  24. /**
  25. * Whether or not the background should have its visibility hidden.
  26. */
  27. hidden: boolean,
  28. /**
  29. * Whether or not the video should display flipped horizontally, so left
  30. * becomes right and right becomes left.
  31. */
  32. mirror: boolean,
  33. /**
  34. * Whether the component should ensure full width of the video is displayed
  35. * (landscape) or full height (portrait).
  36. */
  37. orientationFit: string,
  38. /**
  39. * The video stream to display.
  40. */
  41. videoElement: Object
  42. };
  43. /**
  44. * Implements a React Component which shows a video element intended to be used
  45. * as a background to fill the empty space of container with another video.
  46. *
  47. * @extends Component
  48. */
  49. export class LargeVideoBackground extends Component<Props> {
  50. _canvasEl: Object;
  51. _updateCanvasInterval: *;
  52. /**
  53. * Initializes new {@code LargeVideoBackground} instance.
  54. *
  55. * @param {*} props - The read-only properties with which the new instance
  56. * is to be initialized.
  57. */
  58. constructor(props: Props) {
  59. super(props);
  60. // Bind event handlers so they are only bound once per instance.
  61. this._setCanvasEl = this._setCanvasEl.bind(this);
  62. this._updateCanvas = this._updateCanvas.bind(this);
  63. }
  64. /**
  65. * If the canvas is not hidden, sets the initial interval to update the
  66. * image displayed in the canvas.
  67. *
  68. * @inheritdoc
  69. * @returns {void}
  70. */
  71. componentDidMount() {
  72. if (this.props.videoElement && !this.props.hidden) {
  73. this._updateCanvas();
  74. this._setUpdateCanvasInterval();
  75. }
  76. }
  77. /**
  78. * Starts or stops the interval to update the image displayed in the canvas.
  79. *
  80. * @inheritdoc
  81. */
  82. componentDidUpdate(prevProps: Props) {
  83. if (prevProps.hidden && !this.props.hidden) {
  84. this._clearCanvas();
  85. this._setUpdateCanvasInterval();
  86. }
  87. if ((!prevProps.hidden && this.props.hidden)
  88. || !this.props.videoElement) {
  89. this._clearCanvas();
  90. this._clearUpdateCanvasInterval();
  91. }
  92. }
  93. /**
  94. * Clears the interval for updating the image displayed in the canvas.
  95. *
  96. * @inheritdoc
  97. */
  98. componentWillUnmount() {
  99. this._clearUpdateCanvasInterval();
  100. }
  101. /**
  102. * Implements React's {@link Component#render()}.
  103. *
  104. * @inheritdoc
  105. * @returns {ReactElement}
  106. */
  107. render() {
  108. const {
  109. hidden,
  110. mirror
  111. } = this.props;
  112. const classNames = `large-video-background ${mirror ? 'flip-x' : ''} ${hidden ? 'invisible' : ''}`;
  113. return (
  114. <div className = { classNames }>
  115. <canvas
  116. id = 'largeVideoBackground'
  117. ref = { this._setCanvasEl } />
  118. </div>
  119. );
  120. }
  121. /**
  122. * Removes any image displayed on the canvas.
  123. *
  124. * @private
  125. * @returns {void}
  126. */
  127. _clearCanvas() {
  128. const cavnasContext = this._canvasEl.getContext('2d');
  129. cavnasContext.clearRect(
  130. 0, 0, this._canvasEl.width, this._canvasEl.height);
  131. }
  132. /**
  133. * Clears the interval for updating the image displayed in the canvas.
  134. *
  135. * @private
  136. * @returns {void}
  137. */
  138. _clearUpdateCanvasInterval() {
  139. clearInterval(this._updateCanvasInterval);
  140. }
  141. _setCanvasEl: () => void;
  142. /**
  143. * Sets the instance variable for the component's canvas element so it can
  144. * be accessed directly for drawing on.
  145. *
  146. * @param {Object} element - The DOM element for the component's canvas.
  147. * @private
  148. * @returns {void}
  149. */
  150. _setCanvasEl(element) {
  151. this._canvasEl = element;
  152. }
  153. /**
  154. * Starts the interval for updating the image displayed in the canvas.
  155. *
  156. * @private
  157. * @returns {void}
  158. */
  159. _setUpdateCanvasInterval() {
  160. this._clearUpdateCanvasInterval();
  161. this._updateCanvasInterval = setInterval(this._updateCanvas, 200);
  162. }
  163. _updateCanvas: () => void;
  164. /**
  165. * Draws the current frame of the passed in video element onto the canvas.
  166. *
  167. * @private
  168. * @returns {void}
  169. */
  170. _updateCanvas() {
  171. const { videoElement } = this.props;
  172. const { videoWidth, videoHeight } = videoElement;
  173. const {
  174. height: canvasHeight,
  175. width: canvasWidth
  176. } = this._canvasEl;
  177. const cavnasContext = this._canvasEl.getContext('2d');
  178. if (this.props.orientationFit === ORIENTATION.LANDSCAPE) {
  179. const heightScaledToFit = (canvasWidth / videoWidth) * videoHeight;
  180. cavnasContext.drawImage(
  181. videoElement, 0, 0, canvasWidth, heightScaledToFit);
  182. } else {
  183. const widthScaledToFit = (canvasHeight / videoHeight) * videoWidth;
  184. cavnasContext.drawImage(
  185. videoElement, 0, 0, widthScaledToFit, canvasHeight);
  186. }
  187. }
  188. }