chore: version inicial del codigo fuente del LMS Estafeta

This commit is contained in:
2026-10-02 20:33:12 -06:00
commit c8bb6b97b9
1572 changed files with 457520 additions and 0 deletions
@@ -0,0 +1,171 @@
/* *
*
* (c) 2009-2020 Øystein Moseng
*
* Handle forcing series markers.
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
'use strict';
import H from '../../../Core/Globals.js';
import U from '../../../Core/Utilities.js';
var addEvent = U.addEvent, merge = U.merge;
/* eslint-disable no-invalid-this, valid-jsdoc */
/**
* @private
*/
function isWithinDescriptionThreshold(series) {
var a11yOptions = series.chart.options.accessibility;
return series.points.length <
a11yOptions.series.pointDescriptionEnabledThreshold ||
a11yOptions.series.pointDescriptionEnabledThreshold === false;
}
/**
* @private
*/
function shouldForceMarkers(series) {
var chart = series.chart, chartA11yEnabled = chart.options.accessibility.enabled, seriesA11yEnabled = (series.options.accessibility &&
series.options.accessibility.enabled) !== false;
return chartA11yEnabled && seriesA11yEnabled && isWithinDescriptionThreshold(series);
}
/**
* @private
*/
function hasIndividualPointMarkerOptions(series) {
return !!(series._hasPointMarkers && series.points && series.points.length);
}
/**
* @private
*/
function unforceSeriesMarkerOptions(series) {
var resetMarkerOptions = series.resetA11yMarkerOptions;
if (resetMarkerOptions) {
merge(true, series.options, {
marker: {
enabled: resetMarkerOptions.enabled,
states: {
normal: {
opacity: resetMarkerOptions.states &&
resetMarkerOptions.states.normal &&
resetMarkerOptions.states.normal.opacity
}
}
}
});
}
}
/**
* @private
*/
function forceZeroOpacityMarkerOptions(options) {
merge(true, options, {
marker: {
enabled: true,
states: {
normal: {
opacity: 0
}
}
}
});
}
/**
* @private
*/
function getPointMarkerOpacity(pointOptions) {
return pointOptions.marker.states &&
pointOptions.marker.states.normal &&
pointOptions.marker.states.normal.opacity || 1;
}
/**
* @private
*/
function unforcePointMarkerOptions(pointOptions) {
merge(true, pointOptions.marker, {
states: {
normal: {
opacity: getPointMarkerOpacity(pointOptions)
}
}
});
}
/**
* @private
*/
function handleForcePointMarkers(series) {
var i = series.points.length;
while (i--) {
var point = series.points[i];
var pointOptions = point.options;
delete point.hasForcedA11yMarker;
if (pointOptions.marker) {
if (pointOptions.marker.enabled) {
unforcePointMarkerOptions(pointOptions);
point.hasForcedA11yMarker = false;
}
else {
forceZeroOpacityMarkerOptions(pointOptions);
point.hasForcedA11yMarker = true;
}
}
}
}
/**
* @private
*/
function addForceMarkersEvents() {
/**
* Keep track of forcing markers.
* @private
*/
addEvent(H.Series, 'render', function () {
var series = this, options = series.options;
if (shouldForceMarkers(series)) {
if (options.marker && options.marker.enabled === false) {
series.a11yMarkersForced = true;
forceZeroOpacityMarkerOptions(series.options);
}
if (hasIndividualPointMarkerOptions(series)) {
handleForcePointMarkers(series);
}
}
else if (series.a11yMarkersForced) {
delete series.a11yMarkersForced;
unforceSeriesMarkerOptions(series);
}
});
/**
* Keep track of options to reset markers to if no longer forced.
* @private
*/
addEvent(H.Series, 'afterSetOptions', function (e) {
this.resetA11yMarkerOptions = merge(e.options.marker || {}, this.userOptions.marker || {});
});
/**
* Process marker graphics after render
* @private
*/
addEvent(H.Series, 'afterRender', function () {
var series = this;
// For styled mode the rendered graphic does not reflect the style
// options, and we need to add/remove classes to achieve the same.
if (series.chart.styledMode) {
if (series.markerGroup) {
series.markerGroup[series.a11yMarkersForced ? 'addClass' : 'removeClass']('highcharts-a11y-markers-hidden');
}
// Do we need to handle individual points?
if (hasIndividualPointMarkerOptions(series)) {
series.points.forEach(function (point) {
if (point.graphic) {
point.graphic[point.hasForcedA11yMarker ? 'addClass' : 'removeClass']('highcharts-a11y-marker-hidden');
point.graphic[point.hasForcedA11yMarker === false ? 'addClass' : 'removeClass']('highcharts-a11y-marker-visible');
}
});
}
}
});
}
export default addForceMarkersEvents;
@@ -0,0 +1,254 @@
/* *
*
* (c) 2009-2020 Øystein Moseng
*
* Handle announcing new data for a chart.
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
'use strict';
import H from '../../../Core/Globals.js';
import U from '../../../Core/Utilities.js';
var extend = U.extend, defined = U.defined;
import ChartUtilities from '../../Utils/ChartUtilities.js';
var getChartTitle = ChartUtilities.getChartTitle;
import SeriesDescriber from './SeriesDescriber.js';
var defaultPointDescriptionFormatter = SeriesDescriber
.defaultPointDescriptionFormatter, defaultSeriesDescriptionFormatter = SeriesDescriber
.defaultSeriesDescriptionFormatter;
import Announcer from '../../Utils/Announcer.js';
import EventProvider from '../../Utils/EventProvider.js';
/* eslint-disable no-invalid-this, valid-jsdoc */
/**
* @private
*/
function chartHasAnnounceEnabled(chart) {
return !!chart.options.accessibility.announceNewData.enabled;
}
/**
* @private
*/
function findPointInDataArray(point) {
var candidates = point.series.data.filter(function (candidate) {
return point.x === candidate.x && point.y === candidate.y;
});
return candidates.length === 1 ? candidates[0] : point;
}
/**
* Get array of unique series from two arrays
* @private
*/
function getUniqueSeries(arrayA, arrayB) {
var uniqueSeries = (arrayA || []).concat(arrayB || [])
.reduce(function (acc, cur) {
acc[cur.name + cur.index] = cur;
return acc;
}, {});
return Object.keys(uniqueSeries).map(function (ix) {
return uniqueSeries[ix];
});
}
/**
* @private
* @class
*/
var NewDataAnnouncer = function (chart) {
this.chart = chart;
};
extend(NewDataAnnouncer.prototype, {
/**
* Initialize the new data announcer.
* @private
*/
init: function () {
var chart = this.chart;
var announceOptions = chart.options.accessibility.announceNewData;
var announceType = announceOptions.interruptUser ? 'assertive' : 'polite';
this.lastAnnouncementTime = 0;
this.dirty = {
allSeries: {}
};
this.eventProvider = new EventProvider();
this.announcer = new Announcer(chart, announceType);
this.addEventListeners();
},
/**
* Remove traces of announcer.
* @private
*/
destroy: function () {
this.eventProvider.removeAddedEvents();
this.announcer.destroy();
},
/**
* Add event listeners for the announcer
* @private
*/
addEventListeners: function () {
var announcer = this, chart = this.chart, e = this.eventProvider;
e.addEvent(chart, 'afterDrilldown', function () {
announcer.lastAnnouncementTime = 0;
});
e.addEvent(H.Series, 'updatedData', function () {
announcer.onSeriesUpdatedData(this);
});
e.addEvent(chart, 'afterAddSeries', function (e) {
announcer.onSeriesAdded(e.series);
});
e.addEvent(H.Series, 'addPoint', function (e) {
announcer.onPointAdded(e.point);
});
e.addEvent(chart, 'redraw', function () {
announcer.announceDirtyData();
});
},
/**
* On new data in the series, make sure we add it to the dirty list.
* @private
* @param {Highcharts.Series} series
*/
onSeriesUpdatedData: function (series) {
var chart = this.chart;
if (series.chart === chart && chartHasAnnounceEnabled(chart)) {
this.dirty.hasDirty = true;
this.dirty.allSeries[series.name + series.index] = series;
}
},
/**
* On new data series added, update dirty list.
* @private
* @param {Highcharts.Series} series
*/
onSeriesAdded: function (series) {
if (chartHasAnnounceEnabled(this.chart)) {
this.dirty.hasDirty = true;
this.dirty.allSeries[series.name + series.index] = series;
// Add it to newSeries storage unless we already have one
this.dirty.newSeries = defined(this.dirty.newSeries) ?
void 0 : series;
}
},
/**
* On new point added, update dirty list.
* @private
* @param {Highcharts.Point} point
*/
onPointAdded: function (point) {
var chart = point.series.chart;
if (this.chart === chart && chartHasAnnounceEnabled(chart)) {
// Add it to newPoint storage unless we already have one
this.dirty.newPoint = defined(this.dirty.newPoint) ?
void 0 : point;
}
},
/**
* Gather what we know and announce the data to user.
* @private
*/
announceDirtyData: function () {
var chart = this.chart, announcer = this;
if (chart.options.accessibility.announceNewData &&
this.dirty.hasDirty) {
var newPoint = this.dirty.newPoint;
// If we have a single new point, see if we can find it in the
// data array. Otherwise we can only pass through options to
// the description builder, and it is a bit sparse in info.
if (newPoint) {
newPoint = findPointInDataArray(newPoint);
}
this.queueAnnouncement(Object.keys(this.dirty.allSeries).map(function (ix) {
return announcer.dirty.allSeries[ix];
}), this.dirty.newSeries, newPoint);
// Reset
this.dirty = {
allSeries: {}
};
}
},
/**
* Announce to user that there is new data.
* @private
* @param {Array<Highcharts.Series>} dirtySeries
* Array of series with new data.
* @param {Highcharts.Series} [newSeries]
* If a single new series was added, a reference to this series.
* @param {Highcharts.Point} [newPoint]
* If a single point was added, a reference to this point.
*/
queueAnnouncement: function (dirtySeries, newSeries, newPoint) {
var _this = this;
var chart = this.chart;
var annOptions = chart.options.accessibility.announceNewData;
if (annOptions.enabled) {
var now = +new Date();
var dTime = now - this.lastAnnouncementTime;
var time = Math.max(0, annOptions.minAnnounceInterval - dTime);
// Add series from previously queued announcement.
var allSeries = getUniqueSeries(this.queuedAnnouncement && this.queuedAnnouncement.series, dirtySeries);
// Build message and announce
var message = this.buildAnnouncementMessage(allSeries, newSeries, newPoint);
if (message) {
// Is there already one queued?
if (this.queuedAnnouncement) {
clearTimeout(this.queuedAnnouncementTimer);
}
// Build the announcement
this.queuedAnnouncement = {
time: now,
message: message,
series: allSeries
};
// Queue the announcement
this.queuedAnnouncementTimer = setTimeout(function () {
if (_this && _this.announcer) {
_this.lastAnnouncementTime = +new Date();
_this.announcer.announce(_this.queuedAnnouncement.message);
delete _this.queuedAnnouncement;
delete _this.queuedAnnouncementTimer;
}
}, time);
}
}
},
/**
* Get announcement message for new data.
* @private
* @param {Array<Highcharts.Series>} dirtySeries
* Array of series with new data.
* @param {Highcharts.Series} [newSeries]
* If a single new series was added, a reference to this series.
* @param {Highcharts.Point} [newPoint]
* If a single point was added, a reference to this point.
*
* @return {string|null}
* The announcement message to give to user.
*/
buildAnnouncementMessage: function (dirtySeries, newSeries, newPoint) {
var chart = this.chart, annOptions = chart.options.accessibility.announceNewData;
// User supplied formatter?
if (annOptions.announcementFormatter) {
var formatterRes = annOptions.announcementFormatter(dirtySeries, newSeries, newPoint);
if (formatterRes !== false) {
return formatterRes.length ? formatterRes : null;
}
}
// Default formatter - use lang options
var multiple = H.charts && H.charts.length > 1 ? 'Multiple' : 'Single', langKey = newSeries ? 'newSeriesAnnounce' + multiple :
newPoint ? 'newPointAnnounce' + multiple : 'newDataAnnounce', chartTitle = getChartTitle(chart);
return chart.langFormat('accessibility.announceNewData.' + langKey, {
chartTitle: chartTitle,
seriesDesc: newSeries ?
defaultSeriesDescriptionFormatter(newSeries) :
null,
pointDesc: newPoint ?
defaultPointDescriptionFormatter(newPoint) :
null,
point: newPoint,
series: newSeries
});
}
});
export default NewDataAnnouncer;
@@ -0,0 +1,109 @@
/* *
*
* (c) 2009-2020 Øystein Moseng
*
* Accessibility component for series and points.
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
'use strict';
import H from '../../../Core/Globals.js';
import U from '../../../Core/Utilities.js';
var extend = U.extend;
import AccessibilityComponent from '../../AccessibilityComponent.js';
import SeriesKeyboardNavigation from './SeriesKeyboardNavigation.js';
import NewDataAnnouncer from './NewDataAnnouncer.js';
import addForceMarkersEvents from './ForcedMarkers.js';
import ChartUtilities from '../../Utils/ChartUtilities.js';
var hideSeriesFromAT = ChartUtilities.hideSeriesFromAT;
import SeriesDescriber from './SeriesDescriber.js';
var describeSeries = SeriesDescriber.describeSeries;
import Tooltip from '../../../Core/Tooltip.js';
// Expose functionality to users
H.SeriesAccessibilityDescriber = SeriesDescriber;
// Handle forcing markers
addForceMarkersEvents();
/* eslint-disable no-invalid-this, valid-jsdoc */
/**
* The SeriesComponent class
*
* @private
* @class
* @name Highcharts.SeriesComponent
*/
var SeriesComponent = function () { };
SeriesComponent.prototype = new AccessibilityComponent();
extend(SeriesComponent.prototype, /** @lends Highcharts.SeriesComponent */ {
/**
* Init the component.
*/
init: function () {
this.newDataAnnouncer = new NewDataAnnouncer(this.chart);
this.newDataAnnouncer.init();
this.keyboardNavigation = new SeriesKeyboardNavigation(this.chart, this.keyCodes);
this.keyboardNavigation.init();
this.hideTooltipFromATWhenShown();
this.hideSeriesLabelsFromATWhenShown();
},
/**
* @private
*/
hideTooltipFromATWhenShown: function () {
var component = this;
this.addEvent(Tooltip, 'refresh', function () {
if (this.chart === component.chart &&
this.label &&
this.label.element) {
this.label.element.setAttribute('aria-hidden', true);
}
});
},
/**
* @private
*/
hideSeriesLabelsFromATWhenShown: function () {
this.addEvent(this.chart, 'afterDrawSeriesLabels', function () {
this.series.forEach(function (series) {
if (series.labelBySeries) {
series.labelBySeries.attr('aria-hidden', true);
}
});
});
},
/**
* Called on chart render. It is necessary to do this for render in case
* markers change on zoom/pixel density.
*/
onChartRender: function () {
var chart = this.chart;
chart.series.forEach(function (series) {
var shouldDescribeSeries = (series.options.accessibility &&
series.options.accessibility.enabled) !== false &&
series.visible;
if (shouldDescribeSeries) {
describeSeries(series);
}
else {
hideSeriesFromAT(series);
}
});
},
/**
* Get keyboard navigation handler for this component.
* @return {Highcharts.KeyboardNavigationHandler}
*/
getKeyboardNavigation: function () {
return this.keyboardNavigation.getKeyboardNavigationHandler();
},
/**
* Remove traces
*/
destroy: function () {
this.newDataAnnouncer.destroy();
this.keyboardNavigation.destroy();
}
});
export default SeriesComponent;
@@ -0,0 +1,397 @@
/* *
*
* (c) 2009-2020 Øystein Moseng
*
* Place desriptions on a series and its points.
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
'use strict';
import U from '../../../Core/Utilities.js';
var find = U.find, format = U.format, isNumber = U.isNumber, numberFormat = U.numberFormat, pick = U.pick, defined = U.defined;
import AnnotationsA11y from '../AnnotationsA11y.js';
var getPointAnnotationTexts = AnnotationsA11y.getPointAnnotationTexts;
import HTMLUtilities from '../../Utils/HTMLUtilities.js';
var escapeStringForHTML = HTMLUtilities.escapeStringForHTML, reverseChildNodes = HTMLUtilities.reverseChildNodes, stripHTMLTags = HTMLUtilities.stripHTMLTagsFromString;
import ChartUtilities from '../../Utils/ChartUtilities.js';
var getAxisDescription = ChartUtilities.getAxisDescription, getSeriesFirstPointElement = ChartUtilities.getSeriesFirstPointElement, getSeriesA11yElement = ChartUtilities.getSeriesA11yElement, unhideChartElementFromAT = ChartUtilities.unhideChartElementFromAT;
import Tooltip from '../../../Core/Tooltip.js';
/* eslint-disable valid-jsdoc */
/**
* @private
*/
function findFirstPointWithGraphic(point) {
var sourcePointIndex = point.index;
if (!point.series || !point.series.data || !defined(sourcePointIndex)) {
return null;
}
return find(point.series.data, function (p) {
return !!(p &&
typeof p.index !== 'undefined' &&
p.index > sourcePointIndex &&
p.graphic &&
p.graphic.element);
}) || null;
}
/**
* @private
*/
function shouldAddDummyPoint(point) {
// Note: Sunburst series use isNull for hidden points on drilldown.
// Ignore these.
var isSunburst = point.series && point.series.is('sunburst'), isNull = point.isNull;
return isNull && !isSunburst;
}
/**
* @private
*/
function makeDummyElement(point, pos) {
var renderer = point.series.chart.renderer, dummy = renderer.rect(pos.x, pos.y, 1, 1);
dummy.attr({
'class': 'highcharts-a11y-dummy-point',
fill: 'none',
opacity: 0,
'fill-opacity': 0,
'stroke-opacity': 0
});
return dummy;
}
/**
* @private
* @param {Highcharts.Point} point
* @return {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement|undefined}
*/
function addDummyPointElement(point) {
var series = point.series, firstPointWithGraphic = findFirstPointWithGraphic(point), firstGraphic = firstPointWithGraphic && firstPointWithGraphic.graphic, parentGroup = firstGraphic ?
firstGraphic.parentGroup :
series.graph || series.group, dummyPos = firstPointWithGraphic ? {
x: pick(point.plotX, firstPointWithGraphic.plotX, 0),
y: pick(point.plotY, firstPointWithGraphic.plotY, 0)
} : {
x: pick(point.plotX, 0),
y: pick(point.plotY, 0)
}, dummyElement = makeDummyElement(point, dummyPos);
if (parentGroup && parentGroup.element) {
point.graphic = dummyElement;
point.hasDummyGraphic = true;
dummyElement.add(parentGroup);
// Move to correct pos in DOM
parentGroup.element.insertBefore(dummyElement.element, firstGraphic ? firstGraphic.element : null);
return dummyElement.element;
}
}
/**
* @private
* @param {Highcharts.Series} series
* @return {boolean}
*/
function hasMorePointsThanDescriptionThreshold(series) {
var chartA11yOptions = series.chart.options.accessibility, threshold = (chartA11yOptions.series.pointDescriptionEnabledThreshold);
return !!(threshold !== false &&
series.points &&
series.points.length >= threshold);
}
/**
* @private
* @param {Highcharts.Series} series
* @return {boolean}
*/
function shouldSetScreenReaderPropsOnPoints(series) {
var seriesA11yOptions = series.options.accessibility || {};
return !hasMorePointsThanDescriptionThreshold(series) &&
!seriesA11yOptions.exposeAsGroupOnly;
}
/**
* @private
* @param {Highcharts.Series} series
* @return {boolean}
*/
function shouldSetKeyboardNavPropsOnPoints(series) {
var chartA11yOptions = series.chart.options.accessibility, seriesNavOptions = chartA11yOptions.keyboardNavigation.seriesNavigation;
return !!(series.points && (series.points.length <
seriesNavOptions.pointNavigationEnabledThreshold ||
seriesNavOptions.pointNavigationEnabledThreshold === false));
}
/**
* @private
* @param {Highcharts.Series} series
* @return {boolean}
*/
function shouldDescribeSeriesElement(series) {
var chart = series.chart, chartOptions = chart.options.chart || {}, chartHas3d = chartOptions.options3d && chartOptions.options3d.enabled, hasMultipleSeries = chart.series.length > 1, describeSingleSeriesOption = chart.options.accessibility.series.describeSingleSeries, exposeAsGroupOnlyOption = (series.options.accessibility || {}).exposeAsGroupOnly, noDescribe3D = chartHas3d && hasMultipleSeries;
return !noDescribe3D && (hasMultipleSeries || describeSingleSeriesOption ||
exposeAsGroupOnlyOption || hasMorePointsThanDescriptionThreshold(series));
}
/**
* @private
* @param {Highcharts.Point} point
* @param {number} value
* @return {string}
*/
function pointNumberToString(point, value) {
var chart = point.series.chart, a11yPointOptions = chart.options.accessibility.point || {}, tooltipOptions = point.series.tooltipOptions || {}, lang = chart.options.lang;
if (isNumber(value)) {
return numberFormat(value, a11yPointOptions.valueDecimals ||
tooltipOptions.valueDecimals ||
-1, lang.decimalPoint, lang.accessibility.thousandsSep || lang.thousandsSep);
}
return value;
}
/**
* @private
* @param {Highcharts.Series} series
* @return {string}
*/
function getSeriesDescriptionText(series) {
var seriesA11yOptions = series.options.accessibility || {}, descOpt = seriesA11yOptions.description;
return descOpt && series.chart.langFormat('accessibility.series.description', {
description: descOpt,
series: series
}) || '';
}
/**
* @private
* @param {Highcharts.series} series
* @param {string} axisCollection
* @return {string}
*/
function getSeriesAxisDescriptionText(series, axisCollection) {
var axis = series[axisCollection];
return series.chart.langFormat('accessibility.series.' + axisCollection + 'Description', {
name: getAxisDescription(axis),
series: series
});
}
/**
* Get accessible time description for a point on a datetime axis.
*
* @private
* @function Highcharts.Point#getTimeDescription
* @param {Highcharts.Point} point
* @return {string|undefined}
* The description as string.
*/
function getPointA11yTimeDescription(point) {
var series = point.series, chart = series.chart, a11yOptions = chart.options.accessibility.point || {}, hasDateXAxis = series.xAxis && series.xAxis.dateTime;
if (hasDateXAxis) {
var tooltipDateFormat = Tooltip.prototype.getXDateFormat.call({
getDateFormat: Tooltip.prototype.getDateFormat,
chart: chart
}, point, chart.options.tooltip, series.xAxis), dateFormat = a11yOptions.dateFormatter &&
a11yOptions.dateFormatter(point) ||
a11yOptions.dateFormat ||
tooltipDateFormat;
return chart.time.dateFormat(dateFormat, point.x, void 0);
}
}
/**
* @private
* @param {Highcharts.Point} point
* @return {string}
*/
function getPointXDescription(point) {
var timeDesc = getPointA11yTimeDescription(point), xAxis = point.series.xAxis || {}, pointCategory = xAxis.categories && defined(point.category) &&
('' + point.category).replace('<br/>', ' '), canUseId = point.id && point.id.indexOf('highcharts-') < 0, fallback = 'x, ' + point.x;
return point.name || timeDesc || pointCategory ||
(canUseId ? point.id : fallback);
}
/**
* @private
* @param {Highcharts.Point} point
* @param {string} prefix
* @param {string} suffix
* @return {string}
*/
function getPointArrayMapValueDescription(point, prefix, suffix) {
var pre = prefix || '', suf = suffix || '', keyToValStr = function (key) {
var num = pointNumberToString(point, pick(point[key], point.options[key]));
return key + ': ' + pre + num + suf;
}, pointArrayMap = point.series.pointArrayMap;
return pointArrayMap.reduce(function (desc, key) {
return desc + (desc.length ? ', ' : '') + keyToValStr(key);
}, '');
}
/**
* @private
* @param {Highcharts.Point} point
* @return {string}
*/
function getPointValue(point) {
var series = point.series, a11yPointOpts = series.chart.options.accessibility.point || {}, tooltipOptions = series.tooltipOptions || {}, valuePrefix = a11yPointOpts.valuePrefix ||
tooltipOptions.valuePrefix || '', valueSuffix = a11yPointOpts.valueSuffix ||
tooltipOptions.valueSuffix || '', fallbackKey = (typeof point.value !==
'undefined' ?
'value' : 'y'), fallbackDesc = pointNumberToString(point, point[fallbackKey]);
if (point.isNull) {
return series.chart.langFormat('accessibility.series.nullPointValue', {
point: point
});
}
if (series.pointArrayMap) {
return getPointArrayMapValueDescription(point, valuePrefix, valueSuffix);
}
return valuePrefix + fallbackDesc + valueSuffix;
}
/**
* Return the description for the annotation(s) connected to a point, or empty
* string if none.
*
* @private
* @param {Highcharts.Point} point The data point to get the annotation info from.
* @return {string} Annotation description
*/
function getPointAnnotationDescription(point) {
var chart = point.series.chart;
var langKey = 'accessibility.series.pointAnnotationsDescription';
var annotations = getPointAnnotationTexts(point);
var context = { point: point, annotations: annotations };
return annotations.length ? chart.langFormat(langKey, context) : '';
}
/**
* Return string with information about point.
* @private
* @return {string}
*/
function getPointValueDescription(point) {
var series = point.series, chart = series.chart, pointValueDescriptionFormat = chart.options.accessibility
.point.valueDescriptionFormat, showXDescription = pick(series.xAxis &&
series.xAxis.options.accessibility &&
series.xAxis.options.accessibility.enabled, !chart.angular), xDesc = showXDescription ? getPointXDescription(point) : '', context = {
point: point,
index: defined(point.index) ? (point.index + 1) : '',
xDescription: xDesc,
value: getPointValue(point),
separator: showXDescription ? ', ' : ''
};
return format(pointValueDescriptionFormat, context, chart);
}
/**
* Return string with information about point.
* @private
* @return {string}
*/
function defaultPointDescriptionFormatter(point) {
var series = point.series, chart = series.chart, valText = getPointValueDescription(point), description = point.options && point.options.accessibility &&
point.options.accessibility.description, userDescText = description ? ' ' + description : '', seriesNameText = chart.series.length > 1 && series.name ?
' ' + series.name + '.' : '', annotationsDesc = getPointAnnotationDescription(point), pointAnnotationsText = annotationsDesc ? ' ' + annotationsDesc : '';
point.accessibility = point.accessibility || {};
point.accessibility.valueDescription = valText;
return valText + userDescText + seriesNameText + pointAnnotationsText;
}
/**
* Set a11y props on a point element
* @private
* @param {Highcharts.Point} point
* @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} pointElement
*/
function setPointScreenReaderAttribs(point, pointElement) {
var series = point.series, a11yPointOptions = series.chart.options.accessibility.point || {}, seriesA11yOptions = series.options.accessibility || {}, label = escapeStringForHTML(stripHTMLTags(seriesA11yOptions.pointDescriptionFormatter &&
seriesA11yOptions.pointDescriptionFormatter(point) ||
a11yPointOptions.descriptionFormatter &&
a11yPointOptions.descriptionFormatter(point) ||
defaultPointDescriptionFormatter(point)));
pointElement.setAttribute('role', 'img');
pointElement.setAttribute('aria-label', label);
}
/**
* Add accessible info to individual point elements of a series
* @private
* @param {Highcharts.Series} series
*/
function describePointsInSeries(series) {
var setScreenReaderProps = shouldSetScreenReaderPropsOnPoints(series), setKeyboardProps = shouldSetKeyboardNavPropsOnPoints(series);
if (setScreenReaderProps || setKeyboardProps) {
series.points.forEach(function (point) {
var pointEl = point.graphic && point.graphic.element ||
shouldAddDummyPoint(point) && addDummyPointElement(point);
if (pointEl) {
// We always set tabindex, as long as we are setting props.
// When setting tabindex, also remove default outline to
// avoid ugly border on click.
pointEl.setAttribute('tabindex', '-1');
pointEl.style.outline = '0';
if (setScreenReaderProps) {
setPointScreenReaderAttribs(point, pointEl);
}
else {
pointEl.setAttribute('aria-hidden', true);
}
}
});
}
}
/**
* Return string with information about series.
* @private
* @return {string}
*/
function defaultSeriesDescriptionFormatter(series) {
var chart = series.chart, chartTypes = chart.types || [], description = getSeriesDescriptionText(series), shouldDescribeAxis = function (coll) {
return chart[coll] && chart[coll].length > 1 && series[coll];
}, xAxisInfo = getSeriesAxisDescriptionText(series, 'xAxis'), yAxisInfo = getSeriesAxisDescriptionText(series, 'yAxis'), summaryContext = {
name: series.name || '',
ix: series.index + 1,
numSeries: chart.series && chart.series.length,
numPoints: series.points && series.points.length,
series: series
}, combinationSuffix = chartTypes.length > 1 ? 'Combination' : '', summary = chart.langFormat('accessibility.series.summary.' + series.type + combinationSuffix, summaryContext) || chart.langFormat('accessibility.series.summary.default' + combinationSuffix, summaryContext);
return summary + (description ? ' ' + description : '') + (shouldDescribeAxis('yAxis') ? ' ' + yAxisInfo : '') + (shouldDescribeAxis('xAxis') ? ' ' + xAxisInfo : '');
}
/**
* Set a11y props on a series element
* @private
* @param {Highcharts.Series} series
* @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} seriesElement
*/
function describeSeriesElement(series, seriesElement) {
var seriesA11yOptions = series.options.accessibility || {}, a11yOptions = series.chart.options.accessibility, landmarkVerbosity = a11yOptions.landmarkVerbosity;
// Handle role attribute
if (seriesA11yOptions.exposeAsGroupOnly) {
seriesElement.setAttribute('role', 'img');
}
else if (landmarkVerbosity === 'all') {
seriesElement.setAttribute('role', 'region');
} /* else do not add role */
seriesElement.setAttribute('tabindex', '-1');
seriesElement.style.outline = '0'; // Don't show browser outline on click, despite tabindex
seriesElement.setAttribute('aria-label', escapeStringForHTML(stripHTMLTags(a11yOptions.series.descriptionFormatter &&
a11yOptions.series.descriptionFormatter(series) ||
defaultSeriesDescriptionFormatter(series))));
}
/**
* Put accessible info on series and points of a series.
* @param {Highcharts.Series} series The series to add info on.
*/
function describeSeries(series) {
var chart = series.chart, firstPointEl = getSeriesFirstPointElement(series), seriesEl = getSeriesA11yElement(series), is3d = chart.is3d && chart.is3d();
if (seriesEl) {
// For some series types the order of elements do not match the
// order of points in series. In that case we have to reverse them
// in order for AT to read them out in an understandable order.
// Due to z-index issues we can not do this for 3D charts.
if (seriesEl.lastChild === firstPointEl && !is3d) {
reverseChildNodes(seriesEl);
}
describePointsInSeries(series);
unhideChartElementFromAT(chart, seriesEl);
if (shouldDescribeSeriesElement(series)) {
describeSeriesElement(series, seriesEl);
}
else {
seriesEl.setAttribute('aria-label', '');
}
}
}
var SeriesDescriber = {
describeSeries: describeSeries,
defaultPointDescriptionFormatter: defaultPointDescriptionFormatter,
defaultSeriesDescriptionFormatter: defaultSeriesDescriptionFormatter,
getPointA11yTimeDescription: getPointA11yTimeDescription,
getPointXDescription: getPointXDescription,
getPointValue: getPointValue,
getPointValueDescription: getPointValueDescription
};
export default SeriesDescriber;
@@ -0,0 +1,569 @@
/* *
*
* (c) 2009-2020 Øystein Moseng
*
* Handle keyboard navigation for series.
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
'use strict';
import Chart from '../../../Core/Chart/Chart.js';
import H from '../../../Core/Globals.js';
import Point from '../../../Core/Series/Point.js';
import U from '../../../Core/Utilities.js';
var defined = U.defined, extend = U.extend;
import KeyboardNavigationHandler from '../../KeyboardNavigationHandler.js';
import EventProvider from '../../Utils/EventProvider.js';
import ChartUtilities from '../../Utils/ChartUtilities.js';
var getPointFromXY = ChartUtilities.getPointFromXY, getSeriesFromName = ChartUtilities.getSeriesFromName, scrollToPoint = ChartUtilities.scrollToPoint;
import '../../../Series/ColumnSeries.js';
import '../../../Series/PieSeries.js';
/* eslint-disable no-invalid-this, valid-jsdoc */
/*
* Set for which series types it makes sense to move to the closest point with
* up/down arrows, and which series types should just move to next series.
*/
H.Series.prototype.keyboardMoveVertical = true;
['column', 'pie'].forEach(function (type) {
if (H.seriesTypes[type]) {
H.seriesTypes[type].prototype.keyboardMoveVertical = false;
}
});
/**
* Get the index of a point in a series. This is needed when using e.g. data
* grouping.
*
* @private
* @function getPointIndex
*
* @param {Highcharts.AccessibilityPoint} point
* The point to find index of.
*
* @return {number|undefined}
* The index in the series.points array of the point.
*/
function getPointIndex(point) {
var index = point.index, points = point.series.points, i = points.length;
if (points[index] !== point) {
while (i--) {
if (points[i] === point) {
return i;
}
}
}
else {
return index;
}
}
/**
* Determine if series navigation should be skipped
*
* @private
* @function isSkipSeries
*
* @param {Highcharts.Series} series
*
* @return {boolean|number|undefined}
*/
function isSkipSeries(series) {
var a11yOptions = series.chart.options.accessibility, seriesNavOptions = a11yOptions.keyboardNavigation.seriesNavigation, seriesA11yOptions = series.options.accessibility || {}, seriesKbdNavOptions = seriesA11yOptions.keyboardNavigation;
return seriesKbdNavOptions && seriesKbdNavOptions.enabled === false ||
seriesA11yOptions.enabled === false ||
series.options.enableMouseTracking === false || // #8440
!series.visible ||
// Skip all points in a series where pointNavigationEnabledThreshold is
// reached
(seriesNavOptions.pointNavigationEnabledThreshold &&
seriesNavOptions.pointNavigationEnabledThreshold <=
series.points.length);
}
/**
* Determine if navigation for a point should be skipped
*
* @private
* @function isSkipPoint
*
* @param {Highcharts.Point} point
*
* @return {boolean|number|undefined}
*/
function isSkipPoint(point) {
var a11yOptions = point.series.chart.options.accessibility;
return point.isNull &&
a11yOptions.keyboardNavigation.seriesNavigation.skipNullPoints ||
point.visible === false ||
isSkipSeries(point.series);
}
/**
* Get the point in a series that is closest (in pixel distance) to a reference
* point. Optionally supply weight factors for x and y directions.
*
* @private
* @function getClosestPoint
*
* @param {Highcharts.Point} point
* @param {Highcharts.Series} series
* @param {number} [xWeight]
* @param {number} [yWeight]
*
* @return {Highcharts.Point|undefined}
*/
function getClosestPoint(point, series, xWeight, yWeight) {
var minDistance = Infinity, dPoint, minIx, distance, i = series.points.length, hasUndefinedPosition = function (point) {
return !(defined(point.plotX) && defined(point.plotY));
};
if (hasUndefinedPosition(point)) {
return;
}
while (i--) {
dPoint = series.points[i];
if (hasUndefinedPosition(dPoint)) {
continue;
}
distance = (point.plotX - dPoint.plotX) *
(point.plotX - dPoint.plotX) *
(xWeight || 1) +
(point.plotY - dPoint.plotY) *
(point.plotY - dPoint.plotY) *
(yWeight || 1);
if (distance < minDistance) {
minDistance = distance;
minIx = i;
}
}
return defined(minIx) ? series.points[minIx] : void 0;
}
/**
* Highlights a point (show tooltip and display hover state).
*
* @private
* @function Highcharts.Point#highlight
*
* @return {Highcharts.Point}
* This highlighted point.
*/
Point.prototype.highlight = function () {
var chart = this.series.chart;
if (!this.isNull) {
this.onMouseOver(); // Show the hover marker and tooltip
}
else {
if (chart.tooltip) {
chart.tooltip.hide(0);
}
// Don't call blur on the element, as it messes up the chart div's focus
}
scrollToPoint(this);
// We focus only after calling onMouseOver because the state change can
// change z-index and mess up the element.
if (this.graphic) {
chart.setFocusToElement(this.graphic);
}
chart.highlightedPoint = this;
return this;
};
/**
* Function to highlight next/previous point in chart.
*
* @private
* @function Highcharts.Chart#highlightAdjacentPoint
*
* @param {boolean} next
* Flag for the direction.
*
* @return {Highcharts.Point|boolean}
* Returns highlighted point on success, false on failure (no adjacent
* point to highlight in chosen direction).
*/
Chart.prototype.highlightAdjacentPoint = function (next) {
var chart = this, series = chart.series, curPoint = chart.highlightedPoint, curPointIndex = curPoint && getPointIndex(curPoint) || 0, curPoints = (curPoint && curPoint.series.points), lastSeries = chart.series && chart.series[chart.series.length - 1], lastPoint = lastSeries && lastSeries.points &&
lastSeries.points[lastSeries.points.length - 1], newSeries, newPoint;
// If no points, return false
if (!series[0] || !series[0].points) {
return false;
}
if (!curPoint) {
// No point is highlighted yet. Try first/last point depending on move
// direction
newPoint = next ? series[0].points[0] : lastPoint;
}
else {
// We have a highlighted point.
// Grab next/prev point & series
newSeries = series[curPoint.series.index + (next ? 1 : -1)];
newPoint = curPoints[curPointIndex + (next ? 1 : -1)];
if (!newPoint && newSeries) {
// Done with this series, try next one
newPoint = newSeries.points[next ? 0 : newSeries.points.length - 1];
}
// If there is no adjacent point, we return false
if (!newPoint) {
return false;
}
}
// Recursively skip points
if (isSkipPoint(newPoint)) {
// If we skip this whole series, move to the end of the series before we
// recurse, just to optimize
newSeries = newPoint.series;
if (isSkipSeries(newSeries)) {
chart.highlightedPoint = next ?
newSeries.points[newSeries.points.length - 1] :
newSeries.points[0];
}
else {
// Otherwise, just move one point
chart.highlightedPoint = newPoint;
}
// Retry
return chart.highlightAdjacentPoint(next);
}
// There is an adjacent point, highlight it
return newPoint.highlight();
};
/**
* Highlight first valid point in a series. Returns the point if successfully
* highlighted, otherwise false. If there is a highlighted point in the series,
* use that as starting point.
*
* @private
* @function Highcharts.Series#highlightFirstValidPoint
*
* @return {boolean|Highcharts.Point}
*/
H.Series.prototype.highlightFirstValidPoint = function () {
var curPoint = this.chart.highlightedPoint, start = (curPoint && curPoint.series) === this ?
getPointIndex(curPoint) :
0, points = this.points, len = points.length;
if (points && len) {
for (var i = start; i < len; ++i) {
if (!isSkipPoint(points[i])) {
return points[i].highlight();
}
}
for (var j = start; j >= 0; --j) {
if (!isSkipPoint(points[j])) {
return points[j].highlight();
}
}
}
return false;
};
/**
* Highlight next/previous series in chart. Returns false if no adjacent series
* in the direction, otherwise returns new highlighted point.
*
* @private
* @function Highcharts.Chart#highlightAdjacentSeries
*
* @param {boolean} down
*
* @return {Highcharts.Point|boolean}
*/
Chart.prototype.highlightAdjacentSeries = function (down) {
var chart = this, newSeries, newPoint, adjacentNewPoint, curPoint = chart.highlightedPoint, lastSeries = chart.series && chart.series[chart.series.length - 1], lastPoint = lastSeries && lastSeries.points &&
lastSeries.points[lastSeries.points.length - 1];
// If no point is highlighted, highlight the first/last point
if (!chart.highlightedPoint) {
newSeries = down ? (chart.series && chart.series[0]) : lastSeries;
newPoint = down ?
(newSeries && newSeries.points && newSeries.points[0]) : lastPoint;
return newPoint ? newPoint.highlight() : false;
}
newSeries = chart.series[curPoint.series.index + (down ? -1 : 1)];
if (!newSeries) {
return false;
}
// We have a new series in this direction, find the right point
// Weigh xDistance as counting much higher than Y distance
newPoint = getClosestPoint(curPoint, newSeries, 4);
if (!newPoint) {
return false;
}
// New series and point exists, but we might want to skip it
if (isSkipSeries(newSeries)) {
// Skip the series
newPoint.highlight();
adjacentNewPoint = chart.highlightAdjacentSeries(down); // Try recurse
if (!adjacentNewPoint) {
// Recurse failed
curPoint.highlight();
return false;
}
// Recurse succeeded
return adjacentNewPoint;
}
// Highlight the new point or any first valid point back or forwards from it
newPoint.highlight();
return newPoint.series.highlightFirstValidPoint();
};
/**
* Highlight the closest point vertically.
*
* @private
* @function Highcharts.Chart#highlightAdjacentPointVertical
*
* @param {boolean} down
*
* @return {Highcharts.Point|boolean}
*/
Chart.prototype.highlightAdjacentPointVertical = function (down) {
var curPoint = this.highlightedPoint, minDistance = Infinity, bestPoint;
if (!defined(curPoint.plotX) || !defined(curPoint.plotY)) {
return false;
}
this.series.forEach(function (series) {
if (isSkipSeries(series)) {
return;
}
series.points.forEach(function (point) {
if (!defined(point.plotY) || !defined(point.plotX) ||
point === curPoint) {
return;
}
var yDistance = point.plotY - curPoint.plotY, width = Math.abs(point.plotX - curPoint.plotX), distance = Math.abs(yDistance) * Math.abs(yDistance) +
width * width * 4; // Weigh horizontal distance highly
// Reverse distance number if axis is reversed
if (series.yAxis && series.yAxis.reversed) {
yDistance *= -1;
}
if (yDistance <= 0 && down || yDistance >= 0 && !down || // Chk dir
distance < 5 || // Points in same spot => infinite loop
isSkipPoint(point)) {
return;
}
if (distance < minDistance) {
minDistance = distance;
bestPoint = point;
}
});
});
return bestPoint ? bestPoint.highlight() : false;
};
/**
* @private
* @param {Highcharts.Chart} chart
* @return {Highcharts.Point|boolean}
*/
function highlightFirstValidPointInChart(chart) {
var res = false;
delete chart.highlightedPoint;
res = chart.series.reduce(function (acc, cur) {
return acc || cur.highlightFirstValidPoint();
}, false);
return res;
}
/**
* @private
* @param {Highcharts.Chart} chart
* @return {Highcharts.Point|boolean}
*/
function highlightLastValidPointInChart(chart) {
var numSeries = chart.series.length, i = numSeries, res = false;
while (i--) {
chart.highlightedPoint = chart.series[i].points[chart.series[i].points.length - 1];
// Highlight first valid point in the series will also
// look backwards. It always starts from currently
// highlighted point.
res = chart.series[i].highlightFirstValidPoint();
if (res) {
break;
}
}
return res;
}
/**
* @private
* @param {Highcharts.Chart} chart
*/
function updateChartFocusAfterDrilling(chart) {
highlightFirstValidPointInChart(chart);
if (chart.focusElement) {
chart.focusElement.removeFocusBorder();
}
}
/**
* @private
* @class
* @name Highcharts.SeriesKeyboardNavigation
*/
function SeriesKeyboardNavigation(chart, keyCodes) {
this.keyCodes = keyCodes;
this.chart = chart;
}
extend(SeriesKeyboardNavigation.prototype, /** @lends Highcharts.SeriesKeyboardNavigation */ {
/**
* Init the keyboard navigation
*/
init: function () {
var keyboardNavigation = this, chart = this.chart, e = this.eventProvider = new EventProvider();
e.addEvent(H.Series, 'destroy', function () {
return keyboardNavigation.onSeriesDestroy(this);
});
e.addEvent(chart, 'afterDrilldown', function () {
updateChartFocusAfterDrilling(this);
});
e.addEvent(chart, 'drilldown', function (e) {
var point = e.point, series = point.series;
keyboardNavigation.lastDrilledDownPoint = {
x: point.x,
y: point.y,
seriesName: series ? series.name : ''
};
});
e.addEvent(chart, 'drillupall', function () {
setTimeout(function () {
keyboardNavigation.onDrillupAll();
}, 10);
});
},
onDrillupAll: function () {
// After drillup we want to find the point that was drilled down to and
// highlight it.
var last = this.lastDrilledDownPoint, chart = this.chart, series = last && getSeriesFromName(chart, last.seriesName), point;
if (last && series && defined(last.x) && defined(last.y)) {
point = getPointFromXY(series, last.x, last.y);
}
// Container focus can be lost on drillup due to deleted elements.
if (chart.container) {
chart.container.focus();
}
if (point && point.highlight) {
point.highlight();
}
if (chart.focusElement) {
chart.focusElement.removeFocusBorder();
}
},
/**
* @return {Highcharts.KeyboardNavigationHandler}
*/
getKeyboardNavigationHandler: function () {
var keyboardNavigation = this, keys = this.keyCodes, chart = this.chart, inverted = chart.inverted;
return new KeyboardNavigationHandler(chart, {
keyCodeMap: [
[inverted ? [keys.up, keys.down] : [keys.left, keys.right], function (keyCode) {
return keyboardNavigation.onKbdSideways(this, keyCode);
}],
[inverted ? [keys.left, keys.right] : [keys.up, keys.down], function (keyCode) {
return keyboardNavigation.onKbdVertical(this, keyCode);
}],
[[keys.enter, keys.space], function () {
if (chart.highlightedPoint) {
chart.highlightedPoint.firePointEvent('click');
}
return this.response.success;
}]
],
init: function (dir) {
return keyboardNavigation.onHandlerInit(this, dir);
},
terminate: function () {
return keyboardNavigation.onHandlerTerminate();
}
});
},
/**
* @private
* @param {Highcharts.KeyboardNavigationHandler} handler
* @param {number} keyCode
* @return {number}
* response
*/
onKbdSideways: function (handler, keyCode) {
var keys = this.keyCodes, isNext = keyCode === keys.right || keyCode === keys.down;
return this.attemptHighlightAdjacentPoint(handler, isNext);
},
/**
* @private
* @param {Highcharts.KeyboardNavigationHandler} handler
* @param {number} keyCode
* @return {number}
* response
*/
onKbdVertical: function (handler, keyCode) {
var chart = this.chart, keys = this.keyCodes, isNext = keyCode === keys.down || keyCode === keys.right, navOptions = chart.options.accessibility.keyboardNavigation
.seriesNavigation;
// Handle serialized mode, act like left/right
if (navOptions.mode && navOptions.mode === 'serialize') {
return this.attemptHighlightAdjacentPoint(handler, isNext);
}
// Normal mode, move between series
var highlightMethod = (chart.highlightedPoint &&
chart.highlightedPoint.series.keyboardMoveVertical) ?
'highlightAdjacentPointVertical' :
'highlightAdjacentSeries';
chart[highlightMethod](isNext);
return handler.response.success;
},
/**
* @private
* @param {Highcharts.KeyboardNavigationHandler} handler
* @param {number} initDirection
* @return {number}
* response
*/
onHandlerInit: function (handler, initDirection) {
var chart = this.chart;
if (initDirection > 0) {
highlightFirstValidPointInChart(chart);
}
else {
highlightLastValidPointInChart(chart);
}
return handler.response.success;
},
/**
* @private
*/
onHandlerTerminate: function () {
var _a, _b;
var chart = this.chart;
var curPoint = chart.highlightedPoint;
(_a = chart.tooltip) === null || _a === void 0 ? void 0 : _a.hide(0);
(_b = curPoint === null || curPoint === void 0 ? void 0 : curPoint.onMouseOut) === null || _b === void 0 ? void 0 : _b.call(curPoint);
delete chart.highlightedPoint;
},
/**
* Function that attempts to highlight next/prev point. Handles wrap around.
* @private
* @param {Highcharts.KeyboardNavigationHandler} handler
* @param {boolean} directionIsNext
* @return {number}
* response
*/
attemptHighlightAdjacentPoint: function (handler, directionIsNext) {
var chart = this.chart, wrapAround = chart.options.accessibility.keyboardNavigation
.wrapAround, highlightSuccessful = chart.highlightAdjacentPoint(directionIsNext);
if (!highlightSuccessful) {
if (wrapAround) {
return handler.init(directionIsNext ? 1 : -1);
}
return handler.response[directionIsNext ? 'next' : 'prev'];
}
return handler.response.success;
},
/**
* @private
*/
onSeriesDestroy: function (series) {
var chart = this.chart, currentHighlightedPointDestroyed = chart.highlightedPoint &&
chart.highlightedPoint.series === series;
if (currentHighlightedPointDestroyed) {
delete chart.highlightedPoint;
if (chart.focusElement) {
chart.focusElement.removeFocusBorder();
}
}
},
/**
* @private
*/
destroy: function () {
this.eventProvider.removeAddedEvents();
}
});
export default SeriesKeyboardNavigation;