diff --git a/change/@fluentui-react-charting-54be2b37-a1dc-497f-9a9f-cb0fd4bca0fb.json b/change/@fluentui-react-charting-54be2b37-a1dc-497f-9a9f-cb0fd4bca0fb.json new file mode 100644 index 00000000000000..6e2eb70ce44923 --- /dev/null +++ b/change/@fluentui-react-charting-54be2b37-a1dc-497f-9a9f-cb0fd4bca0fb.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "[Gauge Chart] Enabling legend multi selection", + "packageName": "@fluentui/react-charting", + "email": "120183316+srmukher@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/charts/react-charting/src/components/DeclarativeChart/DeclarativeChart.tsx b/packages/charts/react-charting/src/components/DeclarativeChart/DeclarativeChart.tsx index f617ad73ae663a..b5ca557356d86e 100644 --- a/packages/charts/react-charting/src/components/DeclarativeChart/DeclarativeChart.tsx +++ b/packages/charts/react-charting/src/components/DeclarativeChart/DeclarativeChart.tsx @@ -265,7 +265,7 @@ export const DeclarativeChart: React.FunctionComponent = return ( diff --git a/packages/charts/react-charting/src/components/GaugeChart/GaugeChart.base.tsx b/packages/charts/react-charting/src/components/GaugeChart/GaugeChart.base.tsx index 238b14273b69a0..7a3dffbeefd7d9 100644 --- a/packages/charts/react-charting/src/components/GaugeChart/GaugeChart.base.tsx +++ b/packages/charts/react-charting/src/components/GaugeChart/GaugeChart.base.tsx @@ -13,6 +13,7 @@ import { IProcessedStyleSet } from '@fluentui/react/lib/Styling'; import { convertToLocaleString } from '../../utilities/locale-util'; import { Points, + areArraysEqual, formatValueWithSIPrefix, getAccessibleDataObject, getColorFromToken, @@ -106,7 +107,7 @@ interface IYValue extends Omit { } export interface IGaugeChartState { hoveredLegend: string; - selectedLegend: string; + selectedLegends: string[]; focusedElement?: string; // eslint-disable-next-line @typescript-eslint/no-explicit-any calloutTarget: any; @@ -144,7 +145,7 @@ export class GaugeChartBase extends React.Component { - if (this.state.selectedLegend === segment.legend) { - this.setState({ selectedLegend: '' }); - } else { - this.setState({ selectedLegend: segment.legend }); - } - }, hoverAction: () => { this.setState({ hoveredLegend: segment.legend }); }, @@ -514,11 +508,32 @@ export class GaugeChartBase extends React.Component - + ); }; + private _onLegendSelectionChange( + selectedLegends: string[], + event: React.MouseEvent, + currentLegend?: ILegend, + ): void { + if (this.props.legendProps?.canSelectMultipleLegends) { + this.setState({ selectedLegends }); + } else { + this.setState({ selectedLegends: selectedLegends.slice(-1) }); + } + if (this.props.legendProps?.onChange) { + this.props.legendProps.onChange(selectedLegends, event, currentLegend); + } + } + /** * This function checks if the given legend is highlighted or not. * A legend can be highlighted in 2 ways: @@ -526,18 +541,24 @@ export class GaugeChartBase extends React.Component { - return ( - this.state.selectedLegend === legend || (this.state.selectedLegend === '' && this.state.hoveredLegend === legend) - ); + return this._getHighlightedLegend().includes(legend!); }; /** * This function checks if none of the legends is selected or hovered. */ private _noLegendHighlighted = () => { - return this.state.selectedLegend === '' && this.state.hoveredLegend === ''; + return this._getHighlightedLegend().length === 0; }; + private _getHighlightedLegend() { + return this.state.selectedLegends.length > 0 + ? this.state.selectedLegends + : this.state.hoveredLegend + ? [this.state.hoveredLegend] + : []; + } + private _handleFocus = (focusEvent: React.FocusEvent, focusedElement: string) => { this._showCallout(focusEvent.target, focusedElement, true); }; @@ -580,9 +601,7 @@ export class GaugeChartBase extends React.Component { } } }); + + it(`should highlight multiple segments when the legend multi select is enabled`, () => { + const { container } = render( + , + ); + + fireEvent.click(screen.getByText(segments[0].legend)); + fireEvent.click(screen.getByText(segments[1].legend)); + const segs = container.querySelectorAll('[class^="segment"]'); + expect(segs[0]).toHaveStyle('fill-opacity: 1'); + expect(segs[1]).toHaveStyle('fill-opacity: 1'); + expect(segs[2]).toHaveStyle('fill-opacity: 0.1'); + }); }); describe('Gauge Chart - axe-core', () => { diff --git a/packages/react-examples/src/react-charting/GaugeChart/GaugeChart.Basic.Example.tsx b/packages/react-examples/src/react-charting/GaugeChart/GaugeChart.Basic.Example.tsx index 66e1541b397947..8fca0a04b362be 100644 --- a/packages/react-examples/src/react-charting/GaugeChart/GaugeChart.Basic.Example.tsx +++ b/packages/react-examples/src/react-charting/GaugeChart/GaugeChart.Basic.Example.tsx @@ -16,6 +16,7 @@ interface IGCBasicExampleState { hideMinMax: boolean; enableGradient: boolean; roundedCorners: boolean; + legendMultiSelect: boolean; } export class GaugeChartBasicExample extends React.Component<{}, IGCBasicExampleState> { @@ -29,6 +30,7 @@ export class GaugeChartBasicExample extends React.Component<{}, IGCBasicExampleS hideMinMax: false, enableGradient: false, roundedCorners: false, + legendMultiSelect: false, }; } @@ -99,6 +101,14 @@ export class GaugeChartBasicExample extends React.Component<{}, IGCBasicExampleS checked={this.state.roundedCorners} onChange={this._onToggleRoundedCorners} /> +    + ); @@ -155,4 +168,8 @@ export class GaugeChartBasicExample extends React.Component<{}, IGCBasicExampleS private _onToggleRoundedCorners = (ev: React.MouseEvent, checked: boolean) => { this.setState({ roundedCorners: checked }); }; + + private _onToggleLegendMultiSelect = (ev: React.MouseEvent, checked: boolean) => { + this.setState({ legendMultiSelect: checked }); + }; }