-
-
Notifications
You must be signed in to change notification settings - Fork 6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Accessibility support for charts. #1060
Comments
A PR is welcome :-) |
What does the support looks like? curious |
See this example for using alt tags to add accessibility support to a web page - http://accessibilityresources.org/joomla/index.php/blog/alt-attributes-it-s-not-that-hard |
If you want to see what an accessible chart looks like on iOS just view the Stocks app from Apple it's got VoiceOver Accessibility for data points. https://pbs.twimg.com/media/DOR8G6lVQAEQ7Hi.jpg:large I found this chart library because they're using it at work and it's not accessible. Can you copy the Apple stocks implementation? |
This commit makes PieChartView adhere to the UIAccessibility container protocol. See the Accessibility section marked for the methods. To allow conformance, 3 properties are added to IPieChartDataSet and PieChartDataSet that enable a more user friendly audio descriptionfor data elements. PieChartRenderer has a new private method createAccessibleElement() that populates the accessiblePieChartElements property, which in turn is used in PieChartView. Note that to prevent contextless audio descriptions, the default Chart Description header text was deleted in Description.swift since it is already an optional.
Hello! Thanks for the great library. I'd be happy to try and tackle this issue for as many chart types as possible, so feel free to assign it to me. While I'm working on it, does anyone have any resources or recommendations for what the Scatter and Combined chart should sound like to a VO user? Right now I'm leaning toward a axis based range summarization (For eg, the sample scatter plot would sound like "0 to 10, DS1: 9 points from 81 to 99, DS2: 5 points between 50 and 87... etc"), however as you can imagine in these two cases, it can be an auditory overload given enough categories. The other option is to simply let the creator describe the visual. But in that case should the description be a required property? This might not work as well for charts with dynamic data. There is also the option for simply narrating a table of values, but usability wise, I think that is a poor choice, since the point of a visualization is to make the information contained palatable. As of now these (and variants) are what I'm working on:
|
Minor changes to spacing in PieChartRenderer.swift. Removed formatting and use of "self." to match library style.
Updated ChartViewBase, ChartData and ChartDataRendererBase to declare the primary properties required for accessibility support within the Charts library. This includes the UIAccessibility protocol methods within ChartViewBase and the internal accessibleChartElements property in the base renderer. ChartData also has 3 optional properties to allow proper formatting of audio.
Thanks for looking into this @mathewa6. This resource might help you. It’s for the web but the same ideas apply https://www.w3.org/WAI/tutorials/images/complex/ |
@petester42 Thanks! I hadn't considered splitting descriptions so that is very helpful. iOS/tvOS allows for a little more interactivity and that way, most folks who use this library will get accessibility "for free" based on titles and legends already provided, without needing to manually add descriptions. Multiple descriptions sounds like it'd be a great way for static scatter/combined plots or even on macOS for static plots. |
At least for the web the idea of having multiple descriptions is for the user to be able skip I if they don’t care. It’s pretty bad experience to read an entire graph without user consent. |
Absolutely. iOS/tvOS let you browse by Header using the VoiceOver rotor. I'm making sure to make the first element of the graphs a Header item (which uses the existing title/legend/description), so they can just skip to next header if they're not interested. Then again, since Charts is cross platform, let me know if you'd prefer a description on all platforms as primary. |
Rotor is also supported in the latest version of macOS. I think it’s fine |
Awesome! Thanks for bringing this up: worth getting these sorts of issues out the way before a PR imo. |
Added accessibilityChildren to ChartViewBase which is a layer over both UIAccessibilityContainer and NSAccessibilityGroup protocols. Updated PieChartRenderer to use the platform agnostic NSUIAccessibilityElement. Added init() overrides in NSUIView declaration for macOS to add .list NSAccessibilityRole. Added Platform+Accessibility.swift which extends NSUIView with accessibility container and group protocols and also declares NSUIAccessibilityElement, which acts as an abstraction over NSAccessibilityElement and UIAccessibilityElement.
Moved Platform+Accessibility.swift to Utils folder. Changed accessibleChartElements to be final since Renderer subclasses should not need to modify its working. Simply populating it in draw() functions will add basic accessibility.
@petester42 |
Quick question: I had a couple VO testers use the sample Radar chart I was working on and we ended up with equal preference for two different ways of parsing the data. I thought I’d ask here, in case there is some statistical or common use case for the chart type that makes one particular method easier. Basically, for the Radar chart, we can present the data in two ways:
Here’s a 30s video demonstrating the difference. Is there a preference on the library's side for these ordering based on how the Charts library is used and/or intended to be used? If not, I will use the first method, since it seemed to make more sense initially to our blind colleagues. |
Created internal property accessibilityOrderedElements to make BarChartRenderer be composed of logically ordered accessible elements (See inline comments for details). Updated ChartDataRendererBase, PieChartRenderer and Platform+Accessibility with updated comments to reflect the platform agnostic NSUIAccessibilityElement's use.
Updated HorizontalBarChartRenderer to populate accessibilityOrderedElements, which in turn is used by the BarChartRenderer superclass to enable accessibility. Added minor note to BarChartRenderer's createAccesibleElement() for edge case where x-axis labels can be inaccurate if multiple data sets are present.
LineChartRenderer now has a private accessibilityOrderedElements nested array that is then used to populate accessibleChartElements. Do note that the nesting is unnecessary for now, but will be needed once a custom rotor is added. Also unlike most other renderers, LineChartRenderer's accessibleChartElements is populated in drawCircles(). This required moving the check for isDrawCirclesEnabled() after accessibleChartElements are populated.
Updated BubbleChartRenderer to mirror LineChartRenderer's nested use of accessibilityOrderedElements to populate accessibleChartElements. Minor updates to comments in LineChartRenderer.
Updated RadarChartRenderer with accessibility properties and calls in drawData and drawDataSet. Due to the unique spatial arrangement of radar charts, accessibleChartElements is populated by dataset, within which variables are ordered in decreasing order.
Fixed crash due to incorrect use of maxEntryCountSet instead of dataSetCount in BubbleChartRenderer and LineChartRenderer's accessibilityCreateEmptyOrderedElements(). Updated BubbleChartRenderer's bubble accessibilityLabel to include percentage size of bubble based on maxSize property of IBubbleChartDataSet.
Updated CandleStickChartRenderer to populate accessibleChartElements. Unlike most other renderers with multiple dataSet support, we do not attempt to order elements logically and hence dataSets are presented to VO in the same order they are drawn with the dataSet label acting as a separating heading.
Added a workaround for non updating accessibility frame when resizing windows and using Charts on macOS by using setAccessibilityFrameInParent() in Platform+Accessibility. See inline comments for details.
Added createAccessibleHeader() to ChartRendererBase.swift that is used to create a descriptive header for all subclasses based on dataSet count and labels. RadarChartRenderer and PieChartRenderer updated to add dataSet label to each item and with documentation respectively.
Added an offset to BarChartRenderer's barRect calculation in prepareBuffer() to prevent calculation of rects outside visible chart area, while still allowing automatic offset of the axis minima visually. This workaround is only used when using auto calculated y-axis minima and isn't used when a custom minimum is manually set.
Updated return value for the index(of:) function to be NSNotFound in Platform+Accessibility's iOS section. This is as required by the documentation for UIAccessibilityContainer protocol.
) Updated Platform+Accessibility with postAnnouncementNotification() to let VoiceOver speak provided strings. Added accessibilityHighlight() to ChartViewBase which finds the highlighted accessibilityElement when an NSUIPanGesture is detected and passes it to a VO notification. For now, this only works with 1 dataset.
Allowed hints to let header elements for Bar and Line charts (set in Bar/Line chart renderers) let users know they can pan to skim. Removed refocus on entire chart in BarLineChartViewBase.
…rg#1060) Allowed manual setting of the ability to allow VoiceOver panning internally in the Charts framework for all views using _allowsHighlightedAccessibilityElements. Currently only Bar and Line chart views set this to true, since panning on other charts can lead to misinterpretation due to their shape/layout. Fixed LineChartRenderer to create accessibilityOrdererElements similarly to BarChartRenderer.
…#1060) Updated ChartViewBase's accessibilityHighlight to account for index calculations into accessibleChartElements when bar chart data is stacked. Also enabled panning support for CandlestickCharts. Added checks for allowsHighlightedAccessibilityElements before adding an accessibilityHint to headers in Line and Bar chart renderers.
Updated BubbleChartView and Renderer to set _allowsHighlightedAccessibilityElements and to more closely mirror Line and Bar chart renderer's indices for accessibilityOrderedElements.
This commit makes PieChartView adhere to the UIAccessibility container protocol. See the Accessibility section marked for the methods. To allow conformance, 3 properties are added to IPieChartDataSet and PieChartDataSet that enable a more user friendly audio descriptionfor data elements. PieChartRenderer has a new private method createAccessibleElement() that populates the accessiblePieChartElements property, which in turn is used in PieChartView. Note that to prevent contextless audio descriptions, the default Chart Description header text was deleted in Description.swift since it is already an optional.
Minor changes to spacing in PieChartRenderer.swift. Removed formatting and use of "self." to match library style.
Updated ChartViewBase, ChartData and ChartDataRendererBase to declare the primary properties required for accessibility support within the Charts library. This includes the UIAccessibility protocol methods within ChartViewBase and the internal accessibleChartElements property in the base renderer. ChartData also has 3 optional properties to allow proper formatting of audio.
Added accessibilityChildren to ChartViewBase which is a layer over both UIAccessibilityContainer and NSAccessibilityGroup protocols. Updated PieChartRenderer to use the platform agnostic NSUIAccessibilityElement. Added init() overrides in NSUIView declaration for macOS to add .list NSAccessibilityRole. Added Platform+Accessibility.swift which extends NSUIView with accessibility container and group protocols and also declares NSUIAccessibilityElement, which acts as an abstraction over NSAccessibilityElement and UIAccessibilityElement.
Moved Platform+Accessibility.swift to Utils folder. Changed accessibleChartElements to be final since Renderer subclasses should not need to modify its working. Simply populating it in draw() functions will add basic accessibility.
Created internal property accessibilityOrderedElements to make BarChartRenderer be composed of logically ordered accessible elements (See inline comments for details). Updated ChartDataRendererBase, PieChartRenderer and Platform+Accessibility with updated comments to reflect the platform agnostic NSUIAccessibilityElement's use.
Updated HorizontalBarChartRenderer to populate accessibilityOrderedElements, which in turn is used by the BarChartRenderer superclass to enable accessibility. Added minor note to BarChartRenderer's createAccesibleElement() for edge case where x-axis labels can be inaccurate if multiple data sets are present.
LineChartRenderer now has a private accessibilityOrderedElements nested array that is then used to populate accessibleChartElements. Do note that the nesting is unnecessary for now, but will be needed once a custom rotor is added. Also unlike most other renderers, LineChartRenderer's accessibleChartElements is populated in drawCircles(). This required moving the check for isDrawCirclesEnabled() after accessibleChartElements are populated.
Updated BubbleChartRenderer to mirror LineChartRenderer's nested use of accessibilityOrderedElements to populate accessibleChartElements. Minor updates to comments in LineChartRenderer.
Updated RadarChartRenderer with accessibility properties and calls in drawData and drawDataSet. Due to the unique spatial arrangement of radar charts, accessibleChartElements is populated by dataset, within which variables are ordered in decreasing order.
Fixed crash due to incorrect use of maxEntryCountSet instead of dataSetCount in BubbleChartRenderer and LineChartRenderer's accessibilityCreateEmptyOrderedElements(). Updated BubbleChartRenderer's bubble accessibilityLabel to include percentage size of bubble based on maxSize property of IBubbleChartDataSet.
Updated CandleStickChartRenderer to populate accessibleChartElements. Unlike most other renderers with multiple dataSet support, we do not attempt to order elements logically and hence dataSets are presented to VO in the same order they are drawn with the dataSet label acting as a separating heading.
Added a workaround for non updating accessibility frame when resizing windows and using Charts on macOS by using setAccessibilityFrameInParent() in Platform+Accessibility. See inline comments for details.
Added createAccessibleHeader() to ChartRendererBase.swift that is used to create a descriptive header for all subclasses based on dataSet count and labels. RadarChartRenderer and PieChartRenderer updated to add dataSet label to each item and with documentation respectively.
Added an offset to BarChartRenderer's barRect calculation in prepareBuffer() to prevent calculation of rects outside visible chart area, while still allowing automatic offset of the axis minima visually. This workaround is only used when using auto calculated y-axis minima and isn't used when a custom minimum is manually set.
Updated return value for the index(of:) function to be NSNotFound in Platform+Accessibility's iOS section. This is as required by the documentation for UIAccessibilityContainer protocol.
@mindgraffiti Does anybody looking at Dynamic Type Support for Chart Labels? |
Hello Sai, Sadly, no. This task was de-prioritized and there are no plans for Woo Mobile to work on it. |
Accessibility support request: is it possible to include the capability for a custom accessibility value that differs from the displayed axis label? I'm working with bar charts containing string values as axis labels. To ensure proper chart rendering, I had to truncate long axis labels to a certain length using a custom AxisValueFormatter implementation. However, for the accessibility value, I want it to announce the complete label string. |
Currently graphs are not accessible to VoiceOver and other accessible technologies.
The text was updated successfully, but these errors were encountered: