NGToolsCSharp/NGTools/Scripts/Highcharts-7.1.1/code/es-modules/modules/accessibility/components/ZoomComponent.js
2024-09-13 16:44:30 +08:00

334 lines
8.5 KiB
JavaScript

/* *
*
* (c) 2009-2019 Øystein Moseng
*
* Accessibility component for chart zoom.
*
* License: www.highcharts.com/license
*
* */
'use strict';
import H from '../../../parts/Globals.js';
import AccessibilityComponent from '../AccessibilityComponent.js';
import KeyboardNavigationHandler from '../KeyboardNavigationHandler.js';
/**
* 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]
*/
H.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 (chart) {
this.initBase(chart);
this.init();
};
ZoomComponent.prototype = new AccessibilityComponent();
H.extend(ZoomComponent.prototype, /** @lends Highcharts.ZoomComponent */ {
/**
* Initialize the component
*/
init: function () {
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 () {
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 () {
this.updateProxyOverlays();
},
/**
* Update proxy overlays, recreating the buttons.
*/
updateProxyOverlays: function () {
var component = this,
chart = this.chart,
proxyButton = function (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 () {
var keys = this.keyCodes,
chart = this.chart,
component = this;
return new KeyboardNavigationHandler(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 () {
return (
chart.mapZoom &&
chart.mapNavButtons &&
chart.mapNavButtons.length === 2
);
},
// Make zoom buttons do their magic
init: function (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 (buttonProp, proxyProp, onClick) {
var keys = this.keyCodes,
component = this,
chart = this.chart;
return new KeyboardNavigationHandler(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 () {
return chart[buttonProp] && chart[buttonProp].box &&
component[proxyProp];
},
// Focus button initially
init: function () {
chart.setFocusToElement(
chart[buttonProp].box, component[proxyProp]
);
}
});
},
/**
* Get keyboard navigation handlers for this component.
* @return {Array<Highcharts.KeyboardNavigationHandler>}
* List of module objects
*/
getKeyboardNavigation: function () {
return [
this.simpleButtonNavigation(
'resetZoomButton',
'resetZoomProxyButton',
function (chart) {
chart.zoomOut();
}
),
this.simpleButtonNavigation(
'drillUpButton',
'drillUpProxyButton',
function (chart) {
chart.drillUp();
}
),
this.getMapZoomNavigation()
];
}
});
export default ZoomComponent;