From ebb19a9e3df4d8953593abfa81fa1a88787e1237 Mon Sep 17 00:00:00 2001 From: ellvix Date: Mon, 14 Oct 2024 22:10:39 -0600 Subject: [PATCH] feat: scale autoplay rate to chart size, expose var AUTOPLAY_RATE to users (#580) --- galleries/bar_plot.html | 4 +- src/js/barplot.js | 5 +- src/js/boxplot.js | 5 +- src/js/constants.js | 1052 +++++++++++++++++++-------------------- src/js/heatmap.js | 5 +- src/js/histogram.js | 19 +- src/js/lineplot.js | 5 +- src/js/scatterplot.js | 5 +- src/js/segmented.js | 5 +- 9 files changed, 546 insertions(+), 559 deletions(-) diff --git a/galleries/bar_plot.html b/galleries/bar_plot.html index 5f9aa39e8..346020850 100644 --- a/galleries/bar_plot.html +++ b/galleries/bar_plot.html @@ -6,7 +6,6 @@ - @@ -1147,7 +1146,6 @@ data: [1610, 4906, 12082, 13791, 21551], }; - + diff --git a/src/js/barplot.js b/src/js/barplot.js index 2141886e5..b7e037068 100644 --- a/src/js/barplot.js +++ b/src/js/barplot.js @@ -166,9 +166,8 @@ class BarChart { } } constants.maxX = this.columnLabels.length; - constants.autoPlayRate = Math.min( - Math.ceil(constants.AUTOPLAY_DURATION / (constants.maxX + 1)), - constants.MAX_SPEED + constants.autoPlayRate = Math.ceil( + constants.AUTOPLAY_DURATION / this.plotData.length ); constants.DEFAULT_SPEED = constants.autoPlayRate; if (constants.autoPlayRate < constants.MIN_SPEED) { diff --git a/src/js/boxplot.js b/src/js/boxplot.js index dda275860..35c1eb3ed 100644 --- a/src/js/boxplot.js +++ b/src/js/boxplot.js @@ -177,10 +177,7 @@ class BoxPlot { constants.minY = 0; constants.maxY = this.plotData.length - 1; } - constants.autoPlayRate = Math.min( - Math.ceil(constants.AUTOPLAY_DURATION / this.plotData.length), - constants.MAX_SPEED - ); + constants.autoPlayRate = Math.ceil(constants.AUTOPLAY_DURATION / 7); constants.DEFAULT_SPEED = constants.autoPlayRate; if (constants.autoPlayRate < constants.MIN_SPEED) { constants.MIN_SPEED = constants.autoPlayRate; diff --git a/src/js/constants.js b/src/js/constants.js index 283783af2..b4fdb5c29 100644 --- a/src/js/constants.js +++ b/src/js/constants.js @@ -12,77 +12,77 @@ class Constants { * @memberof HtmlIds * @default 'chart-container' */ - chart_container_id = "chart-container"; + chart_container_id = 'chart-container'; /** * HTML id of the main container div. * @type {string} * @memberof HtmlIds * @default 'maidr-container' */ - main_container_id = "maidr-container"; + main_container_id = 'maidr-container'; /** * HTML id of the div containing the braille display input * @type {string} * @memberof HtmlIds * @default 'braille-div' */ - braille_container_id = "braille-div"; + braille_container_id = 'braille-div'; /** * HTML id of the actual braille input element. * @type {string} * @memberof HtmlIds * @default 'braille-input' */ - braille_input_id = "braille-input"; + braille_input_id = 'braille-input'; /** * HTML id of the div containing the info box. * @type {string} * @memberof HtmlIds * @default 'info' */ - info_id = "info"; + info_id = 'info'; /** * HTML id of the div containing announcements that hook directly into the screen reader via aria-live. * @type {string} * @memberof HtmlIds * @default 'announcements' */ - announcement_container_id = "announcements"; + announcement_container_id = 'announcements'; /** * HTML id of the div containing the end chime. To be implemented in the future. * @type {string} * @memberof HtmlIds * @default 'end_chime' */ - end_chime_id = "end_chime"; + end_chime_id = 'end_chime'; /** * HTML id of the main container div. * @type {string} * @memberof HtmlIds * @default 'container' */ - container_id = "container"; + container_id = 'container'; /** * The main project id, used throughout the application. * @type {string} * @memberof HtmlIds * @default 'maidr' */ - project_id = "maidr"; + project_id = 'maidr'; /** * HTML id of the div containing the review text. * @type {string} * @memberof HtmlIds * @default 'review_container' */ - review_id_container = "review_container"; + review_id_container = 'review_container'; /** * HTML id of the review input element. * @type {string} * @memberof HtmlIds * @default 'review' */ - review_id = "review"; + review_id = 'review'; /** * Storage element, used to store the last focused element before moving to the review input so we can switch back to it easily. * @type {HTMLElement} @@ -99,7 +99,7 @@ class Constants { * @type {string} * @memberof HtmlIds */ - chartId = ""; + chartId = ''; /** * @typedef {Object} EventListenerSetupObject * @property {HTMLElement} element - The element to attach the event listener to. @@ -128,7 +128,8 @@ class Constants { * @memberof BTSModes * @default 'verbose' */ - textMode = "verbose"; + textMode = 'verbose'; + /** * The current braille mode. Can be 'off' or 'on'. * @type {("off"|"on")} @@ -150,14 +151,14 @@ class Constants { * @memberof BTSModes * @default 'on' */ - sonifMode = "on"; + sonifMode = 'on'; /** * The current review mode. Can be 'on' or 'off'. * @type {("on"|"off")} * @memberof BTSModes * @default 'off' */ - reviewMode = "off"; + reviewMode = 'off'; // basic chart properties /** @@ -198,14 +199,14 @@ class Constants { * @memberof HtmlIds * @default '' */ - plotId = ""; // update with id in chart specific js + plotId = ''; // update with id in chart specific js /** * The chart type, sort of a short name of the chart such as 'box', 'bar', 'line', etc. * @type {string} * @default '' * @memberof BasicChartProperties */ - chartType = ""; + chartType = ''; /** * The navigation orientation of the chart. 0 = row navigation (up/down), 1 = col navigation (left/right). * @type {number} @@ -219,7 +220,7 @@ class Constants { * @default 'horz' * @memberof BasicChartProperties */ - plotOrientation = "horz"; + plotOrientation = 'horz'; /** * @namespace AudioProperties @@ -296,7 +297,7 @@ class Constants { * @default 5000 * @memberof AudioProperties */ - AUTOPLAY_DURATION = 5000; // 5s + AUTOPLAY_DURATION = 2000; // 5s // user settings /** @@ -329,7 +330,7 @@ class Constants { * @default '#03C809' (green) * @memberof UserSettings */ - colorSelected = "#03C809"; + colorSelected = '#03C809'; /** * The length of the braille display in characters. Braille displays have a variety of sizes; 40 is pretty common, 32 is quite reliable. Set this to your actual display length so that the system can scale and display braille properly for you (where possible). * @type {number} @@ -397,7 +398,7 @@ class Constants { * @default 50 * @memberof AdvancedUserSettings */ - colorUnselected = "#595959"; // deprecated, todo: find all instances replace with storing old color method + colorUnselected = '#595959'; // deprecated, todo: find all instances replace with storing old color method /** * Whether or not we're logging user data. This is off by default, but is used for research purposes. * @type {boolean} @@ -425,30 +426,30 @@ class Constants { * @default 'assertive' * @memberof AdvancedUserSettings */ - ariaMode = "assertive"; + ariaMode = 'assertive'; /** * Full list of user settings, used internally to save and load settings. * @type {string[]} */ userSettingsKeys = [ - "vol", - "autoPlayRate", - "brailleDisplayLength", - "colorSelected", - "MIN_FREQUENCY", - "MAX_FREQUENCY", - "keypressInterval", - "ariaMode", - "openAIAuthKey", - "geminiAuthKey", - "skillLevel", - "skillLevelOther", - "LLMModel", - "LLMPreferences", - "LLMOpenAiMulti", - "LLMGeminiMulti", - "autoInitLLM", + 'vol', + 'autoPlayRate', + 'brailleDisplayLength', + 'colorSelected', + 'MIN_FREQUENCY', + 'MAX_FREQUENCY', + 'AUTOPLAY_DURATION', + 'ariaMode', + 'openAIAuthKey', + 'geminiAuthKey', + 'skillLevel', + 'skillLevelOther', + 'LLMModel', + 'LLMPreferences', + 'LLMOpenAiMulti', + 'LLMGeminiMulti', + 'autoInitLLM', ]; // LLM settings @@ -489,14 +490,14 @@ class Constants { * @default 'high' * @memberof LLMSettings */ - LLMDetail = "high"; // low (default for testing, like 100 tokens) / high (default for real, like 1000 tokens) + LLMDetail = 'high'; // low (default for testing, like 100 tokens) / high (default for real, like 1000 tokens) /** * Current LLM model in use. Can be 'openai' (default) or 'gemini' or 'multi'. More to be added. * @type {("openai"|"gemini"|"multi")} * @default 'openai' * @memberof LLMSettings */ - LLMModel = "openai"; + LLMModel = 'openai'; /** * The default system message for the LLM. Helps the LLM understand the context of the chart and its role. * @type {string} @@ -504,21 +505,21 @@ class Constants { * @memberof LLMSettings */ LLMSystemMessage = - "You are a helpful assistant describing the chart to a blind person. "; + 'You are a helpful assistant describing the chart to a blind person. '; /** * The level of skill the user has with statistical charts. Can be 'basic', 'intermediate', 'expert', or 'other'. This is passed to the LLM on the initial message to help it speak correctly to the user. If 'other' is selected, the user can provide a custom skill level. * @type {("basic"|"intermediate"|"expert"|"other")} * @default 'basic' * @memberof LLMSettings */ - skillLevel = "basic"; // basic / intermediate / expert + skillLevel = 'basic'; // basic / intermediate / expert /** * Custom skill level, used if the user selects 'other' as their skill level. * @type {string} * @default '' * @memberof LLMSettings */ - skillLevelOther = ""; // custom skill level + skillLevelOther = ''; // custom skill level /** * The LLM can send the first default message containing the chart image on initialization, so when the user opens the chat window the LLM already has an initial response and is ready for a conversation. * @type {boolean} @@ -532,7 +533,7 @@ class Constants { * @default '' * @memberof LLMSettings */ - verboseText = ""; + verboseText = ''; /** * An internal variable used to turn the waiting beep on and off. * @type {number} @@ -580,35 +581,38 @@ class Constants { * @type {boolean} * @memberof PlatformControls */ - isMac = navigator.userAgent.toLowerCase().includes("mac"); // true if macOS + isMac = navigator.userAgent.toLowerCase().includes('mac'); // true if macOS /** * The control key for the user's platform. Can be 'Cmd' or 'Ctrl'. Used in keyboard shortcut display in help. * @type {"Cmd"|"Ctrl"} * @memberof PlatformControls */ - control = this.isMac ? "Cmd" : "Ctrl"; + control = this.isMac ? 'Cmd' : 'Ctrl'; /** * The alt key for the user's platform. Can be 'option' or 'Alt'. Used in keyboard shortcut display in help. * @type {"option"|"Alt"} * @memberof PlatformControls */ - alt = this.isMac ? "option" : "Alt"; + alt = this.isMac ? 'option' : 'Alt'; /** * The home key for the user's platform. Can be 'fn + Left arrow' or 'Home'. Used in keyboard shortcut display in help. * @type {"fn + Left arrow"|"Home"} * @memberof PlatformControls */ - home = this.isMac ? "fn + Left arrow" : "Home"; + home = this.isMac ? 'fn + Left arrow' : 'Home'; /** * The end key for the user's platform. Can be 'fn + Right arrow' or 'End'. Used in keyboard shortcut display in help. * @type {"fn + Right arrow"|"End"} * @memberof PlatformControls */ - end = this.isMac ? "fn + Right arrow" : "End"; + end = this.isMac ? 'fn + Right arrow' : 'End'; + /** + * The interval we wait for an L + X prefix event + */ + keypressInterval = 2000; // ms or 2s // internal controls // todo: are these even used? Sean doesn't think so (May 2024) - keypressInterval = 2000; // ms or 2s tabMovement = null; // debug stuff @@ -697,13 +701,13 @@ class Constants { */ ConvertHexToRGBString(hexColorString) { return ( - "rgb(" + + 'rgb(' + parseInt(hexColorString.slice(1, 3), 16) + - "," + + ',' + parseInt(hexColorString.slice(3, 5), 16) + - "," + + ',' + parseInt(hexColorString.slice(5, 7), 16) + - ")" + ')' ); } @@ -713,12 +717,12 @@ class Constants { * @returns {string} - hexadecimal color (e.g., "#595959"). */ ConvertRGBStringToHex(rgbColorString) { - let rgb = rgbColorString.replace(/[^\d,]/g, "").split(","); + let rgb = rgbColorString.replace(/[^\d,]/g, '').split(','); return ( - "#" + - rgb[0].toString(16).padStart(2, "0") + - rgb[1].toString(16).padStart(2, "0") + - rgb[2].toString(16).padStart(2, "0") + '#' + + rgb[0].toString(16).padStart(2, '0') + + rgb[1].toString(16).padStart(2, '0') + + rgb[2].toString(16).padStart(2, '0') ); } @@ -730,11 +734,11 @@ class Constants { */ ColorInvert(color) { // invert an rgb color - let rgb = color.replace(/[^\d,]/g, "").split(","); + let rgb = color.replace(/[^\d,]/g, '').split(','); let r = 255 - rgb[0]; let g = 255 - rgb[1]; let b = 255 - rgb[2]; - return "rgb(" + r + "," + g + "," + b + ")"; + return 'rgb(' + r + ',' + g + ',' + b + ')'; } /** @@ -743,11 +747,11 @@ class Constants { * @returns {string} The better color */ GetBetterColor(oldColor) { - if (oldColor.indexOf("#") !== -1) { + if (oldColor.indexOf('#') !== -1) { oldColor = this.ConvertHexToRGBString(oldColor); } let newColor = this.ColorInvert(oldColor); - let rgb = newColor.replace(/[^\d,]/g, "").split(","); + let rgb = newColor.replace(/[^\d,]/g, '').split(','); if ( rgb[1] < rgb[0] + 10 && rgb[1] > rgb[0] - 10 && @@ -769,7 +773,7 @@ class Constants { */ GetStyleArrayFromString(styleString) { // Get an array of CSS style attributes and values from a style string - return styleString.replaceAll(" ", "").split(/[:;]/); + return styleString.replaceAll(' ', '').split(/[:;]/); } /** @@ -779,16 +783,16 @@ class Constants { */ GetStyleStringFromArray(styleArray) { // Get CSS style string from an array of style attributes and values - let styleString = ""; + let styleString = ''; for (let i = 0; i < styleArray.length; i++) { if (i % 2 === 0) { if (i !== styleArray.length - 1) { - styleString += styleArray[i] + ": "; + styleString += styleArray[i] + ': '; } else { styleString += styleArray[i]; } } else { - styleString += styleArray[i] + "; "; + styleString += styleArray[i] + '; '; } } return styleString; @@ -801,35 +805,35 @@ class Constants { class Resources { constructor() {} - language = "en"; // Current language, 2 char lang code - knowledgeLevel = "basic"; // basic, intermediate, expert + language = 'en'; // Current language, 2 char lang code + knowledgeLevel = 'basic'; // basic, intermediate, expert // language strings, per 2 char language code strings = { en: { basic: { - upper_outlier: "Upper Outlier", - lower_outlier: "Lower Outlier", - min: "Minimum", - max: "Maximum", - 25: "25%", - 50: "50%", - 75: "75%", - q1: "25%", - q2: "50%", - q3: "75%", - son_on: "Sonification on", - son_off: "Sonification off", - son_des: "Sonification descrete", - son_comp: "Sonification compare", - son_ch: "Sonification chord", - son_sep: "Sonification separate", - son_same: "Sonification combined", - empty: "Empty", - openai: "OpenAI Vision", - gemini: "Gemini Pro Vision", - multi: "Multiple AI", - processing: "Processing Chart...", + upper_outlier: 'Upper Outlier', + lower_outlier: 'Lower Outlier', + min: 'Minimum', + max: 'Maximum', + 25: '25%', + 50: '50%', + 75: '75%', + q1: '25%', + q2: '50%', + q3: '75%', + son_on: 'Sonification on', + son_off: 'Sonification off', + son_des: 'Sonification descrete', + son_comp: 'Sonification compare', + son_ch: 'Sonification chord', + son_sep: 'Sonification separate', + son_same: 'Sonification combined', + empty: 'Empty', + openai: 'OpenAI Vision', + gemini: 'Gemini Pro Vision', + multi: 'Multiple AI', + processing: 'Processing Chart...', }, }, }; @@ -991,25 +995,20 @@ class Menu {

-

-

+

-

+

Autoplay Duration (ms)

Aria Mode

@@ -1030,7 +1029,7 @@ class Menu {