@x-plat/design-system 0.5.31 → 0.5.33
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 +326 -132
- package/dist/components/Chart/index.css +70 -8
- package/dist/components/Chart/index.js +326 -132
- package/dist/components/Table/index.css +4 -0
- package/dist/components/index.cjs +326 -132
- package/dist/components/index.css +74 -8
- package/dist/components/index.js +326 -132
- package/dist/index.cjs +326 -132
- package/dist/index.css +74 -8
- package/dist/index.js +326 -132
- package/package.json +1 -1
|
@@ -2351,40 +2351,28 @@ var useChartAnimation = (containerRef, dataKey) => {
|
|
|
2351
2351
|
}, [dataKey]);
|
|
2352
2352
|
return animate || prefersReducedMotion();
|
|
2353
2353
|
};
|
|
2354
|
+
var TOOLTIP_OFFSET = 12;
|
|
2354
2355
|
var useChartTooltip = (enabled) => {
|
|
2355
2356
|
const [tooltip, setTooltip] = import_react6.default.useState({
|
|
2356
2357
|
visible: false,
|
|
2357
|
-
|
|
2358
|
-
|
|
2358
|
+
clientX: 0,
|
|
2359
|
+
clientY: 0,
|
|
2359
2360
|
content: ""
|
|
2360
2361
|
});
|
|
2361
2362
|
const containerRef = import_react6.default.useRef(null);
|
|
2362
2363
|
const rafRef = import_react6.default.useRef(0);
|
|
2363
2364
|
const move = import_react6.default.useCallback((e) => {
|
|
2364
2365
|
if (!enabled) return;
|
|
2365
|
-
const
|
|
2366
|
-
const
|
|
2366
|
+
const cx = e.clientX;
|
|
2367
|
+
const cy = e.clientY;
|
|
2367
2368
|
cancelAnimationFrame(rafRef.current);
|
|
2368
2369
|
rafRef.current = requestAnimationFrame(() => {
|
|
2369
|
-
|
|
2370
|
-
if (!rect) return;
|
|
2371
|
-
setTooltip((prev) => ({
|
|
2372
|
-
...prev,
|
|
2373
|
-
x: clientX - rect.left,
|
|
2374
|
-
y: clientY - rect.top - 12
|
|
2375
|
-
}));
|
|
2370
|
+
setTooltip((prev) => ({ ...prev, clientX: cx, clientY: cy }));
|
|
2376
2371
|
});
|
|
2377
2372
|
}, [enabled]);
|
|
2378
2373
|
const show = import_react6.default.useCallback((e, content) => {
|
|
2379
2374
|
if (!enabled) return;
|
|
2380
|
-
|
|
2381
|
-
if (!rect) return;
|
|
2382
|
-
setTooltip({
|
|
2383
|
-
visible: true,
|
|
2384
|
-
x: e.clientX - rect.left,
|
|
2385
|
-
y: e.clientY - rect.top - 12,
|
|
2386
|
-
content
|
|
2387
|
-
});
|
|
2375
|
+
setTooltip({ visible: true, clientX: e.clientX, clientY: e.clientY, content });
|
|
2388
2376
|
}, [enabled]);
|
|
2389
2377
|
const hide = import_react6.default.useCallback(() => {
|
|
2390
2378
|
cancelAnimationFrame(rafRef.current);
|
|
@@ -2416,6 +2404,45 @@ var AxisLabels = import_react6.default.memo(({ labels, count, chartW, height })
|
|
|
2416
2404
|
}) });
|
|
2417
2405
|
});
|
|
2418
2406
|
AxisLabels.displayName = "AxisLabels";
|
|
2407
|
+
var useCrosshair = (seriesPoints, entries, labels, chartH) => {
|
|
2408
|
+
const [activeIndex, setActiveIndex] = import_react6.default.useState(null);
|
|
2409
|
+
const handleMouseMove = import_react6.default.useCallback((e) => {
|
|
2410
|
+
const svg = e.currentTarget;
|
|
2411
|
+
const rect = svg.getBoundingClientRect();
|
|
2412
|
+
const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
|
|
2413
|
+
if (seriesPoints.length === 0 || seriesPoints[0].length === 0) return;
|
|
2414
|
+
const points = seriesPoints[0];
|
|
2415
|
+
const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
|
|
2416
|
+
const threshold = step / 2;
|
|
2417
|
+
let closest = 0;
|
|
2418
|
+
let minDist = Math.abs(points[0].x - mx);
|
|
2419
|
+
for (let i = 1; i < points.length; i++) {
|
|
2420
|
+
const dist = Math.abs(points[i].x - mx);
|
|
2421
|
+
if (dist < minDist) {
|
|
2422
|
+
minDist = dist;
|
|
2423
|
+
closest = i;
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2426
|
+
setActiveIndex(minDist <= threshold ? closest : null);
|
|
2427
|
+
}, [seriesPoints]);
|
|
2428
|
+
const handleMouseLeave = import_react6.default.useCallback(() => {
|
|
2429
|
+
setActiveIndex(null);
|
|
2430
|
+
}, []);
|
|
2431
|
+
const tooltipContent = import_react6.default.useMemo(() => {
|
|
2432
|
+
if (activeIndex === null) return "";
|
|
2433
|
+
return entries.map(([key], di) => {
|
|
2434
|
+
const p = seriesPoints[di]?.[activeIndex];
|
|
2435
|
+
return p ? `${key}: ${p.v}` : "";
|
|
2436
|
+
}).filter(Boolean).join(" / ");
|
|
2437
|
+
}, [activeIndex, entries, seriesPoints]);
|
|
2438
|
+
const getTooltipAt = import_react6.default.useCallback((idx) => {
|
|
2439
|
+
return entries.map(([key], di) => {
|
|
2440
|
+
const p = seriesPoints[di]?.[idx];
|
|
2441
|
+
return p ? `${key}: ${p.v}` : "";
|
|
2442
|
+
}).filter(Boolean).join(" / ");
|
|
2443
|
+
}, [entries, seriesPoints]);
|
|
2444
|
+
return { activeIndex, handleMouseMove, handleMouseLeave, tooltipContent, getTooltipAt };
|
|
2445
|
+
};
|
|
2419
2446
|
var LineChart = import_react6.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
2420
2447
|
const entries = import_react6.default.useMemo(() => Object.entries(data), [data]);
|
|
2421
2448
|
const maxVal = import_react6.default.useMemo(() => {
|
|
@@ -2435,8 +2462,9 @@ var LineChart = import_react6.default.memo(({ data, labels, width, height, anima
|
|
|
2435
2462
|
),
|
|
2436
2463
|
[entries, count, chartW, chartH, maxVal]
|
|
2437
2464
|
);
|
|
2438
|
-
const showPoints = count <= 100;
|
|
2439
2465
|
const lineRefs = import_react6.default.useRef([]);
|
|
2466
|
+
const clipRef = import_react6.default.useRef(null);
|
|
2467
|
+
const { activeIndex, handleMouseMove, handleMouseLeave, getTooltipAt } = useCrosshair(seriesPoints, entries, labels, chartH);
|
|
2440
2468
|
import_react6.default.useEffect(() => {
|
|
2441
2469
|
if (!animate) return;
|
|
2442
2470
|
lineRefs.current.forEach((el) => {
|
|
@@ -2449,61 +2477,123 @@ var LineChart = import_react6.default.memo(({ data, labels, width, height, anima
|
|
|
2449
2477
|
el.style.strokeDashoffset = "0";
|
|
2450
2478
|
});
|
|
2451
2479
|
});
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2480
|
+
if (clipRef.current) {
|
|
2481
|
+
clipRef.current.setAttribute("width", "0");
|
|
2482
|
+
requestAnimationFrame(() => {
|
|
2483
|
+
if (clipRef.current) {
|
|
2484
|
+
clipRef.current.style.transition = "width 1200ms ease-out 200ms";
|
|
2485
|
+
clipRef.current.setAttribute("width", `${width}`);
|
|
2486
|
+
}
|
|
2487
|
+
});
|
|
2488
|
+
}
|
|
2489
|
+
}, [animate, seriesPoints, width]);
|
|
2490
|
+
const activeX = activeIndex !== null ? seriesPoints[0]?.[activeIndex]?.x ?? null : null;
|
|
2491
|
+
const lineClipId = "line-area-clip";
|
|
2492
|
+
return /* @__PURE__ */ (0, import_jsx_runtime307.jsxs)(
|
|
2493
|
+
"svg",
|
|
2494
|
+
{
|
|
2495
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
2496
|
+
className: "chart-svg",
|
|
2497
|
+
onMouseMove: (e) => {
|
|
2498
|
+
handleMouseMove(e);
|
|
2499
|
+
const svg = e.currentTarget;
|
|
2500
|
+
const rect = svg.getBoundingClientRect();
|
|
2501
|
+
const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
|
|
2502
|
+
const points = seriesPoints[0];
|
|
2503
|
+
if (!points || points.length === 0) return;
|
|
2504
|
+
const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
|
|
2505
|
+
let closest = 0;
|
|
2506
|
+
let minDist = Math.abs(points[0].x - mx);
|
|
2507
|
+
for (let i = 1; i < points.length; i++) {
|
|
2508
|
+
const dist = Math.abs(points[i].x - mx);
|
|
2509
|
+
if (dist < minDist) {
|
|
2510
|
+
minDist = dist;
|
|
2511
|
+
closest = i;
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
if (minDist <= step / 2) {
|
|
2515
|
+
onHover(e, `${labels[closest]} \u2014 ${getTooltipAt(closest)}`);
|
|
2516
|
+
} else {
|
|
2517
|
+
onLeave();
|
|
2518
|
+
}
|
|
2519
|
+
},
|
|
2520
|
+
onMouseLeave: () => {
|
|
2521
|
+
handleMouseLeave();
|
|
2522
|
+
onLeave();
|
|
2523
|
+
},
|
|
2524
|
+
children: [
|
|
2525
|
+
animate && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime307.jsx)("clipPath", { id: lineClipId, children: /* @__PURE__ */ (0, import_jsx_runtime307.jsx)("rect", { ref: clipRef, x: "0", y: "0", width: animate ? 0 : width, height }) }) }),
|
|
2526
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)(GridLines, { width, height, chartH, maxVal }),
|
|
2527
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)(AxisLabels, { labels, count, chartW, height }),
|
|
2528
|
+
entries.map(([key], di) => {
|
|
2529
|
+
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
2530
|
+
const color = palette[2];
|
|
2531
|
+
const areaColor = palette[0];
|
|
2532
|
+
const points = seriesPoints[di];
|
|
2533
|
+
const gradientId = `line-gradient-${di}`;
|
|
2534
|
+
const polyPoints = points.map((p) => `${p.x},${p.y}`).join(" ");
|
|
2535
|
+
const areaD = `M ${points[0].x},${points[0].y} ${points.map((p) => `L ${p.x},${p.y}`).join(" ")} L ${points[points.length - 1].x},${PADDING.top + chartH} L ${points[0].x},${PADDING.top + chartH} Z`;
|
|
2536
|
+
return /* @__PURE__ */ (0, import_jsx_runtime307.jsxs)("g", { children: [
|
|
2537
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime307.jsxs)("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
|
|
2538
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.2" }),
|
|
2539
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0" })
|
|
2540
|
+
] }) }),
|
|
2541
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)(
|
|
2542
|
+
"path",
|
|
2543
|
+
{
|
|
2544
|
+
d: areaD,
|
|
2545
|
+
fill: `url(#${gradientId})`,
|
|
2546
|
+
clipPath: animate ? `url(#${lineClipId})` : void 0
|
|
2547
|
+
}
|
|
2548
|
+
),
|
|
2549
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)(
|
|
2550
|
+
"polyline",
|
|
2551
|
+
{
|
|
2552
|
+
ref: (el) => {
|
|
2553
|
+
lineRefs.current[di] = el;
|
|
2554
|
+
},
|
|
2555
|
+
points: polyPoints,
|
|
2556
|
+
fill: "none",
|
|
2557
|
+
stroke: color,
|
|
2558
|
+
strokeWidth: "2"
|
|
2559
|
+
}
|
|
2560
|
+
),
|
|
2561
|
+
activeIndex !== null && points[activeIndex] && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(
|
|
2562
|
+
"circle",
|
|
2563
|
+
{
|
|
2564
|
+
cx: points[activeIndex].x,
|
|
2565
|
+
cy: points[activeIndex].y,
|
|
2566
|
+
r: "5",
|
|
2567
|
+
fill: color,
|
|
2568
|
+
className: "chart-point-active"
|
|
2569
|
+
}
|
|
2570
|
+
)
|
|
2571
|
+
] }, di);
|
|
2572
|
+
}),
|
|
2573
|
+
activeX !== null && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(
|
|
2574
|
+
"line",
|
|
2471
2575
|
{
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2576
|
+
x1: activeX,
|
|
2577
|
+
y1: PADDING.top,
|
|
2578
|
+
x2: activeX,
|
|
2579
|
+
y2: PADDING.top + chartH,
|
|
2580
|
+
className: "chart-crosshair"
|
|
2476
2581
|
}
|
|
2477
2582
|
),
|
|
2478
2583
|
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)(
|
|
2479
|
-
"
|
|
2584
|
+
"rect",
|
|
2480
2585
|
{
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
fill: "
|
|
2486
|
-
|
|
2487
|
-
strokeWidth: "2"
|
|
2586
|
+
x: PADDING.left,
|
|
2587
|
+
y: PADDING.top,
|
|
2588
|
+
width: chartW,
|
|
2589
|
+
height: chartH,
|
|
2590
|
+
fill: "transparent",
|
|
2591
|
+
style: { cursor: "crosshair" }
|
|
2488
2592
|
}
|
|
2489
|
-
)
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
cx: p.x,
|
|
2494
|
-
cy: p.y,
|
|
2495
|
-
r: "4",
|
|
2496
|
-
fill: color,
|
|
2497
|
-
className: "chart-point",
|
|
2498
|
-
onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${p.v}`),
|
|
2499
|
-
onMouseMove: onMove,
|
|
2500
|
-
onMouseLeave: onLeave
|
|
2501
|
-
},
|
|
2502
|
-
i
|
|
2503
|
-
))
|
|
2504
|
-
] }, di);
|
|
2505
|
-
})
|
|
2506
|
-
] });
|
|
2593
|
+
)
|
|
2594
|
+
]
|
|
2595
|
+
}
|
|
2596
|
+
);
|
|
2507
2597
|
});
|
|
2508
2598
|
LineChart.displayName = "LineChart";
|
|
2509
2599
|
var CurveChart = import_react6.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
@@ -2525,8 +2615,9 @@ var CurveChart = import_react6.default.memo(({ data, labels, width, height, anim
|
|
|
2525
2615
|
),
|
|
2526
2616
|
[entries, count, chartW, chartH, maxVal]
|
|
2527
2617
|
);
|
|
2528
|
-
const showPoints = count <= 100;
|
|
2529
2618
|
const lineRefs = import_react6.default.useRef([]);
|
|
2619
|
+
const curveClipRef = import_react6.default.useRef(null);
|
|
2620
|
+
const { activeIndex, handleMouseMove, handleMouseLeave, getTooltipAt } = useCrosshair(seriesPoints, entries, labels, chartH);
|
|
2530
2621
|
import_react6.default.useEffect(() => {
|
|
2531
2622
|
if (!animate) return;
|
|
2532
2623
|
lineRefs.current.forEach((el) => {
|
|
@@ -2539,61 +2630,123 @@ var CurveChart = import_react6.default.memo(({ data, labels, width, height, anim
|
|
|
2539
2630
|
el.style.strokeDashoffset = "0";
|
|
2540
2631
|
});
|
|
2541
2632
|
});
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2633
|
+
if (curveClipRef.current) {
|
|
2634
|
+
curveClipRef.current.setAttribute("width", "0");
|
|
2635
|
+
requestAnimationFrame(() => {
|
|
2636
|
+
if (curveClipRef.current) {
|
|
2637
|
+
curveClipRef.current.style.transition = "width 1200ms ease-out 200ms";
|
|
2638
|
+
curveClipRef.current.setAttribute("width", `${width}`);
|
|
2639
|
+
}
|
|
2640
|
+
});
|
|
2641
|
+
}
|
|
2642
|
+
}, [animate, seriesPoints, width]);
|
|
2643
|
+
const activeX = activeIndex !== null ? seriesPoints[0]?.[activeIndex]?.x ?? null : null;
|
|
2644
|
+
const curveClipId = "curve-area-clip";
|
|
2645
|
+
return /* @__PURE__ */ (0, import_jsx_runtime307.jsxs)(
|
|
2646
|
+
"svg",
|
|
2647
|
+
{
|
|
2648
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
2649
|
+
className: "chart-svg",
|
|
2650
|
+
onMouseMove: (e) => {
|
|
2651
|
+
handleMouseMove(e);
|
|
2652
|
+
const svg = e.currentTarget;
|
|
2653
|
+
const rect = svg.getBoundingClientRect();
|
|
2654
|
+
const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
|
|
2655
|
+
const points = seriesPoints[0];
|
|
2656
|
+
if (!points || points.length === 0) return;
|
|
2657
|
+
const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
|
|
2658
|
+
let closest = 0;
|
|
2659
|
+
let minDist = Math.abs(points[0].x - mx);
|
|
2660
|
+
for (let i = 1; i < points.length; i++) {
|
|
2661
|
+
const dist = Math.abs(points[i].x - mx);
|
|
2662
|
+
if (dist < minDist) {
|
|
2663
|
+
minDist = dist;
|
|
2664
|
+
closest = i;
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
if (minDist <= step / 2) {
|
|
2668
|
+
onHover(e, `${labels[closest]} \u2014 ${getTooltipAt(closest)}`);
|
|
2669
|
+
} else {
|
|
2670
|
+
onLeave();
|
|
2671
|
+
}
|
|
2672
|
+
},
|
|
2673
|
+
onMouseLeave: () => {
|
|
2674
|
+
handleMouseLeave();
|
|
2675
|
+
onLeave();
|
|
2676
|
+
},
|
|
2677
|
+
children: [
|
|
2678
|
+
animate && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime307.jsx)("clipPath", { id: curveClipId, children: /* @__PURE__ */ (0, import_jsx_runtime307.jsx)("rect", { ref: curveClipRef, x: "0", y: "0", width: animate ? 0 : width, height }) }) }),
|
|
2679
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)(GridLines, { width, height, chartH, maxVal }),
|
|
2680
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)(AxisLabels, { labels, count, chartW, height }),
|
|
2681
|
+
entries.map(([key], di) => {
|
|
2682
|
+
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
2683
|
+
const color = palette[2];
|
|
2684
|
+
const areaColor = palette[0];
|
|
2685
|
+
const points = seriesPoints[di];
|
|
2686
|
+
const gradientId = `curve-gradient-${di}`;
|
|
2687
|
+
const linePath = toSmoothPath(points);
|
|
2688
|
+
const areaPath = linePath + ` L ${points[points.length - 1].x} ${PADDING.top + chartH} L ${points[0].x} ${PADDING.top + chartH} Z`;
|
|
2689
|
+
return /* @__PURE__ */ (0, import_jsx_runtime307.jsxs)("g", { children: [
|
|
2690
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime307.jsxs)("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
|
|
2691
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.4" }),
|
|
2692
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0.02" })
|
|
2693
|
+
] }) }),
|
|
2694
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)(
|
|
2695
|
+
"path",
|
|
2696
|
+
{
|
|
2697
|
+
d: areaPath,
|
|
2698
|
+
fill: `url(#${gradientId})`,
|
|
2699
|
+
clipPath: animate ? `url(#${curveClipId})` : void 0
|
|
2700
|
+
}
|
|
2701
|
+
),
|
|
2702
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)(
|
|
2703
|
+
"path",
|
|
2704
|
+
{
|
|
2705
|
+
ref: (el) => {
|
|
2706
|
+
lineRefs.current[di] = el;
|
|
2707
|
+
},
|
|
2708
|
+
d: linePath,
|
|
2709
|
+
fill: "none",
|
|
2710
|
+
stroke: color,
|
|
2711
|
+
strokeWidth: "2"
|
|
2712
|
+
}
|
|
2713
|
+
),
|
|
2714
|
+
activeIndex !== null && points[activeIndex] && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(
|
|
2715
|
+
"circle",
|
|
2716
|
+
{
|
|
2717
|
+
cx: points[activeIndex].x,
|
|
2718
|
+
cy: points[activeIndex].y,
|
|
2719
|
+
r: "5",
|
|
2720
|
+
fill: color,
|
|
2721
|
+
className: "chart-point-active"
|
|
2722
|
+
}
|
|
2723
|
+
)
|
|
2724
|
+
] }, di);
|
|
2725
|
+
}),
|
|
2726
|
+
activeX !== null && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(
|
|
2727
|
+
"line",
|
|
2561
2728
|
{
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2729
|
+
x1: activeX,
|
|
2730
|
+
y1: PADDING.top,
|
|
2731
|
+
x2: activeX,
|
|
2732
|
+
y2: PADDING.top + chartH,
|
|
2733
|
+
className: "chart-crosshair"
|
|
2566
2734
|
}
|
|
2567
2735
|
),
|
|
2568
2736
|
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)(
|
|
2569
|
-
"
|
|
2737
|
+
"rect",
|
|
2570
2738
|
{
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
fill: "
|
|
2576
|
-
|
|
2577
|
-
strokeWidth: "2"
|
|
2739
|
+
x: PADDING.left,
|
|
2740
|
+
y: PADDING.top,
|
|
2741
|
+
width: chartW,
|
|
2742
|
+
height: chartH,
|
|
2743
|
+
fill: "transparent",
|
|
2744
|
+
style: { cursor: "crosshair" }
|
|
2578
2745
|
}
|
|
2579
|
-
)
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
cx: p.x,
|
|
2584
|
-
cy: p.y,
|
|
2585
|
-
r: "4",
|
|
2586
|
-
fill: color,
|
|
2587
|
-
className: "chart-point",
|
|
2588
|
-
onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${p.v}`),
|
|
2589
|
-
onMouseMove: onMove,
|
|
2590
|
-
onMouseLeave: onLeave
|
|
2591
|
-
},
|
|
2592
|
-
i
|
|
2593
|
-
))
|
|
2594
|
-
] }, di);
|
|
2595
|
-
})
|
|
2596
|
-
] });
|
|
2746
|
+
)
|
|
2747
|
+
]
|
|
2748
|
+
}
|
|
2749
|
+
);
|
|
2597
2750
|
});
|
|
2598
2751
|
CurveChart.displayName = "CurveChart";
|
|
2599
2752
|
var BarChart = import_react6.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
@@ -2758,30 +2911,70 @@ var PieDonutChart = import_react6.default.memo(
|
|
|
2758
2911
|
}
|
|
2759
2912
|
);
|
|
2760
2913
|
PieDonutChart.displayName = "PieDonutChart";
|
|
2761
|
-
var
|
|
2914
|
+
var ChartTooltipPortal = ({ clientX, clientY, visible, children }) => {
|
|
2762
2915
|
const ref = import_react6.default.useRef(null);
|
|
2763
|
-
const [
|
|
2764
|
-
import_react6.default.
|
|
2916
|
+
const [pos, setPos] = import_react6.default.useState({ left: 0, top: 0 });
|
|
2917
|
+
import_react6.default.useLayoutEffect(() => {
|
|
2765
2918
|
const el = ref.current;
|
|
2766
2919
|
if (!el) return;
|
|
2767
2920
|
const w = el.offsetWidth;
|
|
2768
|
-
const
|
|
2769
|
-
const
|
|
2770
|
-
let
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2921
|
+
const h = el.offsetHeight;
|
|
2922
|
+
const vw = window.innerWidth;
|
|
2923
|
+
let left = clientX + TOOLTIP_OFFSET;
|
|
2924
|
+
let top = clientY - h - TOOLTIP_OFFSET;
|
|
2925
|
+
if (left + w > vw - 8) left = clientX - w - TOOLTIP_OFFSET;
|
|
2926
|
+
if (top < 8) top = clientY + TOOLTIP_OFFSET;
|
|
2927
|
+
if (left < 8) left = 8;
|
|
2928
|
+
setPos({ left, top });
|
|
2929
|
+
}, [clientX, clientY]);
|
|
2775
2930
|
return /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(
|
|
2776
2931
|
"div",
|
|
2777
2932
|
{
|
|
2778
2933
|
ref,
|
|
2779
|
-
className: "chart-tooltip"
|
|
2780
|
-
style: { left:
|
|
2934
|
+
className: `chart-tooltip ${visible ? "chart-tooltip-show" : "chart-tooltip-hide"}`,
|
|
2935
|
+
style: { position: "fixed", left: pos.left, top: pos.top, zIndex: 1100 },
|
|
2781
2936
|
children
|
|
2782
2937
|
}
|
|
2783
2938
|
);
|
|
2784
2939
|
};
|
|
2940
|
+
var ChartLegend = ({ data, labels, type }) => {
|
|
2941
|
+
const entries = Object.entries(data);
|
|
2942
|
+
if (type === "pie" || type === "doughnut") {
|
|
2943
|
+
const values = entries.flatMap(([, v]) => v);
|
|
2944
|
+
const total = values.reduce((a, b) => a + b, 0) || 1;
|
|
2945
|
+
const firstKey = entries[0]?.[0] ?? "";
|
|
2946
|
+
const colorOffset = hashString(firstKey);
|
|
2947
|
+
return /* @__PURE__ */ (0, import_jsx_runtime307.jsx)("div", { className: "chart-legend", children: values.map((v, i) => {
|
|
2948
|
+
const pct = Math.round(v / total * 100);
|
|
2949
|
+
const color = PIE_COLORS[(i + colorOffset) % PIE_COLORS.length];
|
|
2950
|
+
return /* @__PURE__ */ (0, import_jsx_runtime307.jsxs)("div", { className: "chart-legend-item", children: [
|
|
2951
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)("span", { className: "chart-legend-dot", style: { backgroundColor: color } }),
|
|
2952
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsxs)("div", { className: "chart-legend-text", children: [
|
|
2953
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)("span", { className: "chart-legend-label", children: labels[i] || `${i + 1}` }),
|
|
2954
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsxs)("span", { className: "chart-legend-value", children: [
|
|
2955
|
+
v.toLocaleString(),
|
|
2956
|
+
"(",
|
|
2957
|
+
pct,
|
|
2958
|
+
"%)"
|
|
2959
|
+
] })
|
|
2960
|
+
] })
|
|
2961
|
+
] }, i);
|
|
2962
|
+
}) });
|
|
2963
|
+
}
|
|
2964
|
+
return /* @__PURE__ */ (0, import_jsx_runtime307.jsx)("div", { className: "chart-legend", children: entries.map(([key], di) => {
|
|
2965
|
+
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
2966
|
+
const color = palette[2];
|
|
2967
|
+
const values = entries[di][1];
|
|
2968
|
+
const sum = values.reduce((a, b) => a + b, 0);
|
|
2969
|
+
return /* @__PURE__ */ (0, import_jsx_runtime307.jsxs)("div", { className: "chart-legend-item", children: [
|
|
2970
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)("span", { className: "chart-legend-dot", style: { backgroundColor: color } }),
|
|
2971
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsxs)("div", { className: "chart-legend-text", children: [
|
|
2972
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)("span", { className: "chart-legend-label", children: key }),
|
|
2973
|
+
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)("span", { className: "chart-legend-value", children: sum.toLocaleString() })
|
|
2974
|
+
] })
|
|
2975
|
+
] }, di);
|
|
2976
|
+
}) });
|
|
2977
|
+
};
|
|
2785
2978
|
var Chart = import_react6.default.memo((props) => {
|
|
2786
2979
|
const { type, data, labels, tooltip: showTooltip = true } = props;
|
|
2787
2980
|
const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
|
|
@@ -2797,7 +2990,8 @@ var Chart = import_react6.default.memo((props) => {
|
|
|
2797
2990
|
ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
2798
2991
|
ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
2799
2992
|
ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
2800
|
-
|
|
2993
|
+
ready && (type === "bar" || type === "pie" || type === "doughnut") && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(ChartLegend, { data: stableData, labels: stableLabels, type }),
|
|
2994
|
+
tooltip.content && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(ChartTooltipPortal, { clientX: tooltip.clientX, clientY: tooltip.clientY, visible: tooltip.visible, children: tooltip.content })
|
|
2801
2995
|
] });
|
|
2802
2996
|
});
|
|
2803
2997
|
Chart.displayName = "Chart";
|