maidr 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/.Rbuildignore +1 -0
  2. package/.eslintignore +3 -0
  3. package/.eslintrc.json +6 -0
  4. package/.github/workflows/build.yml +20 -0
  5. package/.prettierignore +3 -0
  6. package/.prettierrc.json +7 -0
  7. package/.vscode/extensions.json +25 -0
  8. package/.vscode/settings.json +30 -0
  9. package/.vscode/tasks.json +57 -0
  10. package/CHANGELOG.md +7 -0
  11. package/CITATION.cff +21 -0
  12. package/CONTRIBUTING.md +87 -0
  13. package/LICENSE.md +595 -0
  14. package/README.md +341 -0
  15. package/dist/maidr.js +8851 -0
  16. package/dist/maidr.min.js +1 -0
  17. package/dist/styles.css +244 -0
  18. package/dist/styles.min.css +1 -0
  19. package/docs/Audio.html +1398 -0
  20. package/docs/Constants.html +256 -0
  21. package/docs/Description.html +582 -0
  22. package/docs/Helper.html +364 -0
  23. package/docs/LogError.html +905 -0
  24. package/docs/Menu.html +665 -0
  25. package/docs/Position.html +174 -0
  26. package/docs/Resources.html +338 -0
  27. package/docs/Review.html +333 -0
  28. package/docs/Tracker.html +965 -0
  29. package/docs/audio.js.html +635 -0
  30. package/docs/constants.js.html +1242 -0
  31. package/docs/display.js.html +1184 -0
  32. package/docs/fonts/OpenSans-Bold-webfont.eot +0 -0
  33. package/docs/fonts/OpenSans-Bold-webfont.svg +1830 -0
  34. package/docs/fonts/OpenSans-Bold-webfont.woff +0 -0
  35. package/docs/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
  36. package/docs/fonts/OpenSans-BoldItalic-webfont.svg +1830 -0
  37. package/docs/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
  38. package/docs/fonts/OpenSans-Italic-webfont.eot +0 -0
  39. package/docs/fonts/OpenSans-Italic-webfont.svg +1830 -0
  40. package/docs/fonts/OpenSans-Italic-webfont.woff +0 -0
  41. package/docs/fonts/OpenSans-Light-webfont.eot +0 -0
  42. package/docs/fonts/OpenSans-Light-webfont.svg +1831 -0
  43. package/docs/fonts/OpenSans-Light-webfont.woff +0 -0
  44. package/docs/fonts/OpenSans-LightItalic-webfont.eot +0 -0
  45. package/docs/fonts/OpenSans-LightItalic-webfont.svg +1835 -0
  46. package/docs/fonts/OpenSans-LightItalic-webfont.woff +0 -0
  47. package/docs/fonts/OpenSans-Regular-webfont.eot +0 -0
  48. package/docs/fonts/OpenSans-Regular-webfont.svg +1831 -0
  49. package/docs/fonts/OpenSans-Regular-webfont.woff +0 -0
  50. package/docs/fonts/OpenSans-Semibold-webfont.eot +0 -0
  51. package/docs/fonts/OpenSans-Semibold-webfont.svg +1830 -0
  52. package/docs/fonts/OpenSans-Semibold-webfont.ttf +0 -0
  53. package/docs/fonts/OpenSans-Semibold-webfont.woff +0 -0
  54. package/docs/fonts/OpenSans-SemiboldItalic-webfont.eot +0 -0
  55. package/docs/fonts/OpenSans-SemiboldItalic-webfont.svg +1830 -0
  56. package/docs/fonts/OpenSans-SemiboldItalic-webfont.ttf +0 -0
  57. package/docs/fonts/OpenSans-SemiboldItalic-webfont.woff +0 -0
  58. package/docs/index.html +66 -0
  59. package/docs/scripts/linenumber.js +25 -0
  60. package/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
  61. package/docs/scripts/prettify/lang-css.js +2 -0
  62. package/docs/scripts/prettify/prettify.js +28 -0
  63. package/docs/styles/jsdoc-default.css +692 -0
  64. package/docs/styles/prettify-jsdoc.css +111 -0
  65. package/docs/styles/prettify-tomorrow.css +132 -0
  66. package/examples/dev_charts/barplot.html +1056 -0
  67. package/examples/dev_charts/boxplot.html +1856 -0
  68. package/examples/dev_charts/boxplot_flipped.svg +727 -0
  69. package/examples/dev_charts/heatmap.html +1217 -0
  70. package/examples/dev_charts/scatterplot/displ.js +18 -0
  71. package/examples/dev_charts/scatterplot/histogram_for_residual.svg +595 -0
  72. package/examples/dev_charts/scatterplot/hwy.js +15 -0
  73. package/examples/dev_charts/scatterplot/layers/point_layer.json +938 -0
  74. package/examples/dev_charts/scatterplot/layers/smooth_layer.json +322 -0
  75. package/examples/dev_charts/scatterplot/point_layer.js +938 -0
  76. package/examples/dev_charts/scatterplot/prediction_array.js +31 -0
  77. package/examples/dev_charts/scatterplot/prediction_array.json +31 -0
  78. package/examples/dev_charts/scatterplot/residual_array.js +29 -0
  79. package/examples/dev_charts/scatterplot/residual_array.json +29 -0
  80. package/examples/dev_charts/scatterplot/scatterplot.svg +1428 -0
  81. package/examples/dev_charts/scatterplot/scatterplot_data.html +2838 -0
  82. package/examples/dev_charts/scatterplot/scatterplot_no_jitter_point_only.svg +1393 -0
  83. package/examples/dev_charts/scatterplot/scatterplot_no_jitter_with_bestfit.svg +1424 -0
  84. package/examples/dev_charts/scatterplot/scatterplot_no_jitter_with_loess_curve.svg +1402 -0
  85. package/examples/dev_charts/scatterplot/smooth_layer.js +322 -0
  86. package/examples/dev_charts/scatterplot.html +4560 -0
  87. package/examples/dodged_bar/dodged_bar.png +0 -0
  88. package/examples/dodged_bar/dodged_bar.svg +198 -0
  89. package/examples/dodged_bar/schema.json +41 -0
  90. package/examples/histogram/histogram_tutorial.svg +482 -0
  91. package/examples/histogram/histogram_tutorial_raw_data.json +362 -0
  92. package/examples/histogram/histogram_user_study.svg +578 -0
  93. package/examples/histogram/histogram_user_study_raw_data.json +362 -0
  94. package/examples/lineplot/lineplot_sample.svg +126 -0
  95. package/examples/lineplot/lineplot_sample_raw_data.json +1 -0
  96. package/examples/lineplot/point+lineplot_sample.svg +700 -0
  97. package/examples/other/audio_oscillator_boxplot.js +95 -0
  98. package/examples/other/barplot_labels.svg +314 -0
  99. package/examples/other/barplot_user_study.svg +313 -0
  100. package/examples/other/boxplot.html +927 -0
  101. package/examples/other/boxplot_data_frame.html +568 -0
  102. package/examples/other/boxplot_label.svg +751 -0
  103. package/examples/other/braille-display_boxplot.js +79 -0
  104. package/examples/other/control_boxplot.js +55 -0
  105. package/examples/other/draft.js +56 -0
  106. package/examples/other/getData.html +400 -0
  107. package/examples/other/getData.js +41 -0
  108. package/examples/other/ggplot_to_svg.R +371 -0
  109. package/examples/other/heatmap.svg +582 -0
  110. package/examples/other/heatmap_label.svg +608 -0
  111. package/examples/other/multiple_barplot.html +2250 -0
  112. package/examples/other/new_scatterplot_user_study_point_layer.json +122 -0
  113. package/examples/other/py_binder_output.html +1167 -0
  114. package/examples/other/scatterplot_label.svg +1429 -0
  115. package/examples/other/seaborn_plot.py +9 -0
  116. package/examples/other/svglite_bar.svg +136 -0
  117. package/examples/other/tutorial_boxplot.svg +727 -0
  118. package/examples/other/tutorial_boxplot_data.json +72 -0
  119. package/examples/other/user_study_boxplot.svg +676 -0
  120. package/examples/stacked_bar/schema.json +41 -0
  121. package/examples/stacked_bar/stack_bar.png +0 -0
  122. package/examples/stacked_bar/stacked_bar.svg +180 -0
  123. package/examples/stacked_normalized_bar/stacked_normalized_bar.png +0 -0
  124. package/examples/stacked_normalized_bar/stacked_normalized_bar.svg +189 -0
  125. package/examples/static/barplot.svg +263 -0
  126. package/examples/static/barplot_diamonds_gridSVG.svg +254 -0
  127. package/examples/static/boxplot.svg +424 -0
  128. package/examples/static/heatmap.svg +373 -0
  129. package/examples/static/heatmap_penguins_table.html +486 -0
  130. package/examples/static/scatterplot.svg +530 -0
  131. package/examples/svglite/task_heatmap.html +802 -0
  132. package/examples/svglite/task_heatmap.svg +111 -0
  133. package/examples/svglite/tutorial_bar.svg +136 -0
  134. package/examples/svglite/tutorial_bar_plot.html +504 -0
  135. package/examples/svglite/tutorial_boxplot.html +1850 -0
  136. package/examples/svglite/tutorial_boxplot.svg +727 -0
  137. package/examples/svglite/tutorial_scatterplot.html +3135 -0
  138. package/examples/svglite/tutorial_scatterplot.svg +311 -0
  139. package/gulpfile.js +49 -0
  140. package/index.html +40 -0
  141. package/jsconfig.json +10 -0
  142. package/jsdoc.json +19 -0
  143. package/package.json +47 -0
  144. package/src/css/styles.css +241 -0
  145. package/src/js/__tests__/audio.test.js +49 -0
  146. package/src/js/__tests__/constants.test.js +622 -0
  147. package/src/js/audio.js +575 -0
  148. package/src/js/barplot.js +254 -0
  149. package/src/js/boxplot.js +682 -0
  150. package/src/js/constants.js +1182 -0
  151. package/src/js/controls.js +3182 -0
  152. package/src/js/display.js +1124 -0
  153. package/src/js/heatmap.js +411 -0
  154. package/src/js/histogram.js +134 -0
  155. package/src/js/init.js +427 -0
  156. package/src/js/lineplot.js +219 -0
  157. package/src/js/scatterplot.js +619 -0
  158. package/src/js/segmented.js +268 -0
  159. package/user_study_pilot/binder_test.html +526 -0
  160. package/user_study_pilot/data/barplot_user_study.svg +492 -0
  161. package/user_study_pilot/data/barplot_user_study_raw_data.json +22 -0
  162. package/user_study_pilot/data/boxplot_tutorial.json +72 -0
  163. package/user_study_pilot/data/boxplot_tutorial_horizontal.svg +727 -0
  164. package/user_study_pilot/data/boxplot_user_study.json +52 -0
  165. package/user_study_pilot/data/boxplot_user_study_vertical.svg +675 -0
  166. package/user_study_pilot/data/boxplot_user_study_vertical_horizontal.svg +676 -0
  167. package/user_study_pilot/data/heatmap_user_study.svg +719 -0
  168. package/user_study_pilot/data/heatmap_user_study_raw_data.json +127 -0
  169. package/user_study_pilot/data/new_barplot_user_study.svg +269 -0
  170. package/user_study_pilot/data/new_heatmap_user_study.svg +367 -0
  171. package/user_study_pilot/data/new_scatterplot_user_study.svg +603 -0
  172. package/user_study_pilot/data/new_scatterplot_user_study_point_layer.json +122 -0
  173. package/user_study_pilot/data/scatterplot_user_study (1).svg +321 -0
  174. package/user_study_pilot/data/scatterplot_user_study.svg +603 -0
  175. package/user_study_pilot/data/scatterplot_user_study_point_layer.json +122 -0
  176. package/user_study_pilot/data/scatterplot_user_study_smooth_layer.json +322 -0
  177. package/user_study_pilot/intro.html +215 -0
  178. package/user_study_pilot/jaws_settings/Chrome.JDF +10 -0
  179. package/user_study_pilot/jaws_settings/Firefox.JDF +10 -0
  180. package/user_study_pilot/jaws_settings/backup_utf8/Chrome.JDF +10 -0
  181. package/user_study_pilot/jaws_settings/backup_utf8/Firefox.JDF +10 -0
  182. package/user_study_pilot/jaws_settings/backup_utf8/msedge.JDF +10 -0
  183. package/user_study_pilot/jaws_settings/msedge.JDF +10 -0
  184. package/user_study_pilot/nvda_settings/chrome.dic +10 -0
  185. package/user_study_pilot/nvda_settings/default.dic +10 -0
  186. package/user_study_pilot/nvda_settings/firefox.dic +10 -0
  187. package/user_study_pilot/nvda_settings/msedge.dic +10 -0
  188. package/user_study_pilot/scatterplot.html +4560 -0
  189. package/user_study_pilot/seaborn_test.html +1059 -0
  190. package/user_study_pilot/svglite_test.html +534 -0
  191. package/user_study_pilot/task1_bar_plot.html +1111 -0
  192. package/user_study_pilot/task2_heatmap.html +1661 -0
  193. package/user_study_pilot/task3_boxplot_horizontal.html +1690 -0
  194. package/user_study_pilot/task3_boxplot_vertical.html +1689 -0
  195. package/user_study_pilot/task4_scatterplot.html +2091 -0
  196. package/user_study_pilot/tutorial1_bar_plot.html +1159 -0
  197. package/user_study_pilot/tutorial2_heatmap.html +1276 -0
  198. package/user_study_pilot/tutorial3_boxplot_horizontal.html +1861 -0
  199. package/user_study_pilot/tutorial3_boxplot_vertical.html +1807 -0
  200. package/user_study_pilot/tutorial4_scatterplot.html +5893 -0
  201. package/user_study_pilot/tutorial5_histogram.html +1553 -0
  202. package/user_study_pilot/tutorial6_lineplot.html +1011 -0
  203. package/user_study_pilot/tutorial7_stacked.html +763 -0
  204. package/user_study_pilot/tutorial8_stacked_normalized.html +796 -0
  205. package/user_study_pilot/tutorial9_dodged_bar.html +831 -0
  206. package/user_study_pilot/voiceover_settings/user_study_VoiceOver Archive.voprefs +573 -0
