Skip to content
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

feat(a11y): add alt text for all chart types #1118

Merged
merged 38 commits into from
May 14, 2021
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
3564f82
feat: add alt text for parititon charts
rshen91 Apr 13, 2021
9f1c52e
feat: add alt text for other chart types
rshen91 Apr 13, 2021
182f417
WIP
rshen91 Apr 14, 2021
38fe695
Merge remote-tracking branch 'upstream/master' into partition_a11y
rshen91 Apr 19, 2021
f13f276
Merge remote-tracking branch 'upstream/master' into partition_a11y
rshen91 Apr 22, 2021
02dd6b7
feat: code review changes from 1121
rshen91 Apr 22, 2021
2b3cf0f
Merge remote-tracking branch 'upstream/master' into partition_a11y
rshen91 Apr 22, 2021
f043d6d
refactor: create types component
rshen91 Apr 22, 2021
55266a7
Merge remote-tracking branch 'upstream/master' into partition_a11y
rshen91 Apr 22, 2021
775b270
feat: update feature parity across charts - not word cloud yet
rshen91 Apr 22, 2021
74c4871
Merge remote-tracking branch 'upstream/master' into partition_a11y
rshen91 Apr 23, 2021
61d3722
feat: add accessibility for word cloud
rshen91 Apr 23, 2021
e56ba40
Merge remote-tracking branch 'upstream/master' into partition_a11y
rshen91 Apr 23, 2021
7627a89
fix: revert jest matcher
rshen91 Apr 23, 2021
91aeb08
Merge remote-tracking branch 'upstream/master' into partition_a11y
rshen91 Apr 26, 2021
46de162
feat: add labels
rshen91 Apr 26, 2021
7c10bb6
test: update chart test
rshen91 Apr 26, 2021
4a137fe
Merge remote-tracking branch 'upstream/master' into partition_a11y
rshen91 Apr 27, 2021
de2cd04
refactor: create screen reader summary component
rshen91 Apr 27, 2021
4caabf3
feat: add seriesTypes to state management
rshen91 Apr 29, 2021
ea91feb
feat: add code review changes
rshen91 Apr 29, 2021
69bda59
fix: update chart test snap
rshen91 Apr 29, 2021
b44acd0
Merge branch 'master' into partition_a11y
rshen91 Apr 30, 2021
8204805
Merge remote-tracking branch 'upstream/master' into partition_a11y
rshen91 Apr 30, 2021
57a2ad7
Merge remote-tracking branch 'origin/partition_a11y' into partition_a11y
rshen91 May 3, 2021
93a93a1
feat: add figure to wordcloud
rshen91 May 3, 2021
e967711
fix: make naming clearer
rshen91 May 3, 2021
fa3ddcd
fix: removing unnecessary chartTypeDescription from mapStateToProps
rshen91 May 3, 2021
9f37beb
fix: update chart snap test
rshen91 May 3, 2021
ebc3430
WIP
rshen91 May 3, 2021
843b955
fix: add code review changges
rshen91 May 10, 2021
03cea92
Merge remote-tracking branch 'upstream/master' into partition_a11y
rshen91 May 10, 2021
d779540
test: update chart snapshot test
rshen91 May 10, 2021
3880768
Merge branch 'master' into partition_a11y
rshen91 May 10, 2021
b17ccc1
Merge remote-tracking branch 'upstream/master' into partition_a11y
rshen91 May 13, 2021
e9c5255
fix: code review changes
rshen91 May 13, 2021
ac5cca4
fix: move ScreenReaderSummary outside svg
markov00 May 14, 2021
4c36a17
fix: small change
rshen91 May 14, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion playground/playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@

import React from 'react';

import { Chart, AreaSeries, LineSeries, BarSeries, ScaleType } from '../src';
import { Chart, AreaSeries, LineSeries, BarSeries, ScaleType, Settings } from '../src';

