maidr 2.7.0 → 2.8.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.
package/dist/maidr.js CHANGED
@@ -70,7 +70,8 @@ class Constants {
70
70
  autoPlayOutlierRate = 50; // ms per tone
71
71
  autoPlayPointsRate = 50; // time between tones in a run
72
72
  colorUnselected = '#595959'; // deprecated, todo: find all instances replace with storing old color method
73
- isTracking = 1; // 0 / 1, is tracking on or off
73
+ canTrack = 1; // 0 / 1, can we track user data
74
+ isTracking = 1; // 0 / 1, is tracking currently on or off
74
75
  visualBraille = false; // do we want to represent braille based on what's visually there or actually there. Like if we have 2 outliers with the same position, do we show 1 (visualBraille true) or 2 (false)
75
76
  globalMinMax = true;
76
77
  ariaMode = 'assertive'; // assertive (default) / polite
@@ -87,6 +88,7 @@ class Constants {
87
88
  skillLevel = 'basic'; // basic / intermediate / expert
88
89
  skillLevelOther = ''; // custom skill level
89
90
  autoInitLLM = true; // auto initialize LLM on page load
91
+ verboseText = '';
90
92
 
91
93
  // user controls (not exposed to menu, with shortcuts usually)
92
94
  showDisplay = 1; // true / false
@@ -923,6 +925,7 @@ class ChatLLM {
923
925
  constructor() {
924
926
  this.firstTime = true;
925
927
  this.firstMulti = true;
928
+ this.firstOpen = true;
926
929
  this.shown = false;
927
930
  this.CreateComponent();
928
931
  this.SetEvents();
@@ -1156,7 +1159,11 @@ class ChatLLM {
1156
1159
  // kill more than 2 newlines in a row
1157
1160
  markdown = markdown.replace(/\n{3,}/g, '\n\n');
1158
1161
 
1159
- navigator.clipboard.writeText(markdown);
1162
+ try {
1163
+ navigator.clipboard.writeText(markdown);
1164
+ } catch (err) {
1165
+ console.error('Failed to copy: ', err);
1166
+ }
1160
1167
  return markdown;
1161
1168
  }
1162
1169
  }
@@ -1218,14 +1225,30 @@ class ChatLLM {
1218
1225
  * @returns {void}
1219
1226
  */
1220
1227
  async Submit(text, firsttime = false) {
1228
+ // misc init
1229
+ let img = null;
1230
+ this.firstMulti = true;
1231
+
1232
+ // if this is the user's first message (or we're gemini, in which case we need to send every time), prepend prompt with user position
1233
+ if (
1234
+ (this.firstOpen || constants.LLMModel == 'gemini') &&
1235
+ !firsttime &&
1236
+ constants.verboseText.length > 0
1237
+ ) {
1238
+ text =
1239
+ "Here is the current position in the chart; no response necessarily needed, use this info only if it's relevant to future questions: " +
1240
+ constants.verboseText +
1241
+ '. My question is: ' +
1242
+ text;
1243
+
1244
+ this.firstOpen = false;
1245
+ }
1246
+
1221
1247
  // start waiting sound
1222
1248
  if (constants.playLLMWaitingSound) {
1223
1249
  this.WaitingSound(true);
1224
1250
  }
1225
1251
 
1226
- let img = null;
1227
- this.firstMulti = true;
1228
-
1229
1252
  if (constants.LLMOpenAiMulti || constants.LLMModel == 'openai') {
1230
1253
  if (firsttime) {
1231
1254
  img = await this.ConvertSVGtoJPG(singleMaidr.id, 'openai');
@@ -1639,6 +1662,7 @@ class ChatLLM {
1639
1662
  document.getElementById('chatLLM_modal_backdrop').classList.add('hidden');
1640
1663
  this.whereWasMyFocus.focus();
1641
1664
  this.whereWasMyFocus = null;
1665
+ this.firstOpen = true;
1642
1666
  }
1643
1667
  }
1644
1668
 
@@ -2020,6 +2044,7 @@ class Helper {
2020
2044
  class Tracker {
2021
2045
  constructor() {
2022
2046
  this.DataSetup();
2047
+ constants.isTracking = true;
2023
2048
  }
2024
2049
 
2025
2050
  /**
@@ -2303,6 +2328,7 @@ class Tracker {
2303
2328
  //console.log("x_tickmark: '", x_tickmark, "', y_tickmark: '", y_tickmark, "', x_label: '", x_label, "', y_label: '", y_label, "', value: '", value, "', fill_value: '", fill_value);
2304
2329
 
2305
2330
  this.SetData('events', eventToLog);
2331
+ //console.log('logged an event');
2306
2332
  }
2307
2333
 
2308
2334
  SetData(key, value) {
@@ -3303,9 +3329,10 @@ class Display {
3303
3329
 
3304
3330
  let output = '';
3305
3331
  let verboseText = '';
3332
+ let terseText = '';
3306
3333
  let reviewText = '';
3307
3334
  if (constants.chartType == 'bar') {
3308
- // {legend x} is {colname x}, {legend y} is {value y}
3335
+ // verbose: {legend x} is {colname x}, {legend y} is {value y}
3309
3336
  if (plot.columnLabels[position.x]) {
3310
3337
  if (plot.plotLegend.x.length > 0) {
3311
3338
  verboseText += plot.plotLegend.x + ' is ';
@@ -3318,20 +3345,16 @@ class Display {
3318
3345
  }
3319
3346
  verboseText += plot.plotData[position.x];
3320
3347
  }
3321
- if (constants.textMode == 'off') {
3322
- // do nothing :D
3323
- } else if (constants.textMode == 'terse') {
3324
- // {colname} {value}
3325
- output +=
3326
- '<p>' +
3327
- plot.columnLabels[position.x] +
3328
- ' ' +
3329
- plot.plotData[position.x] +
3330
- '</p>\n';
3331
- } else if (constants.textMode == 'verbose') {
3332
- output += '<p>' + verboseText + '</p>\n';
3333
- }
3348
+ // terse: {colname} {value}
3349
+ terseText +=
3350
+ '<p>' +
3351
+ plot.columnLabels[position.x] +
3352
+ ' ' +
3353
+ plot.plotData[position.x] +
3354
+ '</p>\n';
3355
+ verboseText = '<p>' + verboseText + '</p>\n';
3334
3356
  } else if (constants.chartType == 'heat') {
3357
+ // verbose
3335
3358
  // col name and value
3336
3359
  if (constants.navigation == 1) {
3337
3360
  verboseText +=
@@ -3364,31 +3387,25 @@ class Display {
3364
3387
  verboseText += plot.data[position.y][position.x];
3365
3388
  // }
3366
3389
  }
3367
- // terse and verbose alternate between columns and rows
3368
- if (constants.textMode == 'off') {
3369
- // do nothing :D
3370
- } else if (constants.textMode == 'terse') {
3371
- // value only
3372
- if (constants.navigation == 1) {
3373
- // column navigation
3374
- output +=
3375
- '<p>' +
3376
- plot.x_labels[position.x] +
3377
- ', ' +
3378
- plot.data[position.y][position.x] +
3379
- '</p>\n';
3380
- } else {
3381
- // row navigation
3382
- output +=
3383
- '<p>' +
3384
- plot.y_labels[position.y] +
3385
- ', ' +
3386
- plot.data[position.y][position.x] +
3387
- '</p>\n';
3388
- }
3389
- } else if (constants.textMode == 'verbose') {
3390
- output += '<p>' + verboseText + '</p>\n';
3390
+ // terse: value only
3391
+ if (constants.navigation == 1) {
3392
+ // column navigation
3393
+ terseText +=
3394
+ '<p>' +
3395
+ plot.x_labels[position.x] +
3396
+ ', ' +
3397
+ plot.data[position.y][position.x] +
3398
+ '</p>\n';
3399
+ } else {
3400
+ // row navigation
3401
+ terseText +=
3402
+ '<p>' +
3403
+ plot.y_labels[position.y] +
3404
+ ', ' +
3405
+ plot.data[position.y][position.x] +
3406
+ '</p>\n';
3391
3407
  }
3408
+ verboseText = '<p>' + verboseText + '</p>\n';
3392
3409
  } else if (constants.chartType == 'box') {
3393
3410
  // setup
3394
3411
  let val = 0;
@@ -3399,8 +3416,6 @@ class Display {
3399
3416
  let sectionKey = plot.GetSectionKey(
3400
3417
  constants.plotOrientation == 'vert' ? position.y : position.x
3401
3418
  );
3402
- let textTerse = '';
3403
- let textVerbose = '';
3404
3419
 
3405
3420
  if (sectionKey == 'lower_outlier' || sectionKey == 'upper_outlier') {
3406
3421
  isOutlier = true;
@@ -3419,67 +3434,64 @@ class Display {
3419
3434
 
3420
3435
  // group label for verbose
3421
3436
  if (constants.navigation) {
3422
- if (plot.x_group_label) textVerbose += plot.x_group_label;
3437
+ if (plot.x_group_label) verboseText += plot.x_group_label;
3423
3438
  } else if (!constants.navigation) {
3424
- if (plot.y_group_label) textVerbose += plot.y_group_label;
3439
+ if (plot.y_group_label) verboseText += plot.y_group_label;
3425
3440
  }
3426
3441
  // and axes label
3427
3442
  if (constants.navigation) {
3428
3443
  if (plot.x_labels[plotPos]) {
3429
- textVerbose += ' is ';
3430
- textTerse += plot.x_labels[plotPos] + ', ';
3431
- textVerbose += plot.x_labels[plotPos] + ', ';
3444
+ verboseText += ' is ';
3445
+ terseText += plot.x_labels[plotPos] + ', ';
3446
+ verboseText += plot.x_labels[plotPos] + ', ';
3432
3447
  } else {
3433
- textVerbose += ', ';
3448
+ verboseText += ', ';
3434
3449
  }
3435
3450
  } else if (!constants.navigation) {
3436
3451
  if (plot.y_labels[plotPos]) {
3437
- textVerbose += ' is ';
3438
- textTerse += plot.y_labels[plotPos] + ', ';
3439
- textVerbose += plot.y_labels[plotPos] + ', ';
3452
+ verboseText += ' is ';
3453
+ terseText += plot.y_labels[plotPos] + ', ';
3454
+ verboseText += plot.y_labels[plotPos] + ', ';
3440
3455
  } else {
3441
- textVerbose += ', ';
3456
+ verboseText += ', ';
3442
3457
  }
3443
3458
  }
3444
3459
  // outliers
3445
3460
  if (isOutlier) {
3446
- textTerse += numPoints + ' ';
3447
- textVerbose += numPoints + ' ';
3461
+ terseText += numPoints + ' ';
3462
+ verboseText += numPoints + ' ';
3448
3463
  }
3449
3464
  // label
3450
- textVerbose += resources.GetString(sectionKey);
3451
- if (numPoints == 1) textVerbose += ' is ';
3465
+ verboseText += resources.GetString(sectionKey);
3466
+ if (numPoints == 1) verboseText += ' is ';
3452
3467
  else {
3453
- textVerbose += 's ';
3454
- if (numPoints > 1) textVerbose += ' are ';
3468
+ verboseText += 's ';
3469
+ if (numPoints > 1) verboseText += ' are ';
3455
3470
  }
3456
3471
  if (
3457
3472
  isOutlier ||
3458
3473
  (constants.navigation && constants.plotOrientation == 'horz') ||
3459
3474
  (!constants.navigation && constants.plotOrientation == 'vert')
3460
3475
  ) {
3461
- textTerse += resources.GetString(sectionKey);
3476
+ terseText += resources.GetString(sectionKey);
3462
3477
 
3463
3478
  // grammar
3464
3479
  if (numPoints != 1) {
3465
- textTerse += 's';
3480
+ terseText += 's';
3466
3481
  }
3467
- textTerse += ' ';
3482
+ terseText += ' ';
3468
3483
  }
3469
3484
  // val
3470
3485
  if (plot.plotData[plotPos][sectionKey] == null && !isOutlier) {
3471
- textTerse += 'empty';
3472
- textVerbose += 'empty';
3486
+ terseText += 'empty';
3487
+ verboseText += 'empty';
3473
3488
  } else {
3474
- textTerse += val;
3475
- textVerbose += val;
3489
+ terseText += val;
3490
+ verboseText += val;
3476
3491
  }
3477
3492
 
3478
- verboseText = textVerbose; // yeah it's an extra var, who cares
3479
- if (constants.textMode == 'verbose')
3480
- output = '<p>' + textVerbose + '</p>\n';
3481
- else if (constants.textMode == 'terse')
3482
- output = '<p>' + textTerse + '</p>\n';
3493
+ verboseText = '<p>' + verboseText + '</p>\n';
3494
+ terseText = '<p>' + terseText + '</p>\n';
3483
3495
  } else if (
3484
3496
  [].concat(singleMaidr.type).includes('point') ||
3485
3497
  [].concat(singleMaidr.type).includes('smooth')
@@ -3496,20 +3508,15 @@ class Display {
3496
3508
  plot.y[position.x].join(', ') +
3497
3509
  ']';
3498
3510
 
3499
- if (constants.textMode == 'off') {
3500
- // do nothing
3501
- } else if (constants.textMode == 'terse') {
3502
- output +=
3503
- '<p>' +
3504
- plot.x[position.x] +
3505
- ', ' +
3506
- '[' +
3507
- plot.y[position.x].join(', ') +
3508
- ']' +
3509
- '</p>\n';
3510
- } else if (constants.textMode == 'verbose') {
3511
- // set from verboseText
3512
- }
3511
+ // terse
3512
+ terseText +=
3513
+ '<p>' +
3514
+ plot.x[position.x] +
3515
+ ', ' +
3516
+ '[' +
3517
+ plot.y[position.x].join(', ') +
3518
+ ']' +
3519
+ '</p>\n';
3513
3520
  } else if (constants.chartType == 'smooth') {
3514
3521
  // best fit smooth layer
3515
3522
  verboseText +=
@@ -3521,42 +3528,31 @@ class Display {
3521
3528
  ' ' +
3522
3529
  plot.curvePoints[positionL1.x]; // verbose mode: x and y values
3523
3530
 
3524
- if (constants.textMode == 'off') {
3525
- // do nothing
3526
- } else if (constants.textMode == 'terse') {
3527
- // terse mode: gradient trend
3528
- // output += '<p>' + plot.gradient[positionL1.x] + '<p>\n';
3531
+ // terse mode: gradient trend
3529
3532
 
3530
- // display absolute gradient of the graph
3531
- output += '<p>' + plot.curvePoints[positionL1.x] + '<p>\n';
3532
- } else if (constants.textMode == 'verbose') {
3533
- // set from verboseText
3534
- }
3533
+ // display absolute gradient of the graph
3534
+ terseText += '<p>' + plot.curvePoints[positionL1.x] + '<p>\n';
3535
3535
  }
3536
- if (constants.textMode == 'verbose')
3537
- output = '<p>' + verboseText + '</p>\n';
3536
+ verboseText = '<p>' + verboseText + '</p>\n';
3538
3537
  } else if (constants.chartType == 'hist') {
3539
- if (constants.textMode == 'terse') {
3540
- // terse: {x}, {y}
3541
- output =
3542
- '<p>' +
3543
- plot.plotData[position.x].x +
3544
- ', ' +
3545
- plot.plotData[position.x].y +
3546
- '</p>\n';
3547
- } else if (constants.textMode == 'verbose') {
3548
- // verbose: {xlabel} is xmin through xmax, {ylabel} is y
3549
- output = '<p>';
3550
- if (plot.legendX) {
3551
- output = plot.legendX + ' is ';
3552
- }
3553
- output += plot.plotData[position.x].xmin;
3554
- output += ' through ' + plot.plotData[position.x].xmax + ', ';
3555
- if (plot.legendY) {
3556
- output += plot.legendY + ' is ';
3557
- }
3558
- output += plot.plotData[position.x].y;
3559
- }
3538
+ // terse: {x}, {y}
3539
+ terseText =
3540
+ '<p>' +
3541
+ plot.plotData[position.x].x +
3542
+ ', ' +
3543
+ plot.plotData[position.x].y +
3544
+ '</p>\n';
3545
+ // verbose: {xlabel} is xmin through xmax, {ylabel} is y
3546
+ verboseText = '<p>';
3547
+ if (plot.legendX) {
3548
+ verboseText = plot.legendX + ' is ';
3549
+ }
3550
+ verboseText += plot.plotData[position.x].xmin;
3551
+ verboseText += ' through ' + plot.plotData[position.x].xmax + ', ';
3552
+ if (plot.legendY) {
3553
+ verboseText += plot.legendY + ' is ';
3554
+ }
3555
+ verboseText += plot.plotData[position.x].y;
3560
3556
  } else if (constants.chartType == 'line') {
3561
3557
  // line layer
3562
3558
  if (plot.plotLegend) {
@@ -3568,19 +3564,15 @@ class Display {
3568
3564
  }
3569
3565
  verboseText += plot.pointValuesY[position.x];
3570
3566
 
3571
- if (constants.textMode == 'off') {
3572
- // do nothing
3573
- } else if (constants.textMode == 'terse') {
3574
- output +=
3575
- '<p>' +
3576
- plot.pointValuesX[position.x] +
3577
- ', ' +
3578
- plot.pointValuesY[position.x] +
3579
- '</p>\n';
3580
- } else if (constants.textMode == 'verbose') {
3581
- // set from verboseText
3582
- output += '<p>' + verboseText + '</p>\n';
3583
- }
3567
+ // terse
3568
+ terseText +=
3569
+ '<p>' +
3570
+ plot.pointValuesX[position.x] +
3571
+ ', ' +
3572
+ plot.pointValuesY[position.x] +
3573
+ '</p>\n';
3574
+
3575
+ verboseText = '<p>' + verboseText + '</p>\n';
3584
3576
  } else if (
3585
3577
  constants.chartType == 'stacked_bar' ||
3586
3578
  constants.chartType == 'stacked_normalized_bar' ||
@@ -3597,30 +3589,33 @@ class Display {
3597
3589
  verboseText += plot.fill[position.y] + ', ';
3598
3590
  verboseText += 'value is ' + plot.plotData[position.x][position.y];
3599
3591
 
3600
- if (constants.textMode == 'off') {
3601
- // do nothing
3602
- } else if (constants.textMode == 'terse') {
3603
- // navigation == 1 ? {colname x} : {colname y} is {plotData[x][y]}
3604
- if (constants.navigation == 1) {
3605
- output +=
3606
- '<p>' +
3607
- plot.level[position.x] +
3608
- ' is ' +
3609
- plot.plotData[position.x][position.y] +
3610
- '</p>\n';
3611
- } else {
3612
- output +=
3613
- '<p>' +
3614
- plot.fill[position.y] +
3615
- ' is ' +
3616
- plot.plotData[position.x][position.y] +
3617
- '</p>\n';
3618
- }
3592
+ // navigation == 1 ? {colname x} : {colname y} is {plotData[x][y]}
3593
+ if (constants.navigation == 1) {
3594
+ terseText +=
3595
+ '<p>' +
3596
+ plot.level[position.x] +
3597
+ ' is ' +
3598
+ plot.plotData[position.x][position.y] +
3599
+ '</p>\n';
3619
3600
  } else {
3620
- output += '<p>' + verboseText + '</p>\n';
3601
+ terseText +=
3602
+ '<p>' +
3603
+ plot.fill[position.y] +
3604
+ ' is ' +
3605
+ plot.plotData[position.x][position.y] +
3606
+ '</p>\n';
3621
3607
  }
3608
+ verboseText = '<p>' + verboseText + '</p>\n';
3622
3609
  }
3623
3610
 
3611
+ // set outout text
3612
+ if (constants.textMode == 'verbose') {
3613
+ output = verboseText;
3614
+ } else if (constants.textMode == 'terse') {
3615
+ output = terseText;
3616
+ }
3617
+ constants.verboseText = verboseText;
3618
+
3624
3619
  if (constants.infoDiv) constants.infoDiv.innerHTML = output;
3625
3620
  if (constants.review) {
3626
3621
  if (output.length > 0) {
@@ -7568,6 +7563,9 @@ class Control {
7568
7563
  // caption
7569
7564
  display.displayInfo('caption', plot.caption);
7570
7565
  pressedL = false;
7566
+ } else if (e.key == 'f') {
7567
+ display.displayInfo('fill', plot.fill);
7568
+ pressedL = false;
7571
7569
  } else if (e.key != 'l') {
7572
7570
  pressedL = false;
7573
7571
  }
@@ -10548,15 +10546,16 @@ document.addEventListener('DOMContentLoaded', function (e) {
10548
10546
  // create global vars
10549
10547
  window.constants = new Constants();
10550
10548
  window.resources = new Resources();
10551
- window.tracker = new Tracker();
10552
10549
  window.logError = new LogError();
10553
10550
 
10554
10551
  // set focus events for all charts matching maidr ids
10555
10552
  let maidrObjects = [];
10556
- if (!Array.isArray(maidr)) {
10557
- maidrObjects.push(maidr);
10558
- } else {
10559
- maidrObjects = maidr;
10553
+ if (typeof maidr != 'undefined') {
10554
+ if (!Array.isArray(maidr)) {
10555
+ maidrObjects.push(maidr);
10556
+ } else {
10557
+ maidrObjects = maidr;
10558
+ }
10560
10559
  }
10561
10560
  // set focus events for all maidr ids
10562
10561
  DestroyMaidr(); // just in case
@@ -10576,13 +10575,16 @@ document.addEventListener('DOMContentLoaded', function (e) {
10576
10575
 
10577
10576
  // events etc for user study page
10578
10577
  // run tracker stuff only on user study page
10579
- if (document.getElementById('download_data_trigger')) {
10580
- // download data button
10581
- document
10582
- .getElementById('download_data_trigger')
10583
- .addEventListener('click', function (e) {
10584
- tracker.DownloadTrackerData();
10585
- });
10578
+ if (constants.canTrack) {
10579
+ window.tracker = new Tracker();
10580
+ if (document.getElementById('download_data_trigger')) {
10581
+ // we're on the intro page, so enable the download data button
10582
+ document
10583
+ .getElementById('download_data_trigger')
10584
+ .addEventListener('click', function (e) {
10585
+ tracker.DownloadTrackerData();
10586
+ });
10587
+ }
10586
10588
 
10587
10589
  // general events
10588
10590
  document.addEventListener('keydown', function (e) {
@@ -10597,14 +10599,12 @@ document.addEventListener('DOMContentLoaded', function (e) {
10597
10599
  location.reload(true);
10598
10600
  }
10599
10601
 
10600
- // Tracker
10601
- if (constants.isTracking) {
10602
- if (e.key == 'F10') {
10603
- //tracker.DownloadTrackerData();
10604
- } else {
10605
- if (plot) {
10606
- tracker.LogEvent(e);
10607
- }
10602
+ // main event tracker, built for individual charts
10603
+ if (e.key == 'F10') {
10604
+ tracker.DownloadTrackerData();
10605
+ } else {
10606
+ if (plot) {
10607
+ tracker.LogEvent(e);
10608
10608
  }
10609
10609
  }
10610
10610