@progress/kendo-charts 1.32.1 → 1.33.0-dev.202311081130

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/dist/cdn/js/kendo-charts.js +1 -1
  2. package/dist/cdn/main.js +1 -1
  3. package/dist/es/chart/bar-chart/bar.js +40 -16
  4. package/dist/es/chart/bubble-chart/bubble.js +10 -0
  5. package/dist/es/chart/bullet-chart/bullet.js +32 -11
  6. package/dist/es/chart/candlestick-chart/candlestick.js +37 -1
  7. package/dist/es/chart/categorical-chart.js +1 -1
  8. package/dist/es/chart/chart.js +307 -26
  9. package/dist/es/chart/constants.js +12 -1
  10. package/dist/es/chart/funnel-chart/funnel-chart.js +5 -3
  11. package/dist/es/chart/funnel-chart/funnel-segment.js +62 -3
  12. package/dist/es/chart/heatmap-chart/heatmap-chart.js +2 -1
  13. package/dist/es/chart/heatmap-chart/heatmap-point.js +68 -29
  14. package/dist/es/chart/legend/legend-item.js +32 -2
  15. package/dist/es/chart/legend/legend.js +6 -1
  16. package/dist/es/chart/line-chart/line-point.js +109 -26
  17. package/dist/es/chart/mixins/accessibility-attributes-mixin.js +36 -0
  18. package/dist/es/chart/pie-chart/pie-chart.js +1 -1
  19. package/dist/es/chart/pie-chart/pie-segment.js +50 -14
  20. package/dist/es/chart/plotarea/categorical-plotarea.js +53 -2
  21. package/dist/es/chart/plotarea/funnel-plotarea.js +8 -0
  22. package/dist/es/chart/plotarea/heatmap-plotarea.js +66 -1
  23. package/dist/es/chart/plotarea/plotarea-base.js +71 -1
  24. package/dist/es/chart/plotarea/radar-plotarea.js +8 -0
  25. package/dist/es/chart/radar-bar-chart/radar-segment.js +4 -0
  26. package/dist/es/chart/range-area-chart/range-area-point.js +26 -1
  27. package/dist/es/chart/range-bar-chart/range-bar.js +3 -24
  28. package/dist/es/chart/scatter-charts/scatter-chart.js +1 -1
  29. package/dist/es/common/constants.js +6 -0
  30. package/dist/es/common/cycleDown.js +5 -0
  31. package/dist/es/common/cycleIndex.js +13 -0
  32. package/dist/es/common/cycleUp.js +3 -0
  33. package/dist/es/common.js +3 -0
  34. package/dist/es/core/chart-element.js +31 -3
  35. package/dist/es/core/shape-builder.js +1 -1
  36. package/dist/es/core/shape-element.js +3 -0
  37. package/dist/es/core/utils/add-accessibility-attributes-to-visual.js +8 -0
  38. package/dist/es/core/utils/guid.js +17 -0
  39. package/dist/es/map/layers/shape.js +0 -2
  40. package/dist/es/map/navigator.js +0 -1
  41. package/dist/es/map/scroller/user-events.js +0 -2
  42. package/dist/es/map/utils.js +0 -18
  43. package/dist/es/map/zoom.js +0 -1
  44. package/dist/es2015/chart/bar-chart/bar.js +40 -16
  45. package/dist/es2015/chart/bubble-chart/bubble.js +10 -0
  46. package/dist/es2015/chart/bullet-chart/bullet.js +32 -11
  47. package/dist/es2015/chart/candlestick-chart/candlestick.js +37 -1
  48. package/dist/es2015/chart/categorical-chart.js +1 -1
  49. package/dist/es2015/chart/chart.js +295 -26
  50. package/dist/es2015/chart/constants.js +12 -1
  51. package/dist/es2015/chart/funnel-chart/funnel-chart.js +5 -3
  52. package/dist/es2015/chart/funnel-chart/funnel-segment.js +62 -3
  53. package/dist/es2015/chart/heatmap-chart/heatmap-chart.js +2 -1
  54. package/dist/es2015/chart/heatmap-chart/heatmap-point.js +68 -29
  55. package/dist/es2015/chart/legend/legend-item.js +32 -2
  56. package/dist/es2015/chart/legend/legend.js +6 -1
  57. package/dist/es2015/chart/line-chart/line-point.js +110 -26
  58. package/dist/es2015/chart/mixins/accessibility-attributes-mixin.js +36 -0
  59. package/dist/es2015/chart/pie-chart/pie-chart.js +1 -1
  60. package/dist/es2015/chart/pie-chart/pie-segment.js +50 -14
  61. package/dist/es2015/chart/plotarea/categorical-plotarea.js +49 -2
  62. package/dist/es2015/chart/plotarea/funnel-plotarea.js +8 -0
  63. package/dist/es2015/chart/plotarea/heatmap-plotarea.js +60 -1
  64. package/dist/es2015/chart/plotarea/plotarea-base.js +67 -1
  65. package/dist/es2015/chart/plotarea/radar-plotarea.js +8 -0
  66. package/dist/es2015/chart/radar-bar-chart/radar-segment.js +4 -0
  67. package/dist/es2015/chart/range-area-chart/range-area-point.js +26 -1
  68. package/dist/es2015/chart/range-bar-chart/range-bar.js +3 -24
  69. package/dist/es2015/chart/scatter-charts/scatter-chart.js +1 -1
  70. package/dist/es2015/common/constants.js +6 -0
  71. package/dist/es2015/common/cycleDown.js +5 -0
  72. package/dist/es2015/common/cycleIndex.js +13 -0
  73. package/dist/es2015/common/cycleUp.js +3 -0
  74. package/dist/es2015/common.js +3 -0
  75. package/dist/es2015/core/chart-element.js +31 -3
  76. package/dist/es2015/core/shape-builder.js +1 -1
  77. package/dist/es2015/core/shape-element.js +3 -0
  78. package/dist/es2015/core/utils/add-accessibility-attributes-to-visual.js +8 -0
  79. package/dist/es2015/core/utils/guid.js +17 -0
  80. package/dist/es2015/map/layers/shape.js +0 -2
  81. package/dist/es2015/map/navigator.js +0 -2
  82. package/dist/es2015/map/scroller/user-events.js +0 -2
  83. package/dist/es2015/map/utils.js +0 -18
  84. package/dist/es2015/map/zoom.js +0 -2
  85. package/dist/npm/main.js +1098 -156
  86. package/dist/systemjs/kendo-charts.js +1 -1
  87. package/package.json +1 -1
  88. package/dist/es/chart/area-chart/area-segment-mixin.js +0 -91
  89. package/dist/es2015/chart/area-chart/area-segment-mixin.js +0 -91
