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

Handling central text overflow and adding tooltip for donut charts #26192

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
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,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import * as React from 'react';
import * as shape from 'd3-shape';
import { classNamesFunction, getRTL } from '@fluentui/react/lib/Utilities';
Expand Down Expand Up @@ -25,6 +26,10 @@ export class Arc extends React.Component<IArcProps, IArcState> {
return null;
}

public constructor(props: IArcProps) {
super(props);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change needed?

}

public updateChart(newProps: IArcProps): void {
_updateChart(newProps);
}
Expand All @@ -40,6 +45,7 @@ export class Arc extends React.Component<IArcProps, IArcState> {
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 && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ export interface IArcStyles {
*/
focusRing: IStyle;

/**
* Style for overflow center text container
*/
nodeTextContainer?: IStyle;

/**
* Style for the arc labels
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,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;
private _emptyChartId: string | null;

public static getDerivedStateFromProps(
Expand Down Expand Up @@ -80,6 +83,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_');
this._emptyChartId = getId('_DonutChart_empty');
}
public componentDidMount(): void {
Expand Down Expand Up @@ -118,11 +123,23 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar
>
<FocusZone direction={FocusZoneDirection.horizontal} handleTabKey={FocusZoneTabbableElements.all}>
<div>
<div
Copy link
Contributor

Choose a reason for hiding this comment

The 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!}
ref={(element: SVGElement | null) => (this._tooltip = element)}
/>
<Pie
width={this.state._width!}
height={this.state._height!}
Expand Down Expand Up @@ -302,7 +319,7 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar
});
return legendValue;
} else {
return valueInsideDonut;
return valueInsideDonut !== undefined ? valueInsideDonut : '';
}
}

Expand All @@ -324,6 +341,23 @@ export class DonutChartBase extends React.Component<IDonutChartProps, IDonutChar
return this.state.selectedLegend || this.state.activeLegend;
}

private _showTooltip = (text: string | number, evt: any) => {
if (this._tooltip) {
this._tooltip!.innerHTML = text ? text.toString() : '';
this._tooltip!.style.display = 'block';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be done using react states and not direct dom interactions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using react states require the title of the rect to be set in which case, there is no way to override the style of the tooltip as it appears as follows:
tooltip_example
As a result, I have created a ref to the tooltip element as used it instead of querying the dom.

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';
}
};

private _isChartEmpty(): boolean {
return !(
this.props.data &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,25 @@ export const getStyles = (props: IDonutChartStyleProps): IDonutChartStyles => {
paddingTop: '16px',
width: `${width}px`,
},
tooltipContainer: {
width: '100%',
height: '100%',
textAlign: 'center',
fill: 'transparent',
display: 'flex',
flexDirection: 'column',
},
tooltip: {
...theme.fonts.medium,
display: 'flex',
flexDirection: 'column',
padding: '8px',
position: 'absolute',
textAlign: 'center',
top: '0px',
background: theme.semanticColors.bodyBackground,
borderRadius: '2px',
pointerEvents: 'none',
},
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,14 @@ export interface IDonutChartStyles {
* Style for the legend container.
*/
legendContainer: IStyle;

/**
* Style for the tool tip container
*/
tooltipContainer?: IStyle;

/**
* Style for the tool tip
*/
tooltip?: IStyle;
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export class Pie extends React.Component<IPieProps, {}> {
{this.props.valueInsideDonut && (
<text
y={5}
id="Donut_center_text"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use getId?

textAnchor="middle"
dominantBaseline="middle"
className={classNames.insideDonutString}
Expand All @@ -97,7 +98,11 @@ export class Pie extends React.Component<IPieProps, {}> {
theme: this.props.theme!,
});

wrapTextInsideDonut(classNames.insideDonutString, this.props.innerRadius! * 2 - TEXT_PADDING);
wrapTextInsideDonut(
classNames.insideDonutString,
this.props.innerRadius! * 2 - TEXT_PADDING,
this.props.valueInsideDonut!.toString(),
);
}

private _focusCallback = (data: IChartDataPoint, id: string, e: SVGPathElement): void => {
Expand Down
Loading