Earcon.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /* *
  2. *
  3. * (c) 2009-2020 Øystein Moseng
  4. *
  5. * Earcons for the sonification module in Highcharts.
  6. *
  7. * License: www.highcharts.com/license
  8. *
  9. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  10. *
  11. * */
  12. 'use strict';
  13. import H from '../../Core/Globals.js';
  14. import U from '../../Core/Utilities.js';
  15. var error = U.error, merge = U.merge, pick = U.pick, uniqueKey = U.uniqueKey;
  16. /**
  17. * Define an Instrument and the options for playing it.
  18. *
  19. * @requires module:modules/sonification
  20. *
  21. * @interface Highcharts.EarconInstrument
  22. */ /**
  23. * An instrument instance or the name of the instrument in the
  24. * Highcharts.sonification.instruments map.
  25. * @name Highcharts.EarconInstrument#instrument
  26. * @type {string|Highcharts.Instrument}
  27. */ /**
  28. * The options to pass to Instrument.play.
  29. * @name Highcharts.EarconInstrument#playOptions
  30. * @type {Highcharts.InstrumentPlayOptionsObject}
  31. */
  32. /**
  33. * Options for an Earcon.
  34. *
  35. * @requires module:modules/sonification
  36. *
  37. * @interface Highcharts.EarconOptionsObject
  38. */ /**
  39. * The instruments and their options defining this earcon.
  40. * @name Highcharts.EarconOptionsObject#instruments
  41. * @type {Array<Highcharts.EarconInstrument>}
  42. */ /**
  43. * The unique ID of the Earcon. Generated if not supplied.
  44. * @name Highcharts.EarconOptionsObject#id
  45. * @type {string|undefined}
  46. */ /**
  47. * Global panning of all instruments. Overrides all panning on individual
  48. * instruments. Can be a number between -1 and 1.
  49. * @name Highcharts.EarconOptionsObject#pan
  50. * @type {number|undefined}
  51. */ /**
  52. * Master volume for all instruments. Volume settings on individual instruments
  53. * can still be used for relative volume between the instruments. This setting
  54. * does not affect volumes set by functions in individual instruments. Can be a
  55. * number between 0 and 1. Defaults to 1.
  56. * @name Highcharts.EarconOptionsObject#volume
  57. * @type {number|undefined}
  58. */ /**
  59. * Callback function to call when earcon has finished playing.
  60. * @name Highcharts.EarconOptionsObject#onEnd
  61. * @type {Function|undefined}
  62. */
  63. /* eslint-disable no-invalid-this, valid-jsdoc */
  64. /**
  65. * The Earcon class. Earcon objects represent a certain sound consisting of
  66. * one or more instruments playing a predefined sound.
  67. *
  68. * @sample highcharts/sonification/earcon/
  69. * Using earcons directly
  70. *
  71. * @requires module:modules/sonification
  72. *
  73. * @class
  74. * @name Highcharts.Earcon
  75. *
  76. * @param {Highcharts.EarconOptionsObject} options
  77. * Options for the Earcon instance.
  78. */
  79. function Earcon(options) {
  80. this.init(options || {});
  81. }
  82. Earcon.prototype.init = function (options) {
  83. this.options = options;
  84. if (!this.options.id) {
  85. this.options.id = this.id = uniqueKey();
  86. }
  87. this.instrumentsPlaying = {};
  88. };
  89. /**
  90. * Play the earcon, optionally overriding init options.
  91. *
  92. * @sample highcharts/sonification/earcon/
  93. * Using earcons directly
  94. *
  95. * @function Highcharts.Earcon#sonify
  96. *
  97. * @param {Highcharts.EarconOptionsObject} options
  98. * Override existing options.
  99. *
  100. * @return {void}
  101. */
  102. Earcon.prototype.sonify = function (options) {
  103. var playOptions = merge(this.options, options);
  104. // Find master volume/pan settings
  105. var masterVolume = pick(playOptions.volume, 1), masterPan = playOptions.pan, earcon = this, playOnEnd = options && options.onEnd, masterOnEnd = earcon.options.onEnd;
  106. // Go through the instruments and play them
  107. playOptions.instruments.forEach(function (opts) {
  108. var instrument = typeof opts.instrument === 'string' ?
  109. H.sonification.instruments[opts.instrument] : opts.instrument, instrumentOpts = merge(opts.playOptions), instrOnEnd, instrumentCopy, copyId = '';
  110. if (instrument && instrument.play) {
  111. if (opts.playOptions) {
  112. instrumentOpts.pan = pick(masterPan, instrumentOpts.pan);
  113. // Handle onEnd
  114. instrOnEnd = instrumentOpts.onEnd;
  115. instrumentOpts.onEnd = function () {
  116. delete earcon.instrumentsPlaying[copyId];
  117. if (instrOnEnd) {
  118. instrOnEnd.apply(this, arguments);
  119. }
  120. if (!Object.keys(earcon.instrumentsPlaying).length) {
  121. if (playOnEnd) {
  122. playOnEnd.apply(this, arguments);
  123. }
  124. if (masterOnEnd) {
  125. masterOnEnd.apply(this, arguments);
  126. }
  127. }
  128. };
  129. // Play the instrument. Use a copy so we can play multiple at
  130. // the same time.
  131. instrumentCopy = instrument.copy();
  132. instrumentCopy.setMasterVolume(masterVolume);
  133. copyId = instrumentCopy.id;
  134. earcon.instrumentsPlaying[copyId] = instrumentCopy;
  135. instrumentCopy.play(instrumentOpts);
  136. }
  137. }
  138. else {
  139. error(30);
  140. }
  141. });
  142. };
  143. /**
  144. * Cancel any current sonification of the Earcon. Calls onEnd functions.
  145. *
  146. * @function Highcharts.Earcon#cancelSonify
  147. *
  148. * @param {boolean} [fadeOut=false]
  149. * Whether or not to fade out as we stop. If false, the earcon is
  150. * cancelled synchronously.
  151. *
  152. * @return {void}
  153. */
  154. Earcon.prototype.cancelSonify = function (fadeOut) {
  155. var playing = this.instrumentsPlaying, instrIds = playing && Object.keys(playing);
  156. if (instrIds && instrIds.length) {
  157. instrIds.forEach(function (instr) {
  158. playing[instr].stop(!fadeOut, null, 'cancelled');
  159. });
  160. this.instrumentsPlaying = {};
  161. }
  162. };
  163. export default Earcon;