-
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
Handling central text overflow and adding tooltip for donut charts #26192
base: master
Are you sure you want to change the base?
Changes from 5 commits
7e3a3c2
42d2636
322ca58
62a5b7f
d1d70a7
66c1fa7
2457a45
8ce67c1
60789fd
b9e2c85
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 |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"type": "patch", | ||
"comment": "Bug Fix", | ||
"packageName": "@fluentui/react-charting", | ||
"email": "[email protected]", | ||
"dependentChangeType": "patch" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,12 @@ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import * as React from 'react'; | ||
import * as shape from 'd3-shape'; | ||
import { classNamesFunction } from '@fluentui/react/lib/Utilities'; | ||
import { getStyles } from './Arc.styles'; | ||
import { IChartDataPoint } from '../index'; | ||
import { IArcProps, IArcStyles } from './index'; | ||
import { wrapTextInsideDonut } from '../../../utilities/index'; | ||
import { IProcessedStyleSet } from '../../../Styling'; | ||
|
||
export interface IArcState { | ||
isCalloutVisible?: boolean; | ||
|
@@ -19,38 +21,44 @@ export class Arc extends React.Component<IArcProps, IArcState> { | |
|
||
public state: {} = {}; | ||
|
||
private _classNames: IProcessedStyleSet<IArcStyles>; | ||
private currentRef = React.createRef<SVGPathElement>(); | ||
|
||
public static getDerivedStateFromProps(nextProps: Readonly<IArcProps>): Partial<IArcState> | null { | ||
_updateChart(nextProps); | ||
return null; | ||
} | ||
|
||
public constructor(props: IArcProps) { | ||
super(props); | ||
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. Is this change needed? |
||
} | ||
|
||
public updateChart(newProps: IArcProps): void { | ||
_updateChart(newProps); | ||
} | ||
|
||
public render(): JSX.Element { | ||
const { arc, href, focusedArcId } = this.props; | ||
const getClassNames = classNamesFunction<IArcProps, IArcStyles>(); | ||
const classNames = getClassNames(getStyles, { | ||
this._classNames = getClassNames(getStyles, { | ||
srmukher marked this conversation as resolved.
Show resolved
Hide resolved
|
||
color: this.props.color, | ||
href: href!, | ||
theme: this.props.theme!, | ||
}); | ||
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; | ||
|
||
return ( | ||
<g ref={this.currentRef}> | ||
{!!focusedArcId && focusedArcId === id && ( | ||
<path id={id + 'focusRing'} d={arc(this.props.focusData)} className={classNames.focusRing} /> | ||
<path id={id + 'focusRing'} d={arc(this.props.focusData)} className={this._classNames.focusRing} /> | ||
)} | ||
<path | ||
id={id} | ||
d={arc(this.props.data)} | ||
onFocus={this._onFocus.bind(this, this.props.data!.data, id)} | ||
className={classNames.root} | ||
className={this._classNames.root} | ||
data-is-focusable={true} | ||
onMouseOver={this._hoverOn.bind(this, this.props.data!.data)} | ||
onMouseMove={this._hoverOn.bind(this, this.props.data!.data)} | ||
|
@@ -61,9 +69,11 @@ export class Arc extends React.Component<IArcProps, IArcState> { | |
aria-label={this._getAriaLabel()} | ||
role="img" | ||
/> | ||
<text textAnchor={'middle'} className={classNames.insideDonutString} y={5}> | ||
{this.props.valueInsideDonut!} | ||
</text> | ||
<g className={this._classNames.nodeTextContainer}> | ||
<text id="Donut_center_text" textAnchor={'middle'} className={this._classNames.insideDonutString} y={5}> | ||
{this.props.valueInsideDonut} | ||
srmukher marked this conversation as resolved.
Show resolved
Hide resolved
|
||
</text> | ||
</g> | ||
</g> | ||
); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,6 +38,9 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar | |
private _currentHoverElement: any; | ||
private _calloutId: string; | ||
private _calloutAnchorPoint: IChartDataPoint | null; | ||
private _tooltip: any; | ||
private _tooltipId: string; | ||
private _rectTooltipId: string; | ||
|
||
public static getDerivedStateFromProps( | ||
nextProps: Readonly<IDonutChartProps>, | ||
|
@@ -70,6 +73,8 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar | |
this._hoverLeave = this._hoverLeave.bind(this); | ||
this._calloutId = getId('callout'); | ||
this._uniqText = getId('_Pie_'); | ||
this._tooltipId = getId('_Donut_tooltip_'); | ||
this._rectTooltipId = getId('_Rect_tooltip_'); | ||
} | ||
public componentDidMount(): void { | ||
/* 80% Height to the Chart | ||
|
@@ -106,11 +111,22 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar | |
> | ||
<FocusZone direction={FocusZoneDirection.horizontal} handleTabKey={FocusZoneTabbableElements.all}> | ||
<div> | ||
<div | ||
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. Can we use SvgTooltipText control here. |
||
id={this._tooltipId} | ||
style={{ position: 'absolute', display: 'none' }} | ||
className={this._classNames.tooltip!} | ||
/> | ||
<svg | ||
className={this._classNames.chart} | ||
aria-label={data?.chartTitle} | ||
ref={(node: SVGElement | null) => this._setViewBox(node)} | ||
> | ||
<rect | ||
id={this._rectTooltipId} | ||
onMouseMove={this._showTooltip.bind(this, this.props.valueInsideDonut)} | ||
onMouseOut={this._hideTooltip.bind(this)} | ||
className={this._classNames.tooltipContainer!} | ||
/> | ||
<Pie | ||
width={this.state._width!} | ||
height={this.state._height!} | ||
|
@@ -302,4 +318,22 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar | |
private _getHighlightedLegend() { | ||
return this.state.selectedLegend || this.state.activeLegend; | ||
} | ||
|
||
private _showTooltip = (text: string | number, evt: any) => { | ||
this._tooltip = document.getElementById(this._tooltipId); | ||
if (this._tooltip) { | ||
this._tooltip!.innerHTML = text.toString(); | ||
this._tooltip!.style.display = 'block'; | ||
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. Can this be done using react states and not direct dom interactions 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._tooltip!.style.opacity = '0.9'; | ||
this._tooltip!.style.left = evt.pageX + 'px'; | ||
this._tooltip!.style.top = evt.pageY - 28 + 'px'; | ||
} | ||
}; | ||
|
||
private _hideTooltip = (evt: any) => { | ||
if (this._tooltip) { | ||
this._tooltip = document.getElementById(this._tooltipId); | ||
this._tooltip!.style.display = 'none'; | ||
} | ||
}; | ||
} |
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.
is there a default theme always available
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.
yes, the theme is coming as a prop from the parent component, which is a required property