maidr 2.27.1 → 2.28.1

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
@@ -7722,12 +7722,8 @@ class Layer0Point {
7722
7722
  * @async
7723
7723
  */
7724
7724
  async ClearPoints() {
7725
- if (document.getElementById('highlight_point'))
7726
- document.getElementById('highlight_point').remove();
7727
- let points = document.getElementsByClassName('highlight_point');
7728
- for (let i = 0; i < points.length; i++) {
7729
- document.getElementsByClassName('highlight_point')[i].remove();
7730
- }
7725
+ // kill all .highlight_point
7726
+ document.querySelectorAll('.highlight_point').forEach((e) => e.remove());
7731
7727
  }
7732
7728
 
7733
7729
  /**
@@ -7803,12 +7799,8 @@ class Layer1Point {
7803
7799
  * @async
7804
7800
  */
7805
7801
  async ClearPoints() {
7806
- let points = document.getElementsByClassName('highlight_point');
7807
- for (let i = 0; i < points.length; i++) {
7808
- document.getElementsByClassName('highlight_point')[i].remove();
7809
- }
7810
- if (document.getElementById('highlight_point'))
7811
- document.getElementById('highlight_point').remove();
7802
+ // kill all .highlight_point
7803
+ document.querySelectorAll('.highlight_point').forEach((e) => e.remove());
7812
7804
  }
7813
7805
 
7814
7806
  /**
@@ -8817,95 +8809,97 @@ class Control {
8817
8809
  SetPrefixControls() {
8818
8810
  // prefix events, l + x, where x is a key for the title, axis, etc
8819
8811
  // we listen for a moment when l is hit for a key to follow
8820
- constants.events.push([
8821
- document,
8822
- 'keydown',
8823
- function (e) {
8824
- // init
8825
- let pressedTimeout = null;
8826
-
8827
- // enable / disable prefix mode
8828
- if (e.key == 'l') {
8829
- control.pressedL = true;
8830
- if (pressedTimeout != null) {
8831
- clearTimeout(pressedTimeout);
8832
- pressedTimeout = null;
8833
- }
8834
- pressedTimeout = setTimeout(function () {
8835
- control.pressedL = false;
8836
- }, constants.keypressInterval);
8837
- }
8838
-
8839
- // Prefix mode stuff: L is enabled, look for these keys
8840
- if (control.pressedL) {
8841
- if (e.key == 'x') {
8842
- // X: x label
8843
- let xlabel = '';
8844
- if (singleMaidr.type == 'bar' || singleMaidr.type == 'line') {
8845
- xlabel = plot.plotLegend.x;
8846
- } else if (singleMaidr.type == 'hist') {
8847
- xlabel = plot.legendX;
8848
- } else if (
8849
- singleMaidr.type == 'heat' ||
8850
- singleMaidr.type == 'box' ||
8851
- singleMaidr.type == 'point' ||
8852
- singleMaidr.type.includes('point')
8853
- ) {
8854
- xlabel = plot.x_group_label;
8855
- } else if (
8856
- singleMaidr.type == 'stacked_bar' ||
8857
- singleMaidr.type == 'stacked_normalized_bar' ||
8858
- singleMaidr.type == 'dodged_bar'
8859
- ) {
8860
- xlabel = plot.plotLegend.x;
8812
+ for (let i = 0; i < this.allControlElements.length; i++) {
8813
+ constants.events.push([
8814
+ this.allControlElements[i],
8815
+ 'keydown',
8816
+ function (e) {
8817
+ // init
8818
+ let pressedTimeout = null;
8819
+
8820
+ // enable / disable prefix mode
8821
+ if (e.key == 'l') {
8822
+ control.pressedL = true;
8823
+ if (pressedTimeout != null) {
8824
+ clearTimeout(pressedTimeout);
8825
+ pressedTimeout = null;
8861
8826
  }
8862
- display.displayInfo('x label', xlabel);
8863
- control.pressedL = false;
8864
- } else if (e.key == 'y') {
8865
- // Y: y label
8866
- let ylabel = '';
8867
- if (singleMaidr.type == 'bar' || singleMaidr.type == 'line') {
8868
- ylabel = plot.plotLegend.y;
8869
- } else if (singleMaidr.type == 'hist') {
8870
- ylabel = plot.legendY;
8871
- } else if (
8872
- singleMaidr.type == 'heat' ||
8873
- singleMaidr.type == 'box' ||
8874
- singleMaidr.type == 'point' ||
8875
- singleMaidr.type == 'line' ||
8876
- singleMaidr.type.includes('point')
8877
- ) {
8878
- ylabel = plot.y_group_label;
8879
- } else if (
8880
- singleMaidr.type == 'stacked_bar' ||
8881
- singleMaidr.type == 'stacked_normalized_bar' ||
8882
- singleMaidr.type == 'dodged_bar'
8883
- ) {
8884
- ylabel = plot.plotLegend.y;
8827
+ pressedTimeout = setTimeout(function () {
8828
+ control.pressedL = false;
8829
+ }, constants.keypressInterval);
8830
+ }
8831
+
8832
+ // Prefix mode stuff: L is enabled, look for these keys
8833
+ if (control.pressedL) {
8834
+ if (e.key == 'x') {
8835
+ // X: x label
8836
+ let xlabel = '';
8837
+ if (singleMaidr.type == 'bar' || singleMaidr.type == 'line') {
8838
+ xlabel = plot.plotLegend.x;
8839
+ } else if (singleMaidr.type == 'hist') {
8840
+ xlabel = plot.legendX;
8841
+ } else if (
8842
+ singleMaidr.type == 'heat' ||
8843
+ singleMaidr.type == 'box' ||
8844
+ singleMaidr.type == 'point' ||
8845
+ singleMaidr.type.includes('point')
8846
+ ) {
8847
+ xlabel = plot.x_group_label;
8848
+ } else if (
8849
+ singleMaidr.type == 'stacked_bar' ||
8850
+ singleMaidr.type == 'stacked_normalized_bar' ||
8851
+ singleMaidr.type == 'dodged_bar'
8852
+ ) {
8853
+ xlabel = plot.plotLegend.x;
8854
+ }
8855
+ display.displayInfo('x label', xlabel);
8856
+ control.pressedL = false;
8857
+ } else if (e.key == 'y') {
8858
+ // Y: y label
8859
+ let ylabel = '';
8860
+ if (singleMaidr.type == 'bar' || singleMaidr.type == 'line') {
8861
+ ylabel = plot.plotLegend.y;
8862
+ } else if (singleMaidr.type == 'hist') {
8863
+ ylabel = plot.legendY;
8864
+ } else if (
8865
+ singleMaidr.type == 'heat' ||
8866
+ singleMaidr.type == 'box' ||
8867
+ singleMaidr.type == 'point' ||
8868
+ singleMaidr.type == 'line' ||
8869
+ singleMaidr.type.includes('point')
8870
+ ) {
8871
+ ylabel = plot.y_group_label;
8872
+ } else if (
8873
+ singleMaidr.type == 'stacked_bar' ||
8874
+ singleMaidr.type == 'stacked_normalized_bar' ||
8875
+ singleMaidr.type == 'dodged_bar'
8876
+ ) {
8877
+ ylabel = plot.plotLegend.y;
8878
+ }
8879
+ display.displayInfo('y label', ylabel);
8880
+ control.pressedL = false;
8881
+ } else if (e.key == 't') {
8882
+ // T: title
8883
+ display.displayInfo('title', plot.title);
8884
+ control.pressedL = false;
8885
+ } else if (e.key == 's') {
8886
+ // subtitle
8887
+ display.displayInfo('subtitle', plot.subtitle);
8888
+ control.pressedL = false;
8889
+ } else if (e.key == 'c') {
8890
+ // caption
8891
+ display.displayInfo('caption', plot.caption);
8892
+ control.pressedL = false;
8893
+ } else if (e.key == 'f') {
8894
+ display.displayInfo('fill', plot.fill);
8895
+ control.pressedL = false;
8896
+ } else if (e.key != 'l') {
8897
+ control.pressedL = false;
8885
8898
  }
8886
- display.displayInfo('y label', ylabel);
8887
- control.pressedL = false;
8888
- } else if (e.key == 't') {
8889
- // T: title
8890
- display.displayInfo('title', plot.title);
8891
- control.pressedL = false;
8892
- } else if (e.key == 's') {
8893
- // subtitle
8894
- display.displayInfo('subtitle', plot.subtitle);
8895
- control.pressedL = false;
8896
- } else if (e.key == 'c') {
8897
- // caption
8898
- display.displayInfo('caption', plot.caption);
8899
- control.pressedL = false;
8900
- } else if (e.key == 'f') {
8901
- display.displayInfo('fill', plot.fill);
8902
- control.pressedL = false;
8903
- } else if (e.key != 'l') {
8904
- control.pressedL = false;
8905
8899
  }
8906
- }
8907
- },
8908
- ]);
8900
+ },
8901
+ ]);
8902
+ }
8909
8903
  }
8910
8904
 
8911
8905
  /**
@@ -11914,6 +11908,199 @@ class Control {
11914
11908
  }
11915
11909
  }
11916
11910
 
11911
+ class Goto {
11912
+ //locations = ['Max Value', 'Min Value', 'Mean', 'Median'];
11913
+ static options = ['Max Value', 'Min Value'];
11914
+
11915
+ constructor() {
11916
+ this.menuOpen = false;
11917
+ this.initMenu();
11918
+ this.attachEventListeners();
11919
+ }
11920
+
11921
+ initMenu() {
11922
+ this.menu = document.createElement('div');
11923
+ this.menu.id = 'goto-menu';
11924
+ this.menu.style.display = 'none';
11925
+ this.menu.innerHTML = `
11926
+ <div class="menu-container">
11927
+ <input
11928
+ type="text"
11929
+ id="menu-search"
11930
+ placeholder="Search locations..."
11931
+ aria-label="Search locations to go to"
11932
+ />
11933
+ <ul id="menu-items">
11934
+ ${Goto.options
11935
+ .map((option) => `<li><button>${option}</button></li>`)
11936
+ .join('')}
11937
+ </ul>
11938
+ </div>
11939
+ `;
11940
+
11941
+ this.menuSearch = this.menu.querySelector('#menu-search');
11942
+ this.menuItems = Array.from(
11943
+ this.menu.querySelectorAll('#menu-items button')
11944
+ );
11945
+
11946
+ constants.gotoMenu = this.menu;
11947
+ document.body.appendChild(this.menu);
11948
+ }
11949
+
11950
+ openMenu() {
11951
+ this.whereWasMyFocus = document.activeElement;
11952
+ constants.tabMovement = 0; // to prevent maidr from being destroyed as we leave the chart
11953
+
11954
+ this.menuOpen = true;
11955
+ this.menu.style.display = 'block';
11956
+ this.menuSearch.focus();
11957
+ }
11958
+
11959
+ closeMenu() {
11960
+ this.menuOpen = false;
11961
+ this.menu.style.display = 'none';
11962
+ this.whereWasMyFocus.focus();
11963
+ this.whereWasMyFocus = null;
11964
+ }
11965
+
11966
+ filterItems(query) {
11967
+ const lowerCaseQuery = query.toLowerCase();
11968
+ this.menuItems.forEach((item) => {
11969
+ if (item.textContent.toLowerCase().includes(lowerCaseQuery)) {
11970
+ item.parentElement.style.display = 'block';
11971
+ } else {
11972
+ item.parentElement.style.display = 'none';
11973
+ }
11974
+ });
11975
+ }
11976
+
11977
+ attachEventListeners() {
11978
+ this.menuSearch.addEventListener('input', (event) =>
11979
+ this.filterItems(event.target.value)
11980
+ );
11981
+
11982
+ // Open the modal when the user presses 'g'
11983
+ constants.events.push([
11984
+ [constants.chart, constants.brailleInput],
11985
+ 'keyup',
11986
+ function (event) {
11987
+ if (event.key === 'g' && !goto.popupOpen) {
11988
+ goto.openMenu();
11989
+ }
11990
+ },
11991
+ ]);
11992
+ // arrow keys to navigate the list, escape to close
11993
+ constants.events.push([
11994
+ constants.gotoMenu,
11995
+ 'keydown',
11996
+ function (event) {
11997
+ if (goto.menuOpen) {
11998
+ const focusableElements = [
11999
+ goto.menuSearch,
12000
+ ...goto.menuItems.filter(
12001
+ (item) => item.parentElement.style.display !== 'none'
12002
+ ),
12003
+ ];
12004
+ const currentIndex = focusableElements.indexOf(
12005
+ document.activeElement
12006
+ );
12007
+
12008
+ if (event.key === 'ArrowDown') {
12009
+ event.preventDefault();
12010
+ const nextIndex = (currentIndex + 1) % focusableElements.length;
12011
+ focusableElements[nextIndex]?.focus();
12012
+ } else if (event.key === 'ArrowUp') {
12013
+ event.preventDefault();
12014
+ const prevIndex =
12015
+ (currentIndex - 1 + focusableElements.length) %
12016
+ focusableElements.length;
12017
+ focusableElements[prevIndex]?.focus();
12018
+ } else {
12019
+ if (event.key === 'Escape') {
12020
+ goto.closeMenu();
12021
+ }
12022
+ }
12023
+ }
12024
+ },
12025
+ ]);
12026
+ // enter to select, which we register as a click event so it works with screen readers
12027
+ constants.events.push([
12028
+ constants.gotoMenu,
12029
+ 'click',
12030
+ function (event) {
12031
+ if (event.target.tagName === 'BUTTON') {
12032
+ let loc = event.target.textContent;
12033
+ goto.closeMenu();
12034
+ goto.goToLocation(loc);
12035
+ }
12036
+ },
12037
+ ]);
12038
+ }
12039
+
12040
+ goToLocation(loc) {
12041
+ console.log(`Navigating to: ${loc}`);
12042
+ // Replace this with your actual navigation logic
12043
+
12044
+ if (loc == 'Max Value') {
12045
+ if (constants.chartType == 'bar' || constants.chartType == 'hist') {
12046
+ // get the max value of this array and return the index
12047
+ let max = Math.max(...plot.plotData);
12048
+ let index = plot.plotData.indexOf(max);
12049
+ position.x = index;
12050
+ control.UpdateAll();
12051
+ } else if (constants.chartType == 'line') {
12052
+ let max = Math.max(...plot.pointValuesY);
12053
+ let index = plot.pointValuesY.indexOf(max);
12054
+ position.x = index;
12055
+ control.UpdateAll();
12056
+ } else if (constants.chartType == 'point') {
12057
+ let max = Math.max(...plot.curvePoints);
12058
+ let index = plot.curvePoints.indexOf(max);
12059
+ position.x = index;
12060
+ control.UpdateAll();
12061
+ } else if (constants.chartType == 'heat') {
12062
+ // here we have a 2d array to search, and we need both y (parent) and x (child) indexes
12063
+ let max = Math.max(...plot.data.flat());
12064
+ let index = plot.data.flat().indexOf(max);
12065
+ let y = Math.floor(index / plot.data[0].length);
12066
+ let x = index % plot.data[0].length;
12067
+ position.x = x;
12068
+ position.y = y;
12069
+ control.UpdateAll();
12070
+ }
12071
+ } else if (loc == 'Min Value') {
12072
+ if (constants.chartType == 'bar' || constants.chartType == 'hist') {
12073
+ // get the min value of this array and return the index
12074
+ let min = Math.min(...plot.plotData);
12075
+ let index = plot.plotData.indexOf(min);
12076
+ position.x = index;
12077
+ control.UpdateAll();
12078
+ } else if (constants.chartType == 'line') {
12079
+ let min = Math.min(...plot.pointValuesY);
12080
+ let index = plot.pointValuesY.indexOf(min);
12081
+ position.x = index;
12082
+ control.UpdateAll();
12083
+ } else if (constants.chartType == 'point') {
12084
+ let min = Math.min(...plot.curvePoints);
12085
+ let index = plot.curvePoints.indexOf(min);
12086
+ position.x = index;
12087
+ control.UpdateAll();
12088
+ } else if (constants.chartType == 'heat') {
12089
+ // here we have a 2d array to search, and we need both y (parent) and x (child) indexes
12090
+ let min = Math.min(...plot.data.flat());
12091
+ let index = plot.data.flat().indexOf(min);
12092
+ let y = Math.floor(index / plot.data[0].length);
12093
+ let x = index % plot.data[0].length;
12094
+ position.x = x;
12095
+ position.y = y;
12096
+ control.UpdateAll();
12097
+ }
12098
+ } else if (loc == 'Mean') {
12099
+ } else if (loc == 'Median') {
12100
+ }
12101
+ }
12102
+ }
12103
+
11917
12104
  // events and init functions
11918
12105
  // we do some setup, but most of the work is done when user focuses on an element matching an id from maidr user data
11919
12106
  document.addEventListener('DOMContentLoaded', function (e) {
@@ -11981,6 +12168,7 @@ function InitMaidr(thisMaidr) {
11981
12168
  window.control = new Control(); // this inits the actual chart object and Position
11982
12169
  window.review = new Review();
11983
12170
  window.display = new Display();
12171
+ window.goto = new Goto();
11984
12172
  window.audio = new Audio();
11985
12173
 
11986
12174
  // blur destruction events