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
package/src/js/init.js ADDED
@@ -0,0 +1,427 @@
1
+ // events and init functions
2
+ // we do some setup, but most of the work is done when user focuses on an element matching an id from maidr user data
3
+ document.addEventListener('DOMContentLoaded', function (e) {
4
+ // we wrap in DOMContentLoaded to make sure everything has loaded before we run anything
5
+
6
+ // create global vars
7
+ window.constants = new Constants();
8
+ window.resources = new Resources();
9
+ window.tracker = new Tracker();
10
+ window.logError = new LogError();
11
+
12
+ // set focus events for all charts matching maidr ids
13
+ let maidrObjects = [];
14
+ if (!Array.isArray(maidr)) {
15
+ maidrObjects.push(maidr);
16
+ } else {
17
+ maidrObjects = maidr;
18
+ }
19
+ // set focus events for all maidr ids
20
+ DestroyMaidr(); // just in case
21
+ window.maidrIds = [];
22
+ for (let i = 0; i < maidrObjects.length; i++) {
23
+ let maidrId = maidrObjects[i].id;
24
+ maidrIds.push(maidrId);
25
+ let maidrElemn = document.getElementById(maidrId);
26
+ if (maidrElemn) {
27
+ maidrElemn.addEventListener('focus', function (e) {
28
+ ShouldWeInitMaidr(maidrObjects[i]);
29
+ });
30
+ // blur done elsewhere
31
+ }
32
+ }
33
+
34
+ // events etc for user study page
35
+ // run tracker stuff only on user study page
36
+ if (document.getElementById('download_data_trigger')) {
37
+ // download data button
38
+ document
39
+ .getElementById('download_data_trigger')
40
+ .addEventListener('click', function (e) {
41
+ tracker.DownloadTrackerData();
42
+ });
43
+
44
+ // general events
45
+ document.addEventListener('keydown', function (e) {
46
+ // reset tracking with Ctrl + F5 / command + F5, and Ctrl + Shift + R / command + Shift + R
47
+ // future todo: this should probably be a button with a confirmation. This is dangerous
48
+ if (
49
+ (e.key == 'F5' && (constants.isMac ? e.metaKey : e.ctrlKey)) ||
50
+ (e.key == 'R' && (constants.isMac ? e.metaKey : e.ctrlKey))
51
+ ) {
52
+ e.preventDefault();
53
+ tracker.Delete();
54
+ location.reload(true);
55
+ }
56
+
57
+ // Tracker
58
+ if (constants.isTracking) {
59
+ if (e.key == 'F10') {
60
+ //tracker.DownloadTrackerData();
61
+ } else {
62
+ if (plot) {
63
+ tracker.LogEvent(e);
64
+ }
65
+ }
66
+ }
67
+
68
+ // Stuff to only run if we're on a chart (so check if the info div exists?)
69
+ if (document.getElementById('info')) {
70
+ }
71
+ });
72
+ }
73
+ });
74
+
75
+ function InitMaidr(thisMaidr) {
76
+ // just in case
77
+ if (typeof constants != 'undefined') {
78
+ // init vars and html
79
+ window.singleMaidr = thisMaidr;
80
+ constants.chartId = singleMaidr.id;
81
+ if (Array.isArray(singleMaidr.type)) {
82
+ constants.chartType = singleMaidr.type[0];
83
+ } else {
84
+ constants.chartType = singleMaidr.type;
85
+ }
86
+ CreateChartComponents(singleMaidr);
87
+ window.control = new Control(); // this inits the plot
88
+ window.review = new Review();
89
+ window.display = new Display();
90
+ window.audio = new Audio();
91
+
92
+ // blur destruction events
93
+ let controlElements = [
94
+ constants.chart,
95
+ constants.brailleInput,
96
+ constants.review,
97
+ ];
98
+ for (let i = 0; i < controlElements.length; i++) {
99
+ constants.events.push([controlElements[i], 'blur', ShouldWeDestroyMaidr]);
100
+ }
101
+
102
+ // kill autoplay event
103
+ constants.events.push([document, 'keydown', KillAutoplayEvent]);
104
+
105
+ this.SetEvents();
106
+
107
+ // once everything is set up, announce the chart name (or title as a backup) to the user
108
+ if ('name' in singleMaidr) {
109
+ display.announceText(singleMaidr.name);
110
+ } else if ('title' in singleMaidr) {
111
+ display.announceText(singleMaidr.title);
112
+ }
113
+ }
114
+ }
115
+
116
+ function ShouldWeInitMaidr(thisMaidr) {
117
+ // conditions:
118
+ // - maidr isn't enabled (check if singleMaidr is undefined or false)
119
+ // - the chart we're moving to isn't the same as the one we're on
120
+ // note: if we move from one to another, destroy the current first
121
+
122
+ if (typeof singleMaidr == 'undefined') {
123
+ // not enabled
124
+ InitMaidr(thisMaidr);
125
+ } else if (!singleMaidr) {
126
+ // not enabled
127
+ InitMaidr(thisMaidr);
128
+ } else if (thisMaidr.id !== singleMaidr.id) {
129
+ // different chart, destroy first
130
+ DestroyMaidr();
131
+ InitMaidr(thisMaidr);
132
+ }
133
+ }
134
+
135
+ function ShouldWeDestroyMaidr(e) {
136
+ // conditions: we've tabbed away from the chart or any component
137
+
138
+ // timeout to delay blur event. I forget why this is necessary, but it is
139
+ setTimeout(() => {
140
+ if (constants.tabMovement == 0) {
141
+ // do nothing, this is an allowed move
142
+ // but also reset so we can leave later
143
+ constants.tabMovement = null;
144
+ } else {
145
+ if (constants.tabMovement == 1 || constants.tabMovement == -1) {
146
+ // move to before / after, and then destroy
147
+ FocusBeforeOrAfter();
148
+ }
149
+ DestroyMaidr();
150
+ }
151
+ }, 0);
152
+ }
153
+
154
+ function FocusBeforeOrAfter() {
155
+ // Tab / forward
156
+ if (constants.tabMovement == 1) {
157
+ let focusTemp = document.createElement('div');
158
+ focusTemp.setAttribute('tabindex', '0');
159
+ constants.main_container.after(focusTemp);
160
+ focusTemp.focus();
161
+ focusTemp.remove();
162
+ }
163
+ // Shift + Tab / backward
164
+ else if (constants.tabMovement == -1) {
165
+ // create an element to focus on, add it before currentFocus, focus it, then remove it
166
+ let focusTemp = document.createElement('div');
167
+ focusTemp.setAttribute('tabindex', '0');
168
+ constants.main_container.before(focusTemp);
169
+ focusTemp.focus();
170
+ focusTemp.remove();
171
+ }
172
+ }
173
+
174
+ function DestroyMaidr() {
175
+ // chart cleanup
176
+ if (constants.chartType == 'bar' || constants.chartType == 'hist') {
177
+ // deselect, if possible
178
+ if (typeof plot.DeselectAll === 'function') {
179
+ plot.DeselectAll();
180
+ }
181
+ if (typeof plot.UnSelectPrevious === 'function') {
182
+ plot.UnSelectPrevious();
183
+ }
184
+ }
185
+
186
+ // remove events
187
+ for (let i = 0; i < constants.events.length; i++) {
188
+ if (Array.isArray(constants.events[i][0])) {
189
+ for (let j = 0; j < constants.events[i][0].length; j++) {
190
+ constants.events[i][0][j].removeEventListener(
191
+ constants.events[i][1],
192
+ constants.events[i][2]
193
+ );
194
+ }
195
+ } else {
196
+ constants.events[i][0].removeEventListener(
197
+ constants.events[i][1],
198
+ constants.events[i][2]
199
+ );
200
+ }
201
+ }
202
+ for (let i = 0; i < constants.postLoadEvents.length; i++) {
203
+ if (Array.isArray(constants.postLoadEvents[i][0])) {
204
+ for (let j = 0; j < constants.postLoadEvents[i][0].length; j++) {
205
+ constants.postLoadEvents[i][0][j].removeEventListener(
206
+ constants.postLoadEvents[i][1],
207
+ constants.postLoadEvents[i][2]
208
+ );
209
+ }
210
+ } else {
211
+ constants.postLoadEvents[i][0].removeEventListener(
212
+ constants.postLoadEvents[i][1],
213
+ constants.postLoadEvents[i][2]
214
+ );
215
+ }
216
+ }
217
+ constants.events = [];
218
+ constants.postLoadEvents = [];
219
+
220
+ // remove global vars
221
+ constants.chartId = null;
222
+ constants.chartType = null;
223
+ constants.tabMovement = null;
224
+ DestroyChartComponents();
225
+
226
+ window.review = null;
227
+ window.display = null;
228
+ window.control = null;
229
+ window.plot = null;
230
+ window.audio = null;
231
+ window.singleMaidr = null;
232
+ }
233
+ function KillAutoplayEvent(e) {
234
+ // Kill autoplay
235
+ if (
236
+ constants.isMac
237
+ ? e.key == 'Meta' || e.key == 'ContextMenu'
238
+ : e.key == 'Control'
239
+ ) {
240
+ // ctrl (either one)
241
+ constants.KillAutoplay();
242
+ }
243
+ }
244
+
245
+ function SetEvents() {
246
+ // add all events
247
+ for (let i = 0; i < constants.events.length; i++) {
248
+ if (Array.isArray(constants.events[i][0])) {
249
+ for (let j = 0; j < constants.events[i][0].length; j++) {
250
+ constants.events[i][0][j].addEventListener(
251
+ constants.events[i][1],
252
+ constants.events[i][2]
253
+ );
254
+ }
255
+ } else {
256
+ constants.events[i][0].addEventListener(
257
+ constants.events[i][1],
258
+ constants.events[i][2]
259
+ );
260
+ }
261
+ }
262
+ // add all post load events
263
+ // we delay adding post load events just a tick so the chart loads
264
+ setTimeout(function () {
265
+ for (let i = 0; i < constants.postLoadEvents.length; i++) {
266
+ if (Array.isArray(constants.postLoadEvents[i][0])) {
267
+ for (let j = 0; j < constants.postLoadEvents[i][0].length; j++) {
268
+ constants.postLoadEvents[i][0][j].addEventListener(
269
+ constants.postLoadEvents[i][1],
270
+ constants.postLoadEvents[i][2]
271
+ );
272
+ }
273
+ } else {
274
+ constants.postLoadEvents[i][0].addEventListener(
275
+ constants.postLoadEvents[i][1],
276
+ constants.postLoadEvents[i][2]
277
+ );
278
+ }
279
+ }
280
+ }, 100);
281
+ }
282
+
283
+ function CreateChartComponents() {
284
+ // init html stuff. aria live regions, braille input, etc
285
+
286
+ // core chart
287
+ let chart = document.getElementById(singleMaidr.id);
288
+
289
+ // we create a structure with a main container, and a chart container
290
+ let main_container = document.createElement('div');
291
+ main_container.id = constants.main_container_id;
292
+ let chart_container = document.createElement('div');
293
+ chart_container.id = constants.chart_container_id;
294
+ // update parents from just chart, to main container > chart container > chart
295
+ chart.parentNode.replaceChild(main_container, chart);
296
+ main_container.appendChild(chart);
297
+ chart.parentNode.replaceChild(chart_container, chart);
298
+ chart_container.appendChild(chart);
299
+ chart.focus(); // focus used to be on chart and just got lost as we rearranged, so redo focus
300
+
301
+ constants.chart = chart;
302
+ constants.chart_container = chart_container;
303
+ constants.main_container = main_container;
304
+
305
+ // braille input, pre sibling of chart container
306
+ constants.chart_container.insertAdjacentHTML(
307
+ 'beforebegin',
308
+ '<div class="hidden" id="' +
309
+ constants.braille_container_id +
310
+ '">\n<input id="' +
311
+ constants.braille_input_id +
312
+ '" class="braille-input" type="text" size="' +
313
+ constants.brailleDisplayLength +
314
+ '" ' +
315
+ 'aria-brailleroledescription="" ' + // this kills the 2 char 'edit' that screen readers add
316
+ '/>\n</div>\n'
317
+ );
318
+
319
+ // info aria live, next sibling of chart container
320
+ constants.chart_container.insertAdjacentHTML(
321
+ 'afterend',
322
+ '<br>\n<div id="' +
323
+ constants.info_id +
324
+ '" aria-live="assertive" aria-atomic="true">\n<p id="x"></p>\n<p id="y"></p>\n</div>\n'
325
+ );
326
+
327
+ // announcements, next sibling of info
328
+ document
329
+ .getElementById(constants.info_id)
330
+ .insertAdjacentHTML(
331
+ 'afterend',
332
+ '<div id="announcements" aria-live="assertive" aria-atomic="true" class="mb-3"></div>\n'
333
+ );
334
+
335
+ // end chime audio element
336
+ document
337
+ .getElementById(constants.info_id)
338
+ .insertAdjacentHTML(
339
+ 'afterend',
340
+ '<div class="hidden"> <audio src="../src/terminalBell.mp3" id="end_chime"></audio> </div>'
341
+ );
342
+
343
+ // review mode form field
344
+ document
345
+ .getElementById(constants.info_id)
346
+ .insertAdjacentHTML(
347
+ 'beforebegin',
348
+ '<div id="' +
349
+ constants.review_id_container +
350
+ '" class="hidden sr-only sr-only-focusable"><input id="' +
351
+ constants.review_id +
352
+ '" type="text" readonly size="50" /></div>'
353
+ );
354
+
355
+ // some tweaks
356
+ constants.chart_container.setAttribute('role', 'application');
357
+
358
+ // set page elements
359
+ constants.brailleContainer = document.getElementById(
360
+ constants.braille_container_id
361
+ );
362
+ constants.brailleInput = document.getElementById(constants.braille_input_id);
363
+ constants.infoDiv = document.getElementById(constants.info_id);
364
+ constants.announceContainer = document.getElementById(
365
+ constants.announcement_container_id
366
+ );
367
+ constants.nonMenuFocus = constants.chart;
368
+ constants.endChime = document.getElementById(constants.end_chime_id);
369
+ constants.review_container = document.querySelector(
370
+ '#' + constants.review_id_container
371
+ );
372
+ constants.review = document.querySelector('#' + constants.review_id);
373
+
374
+ // help menu
375
+ window.menu = new Menu();
376
+
377
+ // Description modal
378
+ window.description = new Description(); // developement on hold
379
+ }
380
+
381
+ function DestroyChartComponents() {
382
+ // remove html stuff
383
+ if (constants.chart_container != null) {
384
+ if (constants.chart != null) {
385
+ if (constants.chart_container.parentNode != null) {
386
+ constants.chart_container.parentNode.replaceChild(
387
+ constants.chart,
388
+ constants.chart_container
389
+ );
390
+ }
391
+ }
392
+ constants.chart_container.remove();
393
+ }
394
+ if (constants.brailleContainer != null) {
395
+ constants.brailleContainer.remove();
396
+ }
397
+ if (constants.infoDiv != null) {
398
+ constants.infoDiv.remove();
399
+ }
400
+ if (constants.announceContainer != null) {
401
+ constants.announceContainer.remove();
402
+ }
403
+ if (constants.endChime != null) {
404
+ constants.endChime.remove();
405
+ }
406
+ if (constants.review_container != null) {
407
+ constants.review_container.remove();
408
+ }
409
+
410
+ if (typeof menu != 'undefined') {
411
+ menu.Destroy();
412
+ }
413
+ if (typeof description != 'undefined') {
414
+ description.Destroy();
415
+ }
416
+
417
+ constants.chart = null;
418
+ constants.chart_container = null;
419
+ constants.brailleContainer = null;
420
+ constants.brailleInput = null;
421
+ constants.infoDiv = null;
422
+ constants.announceContainer = null;
423
+ constants.endChime = null;
424
+ constants.review_container = null;
425
+ menu = null;
426
+ description = null;
427
+ }
@@ -0,0 +1,219 @@
1
+ class LinePlot {
2
+ constructor() {
3
+ this.SetLineLayer();
4
+ this.SetAxes();
5
+
6
+ let legendX = '';
7
+ let legendY = '';
8
+ if ('axes' in singleMaidr) {
9
+ // legend labels
10
+ if (singleMaidr.axes.x) {
11
+ if (singleMaidr.axes.x.label) {
12
+ if (legendX == '') {
13
+ legendX = singleMaidr.axes.x.label;
14
+ }
15
+ }
16
+ }
17
+ if (singleMaidr.axes.y) {
18
+ if (singleMaidr.axes.y.label) {
19
+ if (legendY == '') {
20
+ legendY = singleMaidr.axes.y.label;
21
+ }
22
+ }
23
+ }
24
+ }
25
+
26
+ this.plotLegend = {
27
+ x: legendX,
28
+ y: legendY,
29
+ };
30
+
31
+ // title
32
+ this.title = '';
33
+ if ('labels' in singleMaidr) {
34
+ if ('title' in singleMaidr.labels) {
35
+ this.title = singleMaidr.labels.title;
36
+ }
37
+ }
38
+ if (this.title == '') {
39
+ if ('title' in singleMaidr) {
40
+ this.title = singleMaidr.title;
41
+ }
42
+ }
43
+
44
+ // subtitle
45
+ if ('labels' in singleMaidr) {
46
+ if ('subtitle' in singleMaidr.labels) {
47
+ this.subtitle = singleMaidr.labels.subtitle;
48
+ }
49
+ }
50
+ // caption
51
+ if ('labels' in singleMaidr) {
52
+ if ('caption' in singleMaidr.labels) {
53
+ this.caption = singleMaidr.labels.caption;
54
+ }
55
+ }
56
+ }
57
+
58
+ SetLineLayer() {
59
+ let len = maidr.elements.length;
60
+ this.plotLine = maidr.elements[len - 1];
61
+ if (typeof this.plotLine !== 'undefined') {
62
+ let pointCoords = this.GetPointCoords();
63
+ let pointValues = this.GetPoints();
64
+
65
+ this.chartLineX = pointCoords[0]; // x coordinates of curve
66
+ this.chartLineY = pointCoords[1]; // y coordinates of curve
67
+
68
+ this.pointValuesX = pointValues[0]; // actual values of x
69
+ this.pointValuesY = pointValues[1]; // actual values of y
70
+
71
+ this.curveMinY = Math.min(...this.pointValuesY);
72
+ this.curveMaxY = Math.max(...this.pointValuesY);
73
+ constants.minX = 0;
74
+ constants.maxX = this.pointValuesX.length - 1;
75
+ constants.minY = this.curveMinY;
76
+ constants.maxY = this.curveMaxY;
77
+
78
+ constants.autoPlayRate = Math.min(
79
+ Math.ceil(constants.AUTOPLAY_DURATION / (constants.maxX + 1)),
80
+ constants.MAX_SPEED
81
+ );
82
+ constants.DEFAULT_SPEED = constants.autoPlayRate;
83
+ if (constants.autoPlayRate < constants.MIN_SPEED) {
84
+ constants.MIN_SPEED = constants.autoPlayRate;
85
+ }
86
+
87
+ // this.gradient = this.GetGradient();
88
+ }
89
+ }
90
+
91
+ SetMinMax() {
92
+ constants.minX = 0;
93
+ constants.maxX = this.pointValuesX.length - 1;
94
+ constants.minY = this.curveMinY;
95
+ constants.maxY = this.curveMaxY;
96
+ constants.autoPlayRate = Math.ceil(
97
+ constants.AUTOPLAY_DURATION / (constants.maxX + 1)
98
+ );
99
+ }
100
+
101
+ GetPointCoords() {
102
+ let svgLineCoords = [[], []];
103
+ let points = this.plotLine.getAttribute('points').split(' ');
104
+ for (let i = 0; i < points.length; i++) {
105
+ if (points[i] !== '') {
106
+ let point = points[i].split(',');
107
+ svgLineCoords[0].push(point[0]);
108
+ svgLineCoords[1].push(point[1]);
109
+ }
110
+ }
111
+ return svgLineCoords;
112
+ }
113
+
114
+ GetPoints() {
115
+ let x_points = [];
116
+ let y_points = [];
117
+
118
+ let data;
119
+ if ('data' in singleMaidr) {
120
+ data = singleMaidr.data;
121
+ }
122
+ if (typeof data !== 'undefined') {
123
+ for (let i = 0; i < data.length; i++) {
124
+ x_points.push(data[i].x);
125
+ y_points.push(data[i].y);
126
+ }
127
+ return [x_points, y_points];
128
+ } else {
129
+ return;
130
+ }
131
+ }
132
+
133
+ // GetGradient() {
134
+ // let gradients = [];
135
+
136
+ // for (let i = 0; i < this.pointValuesY.length - 1; i++) {
137
+ // let abs_grad = Math.abs(
138
+ // (this.pointValuesY[i + 1] - this.pointValuesY[i]) /
139
+ // (this.pointValuesX[i + 1] - this.pointValuesX[i])
140
+ // ).toFixed(3);
141
+ // gradients.push(abs_grad);
142
+ // }
143
+
144
+ // gradients.push('end');
145
+
146
+ // return gradients;
147
+ // }
148
+
149
+ SetAxes() {
150
+ this.x_group_label = '';
151
+ this.y_group_label = '';
152
+ this.title = '';
153
+ if ('axes' in singleMaidr) {
154
+ if ('x' in singleMaidr.axes) {
155
+ if (this.x_group_label == '') {
156
+ this.x_group_label = singleMaidr.axes.x.label;
157
+ }
158
+ }
159
+ if ('y' in singleMaidr.axes) {
160
+ if (this.y_group_label == '') {
161
+ this.y_group_label = singleMaidr.axes.y.label;
162
+ }
163
+ }
164
+ }
165
+ if ('title' in singleMaidr) {
166
+ if (this.title == '') {
167
+ this.title = singleMaidr.title;
168
+ }
169
+ }
170
+ }
171
+
172
+ PlayTones() {
173
+ audio.playTone();
174
+ }
175
+ }
176
+
177
+ class Point {
178
+ constructor() {
179
+ this.x = plot.chartLineX[0];
180
+ this.y = plot.chartLineY[0];
181
+ }
182
+
183
+ async UpdatePoints() {
184
+ await this.ClearPoints();
185
+ this.x = plot.chartLineX[position.x];
186
+ this.y = plot.chartLineY[position.x];
187
+ }
188
+
189
+ async PrintPoints() {
190
+ await this.ClearPoints();
191
+ await this.UpdatePoints();
192
+ const svgns = 'http://www.w3.org/2000/svg';
193
+ var point = document.createElementNS(svgns, 'circle');
194
+ point.setAttribute('id', 'highlight_point');
195
+ point.setAttribute('cx', this.x);
196
+ point.setAttribute('cy', this.y);
197
+ point.setAttribute('r', 1.75);
198
+ point.setAttribute(
199
+ 'style',
200
+ 'fill:' + constants.colorSelected + ';stroke:' + constants.colorSelected
201
+ );
202
+ constants.chart.appendChild(point);
203
+ }
204
+
205
+ async ClearPoints() {
206
+ let points = document.getElementsByClassName('highlight_point');
207
+ for (let i = 0; i < points.length; i++) {
208
+ document.getElementsByClassName('highlight_point')[i].remove();
209
+ }
210
+ if (document.getElementById('highlight_point'))
211
+ document.getElementById('highlight_point').remove();
212
+ }
213
+
214
+ UpdatePointDisplay() {
215
+ this.ClearPoints();
216
+ this.UpdatePoints();
217
+ this.PrintPoints();
218
+ }
219
+ }