Skip to content

Commit

Permalink
Fix legends selection bugs (#24563)
Browse files Browse the repository at this point in the history
* fix legends selection reset bug

* sync LineChart legend states

* sync AreaChart legend states

* sync HeatMapChart legend states

* sync StackedBarChart legend states

* sync VerticalBarChart legend states

* sync DonutChart legend states

* sync GroupedVerticalBarChart legend states

* sync VerticalStackedBarChart legend states

* refactor

* add change file

* rename function

* minor

* add comments
  • Loading branch information
krkshitij authored Nov 3, 2022
1 parent 7c951ef commit 6fe1046
Show file tree
Hide file tree
Showing 11 changed files with 409 additions and 479 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Fix legends selection bugs",
"packageName": "@fluentui/react-charting",
"email": "[email protected]",
"dependentChangeType": "patch"
}
79 changes: 40 additions & 39 deletions packages/react-charting/src/components/AreaChart/AreaChart.base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,10 @@ export class AreaChartBase extends React.Component<IAreaChartProps, IAreaChartSt
super(props);
this._createSet = memoizeFunction((data: IChartProps) => this._createDataSet(data.lineChartData!));
this.state = {
selectedLegend: '',
activeLegend: '',
hoverXValue: '',
isCalloutVisible: false,
isLegendSelected: false,
isLegendHovered: false,
refSelected: null,
YValueHover: [],
lineXValue: 0,
Expand Down Expand Up @@ -430,42 +429,28 @@ export class AreaChartBase extends React.Component<IAreaChartProps, IAreaChartSt
this._chart = this._drawGraph(containerHeight, xAxis, yAxis, xElement!);
};

