Accessible text
Because native canvas text is not the best quality at lower screen resolutions and nor is it accessible (to screen readers for example), RGraph now supports using the more accessible DOM text instead of the native canvas API text functionality.
- Caveats with accessible text
- Adding your own event handlers
- Performance advantages with accessible text
- Accessibility advantages with accessible text
- Dealing with text that moves (in animation effects)
Being continually disappointed by the poor quality of the text that's rendered on a canvas, there's now an option to use accessible DOM text positioned over the canvas instead of native canvas rendered text.
The HTML5 canvas tag is a bitmap (not a vector) - so the quality of anything - including text - will degrade as you increase the zoom - similar to how an image becomes blockier the more you zoom in.
Using accessible DOM text instead of native canvas text solves this issue - and text retains its quality regardless of the level of zoom. Try zooming this page (CTRL & + and CTRL & -) and you'll see.
<script> labels = []; tooltips = []; data = []; sales = [ ['Monday', 45], ['Tuesday',49], ['Wednesday',43], ['Thursday',46], ['Friday',32] ]; // Create the labels for (var i=0; i<sales.length; ++i) { data[i] = sales[i][1]; labels[i] = sales[i][0]; tooltips[i] = '{1}: {2}%'.format(labels[i], data[i]); } new RGraph.Bar({ id: 'cvs', data: data, options: { tooltips: labels, xaxisLabels: labels, // textAccessible: true, // The default is true now // textAccessibleOverflow: true, // The default is true now textAccessiblePointerevents: true, textSize: 14, titleSize: 20, titleBold: true, // Default title: 'An example chart using accessible text', yaxisScaleMax: 100, colors: ['Gradient(#fcc:red:red)'], shadowOffsetx: 1, shadowOffsety: 1, shadowBlur: 5, marginLeft: 5, marginRight: 5, marginTop: 50, marginBottom: 5, yaxisScaleUnitsPost: '%', colorsStroke: 'transparent', xaxis: false, yaxis: false, backgroundGridVlines: false, backgroundGridBorder: false, clearto: 'white' } }).wave(); </script>
Caveats with accessible text
There are caveats-a-plenty with accessible text - mainly with interactive features. Things that aren't mentioned here may or may not work!- Angled text doesn't work (though it may come by using CSS 2D transformations)
- Annotating doesn't work 100% correctly with accessible text - the text appears above the annotation. If you only annotate the chart itself though (and not the labels) you may not notice this.
- The interactive key will work but will be rendered using native canvas text
- Some of the 3D charts won't work correctly.
- CSS changes as a result of your media queries (or more general CSS rules) may affect your chart when they are applied (or removed). To work around this you'll need to be more specific with your CSS rules or create exceptions for the RGraph accessible text DIV wrappers.
Adding your own event handlers
Being standard DOM nodes you can work with them as such. References to
the <SPAN>
tags are kept in the RGraph.text.domNodeCache
array. The first key in that array is the canvas ID and then you could
use the for/in loop shown below to loop through the text nodes that
pertain to that canvas tag. If you wanted to you could, in that loop,
add them to a numerically indexed array, which you might then find
easier to work with.
<script> // Loop through all of the accessible text nodes and add them to a one dimension, // numerically indexed array texts = RGraph.text.domNodeCache['cvs']; // Use the canvas ID here arr = new Array(); for (var i in texts) { arr.push(texts[i]); } // This is an example of the sort of thing that you could then add arr[1].onmouseover = function (e) { e.target.style.padding = '2px'; e.target.style.backgroundColor = 'red'; e.target.style.border = '2px solid black'; e.target.style.borderRadius = '5px'; e.target.onmouseout = function (e) { e.target.style.padding = ''; e.target.style.backgroundColor = ''; e.target.style.border = ''; e.target.style.borderRadius = ''; e.target.style.cursor = 'default'; }; } // And this is how to get the length of the text array len = Object.keys(RGraph.text.domNodeCache['cvs']).length; </script>
Performance advantages with accessible text
Drawing text on canvas has, in the past, been called slow. Whether it is still slow is open to discussion. It most certainly won't be as fast though as simply not drawing text at all. And that is evident in the chart above in the smoothness of the animation.
By using accessible text that is essentially what is happening. If the DOM nodes were created and trashed for every frame of an animation then there would be no performance gain and a massive performance loss. But they're not.
The DOM text nodes are created and then the nodes are kept in the
RGraph.text.domNodeCache
array. It's a cache
so that the nodes aren't created over and over again. By doing this
all of the text on the canvas is created once and reused for each
frame of an animation. By repeatedly using the same text
the text drawing part of the chart rendering is eliminated.
Accessibility advantages with accessible text
When it comes to accessibility with canvas - essentially it's an impenetrable black box. Anything drawn on it is unknown to the browser - much like an image. So by using accessible text you make the text as accessible as the other text on your page. The text can gain focus and can be read by screen readers just like normal text. It also responds to zoom operations like other text on your page.
Dealing with text that moves (in animation effects)
If you have text that moves in your chart - in an animated
Bar chart or a Horizontal Bar chart with the
labelsAbove
option enabled - then this can slow
down accessible text. This is because new DOM nodes need to be created for
each bit of moving text on each frame of the animation. This can be worked
around in some cases though by only enabling the text once the animation
has finished. You can do this by using an animation-complete
callback function. The Bar chart and Horizontal Bar chart both accommodate the labelsAbove
text already.
You can use the callback function like this:
.grow(null, function (obj) { obj.set('labelsAbove', true); RGraph.redraw(); });