-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
[Donut] Legends multi selection for Donut Charts #33447
base: master
Are you sure you want to change the base?
Changes from 7 commits
b0c7663
24ce6bf
434fc6d
70b0404
addca43
7293f33
ae348e2
88eb247
db555d3
4fdc773
a1dc7a9
13876f3
cea2d29
be186ba
d4641c5
0e62c96
568ca4e
36e6bdc
a94e9f1
cfd09ea
0e7fc13
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,12 +31,11 @@ export class Arc extends React.Component<IArcProps, IArcState> { | |
} | ||
srmukher marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
public render(): JSX.Element { | ||
const { arc, href, focusedArcId } = this.props; | ||
const { arc, href, focusedArcId, activeArc } = this.props; | ||
const getClassNames = classNamesFunction<IArcStyleProps, IArcStyles>(); | ||
const id = this.props.uniqText! + this.props.data!.data.legend!.replace(/\s+/, '') + this.props.data!.data.data; | ||
const opacity: number = | ||
this.props.activeArc === this.props.data!.data.legend || this.props.activeArc === '' ? 1 : 0.1; | ||
|
||
const isActive = activeArc?.includes(this.props.data?.data.legend!); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so that it can be used to calculate both opacity and data-is-focusable without the need to add same checks again |
||
const opacity: number = activeArc && activeArc.length > 0 ? (isActive ? 1 : 0.1) : 1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
const startAngle = this.props.data?.startAngle ?? 0; | ||
const endAngle = (this.props.data?.endAngle ?? 0) - startAngle; | ||
const cornerRadius = this.props.roundCorners ? 3 : 0; | ||
|
@@ -70,7 +69,10 @@ export class Arc extends React.Component<IArcProps, IArcState> { | |
d={arc.cornerRadius(cornerRadius)(this.props.data)} | ||
onFocus={this._onFocus.bind(this, this.props.data!.data, id)} | ||
className={classNames.root} | ||
data-is-focusable={this.props.activeArc === this.props.data!.data.legend || this.props.activeArc === ''} | ||
data-is-focusable={ | ||
Array.isArray(this.props.activeArc) && | ||
(this.props.activeArc.includes(this.props.data!.data.legend!) || this.props.activeArc.length === 0) | ||
} | ||
onMouseOver={this._hoverOn.bind(this, this.props.data!.data)} | ||
onMouseMove={this._hoverOn.bind(this, this.props.data!.data)} | ||
onMouseLeave={this._hoverOff} | ||
|
@@ -129,7 +131,8 @@ export class Arc extends React.Component<IArcProps, IArcState> { | |
if ( | ||
hideLabels || | ||
Math.abs(data!.endAngle - data!.startAngle) < Math.PI / 12 || | ||
(activeArc !== data!.data.legend && activeArc !== '') | ||
!Array.isArray(activeArc) || | ||
(data!.data.legend && activeArc.includes(data!.data.legend)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same logic is repeating There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. moved to a function |
||
) { | ||
return null; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ export interface IDonutChartState { | |
selectedLegend: string; | ||
dataPointCalloutProps?: IChartDataPoint; | ||
callOutAccessibilityData?: IAccessibilityProps; | ||
selectedLegends: string[]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
} | ||
|
||
export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChartState> { | ||
|
@@ -69,12 +70,13 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar | |
legend: '', | ||
_width: this.props.width || 200, | ||
_height: this.props.height || 200, | ||
activeLegend: '', | ||
activeLegend: undefined, | ||
color: '', | ||
xCalloutValue: '', | ||
yCalloutValue: '', | ||
selectedLegend: '', | ||
focusedArcId: '', | ||
selectedLegends: [], | ||
}; | ||
this._hoverCallback = this._hoverCallback.bind(this); | ||
this._focusCallback = this._focusCallback.bind(this); | ||
|
@@ -138,7 +140,9 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar | |
hoverLeaveCallback={this._hoverLeave} | ||
uniqText={this._uniqText} | ||
onBlurCallback={this._onBlur} | ||
activeArc={this._getHighlightedLegend()} | ||
activeArc={this._getHighlightedLegend().filter( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
(legend): legend is string => legend !== undefined && legend !== '', | ||
)} | ||
focusedArcId={this.state.focusedArcId || ''} | ||
href={this.props.href!} | ||
calloutId={this._calloutId} | ||
|
@@ -240,23 +244,17 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar | |
const legend: ILegend = { | ||
title: point.legend!, | ||
color, | ||
action: () => { | ||
if (this.state.selectedLegend === point.legend) { | ||
this.setState({ selectedLegend: '' }); | ||
} else { | ||
this.setState({ selectedLegend: point.legend! }); | ||
} | ||
}, | ||
hoverAction: () => { | ||
this._handleChartMouseLeave(); | ||
this.setState({ activeLegend: point.legend! }); | ||
}, | ||
onMouseOutAction: () => { | ||
this.setState({ activeLegend: '' }); | ||
this.setState({ activeLegend: undefined }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, checked with a legend having '' title, it does not work in that case There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok |
||
}, | ||
}; | ||
return legend; | ||
}); | ||
|
||
const legends = ( | ||
<Legends | ||
legends={legendDataItems} | ||
|
@@ -265,11 +263,17 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar | |
focusZonePropsInHoverCard={this.props.focusZonePropsForLegendsInHoverCard} | ||
overflowText={this.props.legendsOverflowText} | ||
{...this.props.legendProps} | ||
canSelectMultipleLegends={this.props.canSelectMultipleLegends} | ||
onChange={this._onLegendChange} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. modified as discussed offline There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
/> | ||
); | ||
return legends; | ||
} | ||
|
||
private _onLegendChange = (selectedLegends: string[]) => { | ||
this.setState({ selectedLegends }); | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. keep these functions together with getHighlightedLegends There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
|
||
private _focusCallback = (data: IChartDataPoint, id: string, element: SVGPathElement): void => { | ||
this._currentHoverElement = element; | ||
this.setState({ | ||
|
@@ -324,16 +328,23 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar | |
}; | ||
|
||
private _valueInsideDonut(valueInsideDonut: string | number | undefined, data: IChartDataPoint[]) { | ||
const highlightedLegend = this._getHighlightedLegend(); | ||
if (valueInsideDonut !== undefined && (highlightedLegend !== '' || this.state.showHover)) { | ||
let legendValue = valueInsideDonut; | ||
data!.map((point: IChartDataPoint, index: number) => { | ||
if (point.legend === highlightedLegend || (this.state.showHover && point.legend === this.state.legend)) { | ||
legendValue = point.yAxisCalloutData ? point.yAxisCalloutData : point.data!; | ||
const highlightedLegends = this._getHighlightedLegend().filter(legend => legend !== undefined); | ||
|
||
if (this.state.showHover) { | ||
const legendValue = data.find(point => point.legend === this.state.legend); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. calling it pointValue as point is used in data.find |
||
return legendValue | ||
? legendValue.yAxisCalloutData | ||
? legendValue.yAxisCalloutData | ||
: legendValue.data! | ||
: valueInsideDonut; | ||
} else if (highlightedLegends.length > 0) { | ||
let totalValue = 0; | ||
data.forEach(point => { | ||
if (highlightedLegends.includes(point.legend!)) { | ||
totalValue += point.data!; | ||
} | ||
return; | ||
}); | ||
return legendValue; | ||
return totalValue; | ||
} else { | ||
return valueInsideDonut; | ||
} | ||
|
@@ -354,7 +365,7 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar | |
* Note: This won't work in case of multiple legends selection. | ||
*/ | ||
private _getHighlightedLegend() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this was already modified |
||
return this.state.selectedLegend || this.state.activeLegend; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For multiple select also checking if this.state.selectedLegends is populated other return the this.state.activeLegend |
||
return this.state.selectedLegends.length > 0 ? this.state.selectedLegends : [this.state.activeLegend]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But, in line multiple chart, on multiple legend selection, legend hover is disabled. Shall the experience be not the same? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. We will need a different representation. Currently hover behavior is lost once one or more legend is selected. We will plan for it. You can continue with the current behavior for now. |
||
} | ||
|
||
private _isChartEmpty(): boolean { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,6 +69,12 @@ export interface IDonutChartProps extends ICartesianChartProps { | |
* @default false | ||
*/ | ||
roundCorners?: boolean; | ||
|
||
/** | ||
* Prop to enable the multiple legend selection | ||
* @default false | ||
*/ | ||
canSelectMultipleLegends?: boolean; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
} | ||
|
||
/** | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
revert this change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done