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