Skip to content

Commit 59b99f8

Browse files
Anush2303Anush
andauthored
fix(react-charts): support single value callout in linechart (#35084)
Co-authored-by: Anush <[email protected]>
1 parent bc2137f commit 59b99f8

File tree

5 files changed

+92
-3
lines changed

5 files changed

+92
-3
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "patch",
3+
"comment": "support single value callout in linechart",
4+
"packageName": "@fluentui/react-charts",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

packages/charts/react-charts/library/etc/react-charts.api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,6 +1134,7 @@ export interface LineChartProps extends CartesianChartProps {
11341134
enablePerfOptimization?: boolean;
11351135
eventAnnotationProps?: EventsAnnotationProps;
11361136
getCalloutDescriptionMessage?: (calloutDataProps: CustomizedCalloutData) => string | undefined;
1137+
isCalloutForStack?: boolean;
11371138
onRenderCalloutPerDataPoint?: RenderFunction<CustomizedCalloutData>;
11381139
onRenderCalloutPerStack?: RenderFunction<CustomizedCalloutData>;
11391140
// (undocumented)

packages/charts/react-charts/library/src/components/LineChart/LineChart.tsx

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
ChildProps,
1717
LineChartPoints,
1818
CustomizedCalloutData,
19+
CustomizedCalloutDataPoint,
1920
Margins,
2021
RefArrayData,
2122
ColorFillBarsProps,
@@ -195,6 +196,9 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
195196
const [stackCalloutProps, setStackCalloutProps] = React.useState<CustomizedCalloutData>();
196197
const [clickPosition, setClickPosition] = React.useState({ x: 0, y: 0 });
197198
const [isPopoverOpen, setPopoverOpen] = React.useState(false);
199+
const [YValue, setYValue] = React.useState<number | string>('');
200+
const [legendVal, setLegendVal] = React.useState<string>('');
201+
const [lineColor, setLineColor] = React.useState<string>('');
198202

199203
const pointsRef = React.useRef<LineChartDataWithIndex[] | []>([]);
200204
const calloutPointsRef = React.useRef<any[]>([]);
@@ -586,6 +590,8 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
586590
xAxisCalloutAccessibilityData,
587591
event,
588592
yScale,
593+
legendVal,
594+
lineColor,
589595
)
590596
}
591597
onMouseMove={(event: React.MouseEvent<SVGElement>) =>
@@ -598,6 +604,8 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
598604
xAxisCalloutAccessibilityData,
599605
event,
600606
yScale,
607+
legendVal,
608+
lineColor,
601609
)
602610
}
603611
onMouseOut={_handleMouseOut}
@@ -779,6 +787,8 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
779787
xAxisCalloutAccessibilityData,
780788
event,
781789
yScale,
790+
legendVal,
791+
lineColor,
782792
)
783793
}
784794
onMouseMove={event =>
@@ -791,6 +801,8 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
791801
xAxisCalloutAccessibilityData,
792802
event,
793803
yScale,
804+
legendVal,
805+
lineColor,
794806
)
795807
}
796808
onMouseOut={_handleMouseOut}
@@ -838,6 +850,8 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
838850
xAxisCalloutAccessibilityData,
839851
event,
840852
yScale,
853+
legendVal,
854+
lineColor,
841855
)
842856
}
843857
onMouseMove={(event: React.MouseEvent<SVGElement>) =>
@@ -850,6 +864,8 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
850864
xAxisCalloutAccessibilityData,
851865
event,
852866
yScale,
867+
legendVal,
868+
lineColor,
853869
)
854870
}
855871
onMouseOut={_handleMouseOut}
@@ -902,6 +918,8 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
902918
lastCirlceXCalloutAccessibilityData,
903919
event,
904920
yScale,
921+
legendVal,
922+
lineColor,
905923
)
906924
}
907925
onMouseMove={event =>
@@ -914,6 +932,8 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
914932
lastCirlceXCalloutAccessibilityData,
915933
event,
916934
yScale,
935+
legendVal,
936+
lineColor,
917937
)
918938
}
919939
onMouseOut={_handleMouseOut}
@@ -967,6 +987,8 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
967987
lastCirlceXCalloutAccessibilityData,
968988
event,
969989
yScale,
990+
legendVal,
991+
lineColor,
970992
)
971993
}
972994
onMouseMove={(event: React.MouseEvent<SVGElement>) =>
@@ -979,6 +1001,8 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
9791001
lastCirlceXCalloutAccessibilityData,
9801002
event,
9811003
yScale,
1004+
legendVal,
1005+
lineColor,
9821006
)
9831007
}
9841008
onMouseOut={_handleMouseOut}
@@ -1022,6 +1046,8 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
10221046
lastCirlceXCalloutAccessibilityData,
10231047
event,
10241048
yScale,
1049+
legendVal,
1050+
lineColor,
10251051
)
10261052
}
10271053
onMouseMove={(event: React.MouseEvent<SVGElement>) =>
@@ -1034,6 +1060,8 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
10341060
lastCirlceXCalloutAccessibilityData,
10351061
event,
10361062
yScale,
1063+
legendVal,
1064+
lineColor,
10371065
)
10381066
}
10391067
onFocus={event =>
@@ -1094,6 +1122,8 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
10941122
xAxisCalloutAccessibilityData,
10951123
event,
10961124
yScale,
1125+
legendVal,
1126+
lineColor,
10971127
)
10981128
}
10991129
onMouseMove={event =>
@@ -1106,6 +1136,8 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
11061136
xAxisCalloutAccessibilityData,
11071137
event,
11081138
yScale,
1139+
legendVal,
1140+
lineColor,
11091141
)
11101142
}
11111143
onMouseOut={_handleMouseOut}
@@ -1399,11 +1431,25 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
13991431
xAxisCalloutAccessibilityData: AccessibilityProps | undefined,
14001432
mouseEvent: React.MouseEvent<SVGElement>,
14011433
yScale: ScaleLinear<number, number>,
1434+
legendVal: string,
1435+
lineColor: string,
14021436
) {
14031437
mouseEvent?.persist();
14041438
const formattedData = x instanceof Date ? formatDate(x, props.useUTC) : x;
14051439
const xVal = x instanceof Date ? x.getTime() : x;
1440+
const yVal = y instanceof Date ? y.getTime() : y;
14061441
const found = find(_calloutPoints, (element: { x: string | number }) => element.x === xVal);
1442+
let hoverDp: CustomizedCalloutData | undefined = undefined;
1443+
1444+
if (props.isCalloutForStack === false && found?.values) {
1445+
const dp = find(found.values, (val: CustomizedCalloutDataPoint) => val?.y === yVal);
1446+
if (dp) {
1447+
hoverDp = {
1448+
x: xVal,
1449+
values: [dp],
1450+
};
1451+
}
1452+
}
14071453
// if no points need to be called out then don't show vertical line and callout card
14081454

14091455
if (found) {
@@ -1417,8 +1463,11 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
14171463
updatePosition(mouseEvent.clientX, mouseEvent.clientY);
14181464
xAxisCalloutData ? setHoverXValue(xAxisCalloutData) : setHoverXValue('' + formattedData);
14191465
setYValueHover(found.values);
1466+
setYValue(yVal);
1467+
setLegendVal(legendVal);
1468+
setLineColor(lineColor);
14201469
setStackCalloutProps(found!);
1421-
setDataPointCalloutProps(found!);
1470+
setDataPointCalloutProps(hoverDp);
14221471
setActivePoint(circleId);
14231472
setNearestCircleToHighlight(null);
14241473
}
@@ -1686,6 +1735,10 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
16861735
const calloutProps = {
16871736
YValueHover: YValueHover,
16881737
hoverXValue: hoverXValue,
1738+
YValue: YValue,
1739+
legend: legendVal,
1740+
color: lineColor,
1741+
XValue: hoverXValue! as string,
16891742
descriptionMessage:
16901743
props.getCalloutDescriptionMessage && stackCalloutProps
16911744
? props.getCalloutDescriptionMessage(stackCalloutProps)
@@ -1695,7 +1748,7 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
16951748
...props.calloutProps,
16961749
clickPosition: clickPosition,
16971750
isPopoverOpen: isPopoverOpen,
1698-
isCalloutForStack: true,
1751+
isCalloutForStack: props.isCalloutForStack,
16991752
culture: props.culture ?? 'en-us',
17001753
isCartesian: true,
17011754
customCallout: {
@@ -1776,3 +1829,6 @@ export const LineChart: React.FunctionComponent<LineChartProps> = React.forwardR
17761829
},
17771830
);
17781831
LineChart.displayName = 'LineChart';
1832+
LineChart.defaultProps = {
1833+
isCalloutForStack: true,
1834+
};

packages/charts/react-charts/library/src/components/LineChart/LineChart.types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ export interface LineChartProps extends CartesianChartProps {
8888
* The prop used to enable the perf optimization
8989
*/
9090
enablePerfOptimization?: boolean;
91+
92+
/**
93+
* To enable callout for individual line or complete stack.
94+
* @default true
95+
* @type \{boolean \}
96+
*/
97+
isCalloutForStack?: boolean;
9198
}
9299

93100
/**

packages/charts/react-charts/stories/src/LineChart/LineChartDefault.stories.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import { LineChartProps, LineChart, ChartProps, DataVizPalette } from '@fluentui/react-charts';
3-
import { Switch, Checkbox, makeStyles, tokens } from '@fluentui/react-components';
3+
import { Switch, Checkbox, makeStyles, tokens, Field, Radio, RadioGroup } from '@fluentui/react-components';
44
import type { CheckboxOnChangeData, CheckboxProps } from '@fluentui/react-components';
55

66
const useStyles = makeStyles({
@@ -16,6 +16,7 @@ export const LineChartBasic = (props: LineChartProps) => {
1616
const [allowMultipleShapes, setAllowMultipleShapes] = React.useState<boolean>(false);
1717
const [showAxisTitles, setShowAxisTitles] = React.useState<boolean>(true);
1818
const [useUTC, setUseUTC] = React.useState<CheckboxProps['checked']>(true);
19+
const [selectedCallout, setSelectedCallout] = React.useState<string>('MultiCallout');
1920

2021
const _onWidthChange = (e: React.ChangeEvent<HTMLInputElement>) => {
2122
setWidth(parseInt(e.target.value, 10));
@@ -189,6 +190,21 @@ export const LineChartBasic = (props: LineChartProps) => {
189190
<div style={{ marginTop: '10px' }}>
190191
<Checkbox label="Use UTC time" checked={useUTC} onChange={_onCheckChange} />
191192
</div>
193+
<Field label="Pick one">
194+
<RadioGroup
195+
defaultValue="MultiCallout"
196+
onChange={(_ev, option) => {
197+
if (selectedCallout === 'MultiCallout') {
198+
setSelectedCallout('singleCallout');
199+
} else {
200+
setSelectedCallout('MultiCallout');
201+
}
202+
}}
203+
>
204+
<Radio value="singleCallout" label="Single Callout" />
205+
<Radio value="MultiCallout" label="Stack Callout" />
206+
</RadioGroup>
207+
</Field>
192208
{showAxisTitles && (
193209
<div style={rootStyle}>
194210
<LineChart
@@ -202,6 +218,7 @@ export const LineChartBasic = (props: LineChartProps) => {
202218
xAxisTickCount={10}
203219
allowMultipleShapesForPoints={allowMultipleShapes}
204220
enablePerfOptimization={true}
221+
isCalloutForStack={selectedCallout === 'MultiCallout'}
205222
yAxisTitle={
206223
showAxisTitles
207224
? 'Different categories of mail flow each of which are categorized into different categories'
@@ -226,6 +243,7 @@ export const LineChartBasic = (props: LineChartProps) => {
226243
xAxisTickCount={10}
227244
allowMultipleShapesForPoints={allowMultipleShapes}
228245
enablePerfOptimization={true}
246+
isCalloutForStack={selectedCallout === 'MultiCallout'}
229247
yAxisTitle={showAxisTitles ? 'Different categories of mail flow' : undefined}
230248
xAxisTitle={showAxisTitles ? 'Values of each category' : undefined}
231249
useUTC={useUTC}

0 commit comments

Comments
 (0)