Posted on

Accessible and interactive charts with Angular and Highcharts

Column and line charts don't have to be boring and static. Modern JavaScript libraries enable us to create animated, interactive, and accessible charts.

I'm a fan of Highcharts, a JavaScript charting library based on SVG rendering. Several wrapper libraries exist that integrate Highcharts into the component-based architectures of React and Angular, for example. In my demo app, I'll show you how to interweave Highchart's event handling with Angular components.

A ballpen pointing at column and line charts printed on a piece of paper. Photo: © Lukas / pexels.com

Demo App: Selecting a tab when a column is clicked

I built a demo app with Angular 13, Highcharts and highcharts-angular, a minimal Highcharts wrapper for Angular. A column chart depicts the primary desktop screen reader usage. Several tabs provide more information about the screen readers. When a column in the chart is clicked, the corresponding tab is selected. Try it yourself:

So, how did I do this?

Step 1: Define chart options and display the chart

The Highcharts library is super convenient. You simply define your chart options and let Highcharts do the rest. In my demo app, I define a chart with two column series:

export const EXAMPLE_CHART: Highcharts.Options = { series: [ { data: [ [ScreenreaderName.Jaws, 53.7], [ScreenreaderName.Nvda, 30.7], [ScreenreaderName.VoiceOver, 6.5], [ScreenreaderName.ZoomTextFusion, 4.7], [ScreenreaderName.Other, 4.4], ], name: 'Worldwide', type: 'column', }, { data: [ [ScreenreaderName.Jaws, 40.2], [ScreenreaderName.Nvda, 41.6], ], name: 'Europe', type: 'column', } ], subtitle: { text: '', }, title: { text: 'Primary desktop/laptop screen reader (2021)', }, xAxis: { categories: [ ScreenreaderName.Jaws, ScreenreaderName.Nvda, ScreenreaderName.VoiceOver, ScreenreaderName.ZoomTextFusion, ScreenreaderName.Other, ], }, yAxis: { title: { text: 'Usage in percent', } } }

Then, in my AppComponent, I provide the chart options and the Highcharts library:

import * as Highcharts from 'highcharts'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { public chartOptions = EXAMPLE_CHART; public highchartsLib = Highcharts; }

Finally, in the app component's template, I pass on the library and the chart options to the <highcharts-chart> component:

<highcharts-chart [Highcharts]="highchartsLib" [options]="chartOptions" (chartInstance)="addCustomPropertiesToChart($event)" ></highcharts-chart>

Step 2: Add custom properties to the chart instance

The <highcharts-chart> component provides the output property chartInstance. It emits the chart instance after the chart is created. We use this to add an arrow function as a custom property to the chart instance:

public addCustomPropertiesToChart( chartInstance: Highcharts.Chart ): void { (chartInstance as MyExampleChart) .onSeriesPointClick = (name) => this.selectScreenreaderTab(name); }

Highchart's Chart interface doesn't define a method onSeriesPointClick. Therefore, we need to define our own interface that adds this custom property:

export interface MyExampleChart extends Highcharts.Chart { onSeriesPointClick: (name: ScreenreaderName) => void; }

Now our chart instance provides a method that is directly connected to the chart's parent component. A chart event handler can call this method to communicate, e.g., that a specific series point was clicked.

Step 3: Call the custom method inside an event handler

In the plotOptions property of the chart options, we define a click event handler for all series points:

click: function(this) { const chart = this.series.chart as MyExampleChart; chart.onSeriesPointClick(this.name as ScreenreaderName); }

The event handler retrieves the chart instance that we typecast to our custom MyExampleChart interface. Now we can call the custom method onSeriesPointClick and thereby select the corresponding screenreader tab in our application.

Step 4: Make your chart accessible

Highcharts provides great accessibility features. You can set colors in the chart as pattern fills. This helps people with limited color vision who benefit when information conveyed by color is available in other visual ways as well.

color: { pattern: { backgroundColor: '#96dbe7', color: '#080e38', height: 10, path: 'M 0 0 L 10 10 M 9 - 1 L 11 1 M - 1 9 L 1 11', width: 10, } },

The linkedDescription property enables you to link the chart to an HTML element describing the contents of the chart:

accessibility: { enabled: true, linkedDescription: '#highcharts-description-1', },

Conclusion

Combine Angular and Highcharts to create accessible and beautiful charts with minimal effort. With the help of custom properties, you can even interweave Highchart's event handling with Angular's component-based architecture for even more interactive experiences.

Resources

Posted on