@fluentui/react-charts 9.0.1 → 9.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/CHANGELOG.md +17 -2
  2. package/dist/index.d.ts +463 -36
  3. package/lib/GaugeChart.js +1 -0
  4. package/lib/GaugeChart.js.map +1 -0
  5. package/lib/GroupedVerticalBarChart.js +1 -0
  6. package/lib/GroupedVerticalBarChart.js.map +1 -0
  7. package/lib/ScatterChart.js +1 -0
  8. package/lib/ScatterChart.js.map +1 -0
  9. package/lib/components/GaugeChart/GaugeChart.js +589 -0
  10. package/lib/components/GaugeChart/GaugeChart.js.map +1 -0
  11. package/lib/components/GaugeChart/GaugeChart.types.js +4 -0
  12. package/lib/components/GaugeChart/GaugeChart.types.js.map +1 -0
  13. package/lib/components/GaugeChart/index.js +3 -0
  14. package/lib/components/GaugeChart/index.js.map +1 -0
  15. package/lib/components/GaugeChart/useGaugeChartStyles.styles.js +174 -0
  16. package/lib/components/GaugeChart/useGaugeChartStyles.styles.js.map +1 -0
  17. package/lib/components/GroupedVerticalBarChart/GroupedVerticalBarChart.js +492 -0
  18. package/lib/components/GroupedVerticalBarChart/GroupedVerticalBarChart.js.map +1 -0
  19. package/lib/components/GroupedVerticalBarChart/GroupedVerticalBarChart.types.js +4 -0
  20. package/lib/components/GroupedVerticalBarChart/GroupedVerticalBarChart.types.js.map +1 -0
  21. package/lib/components/GroupedVerticalBarChart/index.js +3 -0
  22. package/lib/components/GroupedVerticalBarChart/index.js.map +1 -0
  23. package/lib/components/GroupedVerticalBarChart/useGroupedVerticalBarChartStyles.styles.js +90 -0
  24. package/lib/components/GroupedVerticalBarChart/useGroupedVerticalBarChartStyles.styles.js.map +1 -0
  25. package/lib/components/Legends/Legends.types.js.map +1 -1
  26. package/lib/components/LineChart/LineChart.js.map +1 -1
  27. package/lib/components/ScatterChart/ScatterChart.js +478 -0
  28. package/lib/components/ScatterChart/ScatterChart.js.map +1 -0
  29. package/lib/components/ScatterChart/ScatterChart.types.js +4 -0
  30. package/lib/components/ScatterChart/ScatterChart.types.js.map +1 -0
  31. package/lib/components/ScatterChart/index.js +3 -0
  32. package/lib/components/ScatterChart/index.js.map +1 -0
  33. package/lib/components/ScatterChart/useScatterChartStyles.styles.js +65 -0
  34. package/lib/components/ScatterChart/useScatterChartStyles.styles.js.map +1 -0
  35. package/lib/components/Sparkline/Sparkline.js.map +1 -1
  36. package/lib/index.js +3 -0
  37. package/lib/index.js.map +1 -1
  38. package/lib/types/DataPoint.js.map +1 -1
  39. package/lib/utilities/utilities.js +123 -5
  40. package/lib/utilities/utilities.js.map +1 -1
  41. package/lib-commonjs/GaugeChart.js +6 -0
  42. package/lib-commonjs/GaugeChart.js.map +1 -0
  43. package/lib-commonjs/GroupedVerticalBarChart.js +6 -0
  44. package/lib-commonjs/GroupedVerticalBarChart.js.map +1 -0
  45. package/lib-commonjs/ScatterChart.js +6 -0
  46. package/lib-commonjs/ScatterChart.js.map +1 -0
  47. package/lib-commonjs/components/GaugeChart/GaugeChart.js +618 -0
  48. package/lib-commonjs/components/GaugeChart/GaugeChart.js.map +1 -0
  49. package/lib-commonjs/components/GaugeChart/GaugeChart.types.js +7 -0
  50. package/lib-commonjs/components/GaugeChart/GaugeChart.types.js.map +1 -0
  51. package/lib-commonjs/components/GaugeChart/index.js +8 -0
  52. package/lib-commonjs/components/GaugeChart/index.js.map +1 -0
  53. package/lib-commonjs/components/GaugeChart/useGaugeChartStyles.styles.js +252 -0
  54. package/lib-commonjs/components/GaugeChart/useGaugeChartStyles.styles.js.map +1 -0
  55. package/lib-commonjs/components/GroupedVerticalBarChart/GroupedVerticalBarChart.js +498 -0
  56. package/lib-commonjs/components/GroupedVerticalBarChart/GroupedVerticalBarChart.js.map +1 -0
  57. package/lib-commonjs/components/GroupedVerticalBarChart/GroupedVerticalBarChart.types.js +7 -0
  58. package/lib-commonjs/components/GroupedVerticalBarChart/GroupedVerticalBarChart.types.js.map +1 -0
  59. package/lib-commonjs/components/GroupedVerticalBarChart/index.js +8 -0
  60. package/lib-commonjs/components/GroupedVerticalBarChart/index.js.map +1 -0
  61. package/lib-commonjs/components/GroupedVerticalBarChart/useGroupedVerticalBarChartStyles.styles.js +139 -0
  62. package/lib-commonjs/components/GroupedVerticalBarChart/useGroupedVerticalBarChartStyles.styles.js.map +1 -0
  63. package/lib-commonjs/components/Legends/Legends.types.js.map +1 -1
  64. package/lib-commonjs/components/LineChart/LineChart.js.map +1 -1
  65. package/lib-commonjs/components/ScatterChart/ScatterChart.js +484 -0
  66. package/lib-commonjs/components/ScatterChart/ScatterChart.js.map +1 -0
  67. package/lib-commonjs/components/ScatterChart/ScatterChart.types.js +7 -0
  68. package/lib-commonjs/components/ScatterChart/ScatterChart.types.js.map +1 -0
  69. package/lib-commonjs/components/ScatterChart/index.js +8 -0
  70. package/lib-commonjs/components/ScatterChart/index.js.map +1 -0
  71. package/lib-commonjs/components/ScatterChart/useScatterChartStyles.styles.js +96 -0
  72. package/lib-commonjs/components/ScatterChart/useScatterChartStyles.styles.js.map +1 -0
  73. package/lib-commonjs/components/Sparkline/Sparkline.js.map +1 -1
  74. package/lib-commonjs/index.js +3 -0
  75. package/lib-commonjs/index.js.map +1 -1
  76. package/lib-commonjs/types/DataPoint.js.map +1 -1
  77. package/lib-commonjs/utilities/utilities.js +115 -5
  78. package/lib-commonjs/utilities/utilities.js.map +1 -1
  79. package/package.json +6 -6