@@ -0,0 +1,635 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <title>audio.js - Documentation</title>
7
+
8
+ <script src="scripts/prettify/prettify.js"></script>
9
+ <script src="scripts/prettify/lang-css.js"></script>
10
+ <!--[if lt IE 9]>
11
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
12
+ <![endif]-->
13
+ <link type="text/css" rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
14
+ <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
15
+ <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
16
+ </head>
17
+ <body>
18
+
19
+ <input type="checkbox" id="nav-trigger" class="nav-trigger" />
20
+ <label for="nav-trigger" class="navicon-button x">
21
+ <div class="navicon"></div>
22
+ </label>
23
+
24
+ <label for="nav-trigger" class="overlay"></label>
25
+
26
+ <nav>
27
+ <li class="nav-link nav-home-link"><a href="index.html">Home</a></li><li class="nav-heading">Classes</li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="Audio.html">Audio</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Audio.html#KillSmooth">KillSmooth</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Audio.html#PlayNull">PlayNull</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Audio.html#SlideBetween">SlideBetween</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Audio.html#compressorSetup">compressorSetup</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Audio.html#playOscillator">playOscillator</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Audio.html#playSmooth">playSmooth</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Audio.html#playTone">playTone</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="Constants.html">Constants</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="Description.html">Description</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Description.html#CreateComponent">CreateComponent</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Description.html#Destroy">Destroy</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Description.html#PopulateData">PopulateData</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Description.html#Toggle">Toggle</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="Helper.html">Helper</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Helper.html#.containsObject">containsObject</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="LogError.html">LogError</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="LogError.html#LogAbsentElement">LogAbsentElement</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="LogError.html#LogCriticalElement">LogCriticalElement</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="LogError.html#LogDifferentLengths">LogDifferentLengths</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="LogError.html#LogNotArray">LogNotArray</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="LogError.html#LogTooManyElements">LogTooManyElements</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="Menu.html">Menu</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Menu.html#CreateMenu">CreateMenu</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Menu.html#LoadDataFromLocalStorage">LoadDataFromLocalStorage</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Menu.html#PopulateData">PopulateData</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Menu.html#SaveData">SaveData</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Menu.html#Toggle">Toggle</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="Position.html">Position</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="Resources.html">Resources</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Resources.html#GetString">GetString</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="Review.html">Review</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Review.html#ToggleReviewMode">ToggleReviewMode</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="Tracker.html">Tracker</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Tracker.html#DataSetup">DataSetup</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Tracker.html#Delete">Delete</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Tracker.html#DownloadTrackerData">DownloadTrackerData</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Tracker.html#GetTrackerData">GetTrackerData</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Tracker.html#LogEvent">LogEvent</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Tracker.html#SaveTrackerData">SaveTrackerData</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Tracker.html#isUndefinedOrNull">isUndefinedOrNull</a></span></li>
28
+ </nav>
29
+
30
+ <div id="main">
31
+
32
+ <h1 class="page-title">audio.js</h1>
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+ <section>
41
+ <article>
42
+ <pre class="prettyprint source linenums"><code>/**
43
+ * Audio class
44
+ * Sets up audio stuff (compressor, gain),
45
+ * sets up an oscillator that has good falloff (no clipping sounds) and can be instanced to be played anytime and can handle overlaps,
46
+ * sets up an actual playTone function that plays tones based on current chart position
47
+ *
48
+ * @class
49
+ */
50
+ class Audio {
51
+ constructor() {
52
+ this.AudioContext = window['AudioContext'] || window['webkitAudioContext'];
53
+ this.audioContext = new AudioContext();
54
+ this.compressor = this.compressorSetup(this.audioContext);
55
+ }
56
+
57
+ /**
58
+ * Sets up a dynamics compressor for better audio quality.
59
+ * @returns {DynamicsCompressorNode} The created compressor.
60
+ */
61
+ compressorSetup() {
62
+ let compressor = this.audioContext.createDynamicsCompressor(); // create compressor for better audio quality
63
+
64
+ compressor.threshold.value = -50;
65
+ compressor.knee.value = 40;
66
+ compressor.ratio.value = 12;
67
+ compressor.attack.value = 0;
68
+ compressor.release.value = 0.25;
69
+ let gainMaster = this.audioContext.createGain(); // create master gain
70
+ gainMaster.gain.value = constants.vol;
71
+ compressor.connect(gainMaster);
72
+ gainMaster.connect(this.audioContext.destination);
73
+
74
+ return compressor;
75
+ }
76
+
77
+ // an oscillator is created and destroyed after some falloff
78
+ /**
79
+ * Plays a tone based on the current chart type and position.
80
+ */
81
+ playTone() {
82
+ let currentDuration = constants.duration;
83
+ let volume = constants.vol;
84
+
85
+ let rawPanning = 0;
86
+ let rawFreq = 0;
87
+ let frequency = 0;
88
+ let panning = 0;
89
+
90
+ let waveType = 'sine';
91
+
92
+ // freq goes between min / max as rawFreq goes between min(0) / max
93
+ if (constants.chartType == 'bar') {
94
+ rawFreq = plot.plotData[position.x];
95
+ rawPanning = position.x;
96
+ frequency = this.SlideBetween(
97
+ rawFreq,
98
+ constants.minY,
99
+ constants.maxY,
100
+ constants.MIN_FREQUENCY,
101
+ constants.MAX_FREQUENCY
102
+ );
103
+ panning = this.SlideBetween(
104
+ rawPanning,
105
+ constants.minX,
106
+ constants.maxX,
107
+ -1,
108
+ 1
109
+ );
110
+ } else if (constants.chartType == 'box') {
111
+ let plotPos =
112
+ constants.plotOrientation == 'vert' ? position.x : position.y;
113
+ let sectionKey = plot.GetSectionKey(
114
+ constants.plotOrientation == 'vert' ? position.y : position.x
115
+ );
116
+ if (Array.isArray(plot.plotData[plotPos][sectionKey])) {
117
+ // outliers are stored in values with a seperate itterator
118
+ rawFreq = plot.plotData[plotPos][sectionKey][position.z];
119
+ } else {
120
+ // normal points
121
+ rawFreq = plot.plotData[plotPos][sectionKey];
122
+ }
123
+ if (plot.plotData[plotPos][sectionKey] != null) {
124
+ if (constants.plotOrientation == 'vert') {
125
+ frequency = this.SlideBetween(
126
+ rawFreq,
127
+ constants.minY,
128
+ constants.maxY,
129
+ constants.MIN_FREQUENCY,
130
+ constants.MAX_FREQUENCY
131
+ );
132
+ panning = this.SlideBetween(
133
+ rawFreq,
134
+ constants.minY,
135
+ constants.maxY,
136
+ -1,
137
+ 1
138
+ );
139
+ } else {
140
+ frequency = this.SlideBetween(
141
+ rawFreq,
142
+ constants.minX,
143
+ constants.maxX,
144
+ constants.MIN_FREQUENCY,
145
+ constants.MAX_FREQUENCY
146
+ );
147
+ panning = this.SlideBetween(
148
+ rawFreq,
149
+ constants.minX,
150
+ constants.maxX,
151
+ -1,
152
+ 1
153
+ );
154
+ }
155
+ } else {
156
+ frequency = constants.MIN_FREQUENCY;
157
+ panning = 0;
158
+ }
159
+ } else if (constants.chartType == 'heat') {
160
+ rawFreq = plot.values[position.y][position.x];
161
+ rawPanning = position.x;
162
+ frequency = this.SlideBetween(
163
+ rawFreq,
164
+ constants.minY,
165
+ constants.maxY,
166
+ constants.MIN_FREQUENCY,
167
+ constants.MAX_FREQUENCY
168
+ );
169
+ panning = this.SlideBetween(
170
+ rawPanning,
171
+ constants.minX,
172
+ constants.maxX,
173
+ -1,
174
+ 1
175
+ );
176
+ } else if (
177
+ constants.chartType == 'point' ||
178
+ constants.chartType == 'smooth'
179
+ ) {
180
+ // are we using global min / max, or just this layer?
181
+ constants.globalMinMax = true;
182
+ let chartMin = constants.minY;
183
+ let chartMax = constants.maxY;
184
+ if (constants.chartType == 'smooth') {
185
+ chartMin = plot.curveMinY;
186
+ chartMax = plot.curveMaxY;
187
+ }
188
+ if (constants.globalMinMax) {
189
+ chartMin = Math.min(constants.minY, plot.curveMinY);
190
+ chartMax = Math.max(constants.maxY, plot.curveMaxY);
191
+ }
192
+ if (constants.chartType == 'point') {
193
+ // point layer
194
+ // more than one point with same x-value
195
+ rawFreq = plot.y[position.x][position.z];
196
+ if (plot.max_count == 1) {
197
+ volume = constants.vol;
198
+ } else {
199
+ volume = this.SlideBetween(
200
+ plot.points_count[position.x][position.z],
201
+ 1,
202
+ plot.max_count,
203
+ constants.vol,
204
+ constants.MAX_VOL
205
+ );
206
+ }
207
+
208
+ rawPanning = position.x;
209
+ frequency = this.SlideBetween(
210
+ rawFreq,
211
+ chartMin,
212
+ chartMax,
213
+ constants.MIN_FREQUENCY,
214
+ constants.MAX_FREQUENCY
215
+ );
216
+ panning = this.SlideBetween(rawPanning, chartMin, chartMax, -1, 1);
217
+ } else if (constants.chartType == 'smooth') {
218
+ // best fit smooth layer
219
+
220
+ rawFreq = plot.curvePoints[positionL1.x];
221
+ rawPanning = positionL1.x;
222
+ frequency = this.SlideBetween(
223
+ rawFreq,
224
+ chartMin,
225
+ chartMax,
226
+ constants.MIN_FREQUENCY,
227
+ constants.MAX_FREQUENCY
228
+ );
229
+ panning = this.SlideBetween(rawPanning, chartMin, chartMax, -1, 1);
230
+ }
231
+ } else if (constants.chartType == 'hist') {
232
+ rawFreq = plot.plotData[position.x].y;
233
+ rawPanning = plot.plotData[position.x].x;
234
+ frequency = this.SlideBetween(
235
+ rawFreq,
236
+ constants.minY,
237
+ constants.maxY,
238
+ constants.MIN_FREQUENCY,
239
+ constants.MAX_FREQUENCY
240
+ );
241
+ panning = this.SlideBetween(
242
+ rawPanning,
243
+ constants.minX,
244
+ constants.maxX,
245
+ -1,
246
+ 1
247
+ );
248
+ } else if (constants.chartType == 'line') {
249
+ rawFreq = plot.pointValuesY[position.x];
250
+ rawPanning = position.x;
251
+ frequency = this.SlideBetween(
252
+ rawFreq,
253
+ constants.minY,
254
+ constants.maxY,
255
+ constants.MIN_FREQUENCY,
256
+ constants.MAX_FREQUENCY
257
+ );
258
+ panning = this.SlideBetween(
259
+ rawPanning,
260
+ constants.minX,
261
+ constants.maxX,
262
+ -1,
263
+ 1
264
+ );
265
+ } else if (
266
+ constants.chartType == 'stacked_bar' ||
267
+ constants.chartType == 'stacked_normalized_bar' ||
268
+ constants.chartType == 'dodged_bar'
269
+ ) {
270
+ rawFreq = plot.plotData[position.x][position.y];
271
+ if (rawFreq == 0) {
272
+ this.PlayNull();
273
+ return;
274
+ } else if (Array.isArray(rawFreq)) {
275
+ rawFreq = rawFreq[position.z];
276
+ }
277
+ rawPanning = position.x;
278
+ frequency = this.SlideBetween(
279
+ rawFreq,
280
+ constants.minY,
281
+ constants.maxY,
282
+ constants.MIN_FREQUENCY,
283
+ constants.MAX_FREQUENCY
284
+ );
285
+ panning = this.SlideBetween(
286
+ rawPanning,
287
+ constants.minX,
288
+ constants.maxX,
289
+ -1,
290
+ 1
291
+ );
292
+ let waveTypeArr = ['triangle', 'square', 'sawtooth', 'sine'];
293
+ waveType = waveTypeArr[position.y];
294
+ }
295
+
296
+ if (constants.debugLevel > 5) {
297
+ console.log('will play tone at freq', frequency);
298
+ if (constants.chartType == 'box') {
299
+ console.log(
300
+ 'based on',
301
+ constants.minY,
302
+ '&lt;',
303
+ rawFreq,
304
+ '&lt;',
305
+ constants.maxY,
306
+ ' | freq min',
307
+ constants.MIN_FREQUENCY,
308
+ 'max',
309
+ constants.MAX_FREQUENCY
310
+ );
311
+ } else {
312
+ console.log(
313
+ 'based on',
314
+ constants.minX,
315
+ '&lt;',
316
+ rawFreq,
317
+ '&lt;',
318
+ constants.maxX,
319
+ ' | freq min',
320
+ constants.MIN_FREQUENCY,
321
+ 'max',
322
+ constants.MAX_FREQUENCY
323
+ );
324
+ }
325
+ }
326
+
327
+ if (constants.chartType == 'box') {
328
+ // different types of sounds for different regions.
329
+ // outlier = short tone
330
+ // whisker = normal tone
331
+ // range = chord
332
+ let sectionKey = plot.GetSectionKey(
333
+ constants.plotOrientation == 'vert' ? position.y : position.x
334
+ );
335
+ if (sectionKey == 'lower_outlier' || sectionKey == 'upper_outlier') {
336
+ currentDuration = constants.outlierDuration;
337
+ } else if (
338
+ sectionKey == 'q1' ||
339
+ sectionKey == 'q2' ||
340
+ sectionKey == 'q3'
341
+ ) {
342
+ //currentDuration = constants.duration * 2;
343
+ } else {
344
+ //currentDuration = constants.duration * 2;
345
+ }
346
+ }
347
+
348
+ // create tones
349
+ this.playOscillator(frequency, currentDuration, panning, volume, waveType);
350
+ if (constants.chartType == 'box') {
351
+ let sectionKey = plot.GetSectionKey(
352
+ constants.plotOrientation == 'vert' ? position.y : position.x
353
+ );
354
+ if (sectionKey == 'q1' || sectionKey == 'q2' || sectionKey == 'q3') {
355
+ // also play an octive below at lower vol
356
+ let freq2 = frequency / 2;
357
+ this.playOscillator(
358
+ freq2,
359
+ currentDuration,
360
+ panning,
361
+ constants.vol / 4,
362
+ 'triangle'
363
+ );
364
+ }
365
+ } else if (constants.chartType == 'heat') {
366
+ // Added heatmap tone feature
367
+ if (rawFreq == 0) {
368
+ this.PlayNull();
369
+ }
370
+ }
371
+ }
372
+
373
+ /**
374
+ * Plays an oscillator with the given frequency, duration, panning, volume, and wave type.
375
+ * @param {number} frequency - The frequency of the oscillator.
376
+ * @param {number} currentDuration - The duration of the oscillator in seconds.
377
+ * @param {number} panning - The panning value of the oscillator.
378
+ * @param {number} [currentVol=1] - The volume of the oscillator.
379
+ * @param {string} [wave='sine'] - The wave type of the oscillator.
380
+ */
381
+ playOscillator(
382
+ frequency,
383
+ currentDuration,
384
+ panning,
385
+ currentVol = 1,
386
+ wave = 'sine'
387
+ ) {
388
+ const t = this.audioContext.currentTime;
389
+ const oscillator = this.audioContext.createOscillator();
390
+ oscillator.type = wave;
391
+ oscillator.frequency.value = parseFloat(frequency);
392
+ oscillator.start();
393
+
394
+ // create gain for this event
395
+ const gainThis = this.audioContext.createGain();
396
+ gainThis.gain.setValueCurveAtTime(
397
+ [
398
+ 0.5 * currentVol,
399
+ 1 * currentVol,
400
+ 0.5 * currentVol,
401
+ 0.5 * currentVol,
402
+ 0.5 * currentVol,
403
+ 0.1 * currentVol,
404
+ 1e-4 * currentVol,
405
+ ],
406
+ t,
407
+ currentDuration
408
+ ); // this is what makes the tones fade out properly and not clip
409
+
410
+ let MAX_DISTANCE = 10000;
411
+ let posZ = 1;
412
+ const panner = new PannerNode(this.audioContext, {
413
+ panningModel: 'HRTF',
414
+ distanceModel: 'linear',
415
+ positionX: position.x,
416
+ positionY: position.y,
417
+ positionZ: posZ,
418
+ plotOrientationX: 0.0,
419
+ plotOrientationY: 0.0,
420
+ plotOrientationZ: -1.0,
421
+ refDistance: 1,
422
+ maxDistance: MAX_DISTANCE,
423
+ rolloffFactor: 10,
424
+ coneInnerAngle: 40,
425
+ coneOuterAngle: 50,
426
+ coneOuterGain: 0.4,
427
+ });
428
+
429
+ // create panning
430
+ const stereoPanner = this.audioContext.createStereoPanner();
431
+ stereoPanner.pan.value = panning;
432
+ oscillator.connect(gainThis);
433
+ gainThis.connect(stereoPanner);
434
+ stereoPanner.connect(panner);
435
+ panner.connect(this.compressor);
436
+
437
+ // create panner node
438
+
439
+ // play sound for duration
440
+ setTimeout(() => {
441
+ panner.disconnect();
442
+ gainThis.disconnect();
443
+ oscillator.stop();
444
+ oscillator.disconnect();
445
+ }, currentDuration * 1e3 * 2);
446
+ }
447
+
448
+ /**
449
+ * Plays a smooth sound with the given frequency array, duration, panning array, volume, and wave type.
450
+ * @param {number[]} freqArr - The array of frequencies to play.
451
+ * @param {number} currentDuration - The duration of the sound in seconds.
452
+ * @param {number[]} panningArr - The array of panning values.
453
+ * @param {number} currentVol - The volume of the sound.
454
+ * @param {string} wave - The type of wave to use for the oscillator.
455
+ */
456
+ playSmooth(
457
+ freqArr = [600, 500, 400, 300],
458
+ currentDuration = 2,
459
+ panningArr = [-1, 0, 1],
460
+ currentVol = 1,
461
+ wave = 'sine'
462
+ ) {
463
+ // todo: make smooth duration dependant on how much line there is to do. Like, at max it should be max duration, but if we only have like a tiny bit to play we should just play for a tiny bit
464
+
465
+ let gainArr = new Array(freqArr.length * 3).fill(0.5 * currentVol);
466
+ gainArr.push(1e-4 * currentVol);
467
+
468
+ const t = this.audioContext.currentTime;
469
+ const smoothOscillator = this.audioContext.createOscillator();
470
+ smoothOscillator.type = wave;
471
+ smoothOscillator.frequency.setValueCurveAtTime(freqArr, t, currentDuration);
472
+ smoothOscillator.start();
473
+ constants.isSmoothAutoplay = true;
474
+
475
+ // create gain for this event
476
+ this.smoothGain = this.audioContext.createGain();
477
+ this.smoothGain.gain.setValueCurveAtTime(gainArr, t, currentDuration); // this is what makes the tones fade out properly and not clip
478
+
479
+ let MAX_DISTANCE = 10000;
480
+ let posZ = 1;
481
+ const panner = new PannerNode(this.audioContext, {
482
+ panningModel: 'HRTF',
483
+ distanceModel: 'linear',
484
+ positionX: position.x,
485
+ positionY: position.y,
486
+ positionZ: posZ,
487
+ plotOrientationX: 0.0,
488
+ plotOrientationY: 0.0,
489
+ plotOrientationZ: -1.0,
490
+ refDistance: 1,
491
+ maxDistance: MAX_DISTANCE,
492
+ rolloffFactor: 10,
493
+ coneInnerAngle: 40,
494
+ coneOuterAngle: 50,
495
+ coneOuterGain: 0.4,
496
+ });
497
+
498
+ // create panning
499
+ const stereoPanner = this.audioContext.createStereoPanner();
500
+ stereoPanner.pan.setValueCurveAtTime(panningArr, t, currentDuration);
501
+ smoothOscillator.connect(this.smoothGain);
502
+ this.smoothGain.connect(stereoPanner);
503
+ stereoPanner.connect(panner);
504
+ panner.connect(this.compressor);
505
+
506
+ // play sound for duration
507
+ constants.smoothId = setTimeout(() => {
508
+ panner.disconnect();
509
+ this.smoothGain.disconnect();
510
+ smoothOscillator.stop();
511
+ smoothOscillator.disconnect();
512
+ constants.isSmoothAutoplay = false;
513
+ }, currentDuration * 1e3 * 2);
514
+ }
515
+
516
+ /**
517
+ * Plays a null frequency sound.
518
+ */
519
+ PlayNull() {
520
+ let frequency = constants.NULL_FREQUENCY;
521
+ let duration = constants.duration;
522
+ let panning = 0;
523
+ let vol = constants.vol;
524
+ let wave = 'triangle';
525
+
526
+ this.playOscillator(frequency, duration, panning, vol, wave);
527
+
528
+ setTimeout(
529
+ function (audioThis) {
530
+ audioThis.playOscillator(
531
+ (frequency * 23) / 24,
532
+ duration,
533
+ panning,
534
+ vol,
535
+ wave
536
+ );
537
+ },
538
+ Math.round((duration / 5) * 1000),
539
+ this
540
+ );
541
+ }
542
+
543
+ /**
544
+ * Plays a pleasant end chime.
545
+ * @function
546
+ * @memberof audio
547
+ * @returns {void}
548
+ */
549
+ playEnd() {
550
+ // play a pleasent end chime. We'll use terminal chime from VSCode
551
+ if (constants.canPlayEndChime) {
552
+ let chimeClone = constants.endChime.cloneNode(true); // we clone so that we can trigger a tone while one is already playing
553
+ /*
554
+ * the following (panning) only works if we're on a server
555
+ let panning = 0;
556
+ try {
557
+ if ( constants.chartType == 'bar' ) {
558
+ panning = this.SlideBetween(position.x, 0, plot.bars.length-1, -1, 1);
559
+ } else if ( constants.chartType == 'box' ) {
560
+ panning = this.SlideBetween(position.x, 0, plot.plotData[position.y].length-1, -1, 1);
561
+ } else if ( constants.chartType == 'heat' ) {
562
+ panning = this.SlideBetween(position.x, 0, plot.num_cols-1, -1, 1);
563
+ } else if ( constants.chartType == 'point' ) {
564
+ panning = this.SlideBetween(position.x, 0, plot.x.length-1, -1, 1);
565
+ }
566
+ } catch {
567
+ }
568
+
569
+ const track = this.audioContext.createMediaElementSource(chimeClone);
570
+ const stereoNode = new StereoPannerNode(this.audioContext, {pan:panning} );
571
+ track.connect(stereoNode).connect(this.audioContext.destination);
572
+ */
573
+ chimeClone.play();
574
+ chimeClone = null;
575
+ }
576
+ }
577
+
578
+ /**
579
+ * Stops the smooth gain and cancels any scheduled values.
580
+ * @function
581
+ * @memberof Audio
582
+ * @instance
583
+ * @returns {void}
584
+ */
585
+ KillSmooth() {
586
+ if (constants.smoothId) {
587
+ this.smoothGain.gain.cancelScheduledValues(0);
588
+ this.smoothGain.gain.exponentialRampToValueAtTime(
589
+ 0.0001,
590
+ this.audioContext.currentTime + 0.03
591
+ );
592
+
593
+ clearTimeout(constants.smoothId);
594
+
595
+ constants.isSmoothAutoplay = false;
596
+ }
597
+ }
598
+
599
+ /**
600
+ * Goes between min and max proportional to how val goes between a and b.
601
+ * @param {number} val - The value to slide between a and b.
602
+ * @param {number} a - The start value of the slide.
603
+ * @param {number} b - The end value of the slide.
604
+ * @param {number} min - The minimum value of the slide.
605
+ * @param {number} max - The maximum value of the slide.
606
+ * @returns {number} The new value between min and max.
607
+ */
608
+ SlideBetween(val, a, b, min, max) {
609
+ // helper function that goes between min and max proportional to how val goes between a and b
610
+ let newVal = ((val - a) / (b - a)) * (max - min) + min;
611
+ if (a == 0 &amp;&amp; b == 0) {
612
+ newVal = 0;
613
+ }
614
+ return newVal;
615
+ }
616
+ }
617
+ </code></pre>
618
+ </article>
619
+ </section>
620
+
621
+
622
+
623
+
624
+ </div>
625
+
626
+ <br class="clear">
627
+
628
+ <footer>
629
+ Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Sun Nov 05 2023 14:27:04 GMT-0600 (Central Standard Time) using the Minami theme.
630
+ </footer>
631
+
632
+ <script>prettyPrint();</script>
633
+ <script src="scripts/linenumber.js"></script>
634
+ </body>
635
+ </html>