@@ -55,6 +55,16 @@ class Bubble extends LinePoint {
55
55
 
56
56
  return highlightGroup;
57
57
  }
58
+
59
+ createFocusHighlight(style) {
60
+ const highlightOptions = this.options.accessibility.highlight;
61
+ const markers = this.options.markers;
62
+ const center = this.box.center();
63
+ const radius = (markers.size + markers.border.width) / 2 + highlightOptions.border.width / 2;
64
+ const highlight = new draw.Circle(new geom.Circle([ center.x, center.y ], radius), style);
65
+
66
+ return highlight;
67
+ }
58
68
  }
59
69
 
60
70
  Bubble.prototype.defaults = deepExtend({}, Bubble.prototype.defaults, {
@@ -12,6 +12,8 @@ import { WHITE, TOP, RIGHT } from '../../common/constants';
12
12
  import { alignPathToPixel, deepExtend, defined, getTemplate, setDefaultOptions, valueOrDefault } from '../../common';
13
13
 
14
14
  import BarLabel from '../bar-chart/bar-label';
15
+ import { CHART_POINT_ROLE_DESCRIPTION, CHART_POINT_CLASSNAME, CHART_POINT_ROLE } from '../constants';
16
+ import AccessibilityAttributesMixin from '../mixins/accessibility-attributes-mixin';
15
17
 
16
18
  class Bullet extends ChartElement {
17
19
  constructor(value, options) {
@@ -56,21 +58,27 @@ class Bullet extends ChartElement {
56
58
  const labels = options.labels;
57
59
 
58
60
  if (labels.visible) {
59
- const pointData = this.pointData();
60
- let labelTemplate = getTemplate(labels);
61
- let labelText;
62
-
63
- if (labelTemplate) {
64
- labelText = labelTemplate(pointData);
65
- } else {
66
- labelText = this.formatValue(labels.format);
67
- }
68
-
69
- this.label = new BarLabel(labelText, labels, pointData);
61
+ this.label = this.createLabelElement(labels);
70
62
  this.append(this.label);
71
63
  }
72
64
  }
73
65
 
66
+ createLabelElement(options) {
67
+ return new BarLabel(this.getLabelText(options),
68
+ options,
69
+ this.pointData());
70
+ }
71
+
72
+ getLabelText(options) {
73
+ let labelTemplate = getTemplate(options);
74
+
75
+ if (labelTemplate) {
76
+ return labelTemplate(this.pointData());
77
+ }
78
+
79
+ return this.formatValue(options.format);
80
+ }
81
+
74
82
  reflow(box) {
75
83
  this.render();
76
84
 
@@ -108,6 +116,8 @@ class Bullet extends ChartElement {
108
116
  createVisual() {
109
117
  super.createVisual();
110
118
 
119
+ this.addAccessibilityAttributesToVisual();
120
+
111
121
  const options = this.options;
112
122
  const body = draw.Path.fromRect(this.box.toRect(), {
113
123
  fill: {
@@ -172,9 +182,14 @@ class Bullet extends ChartElement {
172
182
  overlapsBox(box) {
173
183
  return this.box.overlaps(box);
174
184
  }
185
+
186
+ getIndex() {
187
+ return this.categoryIx;
188
+ }
175
189
  }
176
190
 
177
191
  Bullet.prototype.tooltipAnchor = Bar.prototype.tooltipAnchor;
192
+ Bullet.prototype.createFocusHighlight = Bar.prototype.createFocusHighlight;
178
193
 
179
194
  setDefaultOptions(Bullet, {
180
195
  border: {
@@ -200,10 +215,16 @@ setDefaultOptions(Bullet, {
200
215
  },
201
216
  notes: {
202
217
  label: {}
218
+ },
219
+ accessibility: {
220
+ role: CHART_POINT_ROLE,
221
+ className: CHART_POINT_CLASSNAME,
222
+ ariaRoleDescription: CHART_POINT_ROLE_DESCRIPTION
203
223
  }
204
224
  });
205
225
 
206
226
  deepExtend(Bullet.prototype, PointEventsMixin);
207
227
  deepExtend(Bullet.prototype, NoteMixin);
228
+ deepExtend(Bullet.prototype, AccessibilityAttributesMixin);
208
229
 
209
230
  export default Bullet;
@@ -3,8 +3,10 @@ import { drawing as draw, Color } from '@progress/kendo-drawing';
3
3
  import { ChartElement, Point } from '../../core';
4
4
  import PointEventsMixin from '../mixins/point-events-mixin';
5
5
  import NoteMixin from '../mixins/note-mixin';
6
+ import Bar from '../bar-chart/bar';
7
+ import AccessibilityAttributesMixin from '../mixins/accessibility-attributes-mixin';
6
8
 
7
- import { TOOLTIP_OFFSET } from '../constants';
9
+ import { CHART_POINT_ROLE_DESCRIPTION, CHART_POINT_CLASSNAME, CHART_POINT_ROLE, TOOLTIP_OFFSET } from '../constants';
8
10
  import hasGradientOverlay from '../utils/has-gradient-overlay';
9
11
 
10
12
  import { WHITE, LEFT, TOP } from '../../common/constants';
@@ -16,6 +18,10 @@ class Candlestick extends ChartElement {
16
18
  this.value = value;
17
19
  }
18
20
 
21
+ getLabelText(options) {
22
+ return this.formatValue(options.format);
23
+ }
24
+
19
25
  reflow(box) {
20
26
  const { options, value, owner: chart } = this;
21
27
  const valueAxis = chart.seriesValueAxis(options);
@@ -53,6 +59,9 @@ class Candlestick extends ChartElement {
53
59
 
54
60
  createVisual() {
55
61
  super.createVisual();
62
+
63
+ this.addAccessibilityAttributesToVisual();
64
+
56
65
  this._mainVisual = this.mainVisual(this.options);
57
66
  this.visual.append(
58
67
  this._mainVisual
@@ -196,8 +205,26 @@ class Candlestick extends ChartElement {
196
205
  overlapsBox(box) {
197
206
  return this.box.overlaps(box);
198
207
  }
208
+
209
+ pointData() {
210
+ return {
211
+ dataItem: this.dataItem,
212
+ value: this.value,
213
+ meanPoints: this.meanPoints,
214
+ medianPoints: this.medianPoints,
215
+ whiskerPoints: this.whiskerPoints,
216
+ stackValue: this.stackValue,
217
+ series: this.series
218
+ };
219
+ }
220
+
221
+ getIndex() {
222
+ return this.categoryIx;
223
+ }
199
224
  }
200
225
 
226
+ Candlestick.prototype.createFocusHighlight = Bar.prototype.createFocusHighlight;
227
+
201
228
  setDefaultOptions(Candlestick, {
202
229
  vertical: true,
203
230
  border: {
@@ -218,6 +245,9 @@ setDefaultOptions(Candlestick, {
218
245
  "<tr><td>Close:</td><td>{3:C}</td></tr>" +
219
246
  "</table>"
220
247
  },
248
+ labels: {
249
+ format: ""
250
+ },
221
251
  highlight: {
222
252
  opacity: 1,
223
253
  border: {
@@ -232,10 +262,16 @@ setDefaultOptions(Candlestick, {
232
262
  notes: {
233
263
  visible: true,
234
264
  label: {}
265
+ },
266
+ accessibility: {
267
+ role: CHART_POINT_ROLE,
268
+ className: CHART_POINT_CLASSNAME,
269
+ ariaRoleDescription: CHART_POINT_ROLE_DESCRIPTION
235
270
  }
236
271
  });
237
272
 
238
273
  deepExtend(Candlestick.prototype, PointEventsMixin);
239
274
  deepExtend(Candlestick.prototype, NoteMixin);
275
+ deepExtend(Candlestick.prototype, AccessibilityAttributesMixin);
240
276
 
241
277
  export default Candlestick;
@@ -307,7 +307,7 @@ class CategoricalChart extends ChartElement {
307
307
  excluded: [
308
308
  "data", "aggregate", "_events", "tooltip", "content", "template",
309
309
  "visual", "toggle", "_outOfRangeMinPoint", "_outOfRangeMaxPoint",
310
- "drilldownSeriesFactory"
310
+ "drilldownSeriesFactory", "ariaTemplate"
311
311
  ]
312
312
  };
313
313
 
@@ -20,16 +20,17 @@ import isDateAxis from './utils/is-date-axis';
20
20
  import getDateField from './utils/get-date-field';
21
21
  import { ChartPane, ChartPlotArea, findAxisByName } from './api-elements';
22
22
 
23
- import { X, Y, VALUE, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_SERIES_OPACITY } from '../common/constants';
23
+ import { X, Y, VALUE, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_SERIES_OPACITY,
24
+ ARROW_DOWN, ARROW_UP, ARROW_LEFT, ARROW_RIGHT, ARIA_ACTIVE_DESCENDANT, TAB, TOP, LEFT, BLACK } from '../common/constants';
24
25
  import { addClass, Class, setDefaultOptions, deepExtend, defined, find, isObject, isFunction, elementSize, elementOffset,
25
26
  elementScale, elementStyles, eventCoordinates, bindEvents, unbindEvents, mousewheelDelta, FontLoader, inArray, last, round,
26
- HashMap, valueOrDefault, isString } from '../common';
27
+ HashMap, valueOrDefault, isString, cycleUp, cycleDown } from '../common';
27
28
 
28
29
  import { dateComparer } from '../date-utils';
29
30
 
30
31
  import { DRAG_START, DRAG, DRAG_END, ZOOM_START, ZOOM, ZOOM_END, SELECT_START, SELECT, SELECT_END, PLOT_AREA_HOVER, PLOT_AREA_LEAVE,
31
32
  RENDER, CATEGORY, PIE, DONUT, FUNNEL, PYRAMID, COLUMN, MOUSEWHEEL, MOUSEWHEEL_DELAY, MOUSEWHEEL_ZOOM_RATE, SHOW_TOOLTIP, SERIES_HOVER,
32
- SERIES_OVER, SERIES_LEAVE, SERIES_CLICK, DRILLDOWN } from './constants';
33
+ SERIES_OVER, SERIES_LEAVE, SERIES_CLICK, DRILLDOWN, LEGEND_ITEM_CLICK } from './constants';
33
34
 
34
35
  import './animations';
35
36
  import './register-charts';
@@ -39,6 +40,9 @@ const AXIS_NAMES = [ CATEGORY, VALUE, X, Y ];
39
40
  const MOUSEMOVE = "mousemove";
40
41
  const CONTEXTMENU = "contextmenu";
41
42
  const MOUSELEAVE = "mouseleave";
43
+ const KEYDOWN = "keydown";
44
+ const FOCUS = "focus";
45
+ const BLUR = "blur";
42
46
  const MOUSEMOVE_DELAY = 20;
43
47
 
44
48
  class Chart extends Class {
@@ -56,6 +60,7 @@ class Chart extends Class {
56
60
  this._originalOptions = deepExtend({}, options);
57
61
  this._theme = themeOptions;
58
62
  this._initTheme(options, themeOptions);
63
+ this._focusState = {};
59
64
 
60
65
  this._initHandlers();
61
66
  this._initSurface();
@@ -74,6 +79,9 @@ class Chart extends Class {
74
79
  _initElement(element) {
75
80
  this._setElementClass(element);
76
81
  element.style.position = "relative";
82
+ element.tabIndex = element.getAttribute("tabindex") ? element.getAttribute("tabindex") : 0;
83
+ // To support user agents and assistive technologies based on the ARIA 1.0 specification, authors may wish to include the document role as a fallback value, in the form role="graphics-document document".
84
+ element.setAttribute("role", "graphics-document document");
77
85
  while (element.firstChild) {
78
86
  element.removeChild(element.firstChild);
79
87
  }
@@ -287,8 +295,11 @@ class Chart extends Class {
287
295
 
288
296
  this._destroyView();
289
297
 
298
+ this._setElementAccessibilityAttributes();
299
+
290
300
  this._model = model;
291
301
  this._plotArea = model._plotArea;
302
+ this._legend = model._legend;
292
303
 
293
304
  model.renderVisual();
294
305
 
@@ -326,6 +337,13 @@ class Chart extends Class {
326
337
  }
327
338
  }
328
339
 
340
+ _setElementAccessibilityAttributes() {
341
+ let titleOptions = this.options.title;
342
+ let title = isString(titleOptions) ? titleOptions : (titleOptions.description || titleOptions.text);
343
+
344
+ this.element.setAttribute("aria-roledescription", title);
345
+ }
346
+
329
347
  exportVisual(exportOptions) {
330
348
  let visual;
331
349
  if (exportOptions && (exportOptions.width || exportOptions.height || exportOptions.options)) {
@@ -474,7 +492,9 @@ class Chart extends Class {
474
492
  model.append.apply(model, Title.orderTitles([title, subtitle]));
475
493
 
476
494
  if (options.legend && options.legend.visible) {
477
- model.append(new Legend(plotArea.options.legend, this.chartService));
495
+ const legend = new Legend(plotArea.options.legend, this.chartService);
496
+ model.append(legend);
497
+ model._legend = legend;
478
498
  }
479
499
  model.append(plotArea);
480
500
  model.reflow();
@@ -534,6 +554,9 @@ class Chart extends Class {
534
554
 
535
555
  _initHandlers() {
536
556
  this._clickHandler = this._click.bind(this);
557
+ this._keydownHandler = this._keydown.bind(this);
558
+ this._focusHandler = this._focus.bind(this);
559
+ this._blurHandler = this._blur.bind(this);
537
560
  this._mousewheelHandler = this._mousewheel.bind(this);
538
561
  this._mouseleaveHandler = this._mouseleave.bind(this);
539
562
  this._surfaceMouseenterHandler = this._mouseover.bind(this);
@@ -577,7 +600,10 @@ class Chart extends Class {
577
600
  } else if (name === SERIES_LEAVE) {
578
601
  this._resetDrilldownPoint();
579
602
  } else if (name === SERIES_CLICK) {
603
+ this._focusPoint(args.point);
580
604
  this._startDrilldown(args.point);
605
+ } else if (name === LEGEND_ITEM_CLICK) {
606
+ this._focusLegendItem(args);
581
607
  }
582
608
 
583
609
  const observers = this.observers;
@@ -599,7 +625,10 @@ class Chart extends Class {
599
625
  bindEvents(element, {
600
626
  [ CONTEXTMENU ]: this._clickHandler,
601
627
  [ MOUSEWHEEL ]: this._mousewheelHandler,
602
- [ MOUSELEAVE ]: this._mouseleaveHandler
628
+ [ MOUSELEAVE ]: this._mouseleaveHandler,
629
+ [ KEYDOWN ]: this._keydownHandler,
630
+ [ FOCUS ]: this._focusHandler,
631
+ [ BLUR]: this._blurHandler
603
632
  });
604
633
 
605
634
  if (this._shouldAttachMouseMove()) {
@@ -646,6 +675,7 @@ class Chart extends Class {
646
675
  if (this._mousewheelZoom && !this._stopChartHandlers(e)) {
647
676
  this._gestureDistance = e.distance;
648
677
  this._unsetActivePoint();
678
+ this._clearFocusedElement();
649
679
  this.surface.suspendTracking();
650
680
  }
651
681
  }
@@ -714,6 +744,7 @@ class Chart extends Class {
714
744
  if (this._pannable && this._pannable.start(e)) {
715
745
  this.surface.suspendTracking();
716
746
  this._unsetActivePoint();
747
+ this._clearFocusedElement();
717
748
  this._suppressHover = true;
718
749
  this.chartService.panning = true;
719
750
  }
@@ -833,6 +864,7 @@ class Chart extends Class {
833
864
 
834
865
  if (!this._zooming) {
835
866
  this._unsetActivePoint();
867
+ this._clearFocusedElement();
836
868
  this.surface.suspendTracking();
837
869
  this._zooming = true;
838
870
  }
@@ -916,6 +948,7 @@ class Chart extends Class {
916
948
  } else {
917
949
  this._suppressHover = true;
918
950
  this._unsetActivePoint();
951
+ this._clearFocusedElement();
919
952
  this._navState = {
920
953
  axisRanges: ranges,
921
954
  pane: pane,
@@ -1046,6 +1079,214 @@ class Chart extends Class {
1046
1079
  }
1047
1080
  }
1048
1081
 
1082
+ _isLegendBeforeChart() {
1083
+ const { options: { legend: { position: legendPosition } }, _legend: legend } = this;
1084
+
1085
+ return legend && legend.hasItems() && (legendPosition === TOP || legendPosition === LEFT);
1086
+ }
1087
+
1088
+ _focus() {
1089
+ if (!this._preventInitialPointFocus) {
1090
+ if (this._isLegendBeforeChart()) {
1091
+ this._focusFirstLegendItem();
1092
+ } else {
1093
+ this._focusFirstPoint();
1094
+ }
1095
+ }
1096
+ }
1097
+
1098
+ _keydown(e) {
1099
+ const { _focusState: { legendInFocus }, _legend: legend } = this;
1100
+
1101
+ if (e.key === TAB) {
1102
+ this._clearFocusedElement();
1103
+ const isLegendBeforeChart = this._isLegendBeforeChart();
1104
+
1105
+ if (legendInFocus && isLegendBeforeChart !== e.shiftKey) {
1106
+ this._navigatePoints(e);
1107
+ } else if (!legendInFocus && isLegendBeforeChart === e.shiftKey && legend.hasItems()) {
1108
+ this._navigateLegend(e);
1109
+ }
1110
+ } else if (!legendInFocus) {
1111
+ this._navigatePoints(e);
1112
+ } else {
1113
+ this._navigateLegend(e);
1114
+ }
1115
+ }
1116
+
1117
+ _navigatePoints(e) {
1118
+ const { _focusState: focusState, _plotArea: plotArea } = this;
1119
+
1120
+ focusState.legendInFocus = false;
1121
+
1122
+ if (!focusState.focusedElement) {
1123
+ this._focusFirstPoint();
1124
+ e.preventDefault();
1125
+ return;
1126
+ }
1127
+
1128
+ const moveFocus = (point) => {
1129
+ focusState.focusedPoint = point;
1130
+
1131
+ this._focusElement(focusState.focusedPoint);
1132
+ e.preventDefault();
1133
+ };
1134
+
1135
+ switch (e.key) {
1136
+ case ARROW_RIGHT:
1137
+ moveFocus(plotArea.getPointToTheRight(focusState.focusedPoint));
1138
+ break;
1139
+ case ARROW_LEFT:
1140
+ moveFocus(plotArea.getPointToTheLeft(focusState.focusedPoint));
1141
+ break;
1142
+ case ARROW_DOWN:
1143
+ moveFocus(plotArea.getPointBelow(focusState.focusedPoint));
1144
+ break;
1145
+ case ARROW_UP:
1146
+ moveFocus(plotArea.getPointAbove(focusState.focusedPoint));
1147
+ break;
1148
+ default:
1149
+ break;
1150
+ }
1151
+ }
1152
+
1153
+ _navigateLegend(e) {
1154
+ const { _focusState: focusState, _legend: legend } = this;
1155
+
1156
+ focusState.legendInFocus = true;
1157
+
1158
+ if (!focusState.focusedElement) {
1159
+ this._focusFirstLegendItem();
1160
+ e.preventDefault();
1161
+ return;
1162
+ }
1163
+
1164
+ const itemsLength = legend.getItems().length;
1165
+ const moveFocus = () => {
1166
+ this._focusElement(this._getFocusedLegendItem());
1167
+ e.preventDefault();
1168
+ };
1169
+
1170
+ switch (e.key) {
1171
+ case ARROW_UP:
1172
+ case ARROW_LEFT:
1173
+ focusState.focusedLegendItemIndex = cycleDown(
1174
+ focusState.focusedLegendItemIndex,
1175
+ itemsLength
1176
+ );
1177
+ moveFocus();
1178
+ break;
1179
+ case ARROW_DOWN:
1180
+ case ARROW_RIGHT:
1181
+ focusState.focusedLegendItemIndex = cycleUp(
1182
+ focusState.focusedLegendItemIndex,
1183
+ itemsLength
1184
+ );
1185
+ moveFocus();
1186
+ break;
1187
+ default:
1188
+ break;
1189
+ }
1190
+ }
1191
+
1192
+ _focusFirstPoint() {
1193
+ const point = this._focusState.focusedPoint = this._plotArea.getFirstPoint();
1194
+
1195
+ if (point) {
1196
+ this._focusElement(point);
1197
+ }
1198
+ }
1199
+
1200
+ _focusChart() {
1201
+ if (document.activeElement !== this.element) {
1202
+ this._preventInitialPointFocus = true;
1203
+ this.element.focus();
1204
+ this._preventInitialPointFocus = false;
1205
+ }
1206
+ }
1207
+
1208
+ _focusPoint(point) {
1209
+ this._focusState.focusedPoint = point;
1210
+
1211
+ this._focusChart();
1212
+
1213
+ this._focusElement(point, true);
1214
+ }
1215
+
1216
+ _focusFirstLegendItem() {
1217
+ const { _focusState: focusState } = this;
1218
+
1219
+ focusState.focusedLegendItemIndex = 0;
1220
+ this._focusElement(this._getFocusedLegendItem());
1221
+ focusState.legendInFocus = true;
1222
+ }
1223
+
1224
+ _focusLegendItem(args) {
1225
+ const { _focusState: focusState } = this;
1226
+
1227
+ focusState.focusedLegendItemIndex = args.seriesIndex;
1228
+ focusState.legendInFocus = true;
1229
+
1230
+ this._focusChart();
1231
+
1232
+ this._focusElement(this._getFocusedLegendItem(), true);
1233
+ }
1234
+
1235
+ _getFocusedLegendItem() {
1236
+ const { _focusState: focusState, _legend: legend } = this;
1237
+
1238
+ return legend.getItems()[focusState.focusedLegendItemIndex];
1239
+ }
1240
+
1241
+ _focusElement(element, omitHighlight) {
1242
+ const { _focusState: focusState } = this;
1243
+
1244
+ this._clearFocusedElement();
1245
+
1246
+ focusState.focusedElement = element;
1247
+
1248
+ if (!omitHighlight) {
1249
+ element.focusVisual();
1250
+
1251
+ this._setElementActiveDescendant(element._id);
1252
+
1253
+ if (focusState.legendInFocus) {
1254
+ this._showSeriesInactiveOpacity(focusState.focusedLegendItemIndex);
1255
+ } else {
1256
+ this._showInactiveOpacity(element);
1257
+ }
1258
+ }
1259
+ }
1260
+
1261
+ _clearFocusedElement() {
1262
+ const { _focusState: focusState } = this;
1263
+
1264
+ if (!focusState) {
1265
+ return;
1266
+ }
1267
+
1268
+ if (focusState.focusedElement) {
1269
+ focusState.focusedElement.clearFocusFromVisual();
1270
+ this._setElementActiveDescendant(null);
1271
+ }
1272
+
1273
+ focusState.focusedElement = null;
1274
+ }
1275
+
1276
+ _setElementActiveDescendant(id) {
1277
+ if (id) {
1278
+ this.element.setAttribute(ARIA_ACTIVE_DESCENDANT, id);
1279
+ } else {
1280
+ this.element.removeAttribute(ARIA_ACTIVE_DESCENDANT);
1281
+ }
1282
+ }
1283
+
1284
+ _blur() {
1285
+ this._focusState.legendInFocus = false;
1286
+ this._clearFocusedElement();
1287
+ this._hideInactiveOpacity();
1288
+ }
1289
+
1049
1290
  _startHover(element, e) {
1050
1291
  if (this._suppressHover) {
1051
1292
  return false;
@@ -1055,7 +1296,19 @@ class Chart extends Class {
1055
1296
  return (element.hover || element.over) && !(element instanceof PlotAreaBase);
1056
1297
  });
1057
1298
 
1058
- this._showInactiveOpacity(point, e);
1299
+ const activePoint = this._activePoint;
1300
+
1301
+ this._updateHoveredPoint(point, e);
1302
+
1303
+ if (point && activePoint !== point && point.hover) {
1304
+ this._activePoint = point;
1305
+
1306
+ if (!this._sharedTooltip() && !point.hover(this, e)) {
1307
+ this._displayTooltip(point);
1308
+
1309
+ this._showInactiveOpacity(point);
1310
+ }
1311
+ }
1059
1312
 
1060
1313
  return point;
1061
1314
  }
@@ -1218,28 +1471,15 @@ class Chart extends Class {
1218
1471
  return chartInstance;
1219
1472
  }
1220
1473
 
1221
- _showInactiveOpacity(point, e) {
1222
- const activePoint = this._activePoint;
1474
+ _showInactiveOpacity(point) {
1223
1475
  const multipleSeries = this._plotArea.series.length > 1;
1224
1476
  const hasInactiveOpacity = this._hasInactiveOpacity();
1225
1477
 
1226
- this._updateHoveredPoint(point, e);
1227
-
1228
- if (point && activePoint !== point && point.hover) {
1229
- this._activePoint = point;
1230
-
1231
- if (!this._sharedTooltip() && !point.hover(this, e)) {
1232
- this._displayTooltip(point);
1233
-
1234
- if (hasInactiveOpacity) {
1235
- this._displayInactiveOpacity(point, multipleSeries);
1236
- } else {
1237
- this._highlight.show(point);
1238
- }
1239
- }
1478
+ if (hasInactiveOpacity) {
1479
+ this._displayInactiveOpacity(point, multipleSeries);
1480
+ } else {
1481
+ this._highlight.show(point);
1240
1482
  }
1241
-
1242
- return point;
1243
1483
  }
1244
1484
 
1245
1485
  _hideInactiveOpacity(point) {
@@ -1308,6 +1548,7 @@ class Chart extends Class {
1308
1548
  [ MOUSEMOVE ]: this._mouseMoveTrackHandler
1309
1549
  });
1310
1550
  this._unsetActivePoint();
1551
+ this._clearFocusedElement();
1311
1552
  this._mouseMoveTrackHandler = null;
1312
1553
 
1313
1554
  this._hideInactiveOpacity(point);
@@ -1531,6 +1772,10 @@ class Chart extends Class {
1531
1772
  }
1532
1773
 
1533
1774
  _legendItemHover(seriesIndex, pointIndex) {
1775
+ this._showSeriesInactiveOpacity(seriesIndex, pointIndex);
1776
+ }
1777
+
1778
+ _showSeriesInactiveOpacity(seriesIndex, pointIndex) {
1534
1779
  const { _plotArea: plotArea, _highlight: highlight } = this;
1535
1780
  const currentSeries = (plotArea.srcSeries || plotArea.series)[seriesIndex];
1536
1781
  let items;
@@ -1612,7 +1857,10 @@ class Chart extends Class {
1612
1857
  [ CONTEXTMENU ]: this._clickHandler,
1613
1858
  [ MOUSEWHEEL ]: this._mousewheelHandler,
1614
1859
  [ MOUSEMOVE ]: this._mousemove,
1615
- [ MOUSELEAVE ]: this._mouseleaveHandler
1860
+ [ MOUSELEAVE ]: this._mouseleaveHandler,
1861
+ [ KEYDOWN ]: this._keydownHandler,
1862
+ [ FOCUS ]: this._focusHandler,
1863
+ [ BLUR]: this._blurHandler
1616
1864
  });
1617
1865
 
1618
1866
  if (this.domEvents) {
@@ -1626,6 +1874,8 @@ class Chart extends Class {
1626
1874
  });
1627
1875
  }
1628
1876
 
1877
+ this._focusState = null;
1878
+
1629
1879
  this._destroyView();
1630
1880
 
1631
1881
  this._destroySurface();
@@ -1663,6 +1913,7 @@ class Chart extends Class {
1663
1913
  }
1664
1914
 
1665
1915
  this._unsetActivePoint();
1916
+ this._clearFocusedElement();
1666
1917
  this._resetDrilldownPoint();
1667
1918
  this._destroySelections();
1668
1919
 
@@ -1893,7 +2144,16 @@ setDefaultOptions(Chart, {
1893
2144
  chartArea: {},
1894
2145
  legend: {
1895
2146
  visible: true,
1896
- labels: {}
2147
+ labels: {},
2148
+ accessibility: {
2149
+ highlight: {
2150
+ border: {
2151
+ opacity: 1,
2152
+ color: BLACK,
2153
+ width: 2
2154
+ }
2155
+ }
2156
+ }
1897
2157
  },
1898
2158
  categoryAxis: {},
1899
2159
  seriesDefaults: {
@@ -1905,6 +2165,15 @@ setDefaultOptions(Chart, {
1905
2165
  labels: {},
1906
2166
  negativeValues: {
1907
2167
  visible: false
2168
+ },
2169
+ accessibility: {
2170
+ highlight: {
2171
+ border: {
2172
+ opacity: 1,
2173
+ width: 2
2174
+ },
2175
+ zIndex: 200
2176
+ }
1908
2177
  }
1909
2178
  },
1910
2179
  series: [],