diff --git a/change/@fluentui-react-charting-4722a315-f7b2-4e91-9f26-23585f066b78.json b/change/@fluentui-react-charting-4722a315-f7b2-4e91-9f26-23585f066b78.json new file mode 100644 index 0000000000000..a46878a6f6dec --- /dev/null +++ b/change/@fluentui-react-charting-4722a315-f7b2-4e91-9f26-23585f066b78.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Bug Fix", + "packageName": "@fluentui/react-charting", + "email": "srmukher@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-charting/src/components/DonutChart/Arc/Arc.tsx b/packages/react-charting/src/components/DonutChart/Arc/Arc.tsx index 458f2720492ce..b18de355d58a7 100644 --- a/packages/react-charting/src/components/DonutChart/Arc/Arc.tsx +++ b/packages/react-charting/src/components/DonutChart/Arc/Arc.tsx @@ -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'; @@ -25,6 +26,10 @@ export class Arc extends React.Component { return null; } + public constructor(props: IArcProps) { + super(props); + } + public updateChart(newProps: IArcProps): void { _updateChart(newProps); } @@ -40,6 +45,7 @@ export class Arc extends React.Component { 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 ( {!!focusedArcId && focusedArcId === id && ( diff --git a/packages/react-charting/src/components/DonutChart/Arc/Arc.types.ts b/packages/react-charting/src/components/DonutChart/Arc/Arc.types.ts index 84b84424e1cec..3ff17a2680b03 100644 --- a/packages/react-charting/src/components/DonutChart/Arc/Arc.types.ts +++ b/packages/react-charting/src/components/DonutChart/Arc/Arc.types.ts @@ -139,6 +139,11 @@ export interface IArcStyles { */ focusRing: IStyle; + /** + * Style for overflow center text container + */ + nodeTextContainer?: IStyle; + /** * Style for the arc labels */ diff --git a/packages/react-charting/src/components/DonutChart/DonutChart.base.tsx b/packages/react-charting/src/components/DonutChart/DonutChart.base.tsx index 71280d92ae296..87b4236d130ee 100644 --- a/packages/react-charting/src/components/DonutChart/DonutChart.base.tsx +++ b/packages/react-charting/src/components/DonutChart/DonutChart.base.tsx @@ -41,6 +41,9 @@ export class DonutChartBase extends React.Component
+
this._setViewBox(node)} > + (this._tooltip = element)} + /> { + if (this._tooltip) { + this._tooltip!.innerHTML = text ? text.toString() : ''; + this._tooltip!.style.display = 'block'; + 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 && diff --git a/packages/react-charting/src/components/DonutChart/DonutChart.styles.ts b/packages/react-charting/src/components/DonutChart/DonutChart.styles.ts index 14abedfd6e864..ec38eac050441 100644 --- a/packages/react-charting/src/components/DonutChart/DonutChart.styles.ts +++ b/packages/react-charting/src/components/DonutChart/DonutChart.styles.ts @@ -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', + }, }; }; diff --git a/packages/react-charting/src/components/DonutChart/DonutChart.types.ts b/packages/react-charting/src/components/DonutChart/DonutChart.types.ts index eba2b6ec1826c..3c6b4fbe273c1 100644 --- a/packages/react-charting/src/components/DonutChart/DonutChart.types.ts +++ b/packages/react-charting/src/components/DonutChart/DonutChart.types.ts @@ -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; } diff --git a/packages/react-charting/src/components/DonutChart/Pie/Pie.tsx b/packages/react-charting/src/components/DonutChart/Pie/Pie.tsx index 4628f11f2c1e4..378140d5bac32 100644 --- a/packages/react-charting/src/components/DonutChart/Pie/Pie.tsx +++ b/packages/react-charting/src/components/DonutChart/Pie/Pie.tsx @@ -80,6 +80,7 @@ export class Pie extends React.Component { {this.props.valueInsideDonut && ( { 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 => { diff --git a/packages/react-charting/src/components/DonutChart/__snapshots__/DonutChart.test.tsx.snap b/packages/react-charting/src/components/DonutChart/__snapshots__/DonutChart.test.tsx.snap index 530573c78d09e..34b3f6f0288b6 100644 --- a/packages/react-charting/src/components/DonutChart/__snapshots__/DonutChart.test.tsx.snap +++ b/packages/react-charting/src/components/DonutChart/__snapshots__/DonutChart.test.tsx.snap @@ -24,12 +24,42 @@ exports[`DonutChart - mouse events Should render callout correctly on mouseover &:focus { outline: none; } - data-focuszone-id="FocusZone3" + data-focuszone-id="FocusZone5" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -336,7 +381,7 @@ exports[`DonutChart - mouse events Should render callout correctly on mouseover &:focus { outline: none; } - data-focuszone-id="FocusZone4" + data-focuszone-id="FocusZone6" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} @@ -660,12 +705,42 @@ exports[`DonutChart - mouse events Should render customized callout on mouseover &:focus { outline: none; } - data-focuszone-id="FocusZone3" + data-focuszone-id="FocusZone5" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -890,7 +980,7 @@ exports[`DonutChart - mouse events Should render customized callout on mouseover &:focus { outline: none; } - data-focuszone-id="FocusZone4" + data-focuszone-id="FocusZone6" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} @@ -1214,12 +1304,42 @@ exports[`DonutChart snapShot testing Should render arc labels 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone27" + data-focuszone-id="FocusZone39" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -1252,7 +1387,7 @@ exports[`DonutChart snapShot testing Should render arc labels 1`] = ` } d="M0.6,-59.997A60,60,0,0,1,56.068,-21.363L0,0Z" data-is-focusable={true} - id="_Pie_25first20000" + id="_Pie_35first20000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -1294,7 +1429,7 @@ exports[`DonutChart snapShot testing Should render arc labels 1`] = ` } d="M56.484,-20.237A60,60,0,0,1,-24.404,54.813L0,0Z" data-is-focusable={true} - id="_Pie_25second39000" + id="_Pie_35second39000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -1336,7 +1471,7 @@ exports[`DonutChart snapShot testing Should render arc labels 1`] = ` } d="M-25.495,54.314A60,60,0,0,1,-0.6,-59.997L0,0Z" data-is-focusable={true} - id="_Pie_25third45000" + id="_Pie_35third45000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -1362,6 +1497,7 @@ exports[`DonutChart snapShot testing Should render arc labels 1`] = ` 45.0k +
@@ -1415,7 +1551,7 @@ exports[`DonutChart snapShot testing Should render arc labels 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone28" + data-focuszone-id="FocusZone40" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} @@ -1736,12 +1872,42 @@ exports[`DonutChart snapShot testing Should render arc labels in percentage form &:focus { outline: none; } - data-focuszone-id="FocusZone32" + data-focuszone-id="FocusZone46" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -1774,7 +1955,7 @@ exports[`DonutChart snapShot testing Should render arc labels in percentage form } d="M0.6,-59.997A60,60,0,0,1,56.068,-21.363L0,0Z" data-is-focusable={true} - id="_Pie_30first20000" + id="_Pie_42first20000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -1816,7 +1997,7 @@ exports[`DonutChart snapShot testing Should render arc labels in percentage form } d="M56.484,-20.237A60,60,0,0,1,-24.404,54.813L0,0Z" data-is-focusable={true} - id="_Pie_30second39000" + id="_Pie_42second39000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -1858,7 +2039,7 @@ exports[`DonutChart snapShot testing Should render arc labels in percentage form } d="M-25.495,54.314A60,60,0,0,1,-0.6,-59.997L0,0Z" data-is-focusable={true} - id="_Pie_30third45000" + id="_Pie_42third45000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -1884,6 +2065,7 @@ exports[`DonutChart snapShot testing Should render arc labels in percentage form 43% +
@@ -1937,7 +2119,7 @@ exports[`DonutChart snapShot testing Should render arc labels in percentage form &:focus { outline: none; } - data-focuszone-id="FocusZone33" + data-focuszone-id="FocusZone47" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} @@ -2258,12 +2440,42 @@ exports[`DonutChart snapShot testing renders DonutChart correctly 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone3" + data-focuszone-id="FocusZone5" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -2358,6 +2585,7 @@ exports[`DonutChart snapShot testing renders DonutChart correctly 1`] = ` role="img" /> +
@@ -2411,7 +2639,7 @@ exports[`DonutChart snapShot testing renders DonutChart correctly 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone4" + data-focuszone-id="FocusZone6" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} @@ -2732,12 +2960,42 @@ exports[`DonutChart snapShot testing renders enabledLegendsWrapLines correctly 1 &:focus { outline: none; } - data-focuszone-id="FocusZone17" + data-focuszone-id="FocusZone25" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -2770,7 +3043,7 @@ exports[`DonutChart snapShot testing renders enabledLegendsWrapLines correctly 1 } d="M1,-99.995A100,100,0,0,1,93.447,-35.604L0,0Z" data-is-focusable={true} - id="_Pie_15first20000" + id="_Pie_21first20000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -2796,7 +3069,7 @@ exports[`DonutChart snapShot testing renders enabledLegendsWrapLines correctly 1 } d="M94.14,-33.728A100,100,0,0,1,-40.673,91.355L0,0Z" data-is-focusable={true} - id="_Pie_15second39000" + id="_Pie_21second39000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -2822,7 +3095,7 @@ exports[`DonutChart snapShot testing renders enabledLegendsWrapLines correctly 1 } d="M-42.492,90.523A100,100,0,0,1,-1,-99.995L0,0Z" data-is-focusable={true} - id="_Pie_15third45000" + id="_Pie_21third45000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -2832,6 +3105,7 @@ exports[`DonutChart snapShot testing renders enabledLegendsWrapLines correctly 1 role="img" /> +
@@ -2885,7 +3159,7 @@ exports[`DonutChart snapShot testing renders enabledLegendsWrapLines correctly 1 &:focus { outline: none; } - data-focuszone-id="FocusZone18" + data-focuszone-id="FocusZone26" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} @@ -3206,12 +3480,42 @@ exports[`DonutChart snapShot testing renders hideLegend correctly 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone8" + data-focuszone-id="FocusZone12" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -3244,7 +3563,7 @@ exports[`DonutChart snapShot testing renders hideLegend correctly 1`] = ` } d="M1,-99.995A100,100,0,0,1,93.447,-35.604L0,0Z" data-is-focusable={true} - id="_Pie_6first20000" + id="_Pie_8first20000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -3270,7 +3589,7 @@ exports[`DonutChart snapShot testing renders hideLegend correctly 1`] = ` } d="M94.14,-33.728A100,100,0,0,1,-40.673,91.355L0,0Z" data-is-focusable={true} - id="_Pie_6second39000" + id="_Pie_8second39000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -3296,7 +3615,7 @@ exports[`DonutChart snapShot testing renders hideLegend correctly 1`] = ` } d="M-42.492,90.523A100,100,0,0,1,-1,-99.995L0,0Z" data-is-focusable={true} - id="_Pie_6third45000" + id="_Pie_8third45000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -3306,6 +3625,7 @@ exports[`DonutChart snapShot testing renders hideLegend correctly 1`] = ` role="img" /> +
@@ -3340,12 +3660,42 @@ exports[`DonutChart snapShot testing renders hideTooltip correctly 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone12" + data-focuszone-id="FocusZone18" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -3378,7 +3743,7 @@ exports[`DonutChart snapShot testing renders hideTooltip correctly 1`] = ` } d="M1,-99.995A100,100,0,0,1,93.447,-35.604L0,0Z" data-is-focusable={true} - id="_Pie_10first20000" + id="_Pie_14first20000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -3404,7 +3769,7 @@ exports[`DonutChart snapShot testing renders hideTooltip correctly 1`] = ` } d="M94.14,-33.728A100,100,0,0,1,-40.673,91.355L0,0Z" data-is-focusable={true} - id="_Pie_10second39000" + id="_Pie_14second39000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -3430,7 +3795,7 @@ exports[`DonutChart snapShot testing renders hideTooltip correctly 1`] = ` } d="M-42.492,90.523A100,100,0,0,1,-1,-99.995L0,0Z" data-is-focusable={true} - id="_Pie_10third45000" + id="_Pie_14third45000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -3440,6 +3805,7 @@ exports[`DonutChart snapShot testing renders hideTooltip correctly 1`] = ` role="img" /> +
@@ -3493,7 +3859,7 @@ exports[`DonutChart snapShot testing renders hideTooltip correctly 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone13" + data-focuszone-id="FocusZone19" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} @@ -3814,12 +4180,42 @@ exports[`DonutChart snapShot testing renders value inside onf the pie 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone22" + data-focuszone-id="FocusZone32" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -3852,7 +4263,7 @@ exports[`DonutChart snapShot testing renders value inside onf the pie 1`] = ` } d="M1,-99.995A100,100,0,0,1,93.447,-35.604L0,0Z" data-is-focusable={true} - id="_Pie_20first20000" + id="_Pie_28first20000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -3878,7 +4289,7 @@ exports[`DonutChart snapShot testing renders value inside onf the pie 1`] = ` } d="M94.14,-33.728A100,100,0,0,1,-40.673,91.355L0,0Z" data-is-focusable={true} - id="_Pie_20second39000" + id="_Pie_28second39000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -3904,7 +4315,7 @@ exports[`DonutChart snapShot testing renders value inside onf the pie 1`] = ` } d="M-42.492,90.523A100,100,0,0,1,-1,-99.995L0,0Z" data-is-focusable={true} - id="_Pie_20third45000" + id="_Pie_28third45000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -3927,6 +4338,7 @@ exports[`DonutChart snapShot testing renders value inside onf the pie 1`] = ` } data-is-focusable={true} dominantBaseline="middle" + id="Donut_center_text" textAnchor="middle" y={5} > @@ -3985,7 +4397,7 @@ exports[`DonutChart snapShot testing renders value inside onf the pie 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone23" + data-focuszone-id="FocusZone33" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} diff --git a/packages/react-charting/src/components/DonutChart/__snapshots__/DonutChartRTL.test.tsx.snap b/packages/react-charting/src/components/DonutChart/__snapshots__/DonutChartRTL.test.tsx.snap index 551ad53f5f2a7..d34cc41d63d5c 100644 --- a/packages/react-charting/src/components/DonutChart/__snapshots__/DonutChartRTL.test.tsx.snap +++ b/packages/react-charting/src/components/DonutChart/__snapshots__/DonutChartRTL.test.tsx.snap @@ -24,9 +24,34 @@ exports[`Donut chart interactions Should hide callout on mouse leave 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone3" + data-focuszone-id="FocusZone5" >
+ @@ -300,7 +339,7 @@ exports[`Donut chart interactions Should hide callout on mouse leave 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone4" + data-focuszone-id="FocusZone6" role="listbox" >
+ @@ -751,7 +829,7 @@ exports[`Donut chart interactions Should reflect theme change 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone7" + data-focuszone-id="FocusZone9" role="listbox" >
+
+ @@ -1371,7 +1494,7 @@ exports[`DonutChart - mouse events Should render callout correctly on mouseover &:focus { outline: none; } - data-focuszone-id="FocusZone4" + data-focuszone-id="FocusZone6" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} @@ -1695,12 +1818,42 @@ exports[`DonutChart - mouse events Should render customized callout on mouseover &:focus { outline: none; } - data-focuszone-id="FocusZone3" + data-focuszone-id="FocusZone5" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -1925,7 +2093,7 @@ exports[`DonutChart - mouse events Should render customized callout on mouseover &:focus { outline: none; } - data-focuszone-id="FocusZone4" + data-focuszone-id="FocusZone6" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} @@ -2249,12 +2417,42 @@ exports[`DonutChart snapShot testing Should render arc labels 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone27" + data-focuszone-id="FocusZone39" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -2287,7 +2500,7 @@ exports[`DonutChart snapShot testing Should render arc labels 1`] = ` } d="M0.6,-59.997A60,60,0,0,1,56.068,-21.363L0,0Z" data-is-focusable={true} - id="_Pie_25first20000" + id="_Pie_35first20000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -2329,7 +2542,7 @@ exports[`DonutChart snapShot testing Should render arc labels 1`] = ` } d="M56.484,-20.237A60,60,0,0,1,-24.404,54.813L0,0Z" data-is-focusable={true} - id="_Pie_25second39000" + id="_Pie_35second39000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -2371,7 +2584,7 @@ exports[`DonutChart snapShot testing Should render arc labels 1`] = ` } d="M-25.495,54.314A60,60,0,0,1,-0.6,-59.997L0,0Z" data-is-focusable={true} - id="_Pie_25third45000" + id="_Pie_35third45000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -2397,6 +2610,7 @@ exports[`DonutChart snapShot testing Should render arc labels 1`] = ` 45.0k +
@@ -2450,7 +2664,7 @@ exports[`DonutChart snapShot testing Should render arc labels 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone28" + data-focuszone-id="FocusZone40" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} @@ -2771,12 +2985,42 @@ exports[`DonutChart snapShot testing Should render arc labels in percentage form &:focus { outline: none; } - data-focuszone-id="FocusZone32" + data-focuszone-id="FocusZone46" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -2809,7 +3068,7 @@ exports[`DonutChart snapShot testing Should render arc labels in percentage form } d="M0.6,-59.997A60,60,0,0,1,56.068,-21.363L0,0Z" data-is-focusable={true} - id="_Pie_30first20000" + id="_Pie_42first20000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -2851,7 +3110,7 @@ exports[`DonutChart snapShot testing Should render arc labels in percentage form } d="M56.484,-20.237A60,60,0,0,1,-24.404,54.813L0,0Z" data-is-focusable={true} - id="_Pie_30second39000" + id="_Pie_42second39000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -2893,7 +3152,7 @@ exports[`DonutChart snapShot testing Should render arc labels in percentage form } d="M-25.495,54.314A60,60,0,0,1,-0.6,-59.997L0,0Z" data-is-focusable={true} - id="_Pie_30third45000" + id="_Pie_42third45000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -2919,6 +3178,7 @@ exports[`DonutChart snapShot testing Should render arc labels in percentage form 43% +
@@ -2972,7 +3232,7 @@ exports[`DonutChart snapShot testing Should render arc labels in percentage form &:focus { outline: none; } - data-focuszone-id="FocusZone33" + data-focuszone-id="FocusZone47" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} @@ -3293,12 +3553,42 @@ exports[`DonutChart snapShot testing renders DonutChart correctly 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone3" + data-focuszone-id="FocusZone5" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -3393,6 +3698,7 @@ exports[`DonutChart snapShot testing renders DonutChart correctly 1`] = ` role="img" /> +
@@ -3446,7 +3752,7 @@ exports[`DonutChart snapShot testing renders DonutChart correctly 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone4" + data-focuszone-id="FocusZone6" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} @@ -3767,12 +4073,42 @@ exports[`DonutChart snapShot testing renders enabledLegendsWrapLines correctly 1 &:focus { outline: none; } - data-focuszone-id="FocusZone17" + data-focuszone-id="FocusZone25" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -3805,7 +4156,7 @@ exports[`DonutChart snapShot testing renders enabledLegendsWrapLines correctly 1 } d="M1,-99.995A100,100,0,0,1,93.447,-35.604L0,0Z" data-is-focusable={true} - id="_Pie_15first20000" + id="_Pie_21first20000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -3831,7 +4182,7 @@ exports[`DonutChart snapShot testing renders enabledLegendsWrapLines correctly 1 } d="M94.14,-33.728A100,100,0,0,1,-40.673,91.355L0,0Z" data-is-focusable={true} - id="_Pie_15second39000" + id="_Pie_21second39000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -3857,7 +4208,7 @@ exports[`DonutChart snapShot testing renders enabledLegendsWrapLines correctly 1 } d="M-42.492,90.523A100,100,0,0,1,-1,-99.995L0,0Z" data-is-focusable={true} - id="_Pie_15third45000" + id="_Pie_21third45000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -3867,6 +4218,7 @@ exports[`DonutChart snapShot testing renders enabledLegendsWrapLines correctly 1 role="img" /> +
@@ -3920,7 +4272,7 @@ exports[`DonutChart snapShot testing renders enabledLegendsWrapLines correctly 1 &:focus { outline: none; } - data-focuszone-id="FocusZone18" + data-focuszone-id="FocusZone26" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} @@ -4241,12 +4593,42 @@ exports[`DonutChart snapShot testing renders hideLegend correctly 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone8" + data-focuszone-id="FocusZone12" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -4279,7 +4676,7 @@ exports[`DonutChart snapShot testing renders hideLegend correctly 1`] = ` } d="M1,-99.995A100,100,0,0,1,93.447,-35.604L0,0Z" data-is-focusable={true} - id="_Pie_6first20000" + id="_Pie_8first20000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -4305,7 +4702,7 @@ exports[`DonutChart snapShot testing renders hideLegend correctly 1`] = ` } d="M94.14,-33.728A100,100,0,0,1,-40.673,91.355L0,0Z" data-is-focusable={true} - id="_Pie_6second39000" + id="_Pie_8second39000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -4331,7 +4728,7 @@ exports[`DonutChart snapShot testing renders hideLegend correctly 1`] = ` } d="M-42.492,90.523A100,100,0,0,1,-1,-99.995L0,0Z" data-is-focusable={true} - id="_Pie_6third45000" + id="_Pie_8third45000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -4341,6 +4738,7 @@ exports[`DonutChart snapShot testing renders hideLegend correctly 1`] = ` role="img" /> +
@@ -4375,12 +4773,42 @@ exports[`DonutChart snapShot testing renders hideTooltip correctly 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone12" + data-focuszone-id="FocusZone18" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -4413,7 +4856,7 @@ exports[`DonutChart snapShot testing renders hideTooltip correctly 1`] = ` } d="M1,-99.995A100,100,0,0,1,93.447,-35.604L0,0Z" data-is-focusable={true} - id="_Pie_10first20000" + id="_Pie_14first20000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -4439,7 +4882,7 @@ exports[`DonutChart snapShot testing renders hideTooltip correctly 1`] = ` } d="M94.14,-33.728A100,100,0,0,1,-40.673,91.355L0,0Z" data-is-focusable={true} - id="_Pie_10second39000" + id="_Pie_14second39000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -4465,7 +4908,7 @@ exports[`DonutChart snapShot testing renders hideTooltip correctly 1`] = ` } d="M-42.492,90.523A100,100,0,0,1,-1,-99.995L0,0Z" data-is-focusable={true} - id="_Pie_10third45000" + id="_Pie_14third45000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -4475,6 +4918,7 @@ exports[`DonutChart snapShot testing renders hideTooltip correctly 1`] = ` role="img" /> +
@@ -4528,7 +4972,7 @@ exports[`DonutChart snapShot testing renders hideTooltip correctly 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone13" + data-focuszone-id="FocusZone19" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} @@ -4849,12 +5293,42 @@ exports[`DonutChart snapShot testing renders value inside onf the pie 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone22" + data-focuszone-id="FocusZone32" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} >
+
+ @@ -4887,7 +5376,7 @@ exports[`DonutChart snapShot testing renders value inside onf the pie 1`] = ` } d="M1,-99.995A100,100,0,0,1,93.447,-35.604L0,0Z" data-is-focusable={true} - id="_Pie_20first20000" + id="_Pie_28first20000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -4913,7 +5402,7 @@ exports[`DonutChart snapShot testing renders value inside onf the pie 1`] = ` } d="M94.14,-33.728A100,100,0,0,1,-40.673,91.355L0,0Z" data-is-focusable={true} - id="_Pie_20second39000" + id="_Pie_28second39000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -4939,7 +5428,7 @@ exports[`DonutChart snapShot testing renders value inside onf the pie 1`] = ` } d="M-42.492,90.523A100,100,0,0,1,-1,-99.995L0,0Z" data-is-focusable={true} - id="_Pie_20third45000" + id="_Pie_28third45000" onBlur={[Function]} onFocus={[Function]} onMouseLeave={[Function]} @@ -4962,6 +5451,7 @@ exports[`DonutChart snapShot testing renders value inside onf the pie 1`] = ` } data-is-focusable={true} dominantBaseline="middle" + id="Donut_center_text" textAnchor="middle" y={5} > @@ -5020,7 +5510,7 @@ exports[`DonutChart snapShot testing renders value inside onf the pie 1`] = ` &:focus { outline: none; } - data-focuszone-id="FocusZone23" + data-focuszone-id="FocusZone33" onFocus={[Function]} onKeyDown={[Function]} onMouseDownCapture={[Function]} diff --git a/packages/react-charting/src/utilities/utilities.ts b/packages/react-charting/src/utilities/utilities.ts index 54488a1f10bbf..2d934693aaa72 100644 --- a/packages/react-charting/src/utilities/utilities.ts +++ b/packages/react-charting/src/utilities/utilities.ts @@ -1,7 +1,7 @@ import { axisRight as d3AxisRight, axisBottom as d3AxisBottom, axisLeft as d3AxisLeft, Axis as D3Axis } from 'd3-axis'; import { max as d3Max, min as d3Min } from 'd3-array'; import { scaleLinear as d3ScaleLinear, scaleTime as d3ScaleTime, scaleBand as d3ScaleBand } from 'd3-scale'; -import { select as d3Select, event as d3Event, selectAll as d3SelectAll } from 'd3-selection'; +import { select as d3Select, Selection, event as d3Event, selectAll as d3SelectAll } from 'd3-selection'; import { format as d3Format } from 'd3-format'; import * as d3TimeFormat from 'd3-time-format'; import { @@ -1351,11 +1351,12 @@ export function rotateXAxisLabels(rotateLabelProps: IRotateLabelProps) { return Math.floor(maxHeight / 1.414); // Compute maxHeight/tanInverse(45) to get the vertical height of labels. } -export function wrapTextInsideDonut(selectorClass: string, maxWidth: number) { +export function wrapTextInsideDonut(selectorClass: string, maxWidth: number, val: string) { let idx: number = 0; + d3SelectAll(`.${selectorClass}`).each(function () { const text = d3Select(this); - const words = text.text().split(/\s+/).reverse(); + const words = val.split(/\s+/).reverse(); let word: string = ''; let line: string[] = []; let lineNumber: number = 0; @@ -1370,26 +1371,100 @@ export function wrapTextInsideDonut(selectorClass: string, maxWidth: number) { .attr('y', y) .attr('dy', lineNumber++ * lineHeight + 'em'); + // Determine the length of a line + const lineLength = tspan.node()!.getBoundingClientRect().y; + + // Determine the ellipsis length for word truncation + const ellipsis = '...'; + tspan.text(ellipsis); + const ellipsisLength = tspan.node()!.getComputedTextLength(); + tspan.text(null); while ((word = words.pop()!)) { line.push(word); tspan.text(line.join(' ') + ' '); - if (tspan.node()!.getComputedTextLength() > maxWidth && line.length > 1) { + // Determine if wrapping is required + // If yes, append a new line only if it does not exceed the max height + // here, max width = max height, so maxWidth is reused to check max height + if ( + tspan.node()!.getComputedTextLength() > maxWidth && + line.length > 1 && + tspan.node()!.getBoundingClientRect().y < maxWidth + ) { line.pop(); tspan.text(line.join(' ') + ' '); - line = [word]; - tspan = text - .append('tspan') - .attr('id', `WordBreakId-${idx}-${lineNumber}`) - .attr('x', 0) - .attr('y', y) - .attr('dy', lineNumber++ * lineHeight + 'em') - .text(word); + // append a line only if the line is within the max height + // else truncate horizontally and break + if (tspan.node()!.getBoundingClientRect().y + lineLength < maxWidth) { + line = [word]; + tspan = text + .append('tspan') + .attr('id', `WordBreakId-${idx}-${lineNumber}`) + .attr('x', 0) + .attr('y', y) + .attr('dy', lineNumber++ * lineHeight + 'em') + .text(word); + } else { + truncateHorizontally(tspan, line, maxWidth, ellipsisLength); + break; + } + } + // Determine if truncation is required vertically + // If yes, remove the last line, append ellipsis + // to the last word of the previous line (truncate horizontally) and break + if (tspan.node()!.getBoundingClientRect().y > maxWidth && line.length >= 1) { + line.pop(); + tspan.text(line.join(' ')); + truncateHorizontally(tspan, line, maxWidth, ellipsisLength); + break; + } + // Determine if truncation is required horizontally + if (tspan.node()!.getComputedTextLength() > maxWidth && line.length >= 1) { + truncateHorizontally(tspan, line, maxWidth, ellipsisLength); + break; } } idx += 1; }); } +function truncateHorizontally( + tspan: Selection, + line: string[], + maxWidth: number, + ellipsisLength: number, +) { + const ellipsis = '...'; + let lastWord = ''; + // atleast 3 chars to remove ('...') + // may require more removal based on the locale alphabets + const truncateCount = 4; + // Truncate till the text fits in the maximum allowable width + while (tspan.node()!.getComputedTextLength() > maxWidth - ellipsisLength) { + lastWord = line.pop()!; + if (lastWord !== undefined && lastWord.length >= truncateCount) { + // slice last 4 chars (last char + '...') from current lastword + const sliceWords = lastWord.slice(0, -truncateCount); + if (sliceWords !== '') { + line.pop(); + line = line.concat(sliceWords + ellipsis); + tspan.text(line.join(' ')); + } else { + line.pop(); + tspan.text(line.join(' ') + ellipsis); + } + } else { + break; + } + } + if (!isTextTruncated(tspan.text())) { + tspan.text(line.join(' ') + ellipsis); + } +} + +export function isTextTruncated(text: string): boolean { + return text.slice(-3) === '...'; +} + export function formatValueWithSIPrefix(value: number) { let specifier: string; if (value < 1000) { diff --git a/packages/react-examples/src/react-charting/DonutChart/DonutChart.Dynamic.Example.tsx b/packages/react-examples/src/react-charting/DonutChart/DonutChart.Dynamic.Example.tsx index f1bd6e9cc2e95..ae61ae966acfe 100644 --- a/packages/react-examples/src/react-charting/DonutChart/DonutChart.Dynamic.Example.tsx +++ b/packages/react-examples/src/react-charting/DonutChart/DonutChart.Dynamic.Example.tsx @@ -6,6 +6,7 @@ import { Checkbox } from '@fluentui/react/lib/Checkbox'; export interface IExampleState { dynamicData: IChartDataPoint[]; + dynamicInnerText: string; hideLabels: boolean; showLabelsInPercent: boolean; innerRadius: number; @@ -25,6 +26,16 @@ export class DonutChartDynamicExample extends React.Component +
); } @@ -98,6 +113,12 @@ export class DonutChartDynamicExample extends React.Component, checked: boolean) => { let innerRadius: number; if (checked) {