/* * * * (c) 2009-2019 Øystein Moseng * * Accessibility component for chart zoom. * * License: www.highcharts.com/license * * */ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _Globals = require('../../../parts/Globals.js'); var _Globals2 = _interopRequireDefault(_Globals); var _AccessibilityComponent = require('../AccessibilityComponent.js'); var _AccessibilityComponent2 = _interopRequireDefault(_AccessibilityComponent); var _KeyboardNavigationHandler = require('../KeyboardNavigationHandler.js'); var _KeyboardNavigationHandler2 = _interopRequireDefault(_KeyboardNavigationHandler); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Pan along axis in a direction (1 or -1), optionally with a defined * granularity (number of steps it takes to walk across current view) * * @private * @function Highcharts.Axis#panStep * * @param {number} direction * @param {number} [granularity] */ _Globals2.default.Axis.prototype.panStep = function (direction, granularity) { var gran = granularity || 3, extremes = this.getExtremes(), step = (extremes.max - extremes.min) / gran * direction, newMax = extremes.max + step, newMin = extremes.min + step, size = newMax - newMin; if (direction < 0 && newMin < extremes.dataMin) { newMin = extremes.dataMin; newMax = newMin + size; } else if (direction > 0 && newMax > extremes.dataMax) { newMax = extremes.dataMax; newMin = newMax - size; } this.setExtremes(newMin, newMax); }; /** * The ZoomComponent class * * @private * @class * @name Highcharts.ZoomComponent * @param {Highcharts.Chart} chart * Chart object */ var ZoomComponent = function ZoomComponent(chart) { this.initBase(chart); this.init(); }; ZoomComponent.prototype = new _AccessibilityComponent2.default(); _Globals2.default.extend(ZoomComponent.prototype, /** @lends Highcharts.ZoomComponent */{ /** * Initialize the component */ init: function init() { var component = this, chart = this.chart; ['afterShowResetZoom', 'afterDrilldown', 'drillupall'].forEach(function (eventType) { component.addEvent(chart, eventType, function () { component.updateProxyOverlays(); }); }); }, /** * Called when chart is updated */ onChartUpdate: function onChartUpdate() { var chart = this.chart, component = this; // Make map zoom buttons accessible if (chart.mapNavButtons) { chart.mapNavButtons.forEach(function (button, i) { component.unhideElementFromScreenReaders(button.element); button.element.setAttribute('tabindex', -1); button.element.setAttribute('role', 'button'); button.element.setAttribute('aria-label', chart.langFormat('accessibility.mapZoom' + (i ? 'Out' : 'In'), { chart: chart })); }); } }, /** * Update the proxy overlays on every new render to ensure positions are * correct. */ onChartRender: function onChartRender() { this.updateProxyOverlays(); }, /** * Update proxy overlays, recreating the buttons. */ updateProxyOverlays: function updateProxyOverlays() { var component = this, chart = this.chart, proxyButton = function proxyButton(buttonEl, buttonProp, groupProp, label) { component.removeElement(component[groupProp]); component[groupProp] = component.addProxyGroup(); component[buttonProp] = component.createProxyButton(buttonEl, component[groupProp], { 'aria-label': label, tabindex: -1 }); }; // Always start with a clean slate component.removeElement(component.drillUpProxyGroup); component.removeElement(component.resetZoomProxyGroup); if (chart.resetZoomButton) { proxyButton(chart.resetZoomButton, 'resetZoomProxyButton', 'resetZoomProxyGroup', chart.langFormat('accessibility.resetZoomButton', { chart: chart })); } if (chart.drillUpButton) { proxyButton(chart.drillUpButton, 'drillUpProxyButton', 'drillUpProxyGroup', chart.langFormat('accessibility.drillUpButton', { chart: chart, buttonText: chart.getDrilldownBackText() })); } }, /** * Get keyboard navigation handler for map zoom. * @private * @return {Highcharts.KeyboardNavigationHandler} The module object */ getMapZoomNavigation: function getMapZoomNavigation() { var keys = this.keyCodes, chart = this.chart, component = this; return new _KeyboardNavigationHandler2.default(chart, { keyCodeMap: [ // Arrow keys [[keys.up, keys.down, keys.left, keys.right], function (keyCode) { chart[keyCode === keys.up || keyCode === keys.down ? 'yAxis' : 'xAxis'][0].panStep(keyCode === keys.left || keyCode === keys.up ? -1 : 1); return this.response.success; }], // Tabs [[keys.tab], function (keyCode, e) { var button; // Deselect old chart.mapNavButtons[component.focusedMapNavButtonIx].setState(0); // Trying to go somewhere we can't? if (e.shiftKey && !component.focusedMapNavButtonIx || !e.shiftKey && component.focusedMapNavButtonIx) { chart.mapZoom(); // Reset zoom // Nowhere to go, go to prev/next module return this.response[e.shiftKey ? 'prev' : 'next']; } // Select other button component.focusedMapNavButtonIx += e.shiftKey ? -1 : 1; button = chart.mapNavButtons[component.focusedMapNavButtonIx]; chart.setFocusToElement(button.box, button.element); button.setState(2); return this.response.success; }], // Press button [[keys.space, keys.enter], function () { component.fakeClickEvent(chart.mapNavButtons[component.focusedMapNavButtonIx].element); return this.response.success; }]], // Only run this module if we have map zoom on the chart validate: function validate() { return chart.mapZoom && chart.mapNavButtons && chart.mapNavButtons.length === 2; }, // Make zoom buttons do their magic init: function init(direction) { var zoomIn = chart.mapNavButtons[0], zoomOut = chart.mapNavButtons[1], initialButton = direction > 0 ? zoomIn : zoomOut; chart.setFocusToElement(initialButton.box, initialButton.element); initialButton.setState(2); component.focusedMapNavButtonIx = direction > 0 ? 0 : 1; } }); }, /** * Get keyboard navigation handler for a simple chart button. Provide the * button reference for the chart, and a function to call on click. * * @private * @param {string} buttonProp The property on chart referencing the button. * @return {Highcharts.KeyboardNavigationHandler} The module object */ simpleButtonNavigation: function simpleButtonNavigation(buttonProp, proxyProp, onClick) { var keys = this.keyCodes, component = this, chart = this.chart; return new _KeyboardNavigationHandler2.default(chart, { keyCodeMap: [ // Arrow/tab just move [[keys.tab, keys.up, keys.down, keys.left, keys.right], function (keyCode, e) { return this.response[keyCode === this.tab && e.shiftKey || keyCode === keys.left || keyCode === keys.up ? 'prev' : 'next']; }], // Select to click [[keys.space, keys.enter], function () { onClick(chart); return this.response.success; }]], // Only run if we have the button validate: function validate() { return chart[buttonProp] && chart[buttonProp].box && component[proxyProp]; }, // Focus button initially init: function init() { chart.setFocusToElement(chart[buttonProp].box, component[proxyProp]); } }); }, /** * Get keyboard navigation handlers for this component. * @return {Array} * List of module objects */ getKeyboardNavigation: function getKeyboardNavigation() { return [this.simpleButtonNavigation('resetZoomButton', 'resetZoomProxyButton', function (chart) { chart.zoomOut(); }), this.simpleButtonNavigation('drillUpButton', 'drillUpProxyButton', function (chart) { chart.drillUp(); }), this.getMapZoomNavigation()]; } }); exports.default = ZoomComponent;