@@ -0,0 +1,589 @@
1
+ import * as React from 'react';
2
+ import { useGaugeChartStyles } from './useGaugeChartStyles.styles';
3
+ import { select as d3Select } from 'd3-selection';
4
+ import { arc as d3Arc } from 'd3-shape';
5
+ import { Points, areArraysEqual, formatValueWithSIPrefix, getAccessibleDataObject, getColorFromToken, getNextColor, pointTypes, useRtl } from '../../utilities/index';
6
+ import { convertToLocaleString } from '../../utilities/locale-util';
7
+ import { SVGTooltipText } from '../../utilities/SVGTooltipText';
8
+ import { Legends, Shape } from '../Legends/index';
9
+ import { useFocusableGroup } from '@fluentui/react-tabster';
10
+ import { ChartPopover } from '../CommonComponents/ChartPopover';
11
+ const GAUGE_MARGIN = 16;
12
+ const LABEL_WIDTH = 36;
13
+ const LABEL_HEIGHT = 16;
14
+ const LABEL_OFFSET = 4;
15
+ const TITLE_OFFSET = 11;
16
+ const EXTRA_NEEDLE_LENGTH = 4;
17
+ export const ARC_PADDING = 2;
18
+ export const BREAKPOINTS = [
19
+ {
20
+ minRadius: 52,
21
+ arcWidth: 12,
22
+ fontSize: 20
23
+ },
24
+ {
25
+ minRadius: 70,
26
+ arcWidth: 16,
27
+ fontSize: 24
28
+ },
29
+ {
30
+ minRadius: 88,
31
+ arcWidth: 20,
32
+ fontSize: 32
33
+ },
34
+ {
35
+ minRadius: 106,
36
+ arcWidth: 24,
37
+ fontSize: 32
38
+ },
39
+ {
40
+ minRadius: 124,
41
+ arcWidth: 28,
42
+ fontSize: 40
43
+ },
44
+ {
45
+ minRadius: 142,
46
+ arcWidth: 32,
47
+ fontSize: 40
48
+ }
49
+ ];
50
+ export const calcNeedleRotation = (chartValue, minValue, maxValue)=>{
51
+ let needleRotation = (chartValue - minValue) / (maxValue - minValue) * 180;
52
+ if (needleRotation < 0) {
53
+ needleRotation = 0;
54
+ } else if (needleRotation > 180) {
55
+ needleRotation = 180;
56
+ }
57
+ return needleRotation;
58
+ };
59
+ export const getSegmentLabel = (segment, minValue, maxValue, variant, isAriaLabel = false)=>{
60
+ if (isAriaLabel) {
61
+ return minValue === 0 && variant === 'single-segment' ? `${segment.legend}, ${segment.size} out of ${maxValue} or ${(segment.size / maxValue * 100).toFixed()}%` : `${segment.legend}, ${segment.start} to ${segment.end}`;
62
+ }
63
+ return minValue === 0 && variant === 'single-segment' ? `${segment.size} (${(segment.size / maxValue * 100).toFixed()}%)` : `${segment.start} - ${segment.end}`;
64
+ };
65
+ export const getChartValueLabel = (chartValue, minValue, maxValue, chartValueFormat, forCallout = false)=>{
66
+ if (forCallout) {
67
+ // When displaying the chart value as a percentage, use fractions in the callout, and vice versa.
68
+ // This helps clarify the actual value and avoid repetition.
69
+ return minValue !== 0 ? chartValue.toString() : chartValueFormat === 'fraction' ? `${(chartValue / maxValue * 100).toFixed()}%` : `${chartValue}/${maxValue}`;
70
+ }
71
+ return typeof chartValueFormat === 'function' ? chartValueFormat([
72
+ chartValue - minValue,
73
+ maxValue - minValue
74
+ ]) : minValue !== 0 ? chartValue.toString() : chartValueFormat === 'fraction' ? `${chartValue}/${maxValue}` : `${(chartValue / maxValue * 100).toFixed()}%`;
75
+ };
76
+ export const GaugeChart = /*#__PURE__*/ React.forwardRef((props, forwardedRef)=>{
77
+ var _props_legendProps;
78
+ const _getMargins = ()=>{
79
+ const { hideMinMax, chartTitle, sublabel } = props;
80
+ return {
81
+ left: (!hideMinMax ? LABEL_OFFSET + LABEL_WIDTH : 0) + GAUGE_MARGIN,
82
+ right: (!hideMinMax ? LABEL_OFFSET + LABEL_WIDTH : 0) + GAUGE_MARGIN,
83
+ top: (chartTitle ? TITLE_OFFSET + LABEL_HEIGHT : EXTRA_NEEDLE_LENGTH / 2) + GAUGE_MARGIN,
84
+ bottom: (sublabel ? LABEL_OFFSET + LABEL_HEIGHT : 0) + GAUGE_MARGIN
85
+ };
86
+ };
87
+ const _margins = _getMargins();
88
+ const _legendsHeight = !props.hideLegend ? 24 : 0;
89
+ const _rootElem = React.useRef(null);
90
+ const _isRTL = useRtl();
91
+ const [width, setWidth] = React.useState(140 + _getMargins().left + _getMargins().right);
92
+ const [height, setHeight] = React.useState(70 + _getMargins().top + _getMargins().bottom + _legendsHeight);
93
+ const [hoveredLegend, setHoveredLegend] = React.useState('');
94
+ const [selectedLegends, setSelectedLegends] = React.useState(((_props_legendProps = props.legendProps) === null || _props_legendProps === void 0 ? void 0 : _props_legendProps.selectedLegends) || []);
95
+ const [focusedElement, setFocusedElement] = React.useState('');
96
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
97
+ const [clickPosition, setClickPosition] = React.useState({
98
+ x: 0,
99
+ y: 0
100
+ });
101
+ const [isPopoverOpen, setPopoverOpen] = React.useState(false);
102
+ const [hoverXValue, setHoverXValue] = React.useState('');
103
+ const [hoverYValues, setHoverYValues] = React.useState([]);
104
+ const prevPropsRef = React.useRef(null);
105
+ const _width = props.width || width;
106
+ const _height = props.height || height;
107
+ const _outerRadius = Math.min((_width - (_margins.left + _margins.right)) / 2, _height - (_margins.top + _margins.bottom + _legendsHeight));
108
+ const { arcWidth, chartValueSize } = _getStylesBasedOnBreakpoint();
109
+ const _innerRadius = _outerRadius - arcWidth;
110
+ let _minValue;
111
+ let _maxValue;
112
+ let _segments;
113
+ let _calloutAnchor = '';
114
+ React.useEffect(()=>{
115
+ if (prevPropsRef.current) {
116
+ var _prevProps_legendProps, _props_legendProps;
117
+ const prevProps = prevPropsRef.current;
118
+ if (!areArraysEqual((_prevProps_legendProps = prevProps.legendProps) === null || _prevProps_legendProps === void 0 ? void 0 : _prevProps_legendProps.selectedLegends, (_props_legendProps = props.legendProps) === null || _props_legendProps === void 0 ? void 0 : _props_legendProps.selectedLegends)) {
119
+ var _props_legendProps1;
120
+ setSelectedLegends(((_props_legendProps1 = props.legendProps) === null || _props_legendProps1 === void 0 ? void 0 : _props_legendProps1.selectedLegends) || []);
121
+ }
122
+ if (prevProps.height !== props.height || prevProps.width !== props.width) {
123
+ setWidth(props.width);
124
+ setHeight(props.height);
125
+ }
126
+ }
127
+ prevPropsRef.current = props;
128
+ }, [
129
+ props
130
+ ]);
131
+ const classes = useGaugeChartStyles(props);
132
+ function _getStylesBasedOnBreakpoint() {
133
+ for(let index = BREAKPOINTS.length - 1; index >= 0; index -= 1){
134
+ if (_outerRadius >= BREAKPOINTS[index].minRadius) {
135
+ return {
136
+ arcWidth: BREAKPOINTS[index].arcWidth,
137
+ chartValueSize: BREAKPOINTS[index].fontSize
138
+ };
139
+ }
140
+ }
141
+ return {
142
+ arcWidth: BREAKPOINTS[0].arcWidth,
143
+ chartValueSize: BREAKPOINTS[0].fontSize
144
+ };
145
+ }
146
+ function _processProps() {
147
+ const { minValue = 0, maxValue, segments, roundCorners } = props;
148
+ let total = minValue;
149
+ const processedSegments = segments.map(// eslint-disable-next-line @typescript-eslint/no-explicit-any
150
+ (segment, index)=>{
151
+ const size = Math.max(segment.size, 0);
152
+ total += size;
153
+ return {
154
+ legend: segment.legend,
155
+ size,
156
+ color: typeof segment.color !== 'undefined' ? getColorFromToken(segment.color, false) : getNextColor(index, 0, false),
157
+ accessibilityData: segment.accessibilityData,
158
+ start: total - size,
159
+ end: total
160
+ };
161
+ });
162
+ if (typeof maxValue !== 'undefined' && total < maxValue) {
163
+ processedSegments.push({
164
+ legend: 'Unknown',
165
+ size: maxValue - total,
166
+ color: 'neutralLight',
167
+ start: total,
168
+ end: maxValue
169
+ });
170
+ total = maxValue;
171
+ }
172
+ const arcGenerator = d3Arc().cornerRadius(roundCorners ? 3 : 0).padAngle(ARC_PADDING / _outerRadius).padRadius(_outerRadius);
173
+ const rtlSafeSegments = _isRTL ? Array.from(processedSegments).reverse() : processedSegments;
174
+ let prevAngle = -Math.PI / 2;
175
+ // eslint-disable-next-line @typescript-eslint/no-shadow
176
+ const arcs = rtlSafeSegments.map((segment, index)=>{
177
+ const endAngle = prevAngle + segment.size / (total - minValue) * Math.PI;
178
+ const d = arcGenerator({
179
+ innerRadius: _innerRadius,
180
+ outerRadius: _outerRadius,
181
+ startAngle: prevAngle,
182
+ endAngle
183
+ });
184
+ prevAngle = endAngle;
185
+ return {
186
+ d,
187
+ segmentIndex: _isRTL ? processedSegments.length - 1 - index : index,
188
+ startAngle: prevAngle - segment.size / (total - minValue) * Math.PI,
189
+ endAngle
190
+ };
191
+ });
192
+ _minValue = minValue;
193
+ _maxValue = total;
194
+ _segments = processedSegments;
195
+ return {
196
+ arcs
197
+ };
198
+ }
199
+ function _renderNeedle() {
200
+ const needleRotation = calcNeedleRotation(props.chartValue, _minValue, _maxValue);
201
+ const rtlSafeNeedleRotation = _isRTL ? 180 - needleRotation : needleRotation;
202
+ const strokeWidth = 2;
203
+ const halfStrokeWidth = strokeWidth / 2;
204
+ const needleLength = _outerRadius - _innerRadius + EXTRA_NEEDLE_LENGTH;
205
+ return /*#__PURE__*/ React.createElement("g", {
206
+ transform: `rotate(${rtlSafeNeedleRotation}, 0, 0)`
207
+ }, /*#__PURE__*/ React.createElement("path", {
208
+ d: `
209
+ M 0,${-halfStrokeWidth - 3}
210
+ L ${-needleLength},${-halfStrokeWidth - 1}
211
+ A ${halfStrokeWidth + 1},${halfStrokeWidth + 1},0,0,0,${-needleLength},${halfStrokeWidth + 1}
212
+ L 0,${halfStrokeWidth + 3}
213
+ A ${halfStrokeWidth + 3},${halfStrokeWidth + 3},0,0,0,0,${-halfStrokeWidth - 3}
214
+ `,
215
+ strokeWidth: strokeWidth,
216
+ className: classes.needle,
217
+ transform: `translate(${-_innerRadius + EXTRA_NEEDLE_LENGTH / 2})`,
218
+ "data-is-focusable": true,
219
+ onFocus: (e)=>_handleFocus(e, 'Needle'),
220
+ onBlur: _handleBlur,
221
+ onMouseEnter: (e)=>_handleMouseOver(e, 'Needle'),
222
+ onMouseMove: (e)=>_handleMouseOver(e, 'Needle'),
223
+ role: "img",
224
+ "aria-label": 'Current value: ' + getChartValueLabel(props.chartValue, _minValue, _maxValue, props.chartValueFormat)
225
+ }));
226
+ }
227
+ function _renderLegends() {
228
+ if (props.hideLegend) {
229
+ return null;
230
+ }
231
+ const legends = _segments.map((segment, index)=>{
232
+ const color = segment.color || getNextColor(index, 0, false);
233
+ return {
234
+ title: segment.legend,
235
+ color,
236
+ hoverAction: ()=>{
237
+ setHoveredLegend(segment.legend);
238
+ },
239
+ onMouseOutAction: ()=>{
240
+ setHoveredLegend('');
241
+ }
242
+ };
243
+ });
244
+ return /*#__PURE__*/ React.createElement("div", {
245
+ className: classes.legendsContainer,
246
+ style: {
247
+ width: props.width
248
+ }
249
+ }, /*#__PURE__*/ React.createElement(Legends, {
250
+ legends: legends,
251
+ centerLegends: true,
252
+ ...props.legendProps,
253
+ // eslint-disable-next-line react/jsx-no-bind
254
+ onChange: _onLegendSelectionChange
255
+ }));
256
+ }
257
+ function _onLegendSelectionChange(// eslint-disable-next-line @typescript-eslint/no-shadow
258
+ selectedLegends, event, currentLegend) {
259
+ var _props_legendProps, _props_legendProps1;
260
+ if ((_props_legendProps = props.legendProps) === null || _props_legendProps === void 0 ? void 0 : _props_legendProps.canSelectMultipleLegends) {
261
+ setSelectedLegends(selectedLegends);
262
+ } else {
263
+ setSelectedLegends(selectedLegends.slice(-1));
264
+ }
265
+ if ((_props_legendProps1 = props.legendProps) === null || _props_legendProps1 === void 0 ? void 0 : _props_legendProps1.onChange) {
266
+ props.legendProps.onChange(selectedLegends, event, currentLegend);
267
+ }
268
+ }
269
+ /**
270
+ * This function checks if the given legend is highlighted or not.
271
+ * A legend can be highlighted in 2 ways:
272
+ * 1. selection: if the user clicks on it
273
+ * 2. hovering: if there is no selected legend and the user hovers over it
274
+ */ function _legendHighlighted(legend) {
275
+ return _getHighlightedLegend().includes(legend);
276
+ }
277
+ /**
278
+ * This function checks if none of the legends is selected or hovered.
279
+ */ function _noLegendHighlighted() {
280
+ return _getHighlightedLegend().length === 0;
281
+ }
282
+ function _getHighlightedLegend() {
283
+ return selectedLegends.length > 0 ? selectedLegends : hoveredLegend ? [
284
+ hoveredLegend
285
+ ] : [];
286
+ }
287
+ // eslint-disable-next-line @typescript-eslint/no-shadow
288
+ function _handleFocus(focusEvent, focusedElement) {
289
+ _showCallout(focusEvent, focusedElement, true);
290
+ }
291
+ function _handleBlur() {
292
+ _hideCallout(true);
293
+ }
294
+ function _handleMouseOver(mouseEvent, hoveredElement) {
295
+ _showCallout(mouseEvent, hoveredElement, false);
296
+ }
297
+ function _handleMouseOut() {
298
+ _hideCallout(false);
299
+ }
300
+ function _handleCalloutDismiss() {
301
+ _hideCallout(false);
302
+ }
303
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
304
+ function _showCallout(event, legend, isFocusEvent) {
305
+ if (_calloutAnchor === legend) {
306
+ return;
307
+ }
308
+ let clientX = 0;
309
+ let clientY = 0;
310
+ if ('clientX' in event) {
311
+ clientX = event.clientX;
312
+ clientY = event.clientY;
313
+ } else {
314
+ // eslint-disable-next-line @typescript-eslint/no-shadow
315
+ const target = event.currentTarget;
316
+ if (target && 'getBoundingClientRect' in target) {
317
+ const boundingRect = target.getBoundingClientRect();
318
+ clientX = boundingRect.left + boundingRect.width / 2;
319
+ clientY = boundingRect.top + boundingRect.height / 2;
320
+ }
321
+ }
322
+ _calloutAnchor = legend;
323
+ // eslint-disable-next-line @typescript-eslint/no-shadow
324
+ const hoverXValue = 'Current value is ' + getChartValueLabel(props.chartValue, _minValue, _maxValue, props.chartValueFormat, true);
325
+ // eslint-disable-next-line @typescript-eslint/no-shadow
326
+ const hoverYValues = _segments.map((segment)=>{
327
+ const yValue = {
328
+ legend: segment.legend,
329
+ y: getSegmentLabel(segment, _minValue, _maxValue, props.variant),
330
+ color: segment.color
331
+ };
332
+ return yValue;
333
+ });
334
+ _updatePosition(clientX, clientY);
335
+ setPopoverOpen([
336
+ 'Needle',
337
+ 'Chart value'
338
+ ].includes(legend) || _noLegendHighlighted() || _legendHighlighted(legend));
339
+ setHoverXValue(hoverXValue);
340
+ setHoverYValues(hoverYValues);
341
+ if (isFocusEvent) {
342
+ setFocusedElement(legend);
343
+ }
344
+ }
345
+ function _hideCallout(isBlurEvent) {
346
+ _calloutAnchor = '';
347
+ setPopoverOpen(false);
348
+ setHoverXValue('');
349
+ setHoverYValues([]);
350
+ if (isBlurEvent) {
351
+ setFocusedElement('');
352
+ }
353
+ }
354
+ function _wrapContent(content, id, maxWidth) {
355
+ const textElement = d3Select(`#${id}`);
356
+ textElement.text(content);
357
+ if (!textElement.node()) {
358
+ return false;
359
+ }
360
+ let isOverflowing = false;
361
+ let textLength = textElement.node().getComputedTextLength();
362
+ while(textLength > maxWidth && content.length > 0){
363
+ content = content.slice(0, -1);
364
+ textElement.text(content + '...');
365
+ isOverflowing = true;
366
+ textLength = textElement.node().getComputedTextLength();
367
+ }
368
+ return isOverflowing;
369
+ }
370
+ // TO DO: Write a common functional component for Multi value callout and divide sub count method
371
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
372
+ function _multiValueCallout(calloutProps) {
373
+ const yValueHoverSubCountsExists = _yValueHoverSubCountsExists(calloutProps.YValueHover);
374
+ return /*#__PURE__*/ React.createElement("div", {
375
+ className: classes.calloutContentRoot
376
+ }, /*#__PURE__*/ React.createElement("div", {
377
+ className: classes.calloutDateTimeContainer,
378
+ style: yValueHoverSubCountsExists ? {
379
+ marginBottom: '11px'
380
+ } : {}
381
+ }, /*#__PURE__*/ React.createElement("div", {
382
+ className: classes.calloutContentX,
383
+ ...getAccessibleDataObject(calloutProps.xAxisCalloutAccessibilityData, 'text', false)
384
+ }, convertToLocaleString(calloutProps.hoverXValue, props.culture))), /*#__PURE__*/ React.createElement("div", {
385
+ className: classes.calloutInfoContainer,
386
+ style: yValueHoverSubCountsExists ? {
387
+ display: 'flex'
388
+ } : {}
389
+ }, calloutProps.YValueHover && calloutProps.YValueHover.map((yValue, index, yValues)=>{
390
+ const isLast = index + 1 === yValues.length;
391
+ const { shouldDrawBorderBottom = false } = yValue;
392
+ return /*#__PURE__*/ React.createElement("div", {
393
+ ...getAccessibleDataObject(yValue.callOutAccessibilityData, 'text', false),
394
+ key: `callout-content-${index}`,
395
+ style: yValueHoverSubCountsExists ? {
396
+ display: 'inline-block',
397
+ ...shouldDrawBorderBottom && {
398
+ paddingBottom: '10px'
399
+ }
400
+ } : {
401
+ ...shouldDrawBorderBottom && {
402
+ paddingBottom: '10px'
403
+ }
404
+ }
405
+ }, _getCalloutContent(yValue, index, yValueHoverSubCountsExists, isLast));
406
+ }), !!calloutProps.descriptionMessage && /*#__PURE__*/ React.createElement("div", {
407
+ className: classes.descriptionMessage
408
+ }, calloutProps.descriptionMessage)));
409
+ }
410
+ function _yValueHoverSubCountsExists(yValueHover) {
411
+ if (yValueHover) {
412
+ return yValueHover.some((yValue)=>yValue.yAxisCalloutData && typeof yValue.yAxisCalloutData !== 'string');
413
+ }
414
+ return false;
415
+ }
416
+ function _getCalloutContent(xValue, index, yValueHoverSubCountsExists, isLast) {
417
+ const marginStyle = isLast ? {} : {
418
+ marginRight: '16px'
419
+ };
420
+ const toDrawShape = xValue.index !== undefined && xValue.index !== -1;
421
+ const { culture } = props;
422
+ const yValue = convertToLocaleString(xValue.y, culture);
423
+ if (!xValue.yAxisCalloutData || typeof xValue.yAxisCalloutData === 'string') {
424
+ return /*#__PURE__*/ React.createElement("div", {
425
+ style: yValueHoverSubCountsExists ? marginStyle : {}
426
+ }, yValueHoverSubCountsExists && /*#__PURE__*/ React.createElement("div", {
427
+ className: "ms-fontWeight-semibold",
428
+ style: {
429
+ fontSize: '12pt'
430
+ }
431
+ }, xValue.legend, " (", yValue, ")"), /*#__PURE__*/ React.createElement("div", {
432
+ id: `${index}_${xValue.y}`,
433
+ className: classes.calloutBlockContainer,
434
+ style: {
435
+ borderLeft: `4px solid ${xValue.color}`
436
+ }
437
+ }, toDrawShape && /*#__PURE__*/ React.createElement(Shape, {
438
+ svgProps: {
439
+ className: classes.shapeStyles
440
+ },
441
+ pathProps: {
442
+ fill: xValue.color
443
+ },
444
+ shape: Points[xValue.index % Object.keys(pointTypes).length],
445
+ style: {
446
+ display: 'flex'
447
+ }
448
+ }), /*#__PURE__*/ React.createElement("div", null, /*#__PURE__*/ React.createElement("div", {
449
+ className: classes.calloutlegendText
450
+ }, " ", xValue.legend), /*#__PURE__*/ React.createElement("div", {
451
+ className: classes.calloutContentY
452
+ }, convertToLocaleString(xValue.yAxisCalloutData ? xValue.yAxisCalloutData : xValue.y || xValue.data, culture)))));
453
+ } else {
454
+ const subcounts = xValue.yAxisCalloutData;
455
+ return /*#__PURE__*/ React.createElement("div", {
456
+ style: marginStyle
457
+ }, /*#__PURE__*/ React.createElement("div", {
458
+ className: "ms-fontWeight-semibold",
459
+ style: {
460
+ fontSize: '12pt'
461
+ }
462
+ }, xValue.legend, " (", yValue, ")"), Object.keys(subcounts).map((subcountName)=>{
463
+ return /*#__PURE__*/ React.createElement("div", {
464
+ key: subcountName,
465
+ className: classes.calloutBlockContainer
466
+ }, /*#__PURE__*/ React.createElement("div", {
467
+ className: classes.calloutlegendText
468
+ }, " ", convertToLocaleString(subcountName, culture)), /*#__PURE__*/ React.createElement("div", {
469
+ className: classes.calloutContentY
470
+ }, convertToLocaleString(subcounts[subcountName], culture)));
471
+ }));
472
+ }
473
+ }
474
+ function _updatePosition(newX, newY) {
475
+ const threshold = 1; // Set a threshold for movement
476
+ const { x, y } = clickPosition;
477
+ // Calculate the distance moved
478
+ const distance = Math.sqrt(Math.pow(newX - x, 2) + Math.pow(newY - y, 2));
479
+ // Update the position only if the distance moved is greater than the threshold
480
+ if (distance > threshold) {
481
+ setClickPosition({
482
+ x: newX,
483
+ y: newY
484
+ });
485
+ setPopoverOpen(true);
486
+ }
487
+ }
488
+ function _getChartTitle() {
489
+ const { chartTitle } = props;
490
+ return (chartTitle ? `${chartTitle}. ` : '') + `Gauge chart with ${_segments.length} segments. `;
491
+ }
492
+ const { arcs } = _processProps();
493
+ const focusAttributes = useFocusableGroup();
494
+ return /*#__PURE__*/ React.createElement("div", {
495
+ className: classes.root,
496
+ ref: (el)=>_rootElem.current = el,
497
+ ...focusAttributes
498
+ }, /*#__PURE__*/ React.createElement("svg", {
499
+ className: classes.chart,
500
+ style: {
501
+ width: props.width,
502
+ height: props.height - _legendsHeight
503
+ },
504
+ role: "region",
505
+ "aria-label": _getChartTitle(),
506
+ onMouseLeave: _handleMouseOut
507
+ }, /*#__PURE__*/ React.createElement("g", {
508
+ transform: `translate(${width / 2}, ${height - (_margins.bottom + _legendsHeight)})`
509
+ }, props.chartTitle && /*#__PURE__*/ React.createElement("text", {
510
+ x: 0,
511
+ y: -(_outerRadius + TITLE_OFFSET),
512
+ textAnchor: "middle",
513
+ className: classes.chartTitle,
514
+ "aria-hidden": true
515
+ }, props.chartTitle), !props.hideMinMax && /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement("text", {
516
+ x: (_isRTL ? 1 : -1) * (_outerRadius + LABEL_OFFSET),
517
+ y: 0,
518
+ textAnchor: "end",
519
+ className: classes.limits,
520
+ role: "img",
521
+ "aria-label": `Min value: ${_minValue}`
522
+ }, formatValueWithSIPrefix(_minValue)), /*#__PURE__*/ React.createElement("text", {
523
+ x: (_isRTL ? -1 : 1) * (_outerRadius + LABEL_OFFSET),
524
+ y: 0,
525
+ textAnchor: "start",
526
+ className: classes.limits,
527
+ role: "img",
528
+ "aria-label": `Max value: ${_maxValue}`
529
+ }, formatValueWithSIPrefix(_maxValue))), arcs.map((arc, index)=>{
530
+ const segment = _segments[arc.segmentIndex];
531
+ return /*#__PURE__*/ React.createElement(React.Fragment, {
532
+ key: index
533
+ }, /*#__PURE__*/ React.createElement("path", {
534
+ d: arc.d,
535
+ strokeWidth: focusedElement === segment.legend ? ARC_PADDING : 0,
536
+ className: classes.segment,
537
+ fill: segment.color,
538
+ opacity: _legendHighlighted(segment.legend) || _noLegendHighlighted() ? 1 : 0.1,
539
+ ...getAccessibleDataObject({
540
+ ariaLabel: getSegmentLabel(segment, _minValue, _maxValue, props.variant, true),
541
+ ...segment.accessibilityData
542
+ }, 'img', true),
543
+ onFocus: (e)=>_handleFocus(e, segment.legend),
544
+ onBlur: _handleBlur,
545
+ onMouseEnter: (e)=>_handleMouseOver(e, segment.legend),
546
+ onMouseLeave: (e)=>_handleCalloutDismiss(),
547
+ onMouseMove: (e)=>_handleMouseOver(e, segment.legend),
548
+ "data-is-focusable": _legendHighlighted(segment.legend) || _noLegendHighlighted(),
549
+ tabIndex: segment.legend !== '' ? 0 : undefined
550
+ }));
551
+ }), _renderNeedle(), /*#__PURE__*/ React.createElement("g", {
552
+ onMouseEnter: (e)=>_handleMouseOver(e, 'Chart value'),
553
+ onMouseMove: (e)=>_handleMouseOver(e, 'Chart value')
554
+ }, /*#__PURE__*/ React.createElement(SVGTooltipText, {
555
+ content: getChartValueLabel(props.chartValue, _minValue, _maxValue, props.chartValueFormat),
556
+ textProps: {
557
+ x: 0,
558
+ y: 0,
559
+ textAnchor: 'middle',
560
+ className: classes.chartValue,
561
+ fontSize: chartValueSize,
562
+ 'aria-hidden': 'true'
563
+ },
564
+ maxWidth: _innerRadius * 2 - 24,
565
+ wrapContent: _wrapContent
566
+ })), props.sublabel && /*#__PURE__*/ React.createElement(SVGTooltipText, {
567
+ content: props.sublabel,
568
+ textProps: {
569
+ x: 0,
570
+ y: 4,
571
+ textAnchor: 'middle',
572
+ dominantBaseline: 'hanging',
573
+ className: classes.sublabel
574
+ },
575
+ maxWidth: _innerRadius * 2,
576
+ wrapContent: _wrapContent
577
+ }))), _renderLegends(), !props.hideTooltip && isPopoverOpen && /*#__PURE__*/ React.createElement(ChartPopover, {
578
+ ...props.calloutProps,
579
+ clickPosition: clickPosition,
580
+ isPopoverOpen: isPopoverOpen,
581
+ customCallout: {
582
+ customizedCallout: _multiValueCallout({
583
+ hoverXValue: hoverXValue,
584
+ YValueHover: hoverYValues
585
+ })
586
+ }
587
+ }));
588
+ });
589
+ GaugeChart.displayName = 'GaugeChart';