@trackunit/react-chart-components 1.3.86 → 1.3.87
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/index.cjs.js +380 -96
- package/index.esm.js +361 -97
- package/package.json +5 -4
- package/src/Chart/Chart.d.ts +16 -20
- package/src/{PieChart/PieChart.d.ts → DonutChart/DonutChart.d.ts} +23 -5
- package/src/EChart/EChart.d.ts +43 -0
- package/src/LegendItem/LegendItem.d.ts +5 -2
- package/src/index.d.ts +4 -3
- package/src/utils/useChartColor.d.ts +11 -0
- package/src/utils/useLimitDataSet.d.ts +17 -0
- package/src/Chart/index.d.ts +0 -1
- package/src/LegendItem/index.d.ts +0 -1
- package/src/PieChart/index.d.ts +0 -1
package/index.cjs.js
CHANGED
|
@@ -1,63 +1,191 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var cssClassVarianceUtilities = require('@trackunit/css-class-variance-utilities');
|
|
5
4
|
var reactComponents = require('@trackunit/react-components');
|
|
6
|
-
var
|
|
5
|
+
var cssClassVarianceUtilities = require('@trackunit/css-class-variance-utilities');
|
|
6
|
+
var sharedUtils = require('@trackunit/shared-utils');
|
|
7
|
+
var echarts = require('echarts');
|
|
7
8
|
var react = require('react');
|
|
9
|
+
var uiDesignTokens = require('@trackunit/ui-design-tokens');
|
|
10
|
+
|
|
11
|
+
function _interopNamespaceDefault(e) {
|
|
12
|
+
var n = Object.create(null);
|
|
13
|
+
if (e) {
|
|
14
|
+
Object.keys(e).forEach(function (k) {
|
|
15
|
+
if (k !== 'default') {
|
|
16
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
17
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return e[k]; }
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
n.default = e;
|
|
25
|
+
return Object.freeze(n);
|
|
26
|
+
}
|
|
8
27
|
|
|
28
|
+
var echarts__namespace = /*#__PURE__*/_interopNamespaceDefault(echarts);
|
|
29
|
+
|
|
30
|
+
function isECElementEvent(value) {
|
|
31
|
+
return (typeof value === "object" &&
|
|
32
|
+
value !== null &&
|
|
33
|
+
"type" in value &&
|
|
34
|
+
"componentType" in value &&
|
|
35
|
+
"componentSubType" in value &&
|
|
36
|
+
"componentIndex" in value &&
|
|
37
|
+
"seriesIndex" in value);
|
|
38
|
+
}
|
|
9
39
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* Handles events and click functionality.
|
|
13
|
-
*
|
|
14
|
-
* For more information see the [eCharts documentation](https://github.com/hustcc/echarts-for-react).
|
|
15
|
-
*
|
|
16
|
-
* @param {ChartProps} props - The props for the Chart component
|
|
17
|
-
* @returns {ReactElement} Chart component
|
|
40
|
+
* A React wrapper for ECharts that handles initialization, events, and cleanup.
|
|
18
41
|
*/
|
|
19
|
-
const
|
|
20
|
-
const
|
|
42
|
+
const EChart = ({ option, style, className, onChartReady, onClick, onEvents, notMerge = false, renderer = "canvas", dataTestId, }) => {
|
|
43
|
+
const containerRef = react.useRef(null);
|
|
44
|
+
const internalChartRef = react.useRef(undefined);
|
|
45
|
+
const isInitialRender = react.useRef(true);
|
|
46
|
+
const setupEventHandlers = react.useCallback((chart) => {
|
|
47
|
+
// Handle click events
|
|
48
|
+
if (onClick) {
|
|
49
|
+
chart.on("click", function (event) {
|
|
50
|
+
if (isECElementEvent(event)) {
|
|
51
|
+
onClick(event);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
const zr = chart.getZr();
|
|
55
|
+
zr.setCursorStyle("pointer");
|
|
56
|
+
}
|
|
57
|
+
// Handle other events
|
|
58
|
+
if (onEvents) {
|
|
59
|
+
Object.entries(onEvents).forEach(([eventName, handler]) => {
|
|
60
|
+
if (eventName !== "click" || !onClick) {
|
|
61
|
+
// Don't double-register click if onClick is provided
|
|
62
|
+
chart.on(eventName, function (event) {
|
|
63
|
+
if (isECElementEvent(event)) {
|
|
64
|
+
handler(event);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}, [onClick, onEvents]);
|
|
71
|
+
const initChart = react.useCallback(() => {
|
|
72
|
+
const container = containerRef.current;
|
|
73
|
+
if (!container) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
// Dispose existing instance if any
|
|
77
|
+
if (internalChartRef.current) {
|
|
78
|
+
internalChartRef.current.dispose();
|
|
79
|
+
internalChartRef.current = undefined;
|
|
80
|
+
}
|
|
81
|
+
// Create new chart instance
|
|
82
|
+
const newChart = echarts__namespace.init(container, undefined, {
|
|
83
|
+
renderer,
|
|
84
|
+
width: "auto",
|
|
85
|
+
height: "auto",
|
|
86
|
+
});
|
|
87
|
+
// Store reference and notify ready
|
|
88
|
+
internalChartRef.current = newChart;
|
|
89
|
+
if (onChartReady) {
|
|
90
|
+
onChartReady(newChart);
|
|
91
|
+
}
|
|
92
|
+
}, [renderer, onChartReady]);
|
|
93
|
+
// Initialize chart and handle cleanup
|
|
21
94
|
react.useEffect(() => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
95
|
+
initChart();
|
|
96
|
+
isInitialRender.current = true;
|
|
97
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
98
|
+
const chart = internalChartRef.current;
|
|
99
|
+
if (!chart) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (!chart.isDisposed()) {
|
|
103
|
+
chart.resize();
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
const container = containerRef.current;
|
|
107
|
+
if (container) {
|
|
108
|
+
resizeObserver.observe(container);
|
|
109
|
+
}
|
|
110
|
+
return () => {
|
|
111
|
+
resizeObserver.disconnect();
|
|
112
|
+
const chart = internalChartRef.current;
|
|
113
|
+
if (!chart) {
|
|
114
|
+
return;
|
|
26
115
|
}
|
|
27
|
-
|
|
28
|
-
|
|
116
|
+
if (!chart.isDisposed()) {
|
|
117
|
+
const zr = chart.getZr();
|
|
118
|
+
zr.setCursorStyle("default");
|
|
119
|
+
chart.dispose();
|
|
120
|
+
internalChartRef.current = undefined;
|
|
29
121
|
}
|
|
122
|
+
};
|
|
123
|
+
}, [initChart]);
|
|
124
|
+
// Setup event handlers
|
|
125
|
+
react.useEffect(() => {
|
|
126
|
+
const chart = internalChartRef.current;
|
|
127
|
+
if (chart && !chart.isDisposed()) {
|
|
128
|
+
// Setup handlers
|
|
129
|
+
setupEventHandlers(chart);
|
|
30
130
|
}
|
|
31
131
|
return () => {
|
|
32
|
-
if (
|
|
33
|
-
|
|
132
|
+
if (chart && !chart.isDisposed()) {
|
|
133
|
+
// Clean up all event handlers
|
|
134
|
+
chart.off("click");
|
|
135
|
+
if (onEvents) {
|
|
136
|
+
sharedUtils.objectKeys(onEvents).forEach(eventName => {
|
|
137
|
+
chart.off(eventName);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
34
140
|
}
|
|
35
141
|
};
|
|
36
|
-
}, [
|
|
37
|
-
|
|
142
|
+
}, [onEvents, setupEventHandlers]);
|
|
143
|
+
// Handle options updates
|
|
144
|
+
react.useEffect(() => {
|
|
145
|
+
const chart = internalChartRef.current;
|
|
146
|
+
if (!chart) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (!chart.isDisposed()) {
|
|
150
|
+
// Force notMerge on initial render, respect prop afterwards
|
|
151
|
+
chart.setOption(option, isInitialRender.current || notMerge);
|
|
152
|
+
isInitialRender.current = false;
|
|
153
|
+
}
|
|
154
|
+
}, [option, notMerge]);
|
|
155
|
+
return jsxRuntime.jsx("div", { className: cvaEChart({ className }), "data-testid": dataTestId, ref: containerRef, style: style });
|
|
156
|
+
};
|
|
157
|
+
const cvaEChart = cssClassVarianceUtilities.cvaMerge(["w-full", "h-full"]);
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* The Chart component is a wrapper component for ECharts.
|
|
161
|
+
* Handles events and click functionality.
|
|
162
|
+
*/
|
|
163
|
+
const Chart = ({ options, unsafeOptions, showLoading, className, style, onChartReady, onClick, onEvents, merge = true, loadingOption, timezoneLabel, renderer = "canvas", dataTestId, }) => {
|
|
164
|
+
const containerStyle = {
|
|
165
|
+
height: style?.height ?? "300px",
|
|
166
|
+
width: style?.width ?? "100%",
|
|
167
|
+
...style,
|
|
168
|
+
};
|
|
169
|
+
return (jsxRuntime.jsx("div", { className: "grid h-full w-full grid-cols-1 grid-rows-1 items-center gap-1", "data-testid": dataTestId, style: containerStyle, children: showLoading ? (jsxRuntime.jsxs("div", { className: "grid place-items-center overflow-y-auto", "data-testid": `${dataTestId}-loading`, children: [jsxRuntime.jsx(reactComponents.Spinner, { centering: "centered" }), loadingOption?.text ? (jsxRuntime.jsx(reactComponents.Text, { align: "center", subtle: true, children: loadingOption.text })) : null] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(EChart, { className: className, dataTestId: `${dataTestId}-chart`, notMerge: !merge, onChartReady: onChartReady, onClick: onClick, onEvents: onEvents, option: options ?? unsafeOptions, renderer: renderer, style: style }), timezoneLabel] })) }));
|
|
38
170
|
};
|
|
39
|
-
const cvaChartContainer = cssClassVarianceUtilities.cvaMerge(["grid", "gap-1", "grid-rows-1", "grid-cols-1", "h-full", "w-full", "items-center"]);
|
|
40
|
-
const cvaChartSpinnerContainer = cssClassVarianceUtilities.cvaMerge(["grid", "place-items-center", "overflow-y-auto"]);
|
|
41
171
|
|
|
42
172
|
const cvaLegendItem = cssClassVarianceUtilities.cvaMerge([
|
|
43
|
-
"
|
|
173
|
+
"flex",
|
|
44
174
|
"items-center",
|
|
45
175
|
"transition-all",
|
|
46
176
|
"ease-in-out",
|
|
47
177
|
"duration-200",
|
|
48
|
-
"text-
|
|
49
|
-
"hover:text-
|
|
50
|
-
"text-sm",
|
|
51
|
-
"gap-2",
|
|
178
|
+
"text-secondary-600",
|
|
179
|
+
"hover:text-secondary-900",
|
|
52
180
|
], {
|
|
53
181
|
variants: {
|
|
54
182
|
selected: {
|
|
55
183
|
false: "",
|
|
56
|
-
true: "font-
|
|
184
|
+
true: ["font-semibold", "text-secondary-900"],
|
|
57
185
|
},
|
|
58
186
|
disabled: {
|
|
59
187
|
false: "",
|
|
60
|
-
true: "text-
|
|
188
|
+
true: ["text-secondary-400", "hover:text-secondary-400"],
|
|
61
189
|
},
|
|
62
190
|
isClickable: {
|
|
63
191
|
false: "cursor-default",
|
|
@@ -70,11 +198,11 @@ const cvaLegendItem = cssClassVarianceUtilities.cvaMerge([
|
|
|
70
198
|
isClickable: false,
|
|
71
199
|
},
|
|
72
200
|
});
|
|
73
|
-
const cvaLegendItemIndicator = cssClassVarianceUtilities.cvaMerge(["w-3", "h-3", "rounded-[50%]"], {
|
|
201
|
+
const cvaLegendItemIndicator = cssClassVarianceUtilities.cvaMerge(["w-3", "mr-1", "h-3", "rounded-[50%]", "flex-none"], {
|
|
74
202
|
variants: {
|
|
75
203
|
selected: {
|
|
76
204
|
false: "",
|
|
77
|
-
true: "
|
|
205
|
+
true: "",
|
|
78
206
|
},
|
|
79
207
|
},
|
|
80
208
|
defaultVariants: {
|
|
@@ -88,79 +216,235 @@ const cvaLegendItemIndicator = cssClassVarianceUtilities.cvaMerge(["w-3", "h-3",
|
|
|
88
216
|
* @param {LegendItem} props - The props for the LegendItem component
|
|
89
217
|
* @returns {ReactElement} LegendItem component
|
|
90
218
|
*/
|
|
91
|
-
const LegendItem = ({ className, label, disabled, selected, onClick, color, dataTestId }) => {
|
|
219
|
+
const LegendItem = ({ className, count, label, disabled, selected, onClick, color, dataTestId, onMouseEnter, onMouseLeave, }) => {
|
|
92
220
|
const handleOnClick = onClick && !disabled ? () => onClick() : undefined;
|
|
93
|
-
return (jsxRuntime.jsxs("div", { className: cvaLegendItem({ disabled, selected, isClickable: Boolean(onClick), className }), "data-testid": dataTestId, onClick: handleOnClick, children: [jsxRuntime.jsx("div", { className: cvaLegendItemIndicator({ selected }), "data-testid": dataTestId ? `${dataTestId}-indicator` : null, style: { backgroundColor: color } }),
|
|
221
|
+
return (jsxRuntime.jsxs("div", { className: cvaLegendItem({ disabled, selected, isClickable: !disabled && Boolean(onClick), className }), "data-testid": dataTestId, onClick: handleOnClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, children: [jsxRuntime.jsx("div", { className: cvaLegendItemIndicator({ selected }), "data-testid": dataTestId ? `${dataTestId}-indicator` : null, style: { backgroundColor: color } }), jsxRuntime.jsxs("p", { className: "truncate text-xs", children: [label, "\u00A0"] }), jsxRuntime.jsxs("p", { className: "text-xs", children: ["(", count || 0, ")"] })] }));
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Re-ordered chart colors to ensure that adjacent colors are visually different.
|
|
226
|
+
*
|
|
227
|
+
* @returns {string[]} The reordered chart colors.
|
|
228
|
+
*/
|
|
229
|
+
const useChartColor = () => {
|
|
230
|
+
const chartColor = react.useCallback((index) => {
|
|
231
|
+
return uiDesignTokens.DEFAULT_CHART_COLORS[index % uiDesignTokens.DEFAULT_CHART_COLORS.length] ?? "#000000";
|
|
232
|
+
}, []);
|
|
233
|
+
const chartColorArray = react.useCallback((total) => {
|
|
234
|
+
return Array.from({ length: total }, (_, index) => chartColor(index));
|
|
235
|
+
}, [chartColor]);
|
|
236
|
+
const chartStatusColor = react.useCallback((status) => {
|
|
237
|
+
return uiDesignTokens.CHART_STATUS_COLORS[status];
|
|
238
|
+
}, []);
|
|
239
|
+
return {
|
|
240
|
+
chartColor,
|
|
241
|
+
chartColorArray,
|
|
242
|
+
chartStatusColor,
|
|
243
|
+
};
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Limits the data set to the given limit.
|
|
248
|
+
* If the data set is larger than the limit, the data set is limited to the limit and the rest of the data is added to the "Others" group.
|
|
249
|
+
*
|
|
250
|
+
* @param data - The data set to limit.
|
|
251
|
+
* @param limit - The limit to apply to the data set.
|
|
252
|
+
* @returns {object} The limited data set with and without the "others" category.
|
|
253
|
+
*/
|
|
254
|
+
const useLimitDataSet = (data, limit) => {
|
|
255
|
+
const limitedData = react.useMemo(() => {
|
|
256
|
+
const sortedData = data.sort((a, b) => (b.count ?? 0) - (a.count ?? 0));
|
|
257
|
+
if (sortedData.length > limit) {
|
|
258
|
+
const result = sortedData.slice(0, limit);
|
|
259
|
+
result.push({
|
|
260
|
+
id: "defaultOther",
|
|
261
|
+
name: "Others",
|
|
262
|
+
selected: false,
|
|
263
|
+
count: sortedData.slice(limit).reduce((acc, curr) => acc + (curr.count ?? 0), 0),
|
|
264
|
+
color: uiDesignTokens.DEFAULT_CHART_OTHER,
|
|
265
|
+
original: { defaultOther: true },
|
|
266
|
+
});
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
return sortedData;
|
|
270
|
+
}, [data, limit]);
|
|
271
|
+
const limitedDataWithoutOthers = react.useMemo(() => limitedData.filter(item => !item.original?.defaultOther), [limitedData]);
|
|
272
|
+
return { limitedData, limitedDataWithoutOthers };
|
|
94
273
|
};
|
|
95
274
|
|
|
96
275
|
/**
|
|
97
|
-
* Create a
|
|
276
|
+
* Create a DonutChart with legends based on our current Chart component
|
|
98
277
|
*
|
|
99
|
-
* @param {
|
|
278
|
+
* @param {DonutChartProps} props - The props for the Chart component
|
|
100
279
|
* @returns {ReactElement} Chart component
|
|
101
280
|
*/
|
|
102
|
-
const
|
|
103
|
-
const
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
281
|
+
const DonutChart = ({ data, size = "full", loading, onClick, className, dataTestId, legendPosition = "Right", maxDataPoints = 6, showOthers = true, }) => {
|
|
282
|
+
const containerRef = react.useRef(null);
|
|
283
|
+
const chartRef = react.useRef(null);
|
|
284
|
+
const totalCount = react.useMemo(() => data?.map(item => item.count ?? 0).reduce((a, b) => a + b, 0) ?? 0, [data]);
|
|
285
|
+
const [hoveringItem, setHoveringItem] = react.useState(null);
|
|
286
|
+
const currentCount = react.useMemo(() => hoveringItem?.count ?? totalCount, [hoveringItem, totalCount]);
|
|
287
|
+
const { limitedData, limitedDataWithoutOthers } = useLimitDataSet(data ?? [], maxDataPoints);
|
|
288
|
+
const { chartColor } = useChartColor();
|
|
289
|
+
const handleChartReady = react.useCallback((chart) => {
|
|
290
|
+
chartRef.current = chart;
|
|
291
|
+
}, []);
|
|
292
|
+
const handleChartClick = react.useCallback((evt) => {
|
|
293
|
+
if (onClick && data) {
|
|
294
|
+
const clickedEntry = data.find(x => {
|
|
295
|
+
if (!evt.data || typeof evt.data !== "object" || !("id" in evt.data)) {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
return x.id === evt.data.id;
|
|
299
|
+
});
|
|
300
|
+
if (clickedEntry) {
|
|
301
|
+
onClick(clickedEntry);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}, [onClick, data]);
|
|
305
|
+
const handleChartEvents = react.useMemo(() => ({
|
|
306
|
+
mouseover: (evt) => {
|
|
307
|
+
const hoveredItem = data?.[evt.dataIndex];
|
|
308
|
+
if (hoveredItem) {
|
|
309
|
+
setHoveringItem(hoveredItem);
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
mouseout: () => {
|
|
313
|
+
setHoveringItem(null);
|
|
314
|
+
},
|
|
315
|
+
}), [data, setHoveringItem]);
|
|
316
|
+
const handleLegendMouseEnter = react.useCallback((item) => {
|
|
317
|
+
setHoveringItem(item);
|
|
318
|
+
const chart = chartRef.current;
|
|
319
|
+
if (!chart) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
// Find the index in the current chart data
|
|
323
|
+
const index = (showOthers ? limitedData : limitedDataWithoutOthers).findIndex(d => d.id === item.id);
|
|
324
|
+
if (index !== -1) {
|
|
325
|
+
chart.dispatchAction({
|
|
326
|
+
type: "highlight",
|
|
327
|
+
seriesIndex: 0,
|
|
328
|
+
dataIndex: index,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}, [limitedData, limitedDataWithoutOthers, showOthers]);
|
|
332
|
+
const handleLegendMouseLeave = react.useCallback(() => {
|
|
333
|
+
setHoveringItem(null);
|
|
334
|
+
const chart = chartRef.current;
|
|
335
|
+
if (!chart) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
chart.dispatchAction({
|
|
339
|
+
type: "downplay",
|
|
340
|
+
seriesIndex: 0,
|
|
341
|
+
});
|
|
342
|
+
}, []);
|
|
343
|
+
const chartOptions = react.useMemo(() => {
|
|
344
|
+
return {
|
|
345
|
+
legend: {
|
|
346
|
+
show: false,
|
|
347
|
+
},
|
|
348
|
+
tooltip: {
|
|
349
|
+
show: false,
|
|
350
|
+
},
|
|
351
|
+
series: [
|
|
352
|
+
{
|
|
353
|
+
type: "pie",
|
|
354
|
+
radius: ["50%", "75%"],
|
|
355
|
+
center: ["50%", "50%"],
|
|
356
|
+
minAngle: 5,
|
|
357
|
+
selectedOffset: 8,
|
|
358
|
+
itemStyle: {
|
|
359
|
+
borderColor: "#ffffff",
|
|
360
|
+
borderWidth: 2,
|
|
361
|
+
},
|
|
362
|
+
avoidLabelOverlap: false,
|
|
363
|
+
label: {
|
|
364
|
+
show: true,
|
|
365
|
+
position: "center",
|
|
366
|
+
fontSize: size === "full" ? 18 : 12,
|
|
367
|
+
fontWeight: "bold",
|
|
368
|
+
formatter: currentCount.toString(),
|
|
369
|
+
},
|
|
370
|
+
emphasis: {
|
|
371
|
+
label: {
|
|
372
|
+
show: true,
|
|
373
|
+
formatter: "{c}",
|
|
116
374
|
},
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
show: !hovering,
|
|
131
|
-
position: "center",
|
|
132
|
-
fontSize: size === "full" ? 18 : 12,
|
|
133
|
-
fontWeight: "bold",
|
|
134
|
-
formatter: totalCount.toString(),
|
|
135
|
-
},
|
|
136
|
-
emphasis: {
|
|
137
|
-
label: {
|
|
138
|
-
show: hovering,
|
|
139
|
-
formatter: "{c}",
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
labelLine: {
|
|
143
|
-
show: false,
|
|
144
|
-
},
|
|
145
|
-
data: data?.map(item => ({
|
|
146
|
-
id: item.id,
|
|
147
|
-
name: item.name,
|
|
148
|
-
value: item.count ?? 0,
|
|
149
|
-
itemStyle: { color: item.color },
|
|
150
|
-
})),
|
|
375
|
+
},
|
|
376
|
+
labelLine: {
|
|
377
|
+
show: false,
|
|
378
|
+
},
|
|
379
|
+
data: (showOthers ? limitedData : limitedDataWithoutOthers)
|
|
380
|
+
.map((item, index) => {
|
|
381
|
+
const itemColor = item.color ?? chartColor(index);
|
|
382
|
+
return {
|
|
383
|
+
id: item.id,
|
|
384
|
+
name: item.name,
|
|
385
|
+
value: item.count ?? 0,
|
|
386
|
+
itemStyle: {
|
|
387
|
+
color: itemColor,
|
|
151
388
|
},
|
|
152
|
-
|
|
153
|
-
|
|
389
|
+
emphasis: {
|
|
390
|
+
disabled: false,
|
|
391
|
+
scale: true,
|
|
392
|
+
scaleSize: 5,
|
|
393
|
+
},
|
|
394
|
+
selected: hoveringItem?.id === item.id,
|
|
395
|
+
};
|
|
396
|
+
})
|
|
397
|
+
.filter(item => item.value),
|
|
398
|
+
},
|
|
399
|
+
],
|
|
400
|
+
};
|
|
401
|
+
}, [size, currentCount, showOthers, limitedData, limitedDataWithoutOthers, chartColor, hoveringItem?.id]);
|
|
402
|
+
return (jsxRuntime.jsxs("div", { className: cvaChartRoot({ className, legendPosition }), "data-testid": dataTestId, ref: containerRef, children: [jsxRuntime.jsx("div", { className: cvaChartContainer({ legendPosition }), children: jsxRuntime.jsx(Chart, { className: cvaChart({ legendPosition, size }), dataTestId: "pie-chart", onChartReady: handleChartReady, onClick: handleChartClick, onEvents: handleChartEvents, options: chartOptions, showLoading: loading, style: { width: "100%", height: "100%" } }) }), size === "full" && (jsxRuntime.jsx("div", { className: cvaLegend({ legendPosition }), "data-testid": "legend", children: limitedData.map((item, index) => (jsxRuntime.jsx(LegendItem, { className: "p-1.5 py-0.5", color: item.color ?? chartColor(index), count: item.count, dataTestId: `legend-${item.id}`, disabled: item.count === 0, label: item.name, onClick: onClick ? () => onClick(item) : undefined, onMouseEnter: () => handleLegendMouseEnter(item), onMouseLeave: handleLegendMouseLeave, selected: item.selected }, item.id))) }))] }));
|
|
154
403
|
};
|
|
155
|
-
const cvaChartRoot = cssClassVarianceUtilities.cvaMerge([
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
404
|
+
const cvaChartRoot = cssClassVarianceUtilities.cvaMerge(["flex", "w-full", "h-full", "gap-4"], {
|
|
405
|
+
variants: {
|
|
406
|
+
legendPosition: {
|
|
407
|
+
Right: ["items-center", "justify-items-stretch", "flex-row"],
|
|
408
|
+
Bottom: ["items-center", "flex-col"],
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
});
|
|
412
|
+
const cvaChartContainer = cssClassVarianceUtilities.cvaMerge(["flex-1", "h-full"], {
|
|
413
|
+
variants: {
|
|
414
|
+
legendPosition: {
|
|
415
|
+
Right: ["justify-end"],
|
|
416
|
+
Bottom: ["flex", "items-center", "w-full"],
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
});
|
|
420
|
+
const cvaChart = cssClassVarianceUtilities.cvaMerge(["flex-0", "max-w-[200px]", "max-h-[200px]", "place-self-center"], {
|
|
421
|
+
variants: {
|
|
422
|
+
legendPosition: {
|
|
423
|
+
Right: [],
|
|
424
|
+
Bottom: ["max-h-[230px]"],
|
|
425
|
+
},
|
|
426
|
+
size: {
|
|
427
|
+
full: ["min-h-[140px]"],
|
|
428
|
+
compact: ["w-[60px]", "h-[60px]"],
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
defaultVariants: {
|
|
432
|
+
size: "full",
|
|
433
|
+
},
|
|
434
|
+
});
|
|
435
|
+
const cvaLegend = cssClassVarianceUtilities.cvaMerge(["flex", "overflow-auto"], {
|
|
436
|
+
variants: {
|
|
437
|
+
legendPosition: {
|
|
438
|
+
Right: ["justify-start", "flex-col", "flex-1"],
|
|
439
|
+
Bottom: ["flex-wrap", "justify-end", "flex-row"],
|
|
440
|
+
},
|
|
441
|
+
},
|
|
442
|
+
defaultVariants: {
|
|
443
|
+
legendPosition: "Right",
|
|
444
|
+
},
|
|
445
|
+
});
|
|
163
446
|
|
|
164
447
|
exports.Chart = Chart;
|
|
448
|
+
exports.DonutChart = DonutChart;
|
|
165
449
|
exports.LegendItem = LegendItem;
|
|
166
|
-
exports.
|
|
450
|
+
exports.useChartColor = useChartColor;
|