In amCharts 4, accessibility is not an afterthought, but rather something that was included in the planning from day zero. Result is a charting library that is usable with screen readers and other perception enhancement tools out-of-the box, yet super flexible to modify the behavior to suit particular needs.
This article aims at outlining built-in accessibility features, configuration opportunities, and adherence to standards.
Prerequisites
Some functionality described in this article may not work on older versions of amCharts 4 due to bugs related to accessibility features.
The latest accessibility-related bugs were fixed in version 4.6.9
. Make sure you use it, or better yet, the latest version available at the time.
Common principles
Focusable items
A chart is full of elements: buttons, lines, columns, labels, and million of other items.
Some of those are more relevant for vision-impaired users than the others. We call those "focusable" items.
For example, a column in a ColumnSeries
is important. User needs to be able to TAB through focusable items, so that screen reader can read relevant information.
Other examples of focusable items: togglable legend item, scrollbar grip, zoom out button.
Examples of irrelevant elements: axis labels, grid lines.
Most of the elements that we think should be focusable are already pre-set so by default. Others can be enabled by setting their focusable
property.
For example, if we want to make a specific chart title (more about chart titles later in this article) focusable, we do this:
let title = chart.titles.create(); title.text = "Spending analysis"; title.focusable = true;
var title = chart.titles.create(); title.text = "Spending analysis"; title.focusable = true;
{ // ... "titles": [{ "text": "Spending analysis", "focusable": true }] }
In a nutshell, if an item is "focusable" it can be TAB'ed into or selected with a mouse.
Once a focusable item is selected with a TAB, two things will happen:
- It will be highlighted with a high-contrast outline.
- Screen reader software (if enabled) will read out the information attached to it. (more about this later)
SIDE READING If you'd like to change how focused items look, read "Changing appearance of focused items".
Screen reader text
Default screen reader prompts
Most of the elements in amCharts 4 come with pre-defined screen reader prompts. They are chosen to be as relative and descriptive as possible.
The screen reader information is conveyed via "ARIA" labels, like aria-title
, aria-labelledby
, and aria-describedby
.
For example, the whole chart will indicate it's type.
A series will indicate what type of series it is.
Each individual item in series, like column, will indicate its X and Y value, or if it's a Slice in PieSeries, it's category, value and percent.
Actually, there's a bit of fuzzy logic involved in screen readers and series. This is why we have a separate section in this article, dedicated to series.
Every single element on a chart can have some text for screen readers.
Modifying reader texts
There are two pieces of textual information that element can have: a title and a description.
The former is set via element's readerTitle
property. The latter: via readerDescription
.
Which one will be read out, and in what order depends on actual user's settings and the reader software he or she uses.
As an example, let's revisit the chart title example we had at the beginning of this chapter.
We had its label text set to "Spending analysis". Let's say we want to supply additional information to be read next to "Spending analysis".
We can do that by setting title's readerTitle
:
title.readerTitle = "An interactive chart prepared from finance department";
title.readerTitle = "An interactive chart prepared from finance department";
{ // ... "titles": [{ "text": "Spending analysis", "focusable": true, "readerTitle": "An interactive chart prepared from finance department" }] }
The "An interactive chart prepared from finance department" will not be visible anywhere on the screen, but now when user focuses on the title (or chart as we will see later), he or she will get the full(er) description: "Spending analysis - An interactive chart prepared from finance department".
Keyboard navigation
Remember how we said two things happen when item gains focus (highlight and screen reader)? Actually there's a third thing.
If item is movable (draggable = true
) we can now control it using keyboard arrow keys.
For example, if we TAB until scrollbar's grip is selected, we can now move it using left/right keys (or up/down if it's a vertical scrollbar).
Usually such elements have already pre-defined additional screen reader instructions advertising such capability that will be advertised to user.
Tooltips
Some charts will display a tooltip on hover/touch of certain elements.
E.g. hovering a column in series might be set up to display its value and related information.
For vision-impaired users, hovering elements to display that complimentary information might not be possible.
This is why there is a special setting that allows displaying a related tooltip whenever element is focused (via TAB): hoverOnFocus
.
If set to true
the element will act like it was hovered when it is focused, including displaying related tooltip.
For example, we can enable this feature for ColumnSeries
columns:
series.columns.template.hoverOnFocus = true;
series.columns.template.hoverOnFocus = true;
{ // ... "series": { "type": "ColumnSeries", // ... "columns": { "hoverOnFocus": true } } }
While displaying tooltip might not mean anything visually, it's still serves its purpose. Most screen reader software will single out tooltip as a very important contextual information, and will direct user's attention towards it.
Accessibility of chart elements
Chart itself
Making chart focusable
A chart element is not focusable by default. If we want it to be so, we need to set its focusable
property, like we learned before:
chart.focusable = true;
chart.focusable = true;
{ // ... "focusable": true }
Chart's reader text
By default, a chart will have a default reader title which is "Chart". Not very descriptive.
If we want we can use readerTitle
to add a more meaningful description:
chart.readerTitle = "Spending analysis";
chart.readerTitle = "Spending analysis";
{ // ... "readerTitle": "Spending analysis" }
Re-using chart's title
However, if we have chart's title set (like we saw earlier in the article), the chart is clever enough to use it as a reader text instead of "Chart".
Bottom line: if you have any titles added to chart, you don't need to add any additional reader text (unless you need any additional info), because it will be read out by screen readers when chart is focused.
Series
Series, is perhaps the most important part of each chart: the one that actually visualizes the data the chart is meant to convey.
As the name suggests, it's not a single object bur rather collection (series) of elements.
I.e. ColumnSeries
consists of a number of columns. PieSeries
consists of slices. LineSeries
might have a number of bullets. Etc.
Series item reader text
What goes into each series reader text is a result of a bit different process than regular items.
It's controlled by series' property itemReaderText
. This basically means "use this text as a readerTitle
for each of your items".
It has different defaults for different series types. We'll explore that in a little while.
Some series, like LineSeries
do not have particular elements to focus onto by default, so itemReaderText
does not make a whole lot of sense there and should not be used. We'll explore this series type a bit later.
If we want to override the defaults, we can simply set itemReaderText
on our series:
series.itemReaderText = "Sales volume: {sales}";
series.itemReaderText = "Sales volume: {sales}";
{ // ... "series": { "type": "ColumnSeries", // ... "itemReaderText": "Sales volume: {sales}"; } }
Binding to data
The good news is that reader text, just like visible labels accept data placeholders in curly brackets.
This means that {sales}
above will be replaced by actual value from a data point related to the focused item.
You can refer to almost any property: series properties (e.g. {name}
), data item values (e.g. {valueY}
, {categoryX}
), or data context (e.g. {customValueInData}
).
MORE INFO For more info on how data binding work, check out this article.
ColumnSeries
The default for ColumnSeries
will be automatically constructed out of its data fields.
Say we have a ColumnSeries
on a chart with a CategoryAxis
on X and ValueAxis
on Y.
It's data fields might look like this:
series.dataFields.categoryX = "category"; series.dataFields.valueY = "value";
series.dataFields.categoryX = "category"; series.dataFields.valueY = "value";
{ // ... "series": { "type": "ColumnSeries", // ... "dataFields": { "categoryX": "category", "valueY": "value" } } }
Now, if we do not explicitly set itemReaderText
ourselves, the series will try to do that for us, constructing it from our dataFields
.
The above would result in something like "{categoryX} {valueY}"
, which in turn be read out as "Research & development 1200"
when populated by real values.
We can override it using itemReaderText
of course. Let's say we want the screen reader to read out series name, category, and value when column is focused. We could use this:
series.itemReaderText = "Series: '{name}', Category: '{categoryX}', Sales volume: {valueY} USD";
series.itemReaderText = "Series: '{name}', Category: '{categoryX}', Sales volume: {valueY} USD";
{ // ... "series": { "type": "ColumnSeries", // ... "itemReaderText": "Series: '{name}', Category: '{categoryX}', Sales volume: {valueY} USD"; } }
PercentSeries (PieSeries, FunnelSeries, etc.)
PercentSeries
(which is base for any slice-bsaed series, lie PieSeries
, FunnelSeries
, PyramidSeries
, etc.) defaults work similarly, except with slightly different default: "{category}: {value.percent.formatNumber('#.#')}%"
.
LineSeries
As we mentioned earlier, LineSeries
does not have easily identifiable individual elements, like columns or slices, so itemReaderText
does not apply here.
We still can apply configurable reader text there, for example to its bullets, that could be focusable.
Since a bullet is a completley custom element (there can be any number of bullets in a series), the series will not feel at liberty to go ant add reader text to them so it's up to use to do that using readerTitle
.
let bullet = series.bullets.push(new am4charts.CircleBullet()); bullet.readerTitle = "{categoryX} {valueY}";
var bullet = series.bullets.push(new am4charts.CircleBullet()); bullet.readerTitle = "{categoryX} {valueY}";
{ // ... "series": { "type": "LineSeries", // ... "bullets": [{ "type": "CircleBullet", "readerTitle": "{categoryX} {valueY}" }] } }
Focusable threshold
Say we have a ColumnSeries
with 10 columns. It makes sense for user to be able to TAB through each of those and have their info read.
Now, imagine we have 5 series with 300 data items each.
A user would need a lot of time just to TAB through them, rendering the whole exercise and functionality a bit useless.
This is why series employ a virtual threshold. If there are more items than X, they simply become not focusable. In such case, as a creator of an accessible data visualization, the developer would be responsible to provide an alternative textual representation of data, such as data table.
The defaults differ per series type.
Series type | Default focusable threshold |
---|---|
XYSeries (ColumnSeries , LineSeries , etc.) | 20 |
PercentSeries (PieSeries , FunnelSeries , etc.) | 50 |
We can change the threshold using series' skipFocusThreshold
property:
series.skipFocusThreshold = 50;
series.skipFocusThreshold = 50;
{ // ... "series": [{ // ... "skipFocusThreshold": 50 }] }
Pattern fills
amCharts 4 comes with a "patterns" theme.
If enabled, elements like slices, columns, area series will automatically be filled with distinctive patterns instead of solid colors, making differences more prominent for people with impaired vision and color blindness.
MORE INFO Read "Using patterns theme" for more info.