@x-plat/design-system 0.5.13 → 0.5.15
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/dist/components/Chart/index.cjs +62 -37
- package/dist/components/Chart/index.css +2 -0
- package/dist/components/Chart/index.d.cts +1 -1
- package/dist/components/Chart/index.d.ts +1 -1
- package/dist/components/Chart/index.js +62 -37
- package/dist/components/index.cjs +62 -37
- package/dist/components/index.css +2 -0
- package/dist/components/index.js +62 -37
- package/dist/index.cjs +62 -37
- package/dist/index.css +2 -0
- package/dist/index.js +62 -37
- package/package.json +1 -1
|
@@ -80,26 +80,47 @@ var toSmoothPath = (points) => {
|
|
|
80
80
|
}
|
|
81
81
|
return d;
|
|
82
82
|
};
|
|
83
|
+
var RESIZE_SETTLE_MS = 150;
|
|
83
84
|
var useChartSize = (ref) => {
|
|
84
85
|
const [size, setSize] = import_react.default.useState({ width: 0, height: 0 });
|
|
86
|
+
const settleTimer = import_react.default.useRef(0);
|
|
87
|
+
const committedSize = import_react.default.useRef({ width: 0, height: 0 });
|
|
88
|
+
const initialRef = import_react.default.useRef(true);
|
|
85
89
|
import_react.default.useEffect(() => {
|
|
86
90
|
const el = ref.current;
|
|
87
91
|
if (!el) return;
|
|
88
|
-
let rafId = 0;
|
|
89
92
|
const observer = new ResizeObserver((entries) => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
93
|
+
const entry = entries[0];
|
|
94
|
+
if (!entry) return;
|
|
95
|
+
const { width, height } = entry.contentRect;
|
|
96
|
+
const w = Math.floor(width);
|
|
97
|
+
const h = Math.floor(height);
|
|
98
|
+
if (w <= 0 || h <= 0) return;
|
|
99
|
+
if (w === committedSize.current.width && h === committedSize.current.height) return;
|
|
100
|
+
if (initialRef.current) {
|
|
101
|
+
initialRef.current = false;
|
|
102
|
+
committedSize.current = { width: w, height: h };
|
|
103
|
+
setSize({ width: w, height: h });
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const prev = committedSize.current;
|
|
107
|
+
if (el.firstElementChild && prev.width > 0 && prev.height > 0) {
|
|
108
|
+
const svg = el.firstElementChild;
|
|
109
|
+
svg.style.transformOrigin = "0 0";
|
|
110
|
+
svg.style.transform = `scale(${w / prev.width}, ${h / prev.height})`;
|
|
111
|
+
}
|
|
112
|
+
window.clearTimeout(settleTimer.current);
|
|
113
|
+
settleTimer.current = window.setTimeout(() => {
|
|
114
|
+
if (el.firstElementChild) {
|
|
115
|
+
el.firstElementChild.style.transform = "";
|
|
116
|
+
}
|
|
117
|
+
committedSize.current = { width: w, height: h };
|
|
118
|
+
setSize({ width: w, height: h });
|
|
119
|
+
}, RESIZE_SETTLE_MS);
|
|
99
120
|
});
|
|
100
121
|
observer.observe(el);
|
|
101
122
|
return () => {
|
|
102
|
-
|
|
123
|
+
window.clearTimeout(settleTimer.current);
|
|
103
124
|
observer.disconnect();
|
|
104
125
|
};
|
|
105
126
|
}, [ref]);
|
|
@@ -294,17 +315,19 @@ var BarChart = import_react.default.memo(({ data, labels, width, height, onHover
|
|
|
294
315
|
const chartW = width - PADDING.left - PADDING.right;
|
|
295
316
|
const chartH = height - PADDING.top - PADDING.bottom;
|
|
296
317
|
const groupW = chartW / count;
|
|
297
|
-
const
|
|
318
|
+
const barGap = groupCount > 1 ? 2 : 0;
|
|
319
|
+
const barW = Math.max(1, Math.min(32, (groupW * 0.7 - barGap * (groupCount - 1)) / groupCount));
|
|
298
320
|
const bars = import_react.default.useMemo(
|
|
299
321
|
() => entries.map(
|
|
300
322
|
([, values], di) => values.map((v, i) => {
|
|
323
|
+
const totalBarsW = barW * groupCount + barGap * (groupCount - 1);
|
|
301
324
|
const h = Math.max(0, v / maxVal * chartH);
|
|
302
|
-
const x = PADDING.left + groupW * i + (groupW -
|
|
325
|
+
const x = PADDING.left + groupW * i + (groupW - totalBarsW) / 2 + (barW + barGap) * di;
|
|
303
326
|
const y = PADDING.top + chartH - h;
|
|
304
327
|
return { x, y, w: barW, h, v };
|
|
305
328
|
})
|
|
306
329
|
),
|
|
307
|
-
[entries, maxVal, chartH, groupW, barW, groupCount]
|
|
330
|
+
[entries, maxVal, chartH, groupW, barW, barGap, groupCount]
|
|
308
331
|
);
|
|
309
332
|
const barLabelStep = getLabelStep(count, chartW);
|
|
310
333
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
|
|
@@ -316,22 +339,22 @@ var BarChart = import_react.default.memo(({ data, labels, width, height, onHover
|
|
|
316
339
|
entries.map(([key], di) => {
|
|
317
340
|
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
318
341
|
const color = palette[2];
|
|
319
|
-
return bars[di].map((b, i) =>
|
|
320
|
-
|
|
321
|
-
{
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
)
|
|
342
|
+
return bars[di].map((b, i) => {
|
|
343
|
+
const r = Math.min(4, b.w / 2);
|
|
344
|
+
const d = b.h <= r ? `M ${b.x} ${b.y + b.h} V ${b.y} H ${b.x + b.w} V ${b.y + b.h} Z` : `M ${b.x} ${b.y + b.h} V ${b.y + r} Q ${b.x} ${b.y} ${b.x + r} ${b.y} H ${b.x + b.w - r} Q ${b.x + b.w} ${b.y} ${b.x + b.w} ${b.y + r} V ${b.y + b.h} Z`;
|
|
345
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
346
|
+
"path",
|
|
347
|
+
{
|
|
348
|
+
d,
|
|
349
|
+
fill: color,
|
|
350
|
+
className: "chart-bar",
|
|
351
|
+
onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
|
|
352
|
+
onMouseMove: onMove,
|
|
353
|
+
onMouseLeave: onLeave
|
|
354
|
+
},
|
|
355
|
+
`${di}-${i}`
|
|
356
|
+
);
|
|
357
|
+
});
|
|
335
358
|
})
|
|
336
359
|
] });
|
|
337
360
|
});
|
|
@@ -418,20 +441,22 @@ var TooltipBubble = ({ x, y, containerWidth, children }) => {
|
|
|
418
441
|
}
|
|
419
442
|
);
|
|
420
443
|
};
|
|
421
|
-
var Chart = (props) => {
|
|
444
|
+
var Chart = import_react.default.memo((props) => {
|
|
422
445
|
const { type, data, labels, tooltip: showTooltip = true } = props;
|
|
423
446
|
const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
|
|
424
447
|
const { width, height } = useChartSize(containerRef);
|
|
448
|
+
const stableData = import_react.default.useMemo(() => data, [JSON.stringify(data)]);
|
|
449
|
+
const stableLabels = import_react.default.useMemo(() => labels, [JSON.stringify(labels)]);
|
|
425
450
|
const ready = width > 0 && height > 0;
|
|
426
451
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "lib-xplat-chart", ref: containerRef, children: [
|
|
427
|
-
ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LineChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
428
|
-
ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CurveChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
429
|
-
ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BarChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
430
|
-
ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
431
|
-
ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data, labels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
452
|
+
ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LineChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
453
|
+
ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CurveChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
454
|
+
ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
455
|
+
ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
456
|
+
ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
432
457
|
tooltip.visible && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TooltipBubble, { x: tooltip.x, y: tooltip.y, containerWidth: width, children: tooltip.content })
|
|
433
458
|
] });
|
|
434
|
-
};
|
|
459
|
+
});
|
|
435
460
|
Chart.displayName = "Chart";
|
|
436
461
|
var Chart_default = Chart;
|
|
437
462
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -44,26 +44,47 @@ var toSmoothPath = (points) => {
|
|
|
44
44
|
}
|
|
45
45
|
return d;
|
|
46
46
|
};
|
|
47
|
+
var RESIZE_SETTLE_MS = 150;
|
|
47
48
|
var useChartSize = (ref) => {
|
|
48
49
|
const [size, setSize] = React.useState({ width: 0, height: 0 });
|
|
50
|
+
const settleTimer = React.useRef(0);
|
|
51
|
+
const committedSize = React.useRef({ width: 0, height: 0 });
|
|
52
|
+
const initialRef = React.useRef(true);
|
|
49
53
|
React.useEffect(() => {
|
|
50
54
|
const el = ref.current;
|
|
51
55
|
if (!el) return;
|
|
52
|
-
let rafId = 0;
|
|
53
56
|
const observer = new ResizeObserver((entries) => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
const entry = entries[0];
|
|
58
|
+
if (!entry) return;
|
|
59
|
+
const { width, height } = entry.contentRect;
|
|
60
|
+
const w = Math.floor(width);
|
|
61
|
+
const h = Math.floor(height);
|
|
62
|
+
if (w <= 0 || h <= 0) return;
|
|
63
|
+
if (w === committedSize.current.width && h === committedSize.current.height) return;
|
|
64
|
+
if (initialRef.current) {
|
|
65
|
+
initialRef.current = false;
|
|
66
|
+
committedSize.current = { width: w, height: h };
|
|
67
|
+
setSize({ width: w, height: h });
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const prev = committedSize.current;
|
|
71
|
+
if (el.firstElementChild && prev.width > 0 && prev.height > 0) {
|
|
72
|
+
const svg = el.firstElementChild;
|
|
73
|
+
svg.style.transformOrigin = "0 0";
|
|
74
|
+
svg.style.transform = `scale(${w / prev.width}, ${h / prev.height})`;
|
|
75
|
+
}
|
|
76
|
+
window.clearTimeout(settleTimer.current);
|
|
77
|
+
settleTimer.current = window.setTimeout(() => {
|
|
78
|
+
if (el.firstElementChild) {
|
|
79
|
+
el.firstElementChild.style.transform = "";
|
|
80
|
+
}
|
|
81
|
+
committedSize.current = { width: w, height: h };
|
|
82
|
+
setSize({ width: w, height: h });
|
|
83
|
+
}, RESIZE_SETTLE_MS);
|
|
63
84
|
});
|
|
64
85
|
observer.observe(el);
|
|
65
86
|
return () => {
|
|
66
|
-
|
|
87
|
+
window.clearTimeout(settleTimer.current);
|
|
67
88
|
observer.disconnect();
|
|
68
89
|
};
|
|
69
90
|
}, [ref]);
|
|
@@ -258,17 +279,19 @@ var BarChart = React.memo(({ data, labels, width, height, onHover, onMove, onLea
|
|
|
258
279
|
const chartW = width - PADDING.left - PADDING.right;
|
|
259
280
|
const chartH = height - PADDING.top - PADDING.bottom;
|
|
260
281
|
const groupW = chartW / count;
|
|
261
|
-
const
|
|
282
|
+
const barGap = groupCount > 1 ? 2 : 0;
|
|
283
|
+
const barW = Math.max(1, Math.min(32, (groupW * 0.7 - barGap * (groupCount - 1)) / groupCount));
|
|
262
284
|
const bars = React.useMemo(
|
|
263
285
|
() => entries.map(
|
|
264
286
|
([, values], di) => values.map((v, i) => {
|
|
287
|
+
const totalBarsW = barW * groupCount + barGap * (groupCount - 1);
|
|
265
288
|
const h = Math.max(0, v / maxVal * chartH);
|
|
266
|
-
const x = PADDING.left + groupW * i + (groupW -
|
|
289
|
+
const x = PADDING.left + groupW * i + (groupW - totalBarsW) / 2 + (barW + barGap) * di;
|
|
267
290
|
const y = PADDING.top + chartH - h;
|
|
268
291
|
return { x, y, w: barW, h, v };
|
|
269
292
|
})
|
|
270
293
|
),
|
|
271
|
-
[entries, maxVal, chartH, groupW, barW, groupCount]
|
|
294
|
+
[entries, maxVal, chartH, groupW, barW, barGap, groupCount]
|
|
272
295
|
);
|
|
273
296
|
const barLabelStep = getLabelStep(count, chartW);
|
|
274
297
|
return /* @__PURE__ */ jsxs("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
|
|
@@ -280,22 +303,22 @@ var BarChart = React.memo(({ data, labels, width, height, onHover, onMove, onLea
|
|
|
280
303
|
entries.map(([key], di) => {
|
|
281
304
|
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
282
305
|
const color = palette[2];
|
|
283
|
-
return bars[di].map((b, i) =>
|
|
284
|
-
|
|
285
|
-
{
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
)
|
|
306
|
+
return bars[di].map((b, i) => {
|
|
307
|
+
const r = Math.min(4, b.w / 2);
|
|
308
|
+
const d = b.h <= r ? `M ${b.x} ${b.y + b.h} V ${b.y} H ${b.x + b.w} V ${b.y + b.h} Z` : `M ${b.x} ${b.y + b.h} V ${b.y + r} Q ${b.x} ${b.y} ${b.x + r} ${b.y} H ${b.x + b.w - r} Q ${b.x + b.w} ${b.y} ${b.x + b.w} ${b.y + r} V ${b.y + b.h} Z`;
|
|
309
|
+
return /* @__PURE__ */ jsx(
|
|
310
|
+
"path",
|
|
311
|
+
{
|
|
312
|
+
d,
|
|
313
|
+
fill: color,
|
|
314
|
+
className: "chart-bar",
|
|
315
|
+
onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
|
|
316
|
+
onMouseMove: onMove,
|
|
317
|
+
onMouseLeave: onLeave
|
|
318
|
+
},
|
|
319
|
+
`${di}-${i}`
|
|
320
|
+
);
|
|
321
|
+
});
|
|
299
322
|
})
|
|
300
323
|
] });
|
|
301
324
|
});
|
|
@@ -382,20 +405,22 @@ var TooltipBubble = ({ x, y, containerWidth, children }) => {
|
|
|
382
405
|
}
|
|
383
406
|
);
|
|
384
407
|
};
|
|
385
|
-
var Chart = (props) => {
|
|
408
|
+
var Chart = React.memo((props) => {
|
|
386
409
|
const { type, data, labels, tooltip: showTooltip = true } = props;
|
|
387
410
|
const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
|
|
388
411
|
const { width, height } = useChartSize(containerRef);
|
|
412
|
+
const stableData = React.useMemo(() => data, [JSON.stringify(data)]);
|
|
413
|
+
const stableLabels = React.useMemo(() => labels, [JSON.stringify(labels)]);
|
|
389
414
|
const ready = width > 0 && height > 0;
|
|
390
415
|
return /* @__PURE__ */ jsxs("div", { className: "lib-xplat-chart", ref: containerRef, children: [
|
|
391
|
-
ready && type === "line" && /* @__PURE__ */ jsx(LineChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
392
|
-
ready && type === "curve" && /* @__PURE__ */ jsx(CurveChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
393
|
-
ready && type === "bar" && /* @__PURE__ */ jsx(BarChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
394
|
-
ready && type === "pie" && /* @__PURE__ */ jsx(PieDonutChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
395
|
-
ready && type === "doughnut" && /* @__PURE__ */ jsx(PieDonutChart, { data, labels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
416
|
+
ready && type === "line" && /* @__PURE__ */ jsx(LineChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
417
|
+
ready && type === "curve" && /* @__PURE__ */ jsx(CurveChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
418
|
+
ready && type === "bar" && /* @__PURE__ */ jsx(BarChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
419
|
+
ready && type === "pie" && /* @__PURE__ */ jsx(PieDonutChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
420
|
+
ready && type === "doughnut" && /* @__PURE__ */ jsx(PieDonutChart, { data: stableData, labels: stableLabels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
396
421
|
tooltip.visible && /* @__PURE__ */ jsx(TooltipBubble, { x: tooltip.x, y: tooltip.y, containerWidth: width, children: tooltip.content })
|
|
397
422
|
] });
|
|
398
|
-
};
|
|
423
|
+
});
|
|
399
424
|
Chart.displayName = "Chart";
|
|
400
425
|
var Chart_default = Chart;
|
|
401
426
|
export {
|
|
@@ -2151,26 +2151,47 @@ var toSmoothPath = (points) => {
|
|
|
2151
2151
|
}
|
|
2152
2152
|
return d;
|
|
2153
2153
|
};
|
|
2154
|
+
var RESIZE_SETTLE_MS = 150;
|
|
2154
2155
|
var useChartSize = (ref) => {
|
|
2155
2156
|
const [size, setSize] = import_react5.default.useState({ width: 0, height: 0 });
|
|
2157
|
+
const settleTimer = import_react5.default.useRef(0);
|
|
2158
|
+
const committedSize = import_react5.default.useRef({ width: 0, height: 0 });
|
|
2159
|
+
const initialRef = import_react5.default.useRef(true);
|
|
2156
2160
|
import_react5.default.useEffect(() => {
|
|
2157
2161
|
const el = ref.current;
|
|
2158
2162
|
if (!el) return;
|
|
2159
|
-
let rafId = 0;
|
|
2160
2163
|
const observer = new ResizeObserver((entries) => {
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2164
|
+
const entry = entries[0];
|
|
2165
|
+
if (!entry) return;
|
|
2166
|
+
const { width, height } = entry.contentRect;
|
|
2167
|
+
const w = Math.floor(width);
|
|
2168
|
+
const h = Math.floor(height);
|
|
2169
|
+
if (w <= 0 || h <= 0) return;
|
|
2170
|
+
if (w === committedSize.current.width && h === committedSize.current.height) return;
|
|
2171
|
+
if (initialRef.current) {
|
|
2172
|
+
initialRef.current = false;
|
|
2173
|
+
committedSize.current = { width: w, height: h };
|
|
2174
|
+
setSize({ width: w, height: h });
|
|
2175
|
+
return;
|
|
2176
|
+
}
|
|
2177
|
+
const prev = committedSize.current;
|
|
2178
|
+
if (el.firstElementChild && prev.width > 0 && prev.height > 0) {
|
|
2179
|
+
const svg = el.firstElementChild;
|
|
2180
|
+
svg.style.transformOrigin = "0 0";
|
|
2181
|
+
svg.style.transform = `scale(${w / prev.width}, ${h / prev.height})`;
|
|
2182
|
+
}
|
|
2183
|
+
window.clearTimeout(settleTimer.current);
|
|
2184
|
+
settleTimer.current = window.setTimeout(() => {
|
|
2185
|
+
if (el.firstElementChild) {
|
|
2186
|
+
el.firstElementChild.style.transform = "";
|
|
2187
|
+
}
|
|
2188
|
+
committedSize.current = { width: w, height: h };
|
|
2189
|
+
setSize({ width: w, height: h });
|
|
2190
|
+
}, RESIZE_SETTLE_MS);
|
|
2170
2191
|
});
|
|
2171
2192
|
observer.observe(el);
|
|
2172
2193
|
return () => {
|
|
2173
|
-
|
|
2194
|
+
window.clearTimeout(settleTimer.current);
|
|
2174
2195
|
observer.disconnect();
|
|
2175
2196
|
};
|
|
2176
2197
|
}, [ref]);
|
|
@@ -2365,17 +2386,19 @@ var BarChart = import_react5.default.memo(({ data, labels, width, height, onHove
|
|
|
2365
2386
|
const chartW = width - PADDING.left - PADDING.right;
|
|
2366
2387
|
const chartH = height - PADDING.top - PADDING.bottom;
|
|
2367
2388
|
const groupW = chartW / count;
|
|
2368
|
-
const
|
|
2389
|
+
const barGap = groupCount > 1 ? 2 : 0;
|
|
2390
|
+
const barW = Math.max(1, Math.min(32, (groupW * 0.7 - barGap * (groupCount - 1)) / groupCount));
|
|
2369
2391
|
const bars = import_react5.default.useMemo(
|
|
2370
2392
|
() => entries.map(
|
|
2371
2393
|
([, values], di) => values.map((v, i) => {
|
|
2394
|
+
const totalBarsW = barW * groupCount + barGap * (groupCount - 1);
|
|
2372
2395
|
const h = Math.max(0, v / maxVal * chartH);
|
|
2373
|
-
const x = PADDING.left + groupW * i + (groupW -
|
|
2396
|
+
const x = PADDING.left + groupW * i + (groupW - totalBarsW) / 2 + (barW + barGap) * di;
|
|
2374
2397
|
const y = PADDING.top + chartH - h;
|
|
2375
2398
|
return { x, y, w: barW, h, v };
|
|
2376
2399
|
})
|
|
2377
2400
|
),
|
|
2378
|
-
[entries, maxVal, chartH, groupW, barW, groupCount]
|
|
2401
|
+
[entries, maxVal, chartH, groupW, barW, barGap, groupCount]
|
|
2379
2402
|
);
|
|
2380
2403
|
const barLabelStep = getLabelStep(count, chartW);
|
|
2381
2404
|
return /* @__PURE__ */ (0, import_jsx_runtime305.jsxs)("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
|
|
@@ -2387,22 +2410,22 @@ var BarChart = import_react5.default.memo(({ data, labels, width, height, onHove
|
|
|
2387
2410
|
entries.map(([key], di) => {
|
|
2388
2411
|
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
2389
2412
|
const color = palette[2];
|
|
2390
|
-
return bars[di].map((b, i) =>
|
|
2391
|
-
|
|
2392
|
-
{
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
)
|
|
2413
|
+
return bars[di].map((b, i) => {
|
|
2414
|
+
const r2 = Math.min(4, b.w / 2);
|
|
2415
|
+
const d = b.h <= r2 ? `M ${b.x} ${b.y + b.h} V ${b.y} H ${b.x + b.w} V ${b.y + b.h} Z` : `M ${b.x} ${b.y + b.h} V ${b.y + r2} Q ${b.x} ${b.y} ${b.x + r2} ${b.y} H ${b.x + b.w - r2} Q ${b.x + b.w} ${b.y} ${b.x + b.w} ${b.y + r2} V ${b.y + b.h} Z`;
|
|
2416
|
+
return /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(
|
|
2417
|
+
"path",
|
|
2418
|
+
{
|
|
2419
|
+
d,
|
|
2420
|
+
fill: color,
|
|
2421
|
+
className: "chart-bar",
|
|
2422
|
+
onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
|
|
2423
|
+
onMouseMove: onMove,
|
|
2424
|
+
onMouseLeave: onLeave
|
|
2425
|
+
},
|
|
2426
|
+
`${di}-${i}`
|
|
2427
|
+
);
|
|
2428
|
+
});
|
|
2406
2429
|
})
|
|
2407
2430
|
] });
|
|
2408
2431
|
});
|
|
@@ -2489,20 +2512,22 @@ var TooltipBubble = ({ x, y, containerWidth, children }) => {
|
|
|
2489
2512
|
}
|
|
2490
2513
|
);
|
|
2491
2514
|
};
|
|
2492
|
-
var Chart = (props) => {
|
|
2515
|
+
var Chart = import_react5.default.memo((props) => {
|
|
2493
2516
|
const { type, data, labels, tooltip: showTooltip = true } = props;
|
|
2494
2517
|
const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
|
|
2495
2518
|
const { width, height } = useChartSize(containerRef);
|
|
2519
|
+
const stableData = import_react5.default.useMemo(() => data, [JSON.stringify(data)]);
|
|
2520
|
+
const stableLabels = import_react5.default.useMemo(() => labels, [JSON.stringify(labels)]);
|
|
2496
2521
|
const ready = width > 0 && height > 0;
|
|
2497
2522
|
return /* @__PURE__ */ (0, import_jsx_runtime305.jsxs)("div", { className: "lib-xplat-chart", ref: containerRef, children: [
|
|
2498
|
-
ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(LineChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
2499
|
-
ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(CurveChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
2500
|
-
ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(BarChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
2501
|
-
ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(PieDonutChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
2502
|
-
ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(PieDonutChart, { data, labels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
2523
|
+
ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(LineChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
2524
|
+
ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(CurveChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
2525
|
+
ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
2526
|
+
ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
2527
|
+
ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
2503
2528
|
tooltip.visible && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(TooltipBubble, { x: tooltip.x, y: tooltip.y, containerWidth: width, children: tooltip.content })
|
|
2504
2529
|
] });
|
|
2505
|
-
};
|
|
2530
|
+
});
|
|
2506
2531
|
Chart.displayName = "Chart";
|
|
2507
2532
|
var Chart_default = Chart;
|
|
2508
2533
|
|
package/dist/components/index.js
CHANGED
|
@@ -2063,26 +2063,47 @@ var toSmoothPath = (points) => {
|
|
|
2063
2063
|
}
|
|
2064
2064
|
return d;
|
|
2065
2065
|
};
|
|
2066
|
+
var RESIZE_SETTLE_MS = 150;
|
|
2066
2067
|
var useChartSize = (ref) => {
|
|
2067
2068
|
const [size, setSize] = React5.useState({ width: 0, height: 0 });
|
|
2069
|
+
const settleTimer = React5.useRef(0);
|
|
2070
|
+
const committedSize = React5.useRef({ width: 0, height: 0 });
|
|
2071
|
+
const initialRef = React5.useRef(true);
|
|
2068
2072
|
React5.useEffect(() => {
|
|
2069
2073
|
const el = ref.current;
|
|
2070
2074
|
if (!el) return;
|
|
2071
|
-
let rafId = 0;
|
|
2072
2075
|
const observer = new ResizeObserver((entries) => {
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2076
|
+
const entry = entries[0];
|
|
2077
|
+
if (!entry) return;
|
|
2078
|
+
const { width, height } = entry.contentRect;
|
|
2079
|
+
const w = Math.floor(width);
|
|
2080
|
+
const h = Math.floor(height);
|
|
2081
|
+
if (w <= 0 || h <= 0) return;
|
|
2082
|
+
if (w === committedSize.current.width && h === committedSize.current.height) return;
|
|
2083
|
+
if (initialRef.current) {
|
|
2084
|
+
initialRef.current = false;
|
|
2085
|
+
committedSize.current = { width: w, height: h };
|
|
2086
|
+
setSize({ width: w, height: h });
|
|
2087
|
+
return;
|
|
2088
|
+
}
|
|
2089
|
+
const prev = committedSize.current;
|
|
2090
|
+
if (el.firstElementChild && prev.width > 0 && prev.height > 0) {
|
|
2091
|
+
const svg = el.firstElementChild;
|
|
2092
|
+
svg.style.transformOrigin = "0 0";
|
|
2093
|
+
svg.style.transform = `scale(${w / prev.width}, ${h / prev.height})`;
|
|
2094
|
+
}
|
|
2095
|
+
window.clearTimeout(settleTimer.current);
|
|
2096
|
+
settleTimer.current = window.setTimeout(() => {
|
|
2097
|
+
if (el.firstElementChild) {
|
|
2098
|
+
el.firstElementChild.style.transform = "";
|
|
2099
|
+
}
|
|
2100
|
+
committedSize.current = { width: w, height: h };
|
|
2101
|
+
setSize({ width: w, height: h });
|
|
2102
|
+
}, RESIZE_SETTLE_MS);
|
|
2082
2103
|
});
|
|
2083
2104
|
observer.observe(el);
|
|
2084
2105
|
return () => {
|
|
2085
|
-
|
|
2106
|
+
window.clearTimeout(settleTimer.current);
|
|
2086
2107
|
observer.disconnect();
|
|
2087
2108
|
};
|
|
2088
2109
|
}, [ref]);
|
|
@@ -2277,17 +2298,19 @@ var BarChart = React5.memo(({ data, labels, width, height, onHover, onMove, onLe
|
|
|
2277
2298
|
const chartW = width - PADDING.left - PADDING.right;
|
|
2278
2299
|
const chartH = height - PADDING.top - PADDING.bottom;
|
|
2279
2300
|
const groupW = chartW / count;
|
|
2280
|
-
const
|
|
2301
|
+
const barGap = groupCount > 1 ? 2 : 0;
|
|
2302
|
+
const barW = Math.max(1, Math.min(32, (groupW * 0.7 - barGap * (groupCount - 1)) / groupCount));
|
|
2281
2303
|
const bars = React5.useMemo(
|
|
2282
2304
|
() => entries.map(
|
|
2283
2305
|
([, values], di) => values.map((v, i) => {
|
|
2306
|
+
const totalBarsW = barW * groupCount + barGap * (groupCount - 1);
|
|
2284
2307
|
const h = Math.max(0, v / maxVal * chartH);
|
|
2285
|
-
const x = PADDING.left + groupW * i + (groupW -
|
|
2308
|
+
const x = PADDING.left + groupW * i + (groupW - totalBarsW) / 2 + (barW + barGap) * di;
|
|
2286
2309
|
const y = PADDING.top + chartH - h;
|
|
2287
2310
|
return { x, y, w: barW, h, v };
|
|
2288
2311
|
})
|
|
2289
2312
|
),
|
|
2290
|
-
[entries, maxVal, chartH, groupW, barW, groupCount]
|
|
2313
|
+
[entries, maxVal, chartH, groupW, barW, barGap, groupCount]
|
|
2291
2314
|
);
|
|
2292
2315
|
const barLabelStep = getLabelStep(count, chartW);
|
|
2293
2316
|
return /* @__PURE__ */ jsxs196("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
|
|
@@ -2299,22 +2322,22 @@ var BarChart = React5.memo(({ data, labels, width, height, onHover, onMove, onLe
|
|
|
2299
2322
|
entries.map(([key], di) => {
|
|
2300
2323
|
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
2301
2324
|
const color = palette[2];
|
|
2302
|
-
return bars[di].map((b, i) =>
|
|
2303
|
-
|
|
2304
|
-
{
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
)
|
|
2325
|
+
return bars[di].map((b, i) => {
|
|
2326
|
+
const r2 = Math.min(4, b.w / 2);
|
|
2327
|
+
const d = b.h <= r2 ? `M ${b.x} ${b.y + b.h} V ${b.y} H ${b.x + b.w} V ${b.y + b.h} Z` : `M ${b.x} ${b.y + b.h} V ${b.y + r2} Q ${b.x} ${b.y} ${b.x + r2} ${b.y} H ${b.x + b.w - r2} Q ${b.x + b.w} ${b.y} ${b.x + b.w} ${b.y + r2} V ${b.y + b.h} Z`;
|
|
2328
|
+
return /* @__PURE__ */ jsx305(
|
|
2329
|
+
"path",
|
|
2330
|
+
{
|
|
2331
|
+
d,
|
|
2332
|
+
fill: color,
|
|
2333
|
+
className: "chart-bar",
|
|
2334
|
+
onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
|
|
2335
|
+
onMouseMove: onMove,
|
|
2336
|
+
onMouseLeave: onLeave
|
|
2337
|
+
},
|
|
2338
|
+
`${di}-${i}`
|
|
2339
|
+
);
|
|
2340
|
+
});
|
|
2318
2341
|
})
|
|
2319
2342
|
] });
|
|
2320
2343
|
});
|
|
@@ -2401,20 +2424,22 @@ var TooltipBubble = ({ x, y, containerWidth, children }) => {
|
|
|
2401
2424
|
}
|
|
2402
2425
|
);
|
|
2403
2426
|
};
|
|
2404
|
-
var Chart = (props) => {
|
|
2427
|
+
var Chart = React5.memo((props) => {
|
|
2405
2428
|
const { type, data, labels, tooltip: showTooltip = true } = props;
|
|
2406
2429
|
const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
|
|
2407
2430
|
const { width, height } = useChartSize(containerRef);
|
|
2431
|
+
const stableData = React5.useMemo(() => data, [JSON.stringify(data)]);
|
|
2432
|
+
const stableLabels = React5.useMemo(() => labels, [JSON.stringify(labels)]);
|
|
2408
2433
|
const ready = width > 0 && height > 0;
|
|
2409
2434
|
return /* @__PURE__ */ jsxs196("div", { className: "lib-xplat-chart", ref: containerRef, children: [
|
|
2410
|
-
ready && type === "line" && /* @__PURE__ */ jsx305(LineChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
2411
|
-
ready && type === "curve" && /* @__PURE__ */ jsx305(CurveChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
2412
|
-
ready && type === "bar" && /* @__PURE__ */ jsx305(BarChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
2413
|
-
ready && type === "pie" && /* @__PURE__ */ jsx305(PieDonutChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
2414
|
-
ready && type === "doughnut" && /* @__PURE__ */ jsx305(PieDonutChart, { data, labels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
2435
|
+
ready && type === "line" && /* @__PURE__ */ jsx305(LineChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
2436
|
+
ready && type === "curve" && /* @__PURE__ */ jsx305(CurveChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
2437
|
+
ready && type === "bar" && /* @__PURE__ */ jsx305(BarChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
2438
|
+
ready && type === "pie" && /* @__PURE__ */ jsx305(PieDonutChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
2439
|
+
ready && type === "doughnut" && /* @__PURE__ */ jsx305(PieDonutChart, { data: stableData, labels: stableLabels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
2415
2440
|
tooltip.visible && /* @__PURE__ */ jsx305(TooltipBubble, { x: tooltip.x, y: tooltip.y, containerWidth: width, children: tooltip.content })
|
|
2416
2441
|
] });
|
|
2417
|
-
};
|
|
2442
|
+
});
|
|
2418
2443
|
Chart.displayName = "Chart";
|
|
2419
2444
|
var Chart_default = Chart;
|
|
2420
2445
|
|
package/dist/index.cjs
CHANGED
|
@@ -6562,26 +6562,47 @@ var toSmoothPath = (points) => {
|
|
|
6562
6562
|
}
|
|
6563
6563
|
return d;
|
|
6564
6564
|
};
|
|
6565
|
+
var RESIZE_SETTLE_MS = 150;
|
|
6565
6566
|
var useChartSize = (ref) => {
|
|
6566
6567
|
const [size, setSize] = import_react5.default.useState({ width: 0, height: 0 });
|
|
6568
|
+
const settleTimer = import_react5.default.useRef(0);
|
|
6569
|
+
const committedSize = import_react5.default.useRef({ width: 0, height: 0 });
|
|
6570
|
+
const initialRef = import_react5.default.useRef(true);
|
|
6567
6571
|
import_react5.default.useEffect(() => {
|
|
6568
6572
|
const el = ref.current;
|
|
6569
6573
|
if (!el) return;
|
|
6570
|
-
let rafId = 0;
|
|
6571
6574
|
const observer = new ResizeObserver((entries) => {
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6575
|
+
const entry = entries[0];
|
|
6576
|
+
if (!entry) return;
|
|
6577
|
+
const { width, height } = entry.contentRect;
|
|
6578
|
+
const w = Math.floor(width);
|
|
6579
|
+
const h = Math.floor(height);
|
|
6580
|
+
if (w <= 0 || h <= 0) return;
|
|
6581
|
+
if (w === committedSize.current.width && h === committedSize.current.height) return;
|
|
6582
|
+
if (initialRef.current) {
|
|
6583
|
+
initialRef.current = false;
|
|
6584
|
+
committedSize.current = { width: w, height: h };
|
|
6585
|
+
setSize({ width: w, height: h });
|
|
6586
|
+
return;
|
|
6587
|
+
}
|
|
6588
|
+
const prev = committedSize.current;
|
|
6589
|
+
if (el.firstElementChild && prev.width > 0 && prev.height > 0) {
|
|
6590
|
+
const svg = el.firstElementChild;
|
|
6591
|
+
svg.style.transformOrigin = "0 0";
|
|
6592
|
+
svg.style.transform = `scale(${w / prev.width}, ${h / prev.height})`;
|
|
6593
|
+
}
|
|
6594
|
+
window.clearTimeout(settleTimer.current);
|
|
6595
|
+
settleTimer.current = window.setTimeout(() => {
|
|
6596
|
+
if (el.firstElementChild) {
|
|
6597
|
+
el.firstElementChild.style.transform = "";
|
|
6598
|
+
}
|
|
6599
|
+
committedSize.current = { width: w, height: h };
|
|
6600
|
+
setSize({ width: w, height: h });
|
|
6601
|
+
}, RESIZE_SETTLE_MS);
|
|
6581
6602
|
});
|
|
6582
6603
|
observer.observe(el);
|
|
6583
6604
|
return () => {
|
|
6584
|
-
|
|
6605
|
+
window.clearTimeout(settleTimer.current);
|
|
6585
6606
|
observer.disconnect();
|
|
6586
6607
|
};
|
|
6587
6608
|
}, [ref]);
|
|
@@ -6776,17 +6797,19 @@ var BarChart = import_react5.default.memo(({ data, labels, width, height, onHove
|
|
|
6776
6797
|
const chartW = width - PADDING.left - PADDING.right;
|
|
6777
6798
|
const chartH = height - PADDING.top - PADDING.bottom;
|
|
6778
6799
|
const groupW = chartW / count;
|
|
6779
|
-
const
|
|
6800
|
+
const barGap = groupCount > 1 ? 2 : 0;
|
|
6801
|
+
const barW = Math.max(1, Math.min(32, (groupW * 0.7 - barGap * (groupCount - 1)) / groupCount));
|
|
6780
6802
|
const bars = import_react5.default.useMemo(
|
|
6781
6803
|
() => entries.map(
|
|
6782
6804
|
([, values], di) => values.map((v, i) => {
|
|
6805
|
+
const totalBarsW = barW * groupCount + barGap * (groupCount - 1);
|
|
6783
6806
|
const h = Math.max(0, v / maxVal * chartH);
|
|
6784
|
-
const x = PADDING.left + groupW * i + (groupW -
|
|
6807
|
+
const x = PADDING.left + groupW * i + (groupW - totalBarsW) / 2 + (barW + barGap) * di;
|
|
6785
6808
|
const y = PADDING.top + chartH - h;
|
|
6786
6809
|
return { x, y, w: barW, h, v };
|
|
6787
6810
|
})
|
|
6788
6811
|
),
|
|
6789
|
-
[entries, maxVal, chartH, groupW, barW, groupCount]
|
|
6812
|
+
[entries, maxVal, chartH, groupW, barW, barGap, groupCount]
|
|
6790
6813
|
);
|
|
6791
6814
|
const barLabelStep = getLabelStep(count, chartW);
|
|
6792
6815
|
return /* @__PURE__ */ (0, import_jsx_runtime305.jsxs)("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
|
|
@@ -6798,22 +6821,22 @@ var BarChart = import_react5.default.memo(({ data, labels, width, height, onHove
|
|
|
6798
6821
|
entries.map(([key], di) => {
|
|
6799
6822
|
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
6800
6823
|
const color = palette[2];
|
|
6801
|
-
return bars[di].map((b, i) =>
|
|
6802
|
-
|
|
6803
|
-
{
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
)
|
|
6824
|
+
return bars[di].map((b, i) => {
|
|
6825
|
+
const r2 = Math.min(4, b.w / 2);
|
|
6826
|
+
const d = b.h <= r2 ? `M ${b.x} ${b.y + b.h} V ${b.y} H ${b.x + b.w} V ${b.y + b.h} Z` : `M ${b.x} ${b.y + b.h} V ${b.y + r2} Q ${b.x} ${b.y} ${b.x + r2} ${b.y} H ${b.x + b.w - r2} Q ${b.x + b.w} ${b.y} ${b.x + b.w} ${b.y + r2} V ${b.y + b.h} Z`;
|
|
6827
|
+
return /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(
|
|
6828
|
+
"path",
|
|
6829
|
+
{
|
|
6830
|
+
d,
|
|
6831
|
+
fill: color,
|
|
6832
|
+
className: "chart-bar",
|
|
6833
|
+
onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
|
|
6834
|
+
onMouseMove: onMove,
|
|
6835
|
+
onMouseLeave: onLeave
|
|
6836
|
+
},
|
|
6837
|
+
`${di}-${i}`
|
|
6838
|
+
);
|
|
6839
|
+
});
|
|
6817
6840
|
})
|
|
6818
6841
|
] });
|
|
6819
6842
|
});
|
|
@@ -6900,20 +6923,22 @@ var TooltipBubble = ({ x, y, containerWidth, children }) => {
|
|
|
6900
6923
|
}
|
|
6901
6924
|
);
|
|
6902
6925
|
};
|
|
6903
|
-
var Chart = (props) => {
|
|
6926
|
+
var Chart = import_react5.default.memo((props) => {
|
|
6904
6927
|
const { type, data, labels, tooltip: showTooltip = true } = props;
|
|
6905
6928
|
const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
|
|
6906
6929
|
const { width, height } = useChartSize(containerRef);
|
|
6930
|
+
const stableData = import_react5.default.useMemo(() => data, [JSON.stringify(data)]);
|
|
6931
|
+
const stableLabels = import_react5.default.useMemo(() => labels, [JSON.stringify(labels)]);
|
|
6907
6932
|
const ready = width > 0 && height > 0;
|
|
6908
6933
|
return /* @__PURE__ */ (0, import_jsx_runtime305.jsxs)("div", { className: "lib-xplat-chart", ref: containerRef, children: [
|
|
6909
|
-
ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(LineChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
6910
|
-
ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(CurveChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
6911
|
-
ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(BarChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
6912
|
-
ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(PieDonutChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
6913
|
-
ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(PieDonutChart, { data, labels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
6934
|
+
ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(LineChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
6935
|
+
ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(CurveChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
6936
|
+
ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
6937
|
+
ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
6938
|
+
ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
6914
6939
|
tooltip.visible && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(TooltipBubble, { x: tooltip.x, y: tooltip.y, containerWidth: width, children: tooltip.content })
|
|
6915
6940
|
] });
|
|
6916
|
-
};
|
|
6941
|
+
});
|
|
6917
6942
|
Chart.displayName = "Chart";
|
|
6918
6943
|
var Chart_default = Chart;
|
|
6919
6944
|
|
package/dist/index.css
CHANGED
package/dist/index.js
CHANGED
|
@@ -6165,26 +6165,47 @@ var toSmoothPath = (points) => {
|
|
|
6165
6165
|
}
|
|
6166
6166
|
return d;
|
|
6167
6167
|
};
|
|
6168
|
+
var RESIZE_SETTLE_MS = 150;
|
|
6168
6169
|
var useChartSize = (ref) => {
|
|
6169
6170
|
const [size, setSize] = React5.useState({ width: 0, height: 0 });
|
|
6171
|
+
const settleTimer = React5.useRef(0);
|
|
6172
|
+
const committedSize = React5.useRef({ width: 0, height: 0 });
|
|
6173
|
+
const initialRef = React5.useRef(true);
|
|
6170
6174
|
React5.useEffect(() => {
|
|
6171
6175
|
const el = ref.current;
|
|
6172
6176
|
if (!el) return;
|
|
6173
|
-
let rafId = 0;
|
|
6174
6177
|
const observer = new ResizeObserver((entries) => {
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6178
|
+
const entry = entries[0];
|
|
6179
|
+
if (!entry) return;
|
|
6180
|
+
const { width, height } = entry.contentRect;
|
|
6181
|
+
const w = Math.floor(width);
|
|
6182
|
+
const h = Math.floor(height);
|
|
6183
|
+
if (w <= 0 || h <= 0) return;
|
|
6184
|
+
if (w === committedSize.current.width && h === committedSize.current.height) return;
|
|
6185
|
+
if (initialRef.current) {
|
|
6186
|
+
initialRef.current = false;
|
|
6187
|
+
committedSize.current = { width: w, height: h };
|
|
6188
|
+
setSize({ width: w, height: h });
|
|
6189
|
+
return;
|
|
6190
|
+
}
|
|
6191
|
+
const prev = committedSize.current;
|
|
6192
|
+
if (el.firstElementChild && prev.width > 0 && prev.height > 0) {
|
|
6193
|
+
const svg = el.firstElementChild;
|
|
6194
|
+
svg.style.transformOrigin = "0 0";
|
|
6195
|
+
svg.style.transform = `scale(${w / prev.width}, ${h / prev.height})`;
|
|
6196
|
+
}
|
|
6197
|
+
window.clearTimeout(settleTimer.current);
|
|
6198
|
+
settleTimer.current = window.setTimeout(() => {
|
|
6199
|
+
if (el.firstElementChild) {
|
|
6200
|
+
el.firstElementChild.style.transform = "";
|
|
6201
|
+
}
|
|
6202
|
+
committedSize.current = { width: w, height: h };
|
|
6203
|
+
setSize({ width: w, height: h });
|
|
6204
|
+
}, RESIZE_SETTLE_MS);
|
|
6184
6205
|
});
|
|
6185
6206
|
observer.observe(el);
|
|
6186
6207
|
return () => {
|
|
6187
|
-
|
|
6208
|
+
window.clearTimeout(settleTimer.current);
|
|
6188
6209
|
observer.disconnect();
|
|
6189
6210
|
};
|
|
6190
6211
|
}, [ref]);
|
|
@@ -6379,17 +6400,19 @@ var BarChart = React5.memo(({ data, labels, width, height, onHover, onMove, onLe
|
|
|
6379
6400
|
const chartW = width - PADDING.left - PADDING.right;
|
|
6380
6401
|
const chartH = height - PADDING.top - PADDING.bottom;
|
|
6381
6402
|
const groupW = chartW / count;
|
|
6382
|
-
const
|
|
6403
|
+
const barGap = groupCount > 1 ? 2 : 0;
|
|
6404
|
+
const barW = Math.max(1, Math.min(32, (groupW * 0.7 - barGap * (groupCount - 1)) / groupCount));
|
|
6383
6405
|
const bars = React5.useMemo(
|
|
6384
6406
|
() => entries.map(
|
|
6385
6407
|
([, values], di) => values.map((v, i) => {
|
|
6408
|
+
const totalBarsW = barW * groupCount + barGap * (groupCount - 1);
|
|
6386
6409
|
const h = Math.max(0, v / maxVal * chartH);
|
|
6387
|
-
const x = PADDING.left + groupW * i + (groupW -
|
|
6410
|
+
const x = PADDING.left + groupW * i + (groupW - totalBarsW) / 2 + (barW + barGap) * di;
|
|
6388
6411
|
const y = PADDING.top + chartH - h;
|
|
6389
6412
|
return { x, y, w: barW, h, v };
|
|
6390
6413
|
})
|
|
6391
6414
|
),
|
|
6392
|
-
[entries, maxVal, chartH, groupW, barW, groupCount]
|
|
6415
|
+
[entries, maxVal, chartH, groupW, barW, barGap, groupCount]
|
|
6393
6416
|
);
|
|
6394
6417
|
const barLabelStep = getLabelStep(count, chartW);
|
|
6395
6418
|
return /* @__PURE__ */ jsxs196("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
|
|
@@ -6401,22 +6424,22 @@ var BarChart = React5.memo(({ data, labels, width, height, onHover, onMove, onLe
|
|
|
6401
6424
|
entries.map(([key], di) => {
|
|
6402
6425
|
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
6403
6426
|
const color = palette[2];
|
|
6404
|
-
return bars[di].map((b, i) =>
|
|
6405
|
-
|
|
6406
|
-
{
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
|
|
6414
|
-
|
|
6415
|
-
|
|
6416
|
-
|
|
6417
|
-
|
|
6418
|
-
|
|
6419
|
-
)
|
|
6427
|
+
return bars[di].map((b, i) => {
|
|
6428
|
+
const r2 = Math.min(4, b.w / 2);
|
|
6429
|
+
const d = b.h <= r2 ? `M ${b.x} ${b.y + b.h} V ${b.y} H ${b.x + b.w} V ${b.y + b.h} Z` : `M ${b.x} ${b.y + b.h} V ${b.y + r2} Q ${b.x} ${b.y} ${b.x + r2} ${b.y} H ${b.x + b.w - r2} Q ${b.x + b.w} ${b.y} ${b.x + b.w} ${b.y + r2} V ${b.y + b.h} Z`;
|
|
6430
|
+
return /* @__PURE__ */ jsx305(
|
|
6431
|
+
"path",
|
|
6432
|
+
{
|
|
6433
|
+
d,
|
|
6434
|
+
fill: color,
|
|
6435
|
+
className: "chart-bar",
|
|
6436
|
+
onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
|
|
6437
|
+
onMouseMove: onMove,
|
|
6438
|
+
onMouseLeave: onLeave
|
|
6439
|
+
},
|
|
6440
|
+
`${di}-${i}`
|
|
6441
|
+
);
|
|
6442
|
+
});
|
|
6420
6443
|
})
|
|
6421
6444
|
] });
|
|
6422
6445
|
});
|
|
@@ -6503,20 +6526,22 @@ var TooltipBubble = ({ x, y, containerWidth, children }) => {
|
|
|
6503
6526
|
}
|
|
6504
6527
|
);
|
|
6505
6528
|
};
|
|
6506
|
-
var Chart = (props) => {
|
|
6529
|
+
var Chart = React5.memo((props) => {
|
|
6507
6530
|
const { type, data, labels, tooltip: showTooltip = true } = props;
|
|
6508
6531
|
const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
|
|
6509
6532
|
const { width, height } = useChartSize(containerRef);
|
|
6533
|
+
const stableData = React5.useMemo(() => data, [JSON.stringify(data)]);
|
|
6534
|
+
const stableLabels = React5.useMemo(() => labels, [JSON.stringify(labels)]);
|
|
6510
6535
|
const ready = width > 0 && height > 0;
|
|
6511
6536
|
return /* @__PURE__ */ jsxs196("div", { className: "lib-xplat-chart", ref: containerRef, children: [
|
|
6512
|
-
ready && type === "line" && /* @__PURE__ */ jsx305(LineChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
6513
|
-
ready && type === "curve" && /* @__PURE__ */ jsx305(CurveChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
6514
|
-
ready && type === "bar" && /* @__PURE__ */ jsx305(BarChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
6515
|
-
ready && type === "pie" && /* @__PURE__ */ jsx305(PieDonutChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
6516
|
-
ready && type === "doughnut" && /* @__PURE__ */ jsx305(PieDonutChart, { data, labels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
6537
|
+
ready && type === "line" && /* @__PURE__ */ jsx305(LineChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
6538
|
+
ready && type === "curve" && /* @__PURE__ */ jsx305(CurveChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
6539
|
+
ready && type === "bar" && /* @__PURE__ */ jsx305(BarChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
6540
|
+
ready && type === "pie" && /* @__PURE__ */ jsx305(PieDonutChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
6541
|
+
ready && type === "doughnut" && /* @__PURE__ */ jsx305(PieDonutChart, { data: stableData, labels: stableLabels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
6517
6542
|
tooltip.visible && /* @__PURE__ */ jsx305(TooltipBubble, { x: tooltip.x, y: tooltip.y, containerWidth: width, children: tooltip.content })
|
|
6518
6543
|
] });
|
|
6519
|
-
};
|
|
6544
|
+
});
|
|
6520
6545
|
Chart.displayName = "Chart";
|
|
6521
6546
|
var Chart_default = Chart;
|
|
6522
6547
|
|