Skip to content

Commit e7fc894

Browse files
authored
MWPW-159299 Add chart role and dynamic aria labels (adobecom#3404)
* MWPW-159299 Add chart role * Update echarts library and dynamically set aria text * Update aria settings
1 parent d53dab7 commit e7fc894

File tree

5 files changed

+87
-17
lines changed

5 files changed

+87
-17
lines changed

libs/blocks/chart/chart.js

+32-14
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
formatExcelDate,
99
} from './utils.js';
1010
import getTheme from './chartLightTheme.js';
11-
import { replaceKey } from '../../features/placeholders.js';
1211

1312
export const SMALL = 'small';
1413
export const MEDIUM = 'medium';
@@ -192,12 +191,13 @@ export const tooltipFormatter = (params, units) => {
192191
return tooltip;
193192
};
194193

195-
export const barSeriesOptions = (chartType, hasOverride, firstDataset, colors, size, yUnits) => {
194+
export const barSeriesOptions = (chartType, hasOverride, dimensions, colors, size, yUnits) => {
196195
const isLarge = size === LARGE;
197196
const isBar = chartType === 'bar';
198197

199-
return firstDataset.map((value, index) => ({
198+
return dimensions.map((value, index) => ({
200199
type: 'bar',
200+
name: value,
201201
label: {
202202
show: isBar,
203203
formatter: `{@[${index + 1}]}${yUnits[0]}`,
@@ -220,11 +220,12 @@ export const barSeriesOptions = (chartType, hasOverride, firstDataset, colors, s
220220
}));
221221
};
222222

223-
export const lineSeriesOptions = (series, firstDataset, xUnit, yUnits) => {
223+
export const lineSeriesOptions = (series, dimensions, xUnit, yUnits) => {
224224
const marks = processMarkData(series, xUnit);
225225

226-
return firstDataset.map((value, index) => {
226+
return dimensions.map((value, index) => {
227227
let options = {
228+
name: value,
228229
type: 'line',
229230
symbol: 'none',
230231
lineStyle: { width: 3 },
@@ -239,9 +240,10 @@ export const lineSeriesOptions = (series, firstDataset, xUnit, yUnits) => {
239240
});
240241
};
241242

242-
export const areaSeriesOptions = (firstDataset) => (
243-
firstDataset.map(() => ({
243+
export const areaSeriesOptions = (dimensions) => (
244+
dimensions.map((value) => ({
244245
type: 'line',
246+
name: value,
245247
symbol: 'none',
246248
areaStyle: { opacity: 1 },
247249
stack: 'area',
@@ -351,7 +353,7 @@ export const getChartOptions = ({
351353
}) => {
352354
const hasOverride = headers ? hasPropertyCI(headers, 'color') : false;
353355
const source = dataset?.source;
354-
const firstDataset = source?.[1]?.slice() || [];
356+
const dimensions = source?.[0]?.slice() || [];
355357
const isBar = chartType === 'bar';
356358
const isColumn = chartType === 'column';
357359
const isPie = chartType === 'pie';
@@ -365,7 +367,7 @@ export const getChartOptions = ({
365367
yUnits = units.length > 1 ? units.slice(1) : [''];
366368
}
367369

368-
firstDataset.shift();
370+
dimensions.shift();
369371

370372
let bottomGrid = 90;
371373

@@ -387,6 +389,21 @@ export const getChartOptions = ({
387389
inactiveColor: '#6C6C6C',
388390
type: 'scroll',
389391
},
392+
aria: {
393+
enabled: true,
394+
label: {
395+
general: { withTitle: 'This is a chart' },
396+
series: {
397+
maxCount: 1,
398+
multiple:
399+
{
400+
prefix: '. It consists of {seriesCount} series count ',
401+
withName: `with series ${dimensions.join(', ')}. `,
402+
},
403+
},
404+
data: { separator: { middle: `${yUnits}, `, end: yUnits } },
405+
},
406+
},
390407
title: isDonut ? donutTitleOptions(source, series, yUnits[0], size) : {},
391408
tooltip: {
392409
show: true,
@@ -431,10 +448,10 @@ export const getChartOptions = ({
431448
))(),
432449
series: (() => {
433450
if (isBar || isColumn) {
434-
return barSeriesOptions(chartType, hasOverride, firstDataset, colors, size, yUnits);
451+
return barSeriesOptions(chartType, hasOverride, dimensions, colors, size, yUnits);
435452
}
436-
if (chartType === 'line') return lineSeriesOptions(series, firstDataset, xUnit, yUnits);
437-
if (chartType === 'area') return areaSeriesOptions(firstDataset);
453+
if (chartType === 'line') return lineSeriesOptions(series, dimensions, xUnit, yUnits);
454+
if (chartType === 'area') return areaSeriesOptions(dimensions);
438455
if (isDonut) return donutSeriesOptions(size);
439456
if (isPie) return pieSeriesOptions(size);
440457
return [];
@@ -464,6 +481,7 @@ const initChart = ({
464481
const chart = window.echarts?.init(chartWrapper, themeName, { renderer: 'svg' });
465482

466483
chartWrapper.tabIndex = 0;
484+
chartWrapper.role = 'img';
467485
chart.setOption(chartOptions);
468486

469487
if (chartType === 'donut') {
@@ -642,6 +660,8 @@ const init = (el) => {
642660
</svg>`;
643661

644662
chartWrapper.innerHTML = html;
663+
chartWrapper.role = 'img';
664+
chartWrapper.ariaLabel = `${number} ${data?.subtitle}`;
645665
})
646666
// eslint-disable-next-line no-console
647667
.catch((error) => console.log('Error loading script:', error));
@@ -692,8 +712,6 @@ const init = (el) => {
692712
observer.observe(el);
693713
}
694714

695-
const title = children[0]?.textContent.trim() || children[1]?.textContent.trim();
696-
chartWrapper.setAttribute('aria-label', `${await replaceKey(`${chartType}-chart`, config)}: ${title}`);
697715
/* c8 ignore next 4 */
698716
window.addEventListener('resize', throttle(
699717
1000,

libs/deps/echarts.common.min.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

+36
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"lint:css": "stylelint 'libs/blocks/**/*.css' 'libs/styles/*.css'",
1818
"build:htm-preact": "microbundle ./build/htm-preact.js -o ./libs/deps/htm-preact.js -f modern --no-sourcemap --target web; mv ./libs/deps/htm-preact.modern.mjs ./libs/deps/htm-preact.js",
1919
"build:preact-debug": "microbundle ./build/htm-preact-debug.js -o ./libs/deps/htm-preact-debug.js -f modern --no-sourcemap --target web; mv ./libs/deps/htm-preact-debug.modern.mjs ./libs/deps/htm-preact-debug.js",
20-
"build:gnav-profile": "microbundle ./libs/blocks/global-navigation/blocks/profile/profile-wrapper.js -o ./build/profile-wrapper-build.js -f umd --external none --no-sourcemap --target web; mv ./build/profile-wrapper-build.umd.js ./build/profile.js"
20+
"build:gnav-profile": "microbundle ./libs/blocks/global-navigation/blocks/profile/profile-wrapper.js -o ./build/profile-wrapper-build.js -f umd --external none --no-sourcemap --target web; mv ./build/profile-wrapper-build.umd.js ./build/profile.js",
21+
"build:echarts": "cp node_modules/echarts/dist/echarts.common.min.js libs/deps/echarts.common.min.js"
2122
},
2223
"repository": {
2324
"type": "git",
@@ -50,6 +51,7 @@
5051
"chai": "^5.1.1",
5152
"chalk": "^4.1.2",
5253
"commander": "^12.1.0",
54+
"echarts": "^5.5.1",
5355
"eslint": "8.11.0",
5456
"eslint-config-airbnb-base": "15.0.0",
5557
"eslint-nibble": "^8.1.0",

test/blocks/chart/chart.test.js

+14
Original file line numberDiff line numberDiff line change
@@ -369,12 +369,14 @@ describe('chart', () => {
369369
expect(Array.isArray(areaSeriesOptions(firstDataset))).to.be.true;
370370
const expected = [
371371
{
372+
name: 1,
372373
areaStyle: { opacity: 1 },
373374
stack: 'area',
374375
symbol: 'none',
375376
type: 'line',
376377
},
377378
{
379+
name: 2,
378380
areaStyle: { opacity: 1 },
379381
stack: 'area',
380382
symbol: 'none',
@@ -510,6 +512,7 @@ describe('chart', () => {
510512
fontSize: 14,
511513
},
512514
colorBy: 'series',
515+
name: 100,
513516
showBackground: true,
514517
backgroundStyle: {
515518
color: '#EA3829',
@@ -532,6 +535,7 @@ describe('chart', () => {
532535
fontSize: 14,
533536
},
534537
colorBy: 'series',
538+
name: 156,
535539
showBackground: true,
536540
backgroundStyle: {
537541
color: '#F48411',
@@ -555,6 +559,7 @@ describe('chart', () => {
555559
const expected = [
556560
{
557561
type: 'line',
562+
name: 100,
558563
symbol: 'none',
559564
lineStyle: { width: 3 },
560565
yAxisIndex: 0,
@@ -598,12 +603,14 @@ describe('chart', () => {
598603
},
599604
{
600605
type: 'line',
606+
name: 156,
601607
symbol: 'none',
602608
lineStyle: { width: 3 },
603609
yAxisIndex: 0,
604610
},
605611
{
606612
type: 'line',
613+
name: 160,
607614
symbol: 'none',
608615
lineStyle: { width: 3 },
609616
yAxisIndex: 0,
@@ -704,6 +711,9 @@ describe('chart', () => {
704711
init(el);
705712
const svg = await waitForElement('svg');
706713
expect(svg).to.exist;
714+
const chartWrapper = await waitForElement('.chart-wrapper');
715+
expect(chartWrapper.getAttribute('role')).to.equal('img');
716+
expect(chartWrapper.getAttribute('aria-label')).to.exist;
707717
});
708718

709719
it('getOversizedNumberSize returns maximum size for 1 character', () => {
@@ -759,5 +769,9 @@ describe('chart', () => {
759769
init(el);
760770
const subheading = await waitForElement('.subheading');
761771
expect(subheading).to.exist;
772+
const chartWrapper = await waitForElement('.chart-wrapper');
773+
expect(chartWrapper).to.exist;
774+
expect(chartWrapper.getAttribute('role')).to.equal('img');
775+
expect(chartWrapper.getAttribute('aria-label')).to.contain('This is a chart');
762776
});
763777
});

0 commit comments

Comments
 (0)