Skip to content

Commit

Permalink
feat(core): aria label for legend title and content
Browse files Browse the repository at this point in the history
Generate a unique identifier for the legend title, then refer to that with aria-labelledby to create a more explicit association between the legend content and the title.
  • Loading branch information
vijithassar committed May 29, 2024
1 parent a861ab4 commit f7b6edd
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 1 deletion.
23 changes: 22 additions & 1 deletion source/legend.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { encodingField } from './encodings.js'
import { feature } from './feature.js'
import { key, mark } from './helpers.js'
import { layerPrimary } from './views.js'
import { extension } from './extensions.js'
import { parseScales } from './scales.js'
import { renderStyles } from './styles.js'
import { list } from './text.js'
Expand Down Expand Up @@ -48,6 +49,19 @@ const legendTitle = s => {
return s.encoding.color.legend?.title || s.encoding.color.title || encodingField(s, 'color')
}

/**
* a string for identifiying the legend in the DOM
* @param {object} s specification
* @return {string|null} legend title identifier string
*/
const legendIdentifier = s => {
if (extension(s, 'id')) {
return `legend-title-${extension(s, 'id')}`
} else {
return null
}
}

/**
* generate a written description for the legend
* @param {object} s Vega Lite specification
Expand Down Expand Up @@ -124,6 +138,7 @@ const swatches = s => {
*/
const swatch = s => {
const renderer = selection => {
const titleIdentifier = feature(s).hasLegendTitle() ? selection.select('h3').attr('id') : null
try {
const dispatcher = dispatchers.get(selection.node())

Expand All @@ -143,6 +158,8 @@ const swatch = s => {
const more = d3.create('ul').classed('items-more', true)
const moreHeader = more.append('h3')

main.attr('aria-labelledby', titleIdentifier)

let target = main

const items = swatches(s).map((_, index) => createLegendItem(itemConfig(s, index)))
Expand Down Expand Up @@ -207,12 +224,16 @@ const swatch = s => {
*/
const legend = _s => {
let s = feature(_s).hasLayers() ? layerPrimary(_s) : _s
const id = legendIdentifier(_s)
return selection => {
if (feature(s).hasLegendTitle()) {
selection
const title = selection
.append('h3')
.classed('title', true)
.text(legendTitle(s))
if (id) {
title.attr('id', id)
}
}
if (feature(s).hasLegend() && (feature(s).isMulticolor() || feature(s).isCircular())) {
selection.call(swatch(s))
Expand Down
1 change: 1 addition & 0 deletions source/markup.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const selectors = [
'.point title',
'.tick',
'.legend',
'.legend .title',
'.legend .pair',
'.legend .items-main',
'.legend .items-more',
Expand Down
12 changes: 12 additions & 0 deletions tests/integration/legend-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,16 @@ module('integration > legend', function() {

assert.notOk(element.querySelector(testSelector('legend-items-more')))
})

test('uses aria-labelledby to associate legend title and content', assert => {
const spec = specificationFixture('circular')
spec.usermeta = { id: 'abdefg' }
const element = render(spec)
const legend = element.querySelector(testSelector('legend'))
const title = legend.querySelector(testSelector('legend-title'))
const id = title.getAttribute('id')
const content = legend.querySelector('ul')
assert.ok(id)
assert.ok(content)
})
})

0 comments on commit f7b6edd

Please sign in to comment.