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.

ConnectionIndicator.js 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. import React, { Component } from 'react';
  2. import JitsiPopover from '../../../../modules/UI/util/JitsiPopover';
  3. import { JitsiParticipantConnectionStatus } from '../../base/lib-jitsi-meet';
  4. import { ConnectionStatsTable } from '../../connection-stats';
  5. declare var $: Object;
  6. declare var interfaceConfig: Object;
  7. // Converts the percent for connection quality into a string recognized for CSS.
  8. const QUALITY_TO_WIDTH = [
  9. // Full (5 bars)
  10. {
  11. percent: 80,
  12. width: '100%'
  13. },
  14. // 4 bars
  15. {
  16. percent: 60,
  17. width: '80%'
  18. },
  19. // 3 bars
  20. {
  21. percent: 40,
  22. width: '55%'
  23. },
  24. // 2 bars
  25. {
  26. percent: 20,
  27. width: '40%'
  28. },
  29. // 1 bar
  30. {
  31. percent: 0,
  32. width: '20%'
  33. }
  34. // Note: we never show 0 bars.
  35. ];
  36. /**
  37. * Implements a React {@link Component} which displays the current connection
  38. * quality percentage and has a popover to show more detailed connection stats.
  39. *
  40. * @extends {Component}
  41. */
  42. class ConnectionIndicator extends Component {
  43. /**
  44. * {@code ConnectionIndicator} component's property types.
  45. *
  46. * @static
  47. */
  48. static propTypes = {
  49. /**
  50. * Whether or not the displays stats are for local video.
  51. */
  52. isLocalVideo: React.PropTypes.bool,
  53. /**
  54. * The callback to invoke when the hover state over the popover changes.
  55. */
  56. onHover: React.PropTypes.func,
  57. /**
  58. * Whether or not the popover should display a link that can toggle
  59. * a more detailed view of the stats.
  60. */
  61. showMoreLink: React.PropTypes.bool,
  62. /**
  63. * An object that contains statistics related to connection quality.
  64. *
  65. * {
  66. * bandwidth: Object,
  67. * bitrate: Object,
  68. * connectionStatus: String,
  69. * framerate: Object,
  70. * packetLoss: Object,
  71. * percent: Number,
  72. * resolution: Object,
  73. * transport: Array
  74. * }
  75. */
  76. stats: React.PropTypes.object,
  77. /**
  78. * Invoked to obtain translated strings.
  79. */
  80. t: React.PropTypes.func
  81. };
  82. /**
  83. * Initializes a new {@code ConnectionIndicator} instance.
  84. *
  85. * @param {Object} props - The read-only properties with which the new
  86. * instance is to be initialized.
  87. */
  88. constructor(props) {
  89. super(props);
  90. /**
  91. * The internal reference to topmost DOM/HTML element backing the React
  92. * {@code Component}. Accessed directly for associating an element as
  93. * the trigger for a popover.
  94. *
  95. * @private
  96. * @type {HTMLDivElement}
  97. */
  98. this._rootElement = null;
  99. this.state = {
  100. /**
  101. * Whether or not the popover content should display additional
  102. * statistics.
  103. *
  104. * @type {boolean}
  105. */
  106. showMoreStats: false
  107. };
  108. // Bind event handlers so they are only bound once for every instance.
  109. this._onToggleShowMore = this._onToggleShowMore.bind(this);
  110. this._setRootElement = this._setRootElement.bind(this);
  111. }
  112. /**
  113. * Creates a popover instance to display when the component is hovered.
  114. *
  115. * @inheritdoc
  116. * returns {void}
  117. */
  118. componentDidMount() {
  119. this.popover = new JitsiPopover($(this._rootElement), {
  120. content: this._renderStatisticsTable(),
  121. skin: 'black',
  122. position: interfaceConfig.VERTICAL_FILMSTRIP ? 'left' : 'top'
  123. });
  124. this.popover.addOnHoverPopover(this.props.onHover);
  125. }
  126. /**
  127. * Updates the contents of the popover. This is done manually because the
  128. * popover is not a React Component yet and so is not automatiucally aware
  129. * of changed data.
  130. *
  131. * @inheritdoc
  132. * returns {void}
  133. */
  134. componentDidUpdate() {
  135. this.popover.updateContent(this._renderStatisticsTable());
  136. }
  137. /**
  138. * Cleans up any popover instance that is linked to the component.
  139. *
  140. * @inheritdoc
  141. * returns {void}
  142. */
  143. componentWillUnmount() {
  144. this.popover.forceHide();
  145. this.popover.remove();
  146. }
  147. /**
  148. * Implements React's {@link Component#render()}.
  149. *
  150. * @inheritdoc
  151. * @returns {ReactElement}
  152. */
  153. render() {
  154. return (
  155. <div
  156. className = 'connection-indicator indicator'
  157. ref = { this._setRootElement }>
  158. <div className = 'connection indicatoricon'>
  159. { this._renderIcon() }
  160. </div>
  161. </div>
  162. );
  163. }
  164. /**
  165. * Callback to invoke when the show more link in the popover content is
  166. * clicked. Sets the state which will determine if the popover should show
  167. * additional statistics about the connection.
  168. *
  169. * @returns {void}
  170. */
  171. _onToggleShowMore() {
  172. this.setState({ showMoreStats: !this.state.showMoreStats });
  173. }
  174. /**
  175. * Creates a ReactElement for displaying an icon that represents the current
  176. * connection quality.
  177. *
  178. * @returns {ReactElement}
  179. */
  180. _renderIcon() {
  181. switch (this.props.stats.connectionStatus) {
  182. case JitsiParticipantConnectionStatus.INTERRUPTED:
  183. return (
  184. <span className = 'connection_lost'>
  185. <i className = 'icon-connection-lost' />
  186. </span>
  187. );
  188. case JitsiParticipantConnectionStatus.INACTIVE:
  189. return (
  190. <span className = 'connection_ninja'>
  191. <i className = 'icon-ninja' />
  192. </span>
  193. );
  194. default: {
  195. const { percent } = this.props.stats;
  196. const width = QUALITY_TO_WIDTH.find(x => percent >= x.percent);
  197. const iconWidth = width && width.width
  198. ? { width: width && width.width } : {};
  199. return [
  200. <span
  201. className = 'connection_empty'
  202. key = 'icon-empty'>
  203. <i className = 'icon-connection' />
  204. </span>,
  205. <span
  206. className = 'connection_full'
  207. key = 'icon-full'
  208. style = { iconWidth }>
  209. <i className = 'icon-connection' />
  210. </span>
  211. ];
  212. }
  213. }
  214. }
  215. /**
  216. * Creates a {@code ConnectionStatisticsTable} instance.
  217. *
  218. * @returns {ReactElement}
  219. */
  220. _renderStatisticsTable() {
  221. const {
  222. bandwidth,
  223. bitrate,
  224. framerate,
  225. packetLoss,
  226. resolution,
  227. transport
  228. } = this.props.stats;
  229. return (
  230. <ConnectionStatsTable
  231. bandwidth = { bandwidth }
  232. bitrate = { bitrate }
  233. framerate = { framerate }
  234. isLocalVideo = { this.props.isLocalVideo }
  235. onShowMore = { this._onToggleShowMore }
  236. packetLoss = { packetLoss }
  237. resolution = { resolution }
  238. shouldShowMore = { this.state.showMoreStats }
  239. transport = { transport } />
  240. );
  241. }
  242. /**
  243. * Sets an internal reference to the component's root element.
  244. *
  245. * @param {Object} element - The highest DOM element in the component.
  246. * @private
  247. * @returns {void}
  248. */
  249. _setRootElement(element) {
  250. this._rootElement = element;
  251. }
  252. }
  253. export default ConnectionIndicator;