private _onLegendClick(customMessage: string): void {
if (this.state.isLegendSelected) {
if (this.state.activeLegend === customMessage) {
this.setState({
isLegendSelected: false,
activeLegend: '',
});
} else {
this.setState({
activeLegend: customMessage,
});
}
private _onLegendClick(legend: string): void {
if (this.state.selectedLegend === legend) {
this.setState({
selectedLegend: '',
});
} else {
this.setState({
activeLegend: customMessage,
selectedLegend: legend,
});
}
}

private _onLegendHover(customMessage: string): void {
if (this.state.isLegendSelected === false) {
this.setState({
activeLegend: customMessage,
isLegendHovered: true,
});
}
private _onLegendHover(legend: string): void {
this.setState({
activeLegend: legend,
});
}

private _onLegendLeave(isLegendFocused?: boolean): void {
if (!!isLegendFocused || this.state.isLegendSelected === false) {
this.setState({
activeLegend: '',
isLegendHovered: false,
isLegendSelected: isLegendFocused ? false : this.state.isLegendSelected,
});
}
private _onLegendLeave(): void {
this.setState({
activeLegend: '',
});
}

private _getLegendData = (palette: IPalette, points: ILineChartPoints[]): JSX.Element => {
Expand Down Expand Up @@ -493,8 +478,8 @@ export class AreaChartBase extends React.Component<IAreaChartProps, IAreaChartSt
hoverAction: () => {
this._onLegendHover(singleChartData.legend);
},
onMouseOutAction: (isLegendSelected?: boolean) => {
this._onLegendLeave(isLegendSelected);
onMouseOutAction: () => {
this._onLegendLeave();
},
};

Expand All @@ -518,14 +503,11 @@ export class AreaChartBase extends React.Component<IAreaChartProps, IAreaChartSt
this.setState({ isCircleClicked: true });
};

private _getOpacity = (selectedArea: string): number => {
private _getOpacity = (legend: string): number => {
if (!this._isMultiStackChart) {
return 0.7;
} else {
let opacity = 0.7;
if (this.state.isLegendHovered || this.state.isLegendSelected) {
opacity = this.state.activeLegend === selectedArea ? 0.7 : 0.1;
}
const opacity = this._legendHighlighted(legend) || this._noLegendHighlighted() ? 0.7 : 0.1;
return opacity;
}
};
Expand All @@ -538,8 +520,8 @@ export class AreaChartBase extends React.Component<IAreaChartProps, IAreaChartSt
if (this.state.isCalloutVisible) {
opacity = 1;
}
if (this.state.isLegendHovered || this.state.isLegendSelected) {
opacity = this.state.activeLegend === legend ? 0 : 0.1;
if (!this._noLegendHighlighted()) {
opacity = this._legendHighlighted(legend) ? 0 : 0.1;
}
return opacity;
}
Expand Down Expand Up @@ -701,4 +683,23 @@ export class AreaChartBase extends React.Component<IAreaChartProps, IAreaChartSt
isCalloutVisible: false,
});
};

/**
* This function checks if the given legend is highlighted or not.
* A legend can be highlighted in 2 ways:
* 1. selection: if the user clicks on it
* 2. hovering: if there is no selected legend and the user hovers over it
*/
private _legendHighlighted = (legend: string) => {
return (
this.state.selectedLegend === legend || (this.state.selectedLegend === '' && this.state.activeLegend === legend)
);
};

/**
* This function checks if none of the legends is selected or hovered.
*/
private _noLegendHighlighted = () => {
return this.state.selectedLegend === '' && this.state.activeLegend === '';
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export interface IDonutChartState {
_height?: number | undefined;
activeLegend?: string;
color?: string | undefined;
isLegendSelected?: boolean;
xCalloutValue?: string;
yCalloutValue?: string;
focusedArcId?: string;
Expand Down Expand Up @@ -61,10 +60,9 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar
_height: this.props.height || 200,
activeLegend: '',
color: '',
isLegendSelected: false,
xCalloutValue: '',
yCalloutValue: '',
selectedLegend: 'none',
selectedLegend: '',
focusedArcId: '',
};
this._hoverCallback = this._hoverCallback.bind(this);
Expand Down Expand Up @@ -124,7 +122,7 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar
hoverLeaveCallback={this._hoverLeave}
uniqText={this._uniqText}
onBlurCallback={this._onBlur}
activeArc={this.state.activeLegend}
activeArc={this._getHighlightedLegend()}
focusedArcId={this.state.focusedArcId || ''}
href={this.props.href!}
calloutId={this._calloutId}
Expand Down Expand Up @@ -196,28 +194,17 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar
title: point.legend!,
color: color,
action: () => {
if (this.state.isLegendSelected) {
if (this.state.activeLegend !== point.legend || this.state.activeLegend === '') {
this.setState({ activeLegend: point.legend!, isLegendSelected: true });
} else {
this.setState({ activeLegend: point.legend });
}
if (this.state.selectedLegend === point.legend) {
this.setState({ selectedLegend: '' });
} else {
this.setState({ activeLegend: point.legend!, isLegendSelected: true });
this.setState({ selectedLegend: point.legend! });
}
},
hoverAction: () => {
if (this.state.activeLegend !== point.legend || this.state.activeLegend === '') {
this.setState({ activeLegend: point.legend! });
} else {
this.setState({ activeLegend: point.legend });
}
this.setState({ activeLegend: point.legend! });
},
onMouseOutAction: () => {
this.setState({
showHover: false,
activeLegend: '',
});
this.setState({ activeLegend: '' });
},
};
return legend;
Expand All @@ -229,7 +216,6 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar
overflowProps={this.props.legendsOverflowProps}
focusZonePropsInHoverCard={this.props.focusZonePropsForLegendsInHoverCard}
overflowText={this.props.legendsOverflowText}
selectedLegend={this.state.selectedLegend}
{...this.props.legendProps}
/>
);
Expand All @@ -240,7 +226,7 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar
this._currentHoverElement = element;
this.setState({
/** Show the callout if highlighted arc is focused and Hide it if unhighlighted arc is focused */
showHover: this.state.activeLegend === data.legend || this.state.activeLegend === '',
showHover: this.state.selectedLegend === '' || this.state.selectedLegend === data.legend,
value: data.data!.toString(),
legend: data.legend,
color: data.color!,
Expand All @@ -258,7 +244,7 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar
this._currentHoverElement = e;
this.setState({
/** Show the callout if highlighted arc is hovered and Hide it if unhighlighted arc is hovered */
showHover: this.state.activeLegend === data.legend || this.state.activeLegend === '',
showHover: this.state.selectedLegend === '' || this.state.selectedLegend === data.legend,
value: data.data!.toString(),
legend: data.legend,
color: data.color!,
Expand All @@ -283,10 +269,11 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar
};

private _valueInsideDonut(valueInsideDonut: string | number | undefined, data: IChartDataPoint[]) {
if (valueInsideDonut !== undefined && this.state.activeLegend !== '' && !this.state.showHover) {
const highlightedLegend = this._getHighlightedLegend();
if (valueInsideDonut !== undefined && highlightedLegend !== '' && !this.state.showHover) {
let legendValue = valueInsideDonut;
data!.map((point: IChartDataPoint, index: number) => {
if (point.legend === this.state.activeLegend) {
if (point.legend === highlightedLegend) {
legendValue = point.yAxisCalloutData ? point.yAxisCalloutData : point.data!;
}
return;
Expand All @@ -304,4 +291,14 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar
}
return localeString?.toString();
}

/**
* This function returns
* the selected legend if there is one
* or the hovered legend if none of the legends is selected.
* Note: This won't work in case of multiple legends selection.
*/
private _getHighlightedLegend() {
return this.state.selectedLegend || this.state.activeLegend;
}
}
Loading

0 comments on commit 6fe1046

Please sign in to comment.