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

235 lines
6.5 KiB
JavaScript

/* *
*
* (c) 2009-2019 Øystein Moseng
*
* Accessibility component for chart legend.
*
* License: www.highcharts.com/license
*
* */
'use strict';
import H from '../../../parts/Globals.js';
import AccessibilityComponent from '../AccessibilityComponent.js';
import KeyboardNavigationHandler from '../KeyboardNavigationHandler.js';
/**
* Highlight legend item by index.
*
* @private
* @function Highcharts.Chart#highlightLegendItem
*
* @param {number} ix
*
* @return {boolean}
*/
H.Chart.prototype.highlightLegendItem = function (ix) {
var items = this.legend.allItems,
oldIx = this.highlightedLegendItemIx;
if (items[ix]) {
if (items[oldIx]) {
H.fireEvent(
items[oldIx].legendGroup.element,
'mouseout'
);
}
// Scroll if we have to
if (items[ix].pageIx !== undefined &&
items[ix].pageIx + 1 !== this.legend.currentPage) {
this.legend.scroll(1 + items[ix].pageIx - this.legend.currentPage);
}
// Focus
this.setFocusToElement(
items[ix].legendItem, items[ix].a11yProxyElement
);
H.fireEvent(items[ix].legendGroup.element, 'mouseover');
return true;
}
return false;
};
// Keep track of pressed state for legend items
H.addEvent(H.Legend, 'afterColorizeItem', function (e) {
var chart = this.chart,
a11yOptions = chart.options.accessibility,
legendItem = e.item;
if (a11yOptions.enabled && legendItem && legendItem.a11yProxyElement) {
legendItem.a11yProxyElement.setAttribute(
'aria-pressed', e.visible ? 'false' : 'true'
);
}
});
/**
* The LegendComponent class
*
* @private
* @class
* @name Highcharts.LegendComponent
* @param {Highcharts.Chart} chart
* Chart object
*/
var LegendComponent = function (chart) {
this.initBase(chart);
};
LegendComponent.prototype = new AccessibilityComponent();
H.extend(LegendComponent.prototype, /** @lends Highcharts.LegendComponent */ {
/**
* The legend needs updates on every render, in order to update positioning
* of the proxy overlays.
*/
onChartRender: function () {
var chart = this.chart,
a11yOptions = chart.options.accessibility,
items = chart.legend && chart.legend.allItems,
component = this;
// Ignore render after proxy clicked. No need to destroy it, and
// destroying also kills focus.
if (component.legendProxyButtonClicked) {
delete component.legendProxyButtonClicked;
return;
}
// Always Remove group if exists
this.removeElement(this.legendProxyGroup);
// Skip everything if we do not have legend items, or if we have a
// color axis
if (
!items || !items.length ||
chart.colorAxis && chart.colorAxis.length ||
!chart.options.legend.accessibility.enabled
) {
return;
}
// Add proxy group
this.legendProxyGroup = this.addProxyGroup({
'aria-label': chart.langFormat(
'accessibility.legendLabel'
),
'role': a11yOptions.landmarkVerbosity === 'all' ?
'region' : null
});
// Proxy the legend items
items.forEach(function (item) {
if (item.legendItem && item.legendItem.element) {
item.a11yProxyElement = component.createProxyButton(
item.legendItem,
component.legendProxyGroup,
{
tabindex: -1,
'aria-pressed': !item.visible,
'aria-label': chart.langFormat(
'accessibility.legendItem',
{
chart: chart,
itemName: component.stripTags(item.name)
}
)
},
// Consider useHTML
item.legendGroup.div ? item.legendItem : item.legendGroup,
// Additional click event (fires first)
function () {
// Keep track of when we should ignore next render
component.legendProxyButtonClicked = true;
}
);
}
});
},
/**
* Get keyboard navigation handler for this component.
* @return {Highcharts.KeyboardNavigationHandler}
*/
getKeyboardNavigation: function () {
var keys = this.keyCodes,
component = this,
chart = this.chart,
a11yOptions = chart.options.accessibility;
return new KeyboardNavigationHandler(chart, {
keyCodeMap: [
// Arrow key handling
[[
keys.left, keys.right, keys.up, keys.down
], function (keyCode) {
var direction = (
keyCode === keys.left || keyCode === keys.up
) ? -1 : 1;
// Try to highlight next/prev legend item
var res = chart.highlightLegendItem(
component.highlightedLegendItemIx + direction
);
if (res) {
component.highlightedLegendItemIx += direction;
return this.response.success;
}
// Failed, can we wrap around?
if (
chart.legend.allItems.length > 1 &&
a11yOptions.keyboardNavigation.wrapAround
) {
// Wrap around if we failed and have more than 1 item
this.init(direction);
return this.response.success;
}
// No wrap, move
return this.response[direction > 0 ? 'next' : 'prev'];
}],
// Click item
[[
keys.enter, keys.space
], function () {
var legendItem = chart.legend.allItems[
component.highlightedLegendItemIx
];
if (legendItem && legendItem.a11yProxyElement) {
H.fireEvent(legendItem.a11yProxyElement, 'click');
}
return this.response.success;
}]
],
// Only run this module if we have at least one legend - wait for
// it - item. Don't run if the legend is populated by a colorAxis.
// Don't run if legend navigation is disabled.
validate: function () {
var legendOptions = chart.options.legend;
return chart.legend && chart.legend.allItems &&
chart.legend.display &&
!(chart.colorAxis && chart.colorAxis.length) &&
legendOptions &&
legendOptions.accessibility &&
legendOptions.accessibility.enabled &&
legendOptions.accessibility.keyboardNavigation &&
legendOptions.accessibility.keyboardNavigation.enabled;
},
// Focus first/last item
init: function (direction) {
var ix = direction > 0 ? 0 : chart.legend.allItems.length - 1;
chart.highlightLegendItem(ix);
component.highlightedLegendItemIx = ix;
}
});
}
});
export default LegendComponent;