export class Playground extends React.Component {
render() {
return (
<div className="App">
<Chart size={[500, 200]}>
<Settings ariaDescription="This is a custom description" />
<AreaSeries
id="lines"
name="test2"
Expand Down
38 changes: 27 additions & 11 deletions src/chart_types/goal_chart/renderer/canvas/connected_component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,14 @@ import React, { MouseEvent, RefObject } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';

import { ScreenReaderSummary } from '../../../../components/accessibility';
import { onChartRendered } from '../../../../state/actions/chart';
import { GlobalChartState } from '../../../../state/chart_state';
import {
A11ySettings,
DEFAULT_A11Y_SETTINGS,
getA11ySettingsSelector,
} from '../../../../state/selectors/get_accessibility_config';
import { getInternalIsInitializedSelector, InitStatus } from '../../../../state/selectors/get_internal_is_intialized';
import { Dimensions } from '../../../../utils/dimensions';
import { nullShapeViewModel, ShapeViewModel } from '../../layout/types/viewmodel_types';
Expand All @@ -33,6 +39,7 @@ interface ReactiveChartStateProps {
initialized: boolean;
geometries: ShapeViewModel;
chartContainerDimensions: Dimensions;
a11ySettings: A11ySettings;
}

interface ReactiveChartDispatchProps {
Expand Down Expand Up @@ -104,23 +111,30 @@ class Component extends React.Component<Props> {
initialized,
chartContainerDimensions: { width, height },
forwardStageRef,
a11ySettings,
} = this.props;
if (!initialized || width === 0 || height === 0) {
return null;
}

return (
<canvas
ref={forwardStageRef}
className="echCanvasRenderer"
width={width * this.devicePixelRatio}
height={height * this.devicePixelRatio}
onMouseMove={this.handleMouseMove.bind(this)}
style={{
width,
height,
}}
/>
<figure aria-labelledby={a11ySettings.labelId} aria-describedby={a11ySettings.descriptionId}>
<canvas
ref={forwardStageRef}
className="echCanvasRenderer"
width={width * this.devicePixelRatio}
height={height * this.devicePixelRatio}
onMouseMove={this.handleMouseMove.bind(this)}
style={{
width,
height,
}}
// eslint-disable-next-line jsx-a11y/no-interactive-element-to-noninteractive-role
role="presentation"
>
<ScreenReaderSummary />
</canvas>
</figure>
);
}

Expand Down Expand Up @@ -157,6 +171,7 @@ const DEFAULT_PROPS: ReactiveChartStateProps = {
left: 0,
top: 0,
},
a11ySettings: DEFAULT_A11Y_SETTINGS,
};

const mapStateToProps = (state: GlobalChartState): ReactiveChartStateProps => {
Expand All @@ -167,6 +182,7 @@ const mapStateToProps = (state: GlobalChartState): ReactiveChartStateProps => {
initialized: true,
geometries: geometries(state),
chartContainerDimensions: state.parentDimensions,
a11ySettings: getA11ySettingsSelector(state),
};
};

Expand Down
5 changes: 5 additions & 0 deletions src/chart_types/goal_chart/state/chart_state.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { LegendItemLabel } from '../../../state/selectors/get_legend_items_label
import { DebugState } from '../../../state/types';
import { Dimensions } from '../../../utils/dimensions';
import { Goal } from '../renderer/canvas/connected_component';
import { getChartTypeDescriptionSelector } from './selectors/get_chart_type_description';
import { getSpecOrNull } from './selectors/goal_spec';
import { isTooltipVisibleSelector } from './selectors/is_tooltip_visible';
import { createOnElementClickCaller } from './selectors/on_element_click_caller';
Expand Down Expand Up @@ -120,6 +121,10 @@ export class GoalState implements InternalChartState {
this.onElementClickCaller(globalState);
}

getChartTypeDescription(globalState: GlobalChartState) {
return getChartTypeDescriptionSelector(globalState);
}

// TODO
getProjectionContainerArea(): Dimensions {
return { width: 0, height: 0, top: 0, left: 0 };
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import createCachedSelector from 're-reselect';

import { getChartIdSelector } from '../../../../state/selectors/get_chart_id';
import { getSpecOrNull } from './goal_spec';

/** @internal */
export const getChartTypeDescriptionSelector = createCachedSelector([getSpecOrNull], (spec) => {
return `${spec?.subtype ?? 'goal'} chart`;
})(getChartIdSelector);
40 changes: 30 additions & 10 deletions src/chart_types/heatmap/renderer/canvas/connected_component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,14 @@ import React, { RefObject } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';

import { ScreenReaderSummary } from '../../../../components/accessibility';
import { onChartRendered } from '../../../../state/actions/chart';
import { GlobalChartState } from '../../../../state/chart_state';
import {
A11ySettings,
DEFAULT_A11Y_SETTINGS,
getA11ySettingsSelector,
} from '../../../../state/selectors/get_accessibility_config';
import { getInternalIsInitializedSelector, InitStatus } from '../../../../state/selectors/get_internal_is_intialized';
import { Dimensions } from '../../../../utils/dimensions';
import { nullShapeViewModel, ShapeViewModel } from '../../layout/types/viewmodel_types';
Expand All @@ -34,6 +40,8 @@ interface ReactiveChartStateProps {
initialized: boolean;
geometries: ShapeViewModel;
chartContainerDimensions: Dimensions;
a11ySettings: A11ySettings;
seriesTypes: string;
nickofthyme marked this conversation as resolved.
Show resolved Hide resolved
}

interface ReactiveChartDispatchProps {
Expand Down Expand Up @@ -97,26 +105,34 @@ class Component extends React.Component<Props> {
}
}

// eslint-disable-next-line @typescript-eslint/member-ordering
render() {
const {
initialized,
chartContainerDimensions: { width, height },
forwardStageRef,
a11ySettings,
} = this.props;
if (!initialized || width === 0 || height === 0) {
return null;
}
return (
<canvas
ref={forwardStageRef}
className="echCanvasRenderer"
width={width * this.devicePixelRatio}
height={height * this.devicePixelRatio}
style={{
width,
height,
}}
/>
<figure aria-labelledby={a11ySettings.labelId} aria-describedby={a11ySettings.descriptionId}>
<canvas
ref={forwardStageRef}
className="echCanvasRenderer"
width={width * this.devicePixelRatio}
height={height * this.devicePixelRatio}
style={{
width,
height,
}}
// eslint-disable-next-line jsx-a11y/no-interactive-element-to-noninteractive-role
role="presentation"
>
<ScreenReaderSummary />
</canvas>
</figure>
);
}
}
Expand All @@ -138,6 +154,8 @@ const DEFAULT_PROPS: ReactiveChartStateProps = {
left: 0,
top: 0,
},
a11ySettings: DEFAULT_A11Y_SETTINGS,
seriesTypes: 'heatmap chart',
};

const mapStateToProps = (state: GlobalChartState): ReactiveChartStateProps => {
Expand All @@ -148,6 +166,8 @@ const mapStateToProps = (state: GlobalChartState): ReactiveChartStateProps => {
initialized: true,
geometries: geometries(state),
chartContainerDimensions: getHeatmapContainerSizeSelector(state),
a11ySettings: getA11ySettingsSelector(state),
seriesTypes: 'heatmap chart',
markov00 marked this conversation as resolved.
Show resolved Hide resolved
};
};

Expand Down
4 changes: 4 additions & 0 deletions src/chart_types/heatmap/state/chart_state.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ export class HeatmapState implements InternalChartState {
return getDebugStateSelector(globalState);
}

getChartTypeDescription() {
return 'Heatmap chart';
}

eventCallbacks(globalState: GlobalChartState) {
this.onElementOverCaller(globalState);
this.onElementOutCaller(globalState);
Expand Down
39 changes: 27 additions & 12 deletions src/chart_types/partition_chart/renderer/canvas/partition.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,15 @@ import React, { MouseEvent, RefObject } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';

import { ScreenReaderSummary } from '../../../../components/accessibility';
import { clearCanvas } from '../../../../renderers/canvas';
import { onChartRendered } from '../../../../state/actions/chart';
import { ChartId, GlobalChartState } from '../../../../state/chart_state';
import {
A11ySettings,
DEFAULT_A11Y_SETTINGS,
getA11ySettingsSelector,
} from '../../../../state/selectors/get_accessibility_config';
import { getChartContainerDimensionsSelector } from '../../../../state/selectors/get_chart_container_dimensions';
import { getChartIdSelector } from '../../../../state/selectors/get_chart_id';
import { getInternalIsInitializedSelector, InitStatus } from '../../../../state/selectors/get_internal_is_intialized';
Expand Down Expand Up @@ -59,6 +65,7 @@ interface ReactiveChartStateProps {
multiGeometries: ShapeViewModel[];
chartContainerDimensions: Dimensions;
chartId: ChartId;
a11ySettings: A11ySettings;
}

interface ReactiveChartDispatchProps {
Expand Down Expand Up @@ -141,23 +148,29 @@ class PartitionComponent extends React.Component<PartitionProps> {
forwardStageRef,
initialized,
chartContainerDimensions: { width, height },
a11ySettings,
} = this.props;
if (!initialized || width === 0 || height === 0) {
return null;
}

return (
<canvas
ref={forwardStageRef}
className="echCanvasRenderer"
width={width * this.devicePixelRatio}
height={height * this.devicePixelRatio}
onMouseMove={this.handleMouseMove.bind(this)}
style={{
width,
height,
}}
/>
<figure aria-labelledby={a11ySettings.labelId} aria-describedby={a11ySettings.descriptionId}>
<canvas
ref={forwardStageRef}
className="echCanvasRenderer"
width={width * this.devicePixelRatio}
height={height * this.devicePixelRatio}
onMouseMove={this.handleMouseMove.bind(this)}
style={{
width,
height,
}}
// eslint-disable-next-line jsx-a11y/no-interactive-element-to-noninteractive-role
role="presentation"
>
<ScreenReaderSummary />
</canvas>
</figure>
);
}

Expand Down Expand Up @@ -205,6 +218,7 @@ const DEFAULT_PROPS: ReactiveChartStateProps = {
left: 0,
top: 0,
},
a11ySettings: DEFAULT_A11Y_SETTINGS,
};

const mapStateToProps = (state: GlobalChartState): ReactiveChartStateProps => {
Expand All @@ -219,6 +233,7 @@ const mapStateToProps = (state: GlobalChartState): ReactiveChartStateProps => {
chartContainerDimensions: getChartContainerDimensionsSelector(state),
geometriesFoci: partitionDrilldownFocus(state),
chartId: getChartIdSelector(state),
a11ySettings: getA11ySettingsSelector(state),
};
};

Expand Down
5 changes: 5 additions & 0 deletions src/chart_types/partition_chart/state/chart_state.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { DebugState } from '../../../state/types';
import { Dimensions } from '../../../utils/dimensions';
import { render } from '../renderer/dom/layered_partition_chart';
import { computeLegendSelector } from './selectors/compute_legend';
import { getChartTypeDescriptionSelector } from './selectors/get_chart_type_description';
import { getDebugStateSelector } from './selectors/get_debug_state';
import { getLegendItemsExtra } from './selectors/get_legend_items_extra';
import { getLegendItemsLabels } from './selectors/get_legend_items_labels';
Expand Down Expand Up @@ -134,4 +135,8 @@ export class PartitionState implements InternalChartState {
getDebugState(state: GlobalChartState): DebugState {
return getDebugStateSelector(state);
}

getChartTypeDescription(state: GlobalChartState): string {
return getChartTypeDescriptionSelector(state);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import createCachedSelector from 're-reselect';

import { getChartIdSelector } from '../../../../state/selectors/get_chart_id';
import { getPartitionSpec } from './partition_spec';

/** @internal */
export const getChartTypeDescriptionSelector = createCachedSelector([getPartitionSpec], (partitionSpec): string => {
return `${partitionSpec?.config.partitionLayout} chart` ?? 'Partition chart';
})(getChartIdSelector);
Loading