react-premium-charts 0.1.6

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/index.js ADDED
@@ -0,0 +1,2053 @@
1
+ import { createContext, useMemo, useContext, useRef, useState, useCallback, useEffect } from 'react';
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+ import { createPortal } from 'react-dom';
4
+ import { line, curveMonotoneX, curveLinear, area, pie, arc } from 'd3-shape';
5
+ import { scaleBand, scaleLinear } from 'd3-scale';
6
+ import { bisector } from 'd3-array';
7
+
8
+ // src/theme/ThemeProvider.tsx
9
+ var Ctx = createContext({
10
+ mode: "light",
11
+ palette: "default",
12
+ isGradientEnabled: true
13
+ });
14
+ function ThemeProvider({
15
+ mode = "light",
16
+ palette = "default",
17
+ isGradientEnabled = true,
18
+ children
19
+ }) {
20
+ const value = useMemo(() => ({ mode, palette, isGradientEnabled }), [mode, palette, isGradientEnabled]);
21
+ return /* @__PURE__ */ jsx(Ctx.Provider, { value, children: /* @__PURE__ */ jsx("div", { className: "msc-root", "data-msc-theme": mode, "data-msc-palette": palette, children }) });
22
+ }
23
+ function useTheme() {
24
+ return useContext(Ctx);
25
+ }
26
+ var ChartCtx = createContext(null);
27
+ function useChart() {
28
+ const v = useContext(ChartCtx);
29
+ if (!v) throw new Error("useChart must be used inside <Chart>");
30
+ return v;
31
+ }
32
+ function Chart({
33
+ width,
34
+ height,
35
+ margin = { top: 16, right: 16, bottom: 28, left: 40 },
36
+ defs,
37
+ children,
38
+ className,
39
+ style
40
+ }) {
41
+ const svgRef = useRef(null);
42
+ const [pointer, setPointer] = useState(null);
43
+ const clearTooltipFns = useRef(/* @__PURE__ */ new Set());
44
+ const registerClearTooltip = useCallback((fn) => {
45
+ clearTooltipFns.current.add(fn);
46
+ return () => {
47
+ clearTooltipFns.current.delete(fn);
48
+ };
49
+ }, []);
50
+ const handleChartLeave = useCallback(() => {
51
+ setPointer(null);
52
+ clearTooltipFns.current.forEach((fn) => fn());
53
+ }, []);
54
+ const clearAllTooltips = useCallback(() => {
55
+ clearTooltipFns.current.forEach((fn) => fn());
56
+ }, []);
57
+ const innerWidth = Math.max(0, width - margin.left - margin.right);
58
+ const innerHeight = Math.max(0, height - margin.top - margin.bottom);
59
+ const value = useMemo(
60
+ () => ({
61
+ size: { width, height },
62
+ margin,
63
+ innerWidth,
64
+ innerHeight,
65
+ svgRef,
66
+ pointer,
67
+ setPointer,
68
+ registerClearTooltip,
69
+ clearAllTooltips
70
+ }),
71
+ [width, height, margin, innerWidth, innerHeight, pointer, registerClearTooltip, clearAllTooltips]
72
+ );
73
+ return /* @__PURE__ */ jsx(ChartCtx.Provider, { value, children: /* @__PURE__ */ jsx(
74
+ "svg",
75
+ {
76
+ ref: svgRef,
77
+ width,
78
+ height,
79
+ viewBox: `0 0 ${width} ${height}`,
80
+ overflow: "visible",
81
+ className,
82
+ style: { background: "var(--msc-panel)", borderRadius: "var(--msc-radius)", ...style },
83
+ onMouseLeave: handleChartLeave,
84
+ onMouseMove: (e) => {
85
+ const svg = svgRef.current;
86
+ if (!svg) return;
87
+ const pt = svg.createSVGPoint();
88
+ pt.x = e.clientX;
89
+ pt.y = e.clientY;
90
+ const screenCTM = svg.getScreenCTM();
91
+ if (!screenCTM) return;
92
+ const local = pt.matrixTransform(screenCTM.inverse());
93
+ setPointer({ x: local.x, y: local.y });
94
+ },
95
+ children: /* @__PURE__ */ jsxs("g", { transform: `translate(${margin.left},${margin.top})`, children: [
96
+ defs,
97
+ children
98
+ ] })
99
+ }
100
+ ) });
101
+ }
102
+ function AxisBottom({
103
+ ticks,
104
+ y = void 0
105
+ }) {
106
+ const { innerHeight } = useChart();
107
+ const yy = y ?? innerHeight;
108
+ return /* @__PURE__ */ jsxs("g", { children: [
109
+ /* @__PURE__ */ jsx("line", { x1: 0, x2: Math.max(...ticks.map((t) => t.x), 0), y1: yy, y2: yy, stroke: "var(--msc-border)" }),
110
+ ticks.map((t) => /* @__PURE__ */ jsxs("g", { transform: `translate(${t.x},${yy})`, children: [
111
+ /* @__PURE__ */ jsx("line", { y2: 6, stroke: "var(--msc-border)" }),
112
+ /* @__PURE__ */ jsx(
113
+ "text",
114
+ {
115
+ y: 18,
116
+ textAnchor: "middle",
117
+ fontSize: 12,
118
+ fill: "var(--msc-muted)",
119
+ children: t.value
120
+ }
121
+ )
122
+ ] }, t.value))
123
+ ] });
124
+ }
125
+ function AxisLeft({
126
+ ticks
127
+ }) {
128
+ const x = 0;
129
+ const maxY = Math.max(...ticks.map((t) => t.y), 0);
130
+ return /* @__PURE__ */ jsxs("g", { children: [
131
+ /* @__PURE__ */ jsx("line", { x1: x, x2: x, y1: 0, y2: maxY, stroke: "var(--msc-border)" }),
132
+ ticks.map((t) => /* @__PURE__ */ jsxs("g", { transform: `translate(${x},${t.y})`, children: [
133
+ /* @__PURE__ */ jsx("line", { x2: -6, stroke: "var(--msc-border)" }),
134
+ /* @__PURE__ */ jsx(
135
+ "text",
136
+ {
137
+ x: -10,
138
+ dy: "0.32em",
139
+ textAnchor: "end",
140
+ fontSize: 12,
141
+ fill: "var(--msc-muted)",
142
+ children: t.value
143
+ }
144
+ )
145
+ ] }, t.value))
146
+ ] });
147
+ }
148
+ function AxisRight({
149
+ ticks,
150
+ x
151
+ }) {
152
+ const maxY = Math.max(...ticks.map((t) => t.y), 0);
153
+ return /* @__PURE__ */ jsxs("g", { children: [
154
+ /* @__PURE__ */ jsx("line", { x1: x, x2: x, y1: 0, y2: maxY, stroke: "var(--msc-border)" }),
155
+ ticks.map((t) => /* @__PURE__ */ jsxs("g", { transform: `translate(${x},${t.y})`, children: [
156
+ /* @__PURE__ */ jsx("line", { x2: 6, stroke: "var(--msc-border)" }),
157
+ /* @__PURE__ */ jsx(
158
+ "text",
159
+ {
160
+ x: 10,
161
+ dy: "0.32em",
162
+ textAnchor: "start",
163
+ fontSize: 12,
164
+ fill: "var(--msc-muted)",
165
+ children: t.value
166
+ }
167
+ )
168
+ ] }, t.value))
169
+ ] });
170
+ }
171
+ function Grid({
172
+ xTicks,
173
+ yTicks
174
+ }) {
175
+ const { innerWidth, innerHeight } = useChart();
176
+ return /* @__PURE__ */ jsxs("g", { "aria-hidden": "true", children: [
177
+ xTicks.map((x) => /* @__PURE__ */ jsx(
178
+ "line",
179
+ {
180
+ x1: x,
181
+ x2: x,
182
+ y1: 0,
183
+ y2: innerHeight,
184
+ stroke: "var(--msc-grid)",
185
+ strokeDasharray: "3 6"
186
+ },
187
+ `x-${x}`
188
+ )),
189
+ yTicks.map((y) => /* @__PURE__ */ jsx(
190
+ "line",
191
+ {
192
+ x1: 0,
193
+ x2: innerWidth,
194
+ y1: y,
195
+ y2: y,
196
+ stroke: "var(--msc-grid)",
197
+ strokeDasharray: "3 6"
198
+ },
199
+ `y-${y}`
200
+ ))
201
+ ] });
202
+ }
203
+ function ThresholdLine({
204
+ value,
205
+ yScale,
206
+ stroke = "var(--msc-s4)",
207
+ strokeWidth = 1.5,
208
+ strokeDasharray = "6 4",
209
+ label
210
+ }) {
211
+ const { innerWidth } = useChart();
212
+ const y = yScale(value);
213
+ return /* @__PURE__ */ jsxs("g", { children: [
214
+ /* @__PURE__ */ jsx(
215
+ "line",
216
+ {
217
+ x1: 0,
218
+ x2: innerWidth,
219
+ y1: y,
220
+ y2: y,
221
+ stroke,
222
+ strokeWidth,
223
+ strokeDasharray
224
+ }
225
+ ),
226
+ label && /* @__PURE__ */ jsx(
227
+ "text",
228
+ {
229
+ x: innerWidth - 4,
230
+ y: y - 6,
231
+ textAnchor: "end",
232
+ fontSize: 11,
233
+ fill: "var(--msc-muted)",
234
+ children: label
235
+ }
236
+ )
237
+ ] });
238
+ }
239
+ function LinearGradient({
240
+ id,
241
+ x1 = "0%",
242
+ y1 = "0%",
243
+ x2 = "0%",
244
+ y2 = "100%",
245
+ stops
246
+ }) {
247
+ return /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("linearGradient", { id, x1, y1, x2, y2, children: stops.map((s, i) => /* @__PURE__ */ jsx(
248
+ "stop",
249
+ {
250
+ offset: s.offset,
251
+ stopColor: s.color,
252
+ stopOpacity: s.opacity ?? 1
253
+ },
254
+ i
255
+ )) }) });
256
+ }
257
+ function RadialGradient({
258
+ id,
259
+ cx = "50%",
260
+ cy = "50%",
261
+ r = "50%",
262
+ fx,
263
+ fy,
264
+ stops
265
+ }) {
266
+ return /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("radialGradient", { id, cx, cy, r, fx, fy, children: stops.map((s, i) => /* @__PURE__ */ jsx(
267
+ "stop",
268
+ {
269
+ offset: s.offset,
270
+ stopColor: s.color,
271
+ stopOpacity: s.opacity ?? 1
272
+ },
273
+ i
274
+ )) }) });
275
+ }
276
+ function ChartTitle({
277
+ title,
278
+ x = 0,
279
+ y = -8
280
+ }) {
281
+ return /* @__PURE__ */ jsx(
282
+ "text",
283
+ {
284
+ x,
285
+ y,
286
+ fontSize: 14,
287
+ fontWeight: 600,
288
+ fill: "var(--msc-muted)",
289
+ children: title
290
+ }
291
+ );
292
+ }
293
+ function Legend({
294
+ items,
295
+ direction = "row"
296
+ }) {
297
+ return /* @__PURE__ */ jsx(
298
+ "div",
299
+ {
300
+ className: "msc-legend",
301
+ style: {
302
+ display: "flex",
303
+ flexWrap: "wrap",
304
+ gap: 12,
305
+ flexDirection: direction,
306
+ alignItems: "center",
307
+ justifyContent: "center",
308
+ marginTop: 12
309
+ },
310
+ children: items.map((item, i) => /* @__PURE__ */ jsxs(
311
+ "div",
312
+ {
313
+ style: {
314
+ display: "flex",
315
+ alignItems: "center",
316
+ gap: 6,
317
+ fontSize: 12,
318
+ color: "var(--msc-muted)"
319
+ },
320
+ children: [
321
+ /* @__PURE__ */ jsx(
322
+ "span",
323
+ {
324
+ className: "msc-dot",
325
+ style: {
326
+ background: item.color,
327
+ width: 8,
328
+ height: 8,
329
+ marginRight: 0
330
+ }
331
+ }
332
+ ),
333
+ /* @__PURE__ */ jsxs("span", { children: [
334
+ item.label,
335
+ item.value != null && `: ${item.value}`
336
+ ] })
337
+ ]
338
+ },
339
+ `${item.label}-${i}`
340
+ ))
341
+ }
342
+ );
343
+ }
344
+ var TOOLTIP_WIDTH = 200;
345
+ var TOOLTIP_HEIGHT = 120;
346
+ var OFFSET = 12;
347
+ var PADDING = 8;
348
+ var TOOLTIP_Z_INDEX = 1e4;
349
+ function computeTooltipPosition(anchorX, anchorY, containerWidth, containerHeight, tooltipWidth = TOOLTIP_WIDTH, tooltipHeight = TOOLTIP_HEIGHT) {
350
+ let x = anchorX + OFFSET;
351
+ let y = anchorY - tooltipHeight - OFFSET;
352
+ if (x + tooltipWidth > containerWidth - PADDING) {
353
+ x = anchorX - tooltipWidth - OFFSET;
354
+ }
355
+ if (x < PADDING) {
356
+ x = PADDING;
357
+ }
358
+ if (y < PADDING) {
359
+ y = anchorY + OFFSET;
360
+ }
361
+ if (y + tooltipHeight > containerHeight - PADDING) {
362
+ y = containerHeight - tooltipHeight - PADDING;
363
+ }
364
+ return { x: Math.max(PADDING, x), y: Math.max(PADDING, y) };
365
+ }
366
+ function useScreenPosition(innerX, innerY, svgRef, margin) {
367
+ const [pos, setPos] = useState(null);
368
+ useEffect(() => {
369
+ const svg = svgRef?.current;
370
+ if (!svg || !margin) return;
371
+ const pt = svg.createSVGPoint();
372
+ pt.x = innerX + margin.left;
373
+ pt.y = innerY + margin.top;
374
+ const ctm = svg.getScreenCTM();
375
+ if (!ctm) return;
376
+ const screen = pt.matrixTransform(ctm);
377
+ setPos({ x: screen.x, y: screen.y });
378
+ }, [innerX, innerY, svgRef, margin]);
379
+ return pos;
380
+ }
381
+ function TooltipPortal({
382
+ x,
383
+ y,
384
+ anchorX,
385
+ anchorY,
386
+ containerWidth,
387
+ containerHeight,
388
+ svgRef,
389
+ margin,
390
+ children
391
+ }) {
392
+ const innerPosition = anchorX != null && anchorY != null && containerWidth != null && containerHeight != null ? computeTooltipPosition(anchorX, anchorY, containerWidth, containerHeight) : { x: x ?? 0, y: y ?? 0 };
393
+ const screenPos = useScreenPosition(
394
+ innerPosition.x,
395
+ innerPosition.y,
396
+ svgRef,
397
+ margin ?? void 0
398
+ );
399
+ const usePortal = svgRef != null && margin != null && screenPos != null;
400
+ if (usePortal && screenPos) {
401
+ return createPortal(
402
+ /* @__PURE__ */ jsx(
403
+ "div",
404
+ {
405
+ style: {
406
+ position: "fixed",
407
+ left: screenPos.x,
408
+ top: screenPos.y,
409
+ zIndex: TOOLTIP_Z_INDEX,
410
+ pointerEvents: "none",
411
+ width: "max-content",
412
+ maxWidth: TOOLTIP_WIDTH,
413
+ minWidth: 140
414
+ },
415
+ children
416
+ }
417
+ ),
418
+ document.body
419
+ );
420
+ }
421
+ return /* @__PURE__ */ jsx(
422
+ "foreignObject",
423
+ {
424
+ x: innerPosition.x,
425
+ y: innerPosition.y,
426
+ width: TOOLTIP_WIDTH + 40,
427
+ height: TOOLTIP_HEIGHT + 40,
428
+ style: { overflow: "visible", pointerEvents: "none" },
429
+ children: /* @__PURE__ */ jsx(
430
+ "div",
431
+ {
432
+ style: {
433
+ width: "max-content",
434
+ maxWidth: TOOLTIP_WIDTH,
435
+ minWidth: 140,
436
+ pointerEvents: "none"
437
+ },
438
+ children
439
+ }
440
+ )
441
+ }
442
+ );
443
+ }
444
+ function DefaultTooltip({
445
+ title,
446
+ rows
447
+ }) {
448
+ return /* @__PURE__ */ jsxs("div", { className: "msc-tooltip", children: [
449
+ /* @__PURE__ */ jsx("div", { className: "msc-tooltip-title", children: title }),
450
+ rows.map((r) => /* @__PURE__ */ jsxs("div", { className: "msc-tooltip-row", children: [
451
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center" }, children: [
452
+ /* @__PURE__ */ jsx("span", { className: "msc-dot", style: { background: r.color } }),
453
+ /* @__PURE__ */ jsx("span", { children: r.label })
454
+ ] }),
455
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 650 }, children: r.value })
456
+ ] }, r.label))
457
+ ] });
458
+ }
459
+ var HOVER_HIT_RADIUS = 12;
460
+ var HOVER_LEAVE_DELAY = 150;
461
+ function LineSeries({
462
+ data,
463
+ x,
464
+ y,
465
+ xScale,
466
+ yScale,
467
+ stroke = "var(--msc-s1)",
468
+ strokeWidth = 2.5,
469
+ curve = "monotone",
470
+ showMarkers = false,
471
+ animate = true,
472
+ duration = 800,
473
+ hoverDimOpacity = 0.5,
474
+ tooltip
475
+ }) {
476
+ const [hoveredIndex, setHoveredIndex] = useState(null);
477
+ const leaveTimeoutRef = useRef(null);
478
+ const { innerWidth, innerHeight, svgRef, margin, registerClearTooltip, clearAllTooltips } = useChart();
479
+ const clearTooltip = () => {
480
+ if (leaveTimeoutRef.current) clearTimeout(leaveTimeoutRef.current);
481
+ leaveTimeoutRef.current = null;
482
+ setHoveredIndex(null);
483
+ };
484
+ useEffect(() => {
485
+ return registerClearTooltip(clearTooltip);
486
+ }, [registerClearTooltip]);
487
+ const handleEnter = (i) => {
488
+ if (leaveTimeoutRef.current) {
489
+ clearTimeout(leaveTimeoutRef.current);
490
+ leaveTimeoutRef.current = null;
491
+ }
492
+ clearAllTooltips();
493
+ setHoveredIndex(i);
494
+ };
495
+ const handleLeave = () => {
496
+ leaveTimeoutRef.current = setTimeout(clearTooltip, HOVER_LEAVE_DELAY);
497
+ };
498
+ const { pathD, points } = useMemo(() => {
499
+ const gen = line().x((dd, i) => xScale(x(dd, i))).y((dd, i) => yScale(y(dd, i))).defined((dd, i) => Number.isFinite(x(dd, i)) && Number.isFinite(y(dd, i))).curve(curve === "monotone" ? curveMonotoneX : curveLinear);
500
+ const pathD2 = gen(data) ?? "";
501
+ const points2 = data.map((d, i) => ({
502
+ x: xScale(x(d, i)),
503
+ y: yScale(y(d, i)),
504
+ datum: d,
505
+ index: i
506
+ }));
507
+ return { pathD: pathD2, points: points2 };
508
+ }, [data, x, y, xScale, yScale, curve]);
509
+ const lineOpacity = hoveredIndex === null ? 1 : hoverDimOpacity;
510
+ return /* @__PURE__ */ jsxs("g", { children: [
511
+ /* @__PURE__ */ jsx(
512
+ "path",
513
+ {
514
+ d: pathD,
515
+ fill: "none",
516
+ stroke,
517
+ strokeWidth,
518
+ opacity: lineOpacity,
519
+ pathLength: animate ? 1 : void 0,
520
+ strokeDasharray: animate ? "1 1" : void 0,
521
+ strokeDashoffset: animate ? 1 : void 0,
522
+ style: {
523
+ ...animate ? { animation: `msc-line-draw ${duration}ms ease-out forwards` } : {},
524
+ transition: "opacity 0.2s ease"
525
+ }
526
+ }
527
+ ),
528
+ points.map((pt, i) => /* @__PURE__ */ jsxs("g", { children: [
529
+ /* @__PURE__ */ jsx(
530
+ "circle",
531
+ {
532
+ cx: pt.x,
533
+ cy: pt.y,
534
+ r: HOVER_HIT_RADIUS,
535
+ fill: "transparent",
536
+ style: { cursor: "pointer" },
537
+ onMouseEnter: () => handleEnter(i),
538
+ onMouseLeave: handleLeave
539
+ }
540
+ ),
541
+ (showMarkers || hoveredIndex === i) && /* @__PURE__ */ jsxs(Fragment, { children: [
542
+ /* @__PURE__ */ jsx(
543
+ "circle",
544
+ {
545
+ cx: pt.x,
546
+ cy: pt.y,
547
+ r: showMarkers ? 4 : 6,
548
+ fill: showMarkers ? stroke : "var(--msc-panel)",
549
+ stroke: showMarkers ? "var(--msc-panel)" : stroke,
550
+ strokeWidth: showMarkers ? 2 : 2.5,
551
+ style: {
552
+ transition: "opacity 0.15s ease",
553
+ transformOrigin: "center",
554
+ ...animate ? {
555
+ animation: `msc-marker-pop 400ms ease-out ${Math.min(300 + i * 80, duration - 100)}ms both`
556
+ } : {}
557
+ }
558
+ }
559
+ ),
560
+ tooltip && hoveredIndex === i && /* @__PURE__ */ jsx(
561
+ TooltipPortal,
562
+ {
563
+ anchorX: pt.x,
564
+ anchorY: pt.y,
565
+ containerWidth: innerWidth,
566
+ containerHeight: innerHeight,
567
+ svgRef,
568
+ margin,
569
+ children: /* @__PURE__ */ jsx(DefaultTooltip, { ...tooltip(pt.datum, i) })
570
+ }
571
+ )
572
+ ] })
573
+ ] }, i))
574
+ ] });
575
+ }
576
+ function AreaSeries({
577
+ data,
578
+ x,
579
+ y,
580
+ y0 = 0,
581
+ xScale,
582
+ yScale,
583
+ fill = "var(--msc-s1)",
584
+ fillOpacity = 0.18,
585
+ curve = "monotone",
586
+ animate = true,
587
+ duration = 600
588
+ }) {
589
+ const d = useMemo(() => {
590
+ const gen = area().x((dd, i) => xScale(x(dd, i))).y1((dd, i) => yScale(y(dd, i))).y0(() => yScale(y0)).defined((dd, i) => Number.isFinite(x(dd, i)) && Number.isFinite(y(dd, i))).curve(curve === "monotone" ? curveMonotoneX : curveLinear);
591
+ return gen(data) ?? "";
592
+ }, [data, x, y, y0, xScale, yScale, curve]);
593
+ return /* @__PURE__ */ jsx(
594
+ "path",
595
+ {
596
+ d,
597
+ fill,
598
+ fillOpacity,
599
+ stroke: "none",
600
+ className: animate ? "msc-area-animate" : void 0,
601
+ style: animate ? {
602
+ animation: `msc-area-reveal ${duration}ms ease-out forwards`
603
+ } : void 0
604
+ }
605
+ );
606
+ }
607
+ var HOVER_LEAVE_DELAY2 = 150;
608
+ function BarSeries({
609
+ data,
610
+ x,
611
+ y,
612
+ xScale,
613
+ yScale,
614
+ fill = "var(--msc-s1)",
615
+ radius = 10,
616
+ animate = true,
617
+ duration = 500,
618
+ hoverDimOpacity = 0.4,
619
+ tooltip
620
+ }) {
621
+ const [hoveredIndex, setHoveredIndex] = useState(null);
622
+ const leaveTimeoutRef = useRef(null);
623
+ const { innerWidth, innerHeight, svgRef, margin, registerClearTooltip, clearAllTooltips } = useChart();
624
+ const barW = xScale.bandwidth();
625
+ const clearTooltip = () => {
626
+ if (leaveTimeoutRef.current) clearTimeout(leaveTimeoutRef.current);
627
+ leaveTimeoutRef.current = null;
628
+ setHoveredIndex(null);
629
+ };
630
+ useEffect(() => {
631
+ return registerClearTooltip(clearTooltip);
632
+ }, [registerClearTooltip]);
633
+ const handleEnter = (i) => {
634
+ if (leaveTimeoutRef.current) {
635
+ clearTimeout(leaveTimeoutRef.current);
636
+ leaveTimeoutRef.current = null;
637
+ }
638
+ clearAllTooltips();
639
+ setHoveredIndex(i);
640
+ };
641
+ const handleLeave = () => {
642
+ leaveTimeoutRef.current = setTimeout(clearTooltip, HOVER_LEAVE_DELAY2);
643
+ };
644
+ return /* @__PURE__ */ jsx("g", { children: data.map((d, i) => {
645
+ const xx = xScale(x(d, i));
646
+ if (xx == null) return null;
647
+ const yVal = y(d, i);
648
+ const yy = yScale(yVal);
649
+ const zeroY = yScale(0);
650
+ const h = zeroY - yy;
651
+ const isHovered = hoveredIndex === i;
652
+ const opacity = hoveredIndex === null ? 0.92 : isHovered ? 1 : hoverDimOpacity;
653
+ const anchorX = xx + barW / 2;
654
+ const anchorY = yy;
655
+ return /* @__PURE__ */ jsxs("g", { children: [
656
+ /* @__PURE__ */ jsx(
657
+ "rect",
658
+ {
659
+ x: xx,
660
+ y: h >= 0 ? yy : zeroY,
661
+ width: barW,
662
+ height: Math.abs(h),
663
+ rx: radius,
664
+ ry: radius,
665
+ fill,
666
+ opacity,
667
+ className: `msc-bar-hoverable ${animate ? "msc-bar-animate" : ""}`.trim(),
668
+ style: {
669
+ ...animate ? { animation: `msc-bar-grow ${duration}ms ease-out ${i * 60}ms both` } : {},
670
+ transition: "opacity 0.2s ease",
671
+ cursor: tooltip ? "pointer" : void 0
672
+ },
673
+ onMouseEnter: () => handleEnter(i),
674
+ onMouseLeave: handleLeave
675
+ }
676
+ ),
677
+ tooltip && isHovered && /* @__PURE__ */ jsx(
678
+ TooltipPortal,
679
+ {
680
+ anchorX,
681
+ anchorY,
682
+ containerWidth: innerWidth,
683
+ containerHeight: innerHeight,
684
+ svgRef,
685
+ margin,
686
+ children: /* @__PURE__ */ jsx(DefaultTooltip, { ...tooltip(d, i) })
687
+ }
688
+ )
689
+ ] }, i);
690
+ }) });
691
+ }
692
+ var HOVER_LEAVE_DELAY3 = 150;
693
+ function HorizontalBarSeries({
694
+ data,
695
+ y,
696
+ x,
697
+ yScale,
698
+ xScale,
699
+ fill = "var(--msc-s1)",
700
+ radius = 6,
701
+ animate = true,
702
+ duration = 500,
703
+ hoverDimOpacity = 0.4,
704
+ tooltip
705
+ }) {
706
+ const [hoveredIndex, setHoveredIndex] = useState(null);
707
+ const leaveTimeoutRef = useRef(null);
708
+ const { innerWidth, innerHeight, svgRef, margin, registerClearTooltip, clearAllTooltips } = useChart();
709
+ const barH = yScale.bandwidth();
710
+ const clearTooltip = () => {
711
+ if (leaveTimeoutRef.current) clearTimeout(leaveTimeoutRef.current);
712
+ leaveTimeoutRef.current = null;
713
+ setHoveredIndex(null);
714
+ };
715
+ useEffect(() => {
716
+ return registerClearTooltip(clearTooltip);
717
+ }, [registerClearTooltip]);
718
+ const handleEnter = (i) => {
719
+ if (leaveTimeoutRef.current) {
720
+ clearTimeout(leaveTimeoutRef.current);
721
+ leaveTimeoutRef.current = null;
722
+ }
723
+ clearAllTooltips();
724
+ setHoveredIndex(i);
725
+ };
726
+ const handleLeave = () => {
727
+ leaveTimeoutRef.current = setTimeout(clearTooltip, HOVER_LEAVE_DELAY3);
728
+ };
729
+ return /* @__PURE__ */ jsx("g", { children: data.map((d, i) => {
730
+ const yy = yScale(y(d, i));
731
+ if (yy == null) return null;
732
+ const xVal = x(d, i);
733
+ const xx = xScale(xVal);
734
+ const zeroX = xScale(0);
735
+ const w = xx - zeroX;
736
+ const isHovered = hoveredIndex === i;
737
+ const opacity = hoveredIndex === null ? 0.92 : isHovered ? 1 : hoverDimOpacity;
738
+ const anchorX = w >= 0 ? zeroX + Math.abs(w) / 2 : zeroX - Math.abs(w) / 2;
739
+ const anchorY = yy + barH / 2;
740
+ return /* @__PURE__ */ jsxs("g", { children: [
741
+ /* @__PURE__ */ jsx(
742
+ "rect",
743
+ {
744
+ x: w >= 0 ? zeroX : xx,
745
+ y: yy,
746
+ width: Math.abs(w),
747
+ height: barH,
748
+ rx: radius,
749
+ ry: radius,
750
+ fill,
751
+ opacity,
752
+ className: `msc-bar-hoverable ${animate ? "msc-bar-animate msc-bar-horizontal" : ""}`.trim(),
753
+ style: {
754
+ ...animate ? { animation: `msc-bar-grow-horizontal ${duration}ms ease-out ${i * 60}ms both` } : {},
755
+ transition: "opacity 0.2s ease",
756
+ cursor: tooltip ? "pointer" : void 0
757
+ },
758
+ onMouseEnter: () => handleEnter(i),
759
+ onMouseLeave: handleLeave
760
+ }
761
+ ),
762
+ tooltip && isHovered && /* @__PURE__ */ jsx(
763
+ TooltipPortal,
764
+ {
765
+ anchorX,
766
+ anchorY,
767
+ containerWidth: innerWidth,
768
+ containerHeight: innerHeight,
769
+ svgRef,
770
+ margin,
771
+ children: /* @__PURE__ */ jsx(DefaultTooltip, { ...tooltip(d, i) })
772
+ }
773
+ )
774
+ ] }, i);
775
+ }) });
776
+ }
777
+ var HOVER_LEAVE_DELAY4 = 150;
778
+ function GroupedBarSeries({
779
+ data,
780
+ x,
781
+ xScale,
782
+ yScale,
783
+ groups,
784
+ radius = 6,
785
+ animate = true,
786
+ duration = 500,
787
+ hoverDimOpacity = 0.4
788
+ }) {
789
+ const [hovered, setHovered] = useState(null);
790
+ const leaveTimeoutRef = useRef(null);
791
+ const { innerWidth, innerHeight, svgRef, margin, registerClearTooltip, clearAllTooltips } = useChart();
792
+ const clearTooltip = () => {
793
+ if (leaveTimeoutRef.current) clearTimeout(leaveTimeoutRef.current);
794
+ leaveTimeoutRef.current = null;
795
+ setHovered(null);
796
+ };
797
+ useEffect(() => {
798
+ return registerClearTooltip(clearTooltip);
799
+ }, [registerClearTooltip]);
800
+ const handleEnter = (groupIdx, dataIdx) => {
801
+ if (leaveTimeoutRef.current) {
802
+ clearTimeout(leaveTimeoutRef.current);
803
+ leaveTimeoutRef.current = null;
804
+ }
805
+ clearAllTooltips();
806
+ setHovered({ groupIdx, dataIdx });
807
+ };
808
+ const handleLeave = () => {
809
+ leaveTimeoutRef.current = setTimeout(clearTooltip, HOVER_LEAVE_DELAY4);
810
+ };
811
+ const groupCount = groups.length;
812
+ const categoryBand = xScale.bandwidth();
813
+ const barGap = 2;
814
+ const barWidth = (categoryBand - barGap * (groupCount - 1)) / groupCount;
815
+ return /* @__PURE__ */ jsx("g", { children: groups.map(
816
+ (group, groupIdx) => data.map((d, i) => {
817
+ const xx = xScale(x(d, i));
818
+ if (xx == null) return null;
819
+ const xOffset = xx + groupIdx * (barWidth + barGap);
820
+ const yVal = group.y(d, i);
821
+ const yy = yScale(yVal);
822
+ const zeroY = yScale(0);
823
+ const h = zeroY - yy;
824
+ const rectY = h >= 0 ? yy : zeroY;
825
+ const isHovered = hovered?.groupIdx === groupIdx && hovered?.dataIdx === i;
826
+ const opacity = hovered === null ? 0.92 : isHovered ? 1 : hoverDimOpacity;
827
+ return /* @__PURE__ */ jsxs("g", { children: [
828
+ /* @__PURE__ */ jsx(
829
+ "rect",
830
+ {
831
+ x: xOffset,
832
+ y: rectY,
833
+ width: barWidth,
834
+ height: Math.abs(h),
835
+ rx: radius,
836
+ ry: radius,
837
+ fill: group.fill,
838
+ opacity,
839
+ className: `msc-bar-hoverable ${animate ? "msc-bar-animate" : ""}`.trim(),
840
+ style: {
841
+ ...animate ? { animation: `msc-bar-grow ${duration}ms ease-out ${(i * groupCount + groupIdx) * 40}ms both` } : {},
842
+ transition: "opacity 0.2s ease",
843
+ cursor: group.tooltip ? "pointer" : void 0
844
+ },
845
+ onMouseEnter: () => handleEnter(groupIdx, i),
846
+ onMouseLeave: handleLeave
847
+ }
848
+ ),
849
+ group.tooltip && isHovered && /* @__PURE__ */ jsx(
850
+ TooltipPortal,
851
+ {
852
+ anchorX: xOffset + barWidth / 2,
853
+ anchorY: yy,
854
+ containerWidth: innerWidth,
855
+ containerHeight: innerHeight,
856
+ svgRef,
857
+ margin,
858
+ children: /* @__PURE__ */ jsx(DefaultTooltip, { ...group.tooltip(d, i) })
859
+ }
860
+ )
861
+ ] }, `${groupIdx}-${i}`);
862
+ })
863
+ ) });
864
+ }
865
+ var HOVER_LEAVE_DELAY5 = 150;
866
+ function StackedBarSeries({
867
+ segments,
868
+ orientation = "horizontal",
869
+ radius = 4,
870
+ animate = true,
871
+ duration = 400,
872
+ hoverDimOpacity = 0.4,
873
+ showValues = true,
874
+ valueFormat = (v) => String(v)
875
+ }) {
876
+ const [hoveredIdx, setHoveredIdx] = useState(null);
877
+ const leaveTimeoutRef = useRef(null);
878
+ const { innerWidth, innerHeight, svgRef, margin, registerClearTooltip, clearAllTooltips } = useChart();
879
+ const clearTooltip = () => {
880
+ if (leaveTimeoutRef.current) clearTimeout(leaveTimeoutRef.current);
881
+ leaveTimeoutRef.current = null;
882
+ setHoveredIdx(null);
883
+ };
884
+ useEffect(() => {
885
+ return registerClearTooltip(clearTooltip);
886
+ }, [registerClearTooltip]);
887
+ const handleEnter = (idx) => {
888
+ if (leaveTimeoutRef.current) {
889
+ clearTimeout(leaveTimeoutRef.current);
890
+ leaveTimeoutRef.current = null;
891
+ }
892
+ clearAllTooltips();
893
+ setHoveredIdx(idx);
894
+ };
895
+ const handleLeave = () => {
896
+ leaveTimeoutRef.current = setTimeout(clearTooltip, HOVER_LEAVE_DELAY5);
897
+ };
898
+ const total = segments.reduce((s, seg) => s + seg.value, 0);
899
+ if (total <= 0) return null;
900
+ const isHorizontal = orientation === "horizontal";
901
+ const barLength = isHorizontal ? innerWidth : innerHeight;
902
+ const barThickness = isHorizontal ? innerHeight : innerWidth;
903
+ const n = segments.length;
904
+ function roundedRectPath(x, y, w, h, r, roundLeft, roundRight) {
905
+ const r2 = Math.min(r, w / 2, h / 2);
906
+ if (r2 <= 0) return `M ${x} ${y} L ${x + w} ${y} L ${x + w} ${y + h} L ${x} ${y + h} Z`;
907
+ if (roundLeft && roundRight) {
908
+ return `M ${x + r2} ${y} L ${x + w - r2} ${y} A ${r2} ${r2} 0 0 1 ${x + w} ${y + r2} L ${x + w} ${y + h - r2} A ${r2} ${r2} 0 0 1 ${x + w - r2} ${y + h} L ${x + r2} ${y + h} A ${r2} ${r2} 0 0 1 ${x} ${y + h - r2} L ${x} ${y + r2} A ${r2} ${r2} 0 0 1 ${x + r2} ${y} Z`;
909
+ }
910
+ if (roundLeft) {
911
+ return `M ${x + r2} ${y} L ${x + w} ${y} L ${x + w} ${y + h} L ${x + r2} ${y + h} A ${r2} ${r2} 0 0 1 ${x} ${y + h - r2} L ${x} ${y + r2} A ${r2} ${r2} 0 0 1 ${x + r2} ${y} Z`;
912
+ }
913
+ if (roundRight) {
914
+ return `M ${x} ${y} L ${x + w - r2} ${y} A ${r2} ${r2} 0 0 1 ${x + w} ${y + r2} L ${x + w} ${y + h - r2} A ${r2} ${r2} 0 0 1 ${x + w - r2} ${y + h} L ${x} ${y + h} Z`;
915
+ }
916
+ return `M ${x} ${y} L ${x + w} ${y} L ${x + w} ${y + h} L ${x} ${y + h} Z`;
917
+ }
918
+ let offset = 0;
919
+ return /* @__PURE__ */ jsx("g", { transform: isHorizontal ? void 0 : `translate(0,${innerHeight}) rotate(-90)`, children: segments.map((seg, idx) => {
920
+ const width = seg.value / total * barLength;
921
+ const x = offset;
922
+ offset += width;
923
+ const isHovered = hoveredIdx === idx;
924
+ const opacity = hoveredIdx === null ? 0.92 : isHovered ? 1 : hoverDimOpacity;
925
+ const textX = x + width / 2;
926
+ const textY = barThickness / 2;
927
+ const minWidthForLabel = 24;
928
+ const isFirst = idx === 0;
929
+ const isLast = idx === n - 1;
930
+ const roundLeft = isFirst;
931
+ const roundRight = isLast;
932
+ const pathD = roundedRectPath(x, 0, Math.max(0, width), barThickness, radius, roundLeft, roundRight);
933
+ return /* @__PURE__ */ jsxs("g", { children: [
934
+ /* @__PURE__ */ jsx(
935
+ "path",
936
+ {
937
+ d: pathD,
938
+ fill: seg.fill,
939
+ opacity,
940
+ style: {
941
+ ...animate ? { animation: `msc-bar-grow ${duration}ms ease-out ${idx * 50}ms both` } : {},
942
+ transition: "opacity 0.2s ease",
943
+ cursor: seg.tooltip ? "pointer" : void 0
944
+ },
945
+ onMouseEnter: () => handleEnter(idx),
946
+ onMouseLeave: handleLeave
947
+ }
948
+ ),
949
+ showValues && width >= minWidthForLabel && /* @__PURE__ */ jsx(
950
+ "text",
951
+ {
952
+ x: textX,
953
+ y: textY,
954
+ textAnchor: "middle",
955
+ dominantBaseline: "central",
956
+ fill: "white",
957
+ style: {
958
+ fontSize: 11,
959
+ fontWeight: 600,
960
+ pointerEvents: "none",
961
+ textShadow: "0 1px 1px rgba(0,0,0,0.3)"
962
+ },
963
+ children: seg.label ? `${seg.label}: ${valueFormat(seg.value)}` : valueFormat(seg.value)
964
+ }
965
+ ),
966
+ seg.tooltip && isHovered && /* @__PURE__ */ jsx(
967
+ TooltipPortal,
968
+ {
969
+ anchorX: x + width / 2,
970
+ anchorY: barThickness / 2,
971
+ containerWidth: innerWidth,
972
+ containerHeight: innerHeight,
973
+ svgRef,
974
+ margin,
975
+ children: /* @__PURE__ */ jsx(DefaultTooltip, { ...seg.tooltip })
976
+ }
977
+ )
978
+ ] }, idx);
979
+ }) });
980
+ }
981
+ var DEFAULT_COLORS = [
982
+ "var(--msc-s1)",
983
+ "var(--msc-s2)",
984
+ "var(--msc-s3)",
985
+ "var(--msc-s4)",
986
+ "var(--msc-s5)"
987
+ ];
988
+ function PieSeries({
989
+ data,
990
+ value,
991
+ colors = DEFAULT_COLORS,
992
+ innerRadius = 0,
993
+ outerRadius,
994
+ padAngle = 0,
995
+ cornerRadius = 0,
996
+ animate = true,
997
+ duration = 600,
998
+ hoverDimOpacity = 0.4,
999
+ tooltip
1000
+ }) {
1001
+ const [hoveredIndex, setHoveredIndex] = useState(null);
1002
+ const leaveTimeoutRef = useRef(null);
1003
+ const { innerWidth, innerHeight, svgRef, margin, registerClearTooltip, clearAllTooltips } = useChart();
1004
+ const clearTooltip = () => {
1005
+ if (leaveTimeoutRef.current) clearTimeout(leaveTimeoutRef.current);
1006
+ leaveTimeoutRef.current = null;
1007
+ setHoveredIndex(null);
1008
+ };
1009
+ useEffect(() => {
1010
+ return registerClearTooltip(clearTooltip);
1011
+ }, [registerClearTooltip]);
1012
+ const handleEnter = (i) => {
1013
+ if (leaveTimeoutRef.current) {
1014
+ clearTimeout(leaveTimeoutRef.current);
1015
+ leaveTimeoutRef.current = null;
1016
+ }
1017
+ clearAllTooltips();
1018
+ setHoveredIndex(i);
1019
+ };
1020
+ const handleLeave = () => {
1021
+ leaveTimeoutRef.current = setTimeout(clearTooltip, 150);
1022
+ };
1023
+ const { arcs, arcGen, cx, cy } = useMemo(() => {
1024
+ const r = outerRadius ?? Math.min(innerWidth, innerHeight) / 2 - 8;
1025
+ const cx2 = innerWidth / 2;
1026
+ const cy2 = innerHeight / 2;
1027
+ const pieGen = pie().value((d, i) => value(d, i)).sort(null);
1028
+ const arcGen2 = arc().innerRadius(innerRadius).outerRadius(r).padAngle(padAngle).cornerRadius(cornerRadius);
1029
+ const arcs2 = pieGen(data).map((d, i) => ({ ...d, index: i }));
1030
+ return { arcs: arcs2, arcGen: arcGen2, cx: cx2, cy: cy2 };
1031
+ }, [data, value, innerWidth, innerHeight, outerRadius, innerRadius, padAngle, cornerRadius]);
1032
+ return /* @__PURE__ */ jsx("g", { transform: `translate(${cx},${cy})`, children: arcs.map((arc, i) => {
1033
+ const d = arcGen(arc);
1034
+ if (!d) return null;
1035
+ const fill = colors[i % colors.length] ?? colors[0];
1036
+ const isHovered = hoveredIndex === i;
1037
+ const fillOpacity = hoveredIndex === null ? 0.92 : isHovered ? 1 : hoverDimOpacity;
1038
+ const [centroidX, centroidY] = arcGen.centroid(arc);
1039
+ return /* @__PURE__ */ jsxs("g", { children: [
1040
+ /* @__PURE__ */ jsx(
1041
+ "path",
1042
+ {
1043
+ d,
1044
+ fill,
1045
+ fillOpacity,
1046
+ className: `msc-pie-slice-hoverable ${animate ? "msc-pie-slice-animate" : ""}`.trim(),
1047
+ style: {
1048
+ ...animate ? { animation: `msc-pie-draw ${duration}ms ease-out ${i * 40}ms both` } : {},
1049
+ transition: "fill-opacity 0.2s ease",
1050
+ cursor: tooltip ? "pointer" : void 0
1051
+ },
1052
+ onMouseEnter: () => handleEnter(i),
1053
+ onMouseLeave: handleLeave
1054
+ }
1055
+ ),
1056
+ tooltip && isHovered && /* @__PURE__ */ jsx(
1057
+ TooltipPortal,
1058
+ {
1059
+ anchorX: cx + centroidX,
1060
+ anchorY: cy + centroidY,
1061
+ containerWidth: innerWidth,
1062
+ containerHeight: innerHeight,
1063
+ svgRef,
1064
+ margin,
1065
+ children: /* @__PURE__ */ jsx(DefaultTooltip, { ...tooltip(arc.data, i) })
1066
+ }
1067
+ )
1068
+ ] }, i);
1069
+ }) });
1070
+ }
1071
+ var DEFAULT_COLORS2 = [
1072
+ "var(--msc-s1)",
1073
+ "var(--msc-s2)",
1074
+ "var(--msc-s3)",
1075
+ "var(--msc-s4)",
1076
+ "var(--msc-s5)"
1077
+ ];
1078
+ var HOVER_LEAVE_DELAY6 = 150;
1079
+ function PolarAreaSeries({
1080
+ data,
1081
+ value,
1082
+ colors = DEFAULT_COLORS2,
1083
+ innerRadius = 0,
1084
+ padAngle = 0.02,
1085
+ cornerRadius = 4,
1086
+ animate = true,
1087
+ duration = 600,
1088
+ hoverDimOpacity = 0.4,
1089
+ tooltip
1090
+ }) {
1091
+ const [hoveredIndex, setHoveredIndex] = useState(null);
1092
+ const leaveTimeoutRef = useRef(null);
1093
+ const { innerWidth, innerHeight, svgRef, margin, registerClearTooltip, clearAllTooltips } = useChart();
1094
+ const clearTooltip = () => {
1095
+ if (leaveTimeoutRef.current) clearTimeout(leaveTimeoutRef.current);
1096
+ leaveTimeoutRef.current = null;
1097
+ setHoveredIndex(null);
1098
+ };
1099
+ useEffect(() => {
1100
+ return registerClearTooltip(clearTooltip);
1101
+ }, [registerClearTooltip]);
1102
+ const handleEnter = (i) => {
1103
+ if (leaveTimeoutRef.current) {
1104
+ clearTimeout(leaveTimeoutRef.current);
1105
+ leaveTimeoutRef.current = null;
1106
+ }
1107
+ clearAllTooltips();
1108
+ setHoveredIndex(i);
1109
+ };
1110
+ const handleLeave = () => {
1111
+ leaveTimeoutRef.current = setTimeout(clearTooltip, HOVER_LEAVE_DELAY6);
1112
+ };
1113
+ const { arcs, arcGen, cx, cy } = useMemo(() => {
1114
+ const r = Math.min(innerWidth, innerHeight) / 2 - 8;
1115
+ const cx2 = innerWidth / 2;
1116
+ const cy2 = innerHeight / 2;
1117
+ const maxVal = Math.max(...data.map((d, i) => value(d, i)), 1);
1118
+ const n = data.length;
1119
+ const angleStep = 2 * Math.PI / n;
1120
+ const arcs2 = data.map((d, i) => {
1121
+ const val = value(d, i);
1122
+ const outerR = innerRadius + val / maxVal * (r - innerRadius);
1123
+ return {
1124
+ data: d,
1125
+ index: i,
1126
+ startAngle: i * angleStep,
1127
+ endAngle: (i + 1) * angleStep,
1128
+ innerRadius,
1129
+ outerRadius: outerR
1130
+ };
1131
+ });
1132
+ const arcGen2 = arc().innerRadius((a) => a.innerRadius).outerRadius((a) => a.outerRadius).padAngle(padAngle).cornerRadius(cornerRadius);
1133
+ return { arcs: arcs2, arcGen: arcGen2, cx: cx2, cy: cy2 };
1134
+ }, [data, value, innerWidth, innerHeight, innerRadius, padAngle, cornerRadius]);
1135
+ return /* @__PURE__ */ jsx("g", { transform: `translate(${cx},${cy})`, children: arcs.map((arc, i) => {
1136
+ const d = arcGen(arc);
1137
+ if (!d) return null;
1138
+ const fill = colors[i % colors.length] ?? colors[0];
1139
+ const isHovered = hoveredIndex === i;
1140
+ const fillOpacity = hoveredIndex === null ? 0.92 : isHovered ? 1 : hoverDimOpacity;
1141
+ const [centroidX, centroidY] = arcGen.centroid(arc);
1142
+ return /* @__PURE__ */ jsxs("g", { children: [
1143
+ /* @__PURE__ */ jsx(
1144
+ "path",
1145
+ {
1146
+ d,
1147
+ fill,
1148
+ fillOpacity,
1149
+ className: `msc-pie-slice-hoverable ${animate ? "msc-pie-slice-animate" : ""}`.trim(),
1150
+ style: {
1151
+ ...animate ? { animation: `msc-pie-draw ${duration}ms ease-out ${i * 40}ms both` } : {},
1152
+ transition: "fill-opacity 0.2s ease",
1153
+ cursor: tooltip ? "pointer" : void 0
1154
+ },
1155
+ onMouseEnter: () => handleEnter(i),
1156
+ onMouseLeave: handleLeave
1157
+ }
1158
+ ),
1159
+ tooltip && isHovered && /* @__PURE__ */ jsx(
1160
+ TooltipPortal,
1161
+ {
1162
+ anchorX: cx + centroidX,
1163
+ anchorY: cy + centroidY,
1164
+ containerWidth: innerWidth,
1165
+ containerHeight: innerHeight,
1166
+ svgRef,
1167
+ margin,
1168
+ children: /* @__PURE__ */ jsx(DefaultTooltip, { ...tooltip(arc.data, i) })
1169
+ }
1170
+ )
1171
+ ] }, i);
1172
+ }) });
1173
+ }
1174
+ var DEFAULT_COLORS3 = [
1175
+ "var(--msc-s1)",
1176
+ "var(--msc-s2)",
1177
+ "var(--msc-s3)",
1178
+ "var(--msc-s4)",
1179
+ "var(--msc-s5)"
1180
+ ];
1181
+ function PieChart({
1182
+ data,
1183
+ value,
1184
+ label,
1185
+ colors = DEFAULT_COLORS3,
1186
+ width = 280,
1187
+ height = 260,
1188
+ margin = { top: 16, right: 16, bottom: 16, left: 16 },
1189
+ showLegend = true,
1190
+ showValues = true,
1191
+ valueFormat = (v) => String(v),
1192
+ innerRadius = 0,
1193
+ padAngle = 0.02,
1194
+ cornerRadius = 4,
1195
+ animate = true,
1196
+ defs,
1197
+ tooltip
1198
+ }) {
1199
+ const getColor = (i) => colors[i % colors.length] ?? colors[0] ?? "var(--msc-s1)";
1200
+ const legendItems = data.map((d, i) => ({
1201
+ label: label ? label(d, i) : `Item ${i + 1}`,
1202
+ value: showValues ? valueFormat(value(d, i)) : void 0,
1203
+ color: getColor(i)
1204
+ }));
1205
+ const defaultTooltip = tooltip ?? ((d, i) => ({
1206
+ title: label ? label(d, i) : `Item ${i + 1}`,
1207
+ rows: [{ label: "Value", value: valueFormat(value(d, i)), color: getColor(i) }]
1208
+ }));
1209
+ const chartMargin = {
1210
+ top: margin.top ?? 16,
1211
+ right: margin.right ?? 16,
1212
+ bottom: margin.bottom ?? 16,
1213
+ left: margin.left ?? 16
1214
+ };
1215
+ return /* @__PURE__ */ jsxs("div", { children: [
1216
+ /* @__PURE__ */ jsxs(Chart, { width, height, margin: chartMargin, children: [
1217
+ defs,
1218
+ /* @__PURE__ */ jsx(
1219
+ PieSeries,
1220
+ {
1221
+ data,
1222
+ value,
1223
+ colors,
1224
+ innerRadius,
1225
+ padAngle,
1226
+ cornerRadius,
1227
+ animate,
1228
+ tooltip: defaultTooltip
1229
+ }
1230
+ )
1231
+ ] }),
1232
+ showLegend && /* @__PURE__ */ jsx(Legend, { items: legendItems })
1233
+ ] });
1234
+ }
1235
+ function ComboChart({
1236
+ data,
1237
+ x,
1238
+ bar,
1239
+ line,
1240
+ barLabel = "Bar",
1241
+ lineLabel = "Line",
1242
+ barFill = "var(--msc-s1)",
1243
+ lineStroke = "var(--msc-s2)",
1244
+ width = 320,
1245
+ height = 200,
1246
+ margin = { top: 24, right: 16, bottom: 28, left: 46 },
1247
+ showMarkers = true,
1248
+ animate = true,
1249
+ defs,
1250
+ barTooltip,
1251
+ lineTooltip
1252
+ }) {
1253
+ const chartMargin = {
1254
+ top: margin.top ?? 24,
1255
+ right: margin.right ?? 16,
1256
+ bottom: margin.bottom ?? 28,
1257
+ left: margin.left ?? 46
1258
+ };
1259
+ const innerW = width - (chartMargin.left ?? 0) - (chartMargin.right ?? 0);
1260
+ const innerH = height - (chartMargin.top ?? 0) - (chartMargin.bottom ?? 0);
1261
+ const xScale = useMemo(
1262
+ () => scaleBand().domain(data.map((d, i) => x(d, i))).range([0, innerW]).padding(0.25),
1263
+ [data, x, innerW]
1264
+ );
1265
+ const yScale = useMemo(() => {
1266
+ const barVals = data.map((d, i) => bar(d, i));
1267
+ const lineVals = data.map((d, i) => line(d, i));
1268
+ const all = [...barVals, ...lineVals];
1269
+ return scaleLinear().domain([Math.min(...all, 0), Math.max(...all)]).nice().range([innerH, 0]);
1270
+ }, [data, bar, line, innerH]);
1271
+ const lineXScale = useMemo(() => {
1272
+ const firstD = data[0];
1273
+ const lastD = data[data.length - 1];
1274
+ const first = firstD ? (xScale(x(firstD, 0)) ?? 0) + xScale.bandwidth() / 2 : 0;
1275
+ const last = data.length > 1 && lastD ? (xScale(x(lastD, data.length - 1)) ?? 0) + xScale.bandwidth() / 2 : first;
1276
+ return scaleLinear().domain([0, Math.max(0, data.length - 1)]).range([first, last]);
1277
+ }, [data, x, xScale]);
1278
+ const bottomTicks = useMemo(
1279
+ () => data.map((d, i) => ({ value: x(d, i), x: (xScale(x(d, i)) ?? 0) + xScale.bandwidth() / 2, y: innerH })),
1280
+ [data, x, xScale, innerH]
1281
+ );
1282
+ const leftTicks = useMemo(() => yScale.ticks(5).map((v) => ({ value: String(v), x: 0, y: yScale(v) })), [yScale]);
1283
+ const xTicks = xScale.domain().map((m) => (xScale(m) ?? 0) + xScale.bandwidth() / 2);
1284
+ const yTicks = yScale.ticks(5).map((v) => yScale(v));
1285
+ const defaultBarTooltip = barTooltip ?? ((d, i) => ({
1286
+ title: x(d, i),
1287
+ rows: [{ label: barLabel, value: String(bar(d, i)), color: barFill }]
1288
+ }));
1289
+ const defaultLineTooltip = lineTooltip ?? ((d, i) => ({
1290
+ title: x(d, i),
1291
+ rows: [{ label: lineLabel, value: String(line(d, i)), color: lineStroke }]
1292
+ }));
1293
+ return /* @__PURE__ */ jsxs(Chart, { width, height, margin: chartMargin, children: [
1294
+ defs,
1295
+ /* @__PURE__ */ jsx(Grid, { xTicks, yTicks }),
1296
+ /* @__PURE__ */ jsx(AxisLeft, { ticks: leftTicks }),
1297
+ /* @__PURE__ */ jsx(AxisBottom, { ticks: bottomTicks }),
1298
+ /* @__PURE__ */ jsx(
1299
+ BarSeries,
1300
+ {
1301
+ data,
1302
+ x,
1303
+ y: bar,
1304
+ xScale,
1305
+ yScale,
1306
+ fill: barFill,
1307
+ animate,
1308
+ tooltip: defaultBarTooltip
1309
+ }
1310
+ ),
1311
+ /* @__PURE__ */ jsx(
1312
+ LineSeries,
1313
+ {
1314
+ data,
1315
+ x: (_, i) => i,
1316
+ y: line,
1317
+ xScale: lineXScale,
1318
+ yScale,
1319
+ stroke: lineStroke,
1320
+ showMarkers,
1321
+ animate,
1322
+ tooltip: defaultLineTooltip
1323
+ }
1324
+ )
1325
+ ] });
1326
+ }
1327
+ var HOVER_LEAVE_DELAY7 = 150;
1328
+ function RadarChart({
1329
+ data,
1330
+ value,
1331
+ label,
1332
+ colors = ["var(--msc-s1)", "var(--msc-s2)", "var(--msc-s3)"],
1333
+ width = 280,
1334
+ height = 280,
1335
+ margin = { top: 24, right: 24, bottom: 24, left: 24 },
1336
+ levels = 5,
1337
+ animate = true,
1338
+ duration = 500,
1339
+ fillOpacity = 0.25,
1340
+ strokeWidth = 2,
1341
+ fill,
1342
+ stroke,
1343
+ defs,
1344
+ tooltip
1345
+ }) {
1346
+ const chartMargin = {
1347
+ top: margin.top ?? 24,
1348
+ right: margin.right ?? 24,
1349
+ bottom: margin.bottom ?? 24,
1350
+ left: margin.left ?? 24
1351
+ };
1352
+ const innerW = width - (chartMargin.left ?? 0) - (chartMargin.right ?? 0);
1353
+ const innerH = height - (chartMargin.top ?? 0) - (chartMargin.bottom ?? 0);
1354
+ const cx = innerW / 2;
1355
+ const cy = innerH / 2;
1356
+ const radius = Math.min(cx, cy) - 16;
1357
+ const n = data.length;
1358
+ const angleStep = 2 * Math.PI / n;
1359
+ const points = useMemo(() => {
1360
+ const maxVal = Math.max(...data.map((d, i) => value(d, i)), 1);
1361
+ return data.map((d, i) => {
1362
+ const angle = i * angleStep - Math.PI / 2;
1363
+ const val = value(d, i);
1364
+ const r = val / maxVal * radius;
1365
+ return {
1366
+ x: cx + r * Math.cos(angle),
1367
+ y: cy + r * Math.sin(angle),
1368
+ label: label(d, i),
1369
+ value: val,
1370
+ datum: d,
1371
+ index: i
1372
+ };
1373
+ });
1374
+ }, [data, value, label, angleStep, radius, cx, cy]);
1375
+ const polygonPoints = points.map((p) => `${p.x},${p.y}`).join(" ");
1376
+ const fillColor = fill ?? colors[0] ?? "var(--msc-s1)";
1377
+ const strokeColor = stroke ?? colors[0] ?? "var(--msc-s1)";
1378
+ return /* @__PURE__ */ jsxs(Chart, { width, height, margin: chartMargin, children: [
1379
+ defs,
1380
+ /* @__PURE__ */ jsx(
1381
+ RadarGrid,
1382
+ {
1383
+ n,
1384
+ levels,
1385
+ cx,
1386
+ cy,
1387
+ radius,
1388
+ angleStep
1389
+ }
1390
+ ),
1391
+ /* @__PURE__ */ jsxs("g", { children: [
1392
+ /* @__PURE__ */ jsx(
1393
+ "polygon",
1394
+ {
1395
+ points: polygonPoints,
1396
+ fill: fillColor,
1397
+ fillOpacity,
1398
+ stroke: strokeColor,
1399
+ strokeWidth,
1400
+ style: {
1401
+ ...animate ? { animation: `msc-area-reveal ${duration}ms ease-out forwards` } : {}
1402
+ }
1403
+ }
1404
+ ),
1405
+ points.map((pt, i) => /* @__PURE__ */ jsx(
1406
+ RadarPoint,
1407
+ {
1408
+ pt,
1409
+ color: strokeColor,
1410
+ animate,
1411
+ duration,
1412
+ delay: i * 60,
1413
+ tooltip
1414
+ },
1415
+ i
1416
+ ))
1417
+ ] }),
1418
+ points.map((pt, i) => /* @__PURE__ */ jsx(
1419
+ "text",
1420
+ {
1421
+ x: pt.x + (pt.x >= cx ? 8 : -8),
1422
+ y: pt.y,
1423
+ textAnchor: pt.x >= cx ? "start" : "end",
1424
+ dominantBaseline: "middle",
1425
+ fontSize: 10,
1426
+ fill: "var(--msc-muted)",
1427
+ children: pt.label
1428
+ },
1429
+ `label-${i}`
1430
+ ))
1431
+ ] });
1432
+ }
1433
+ function RadarGrid({
1434
+ n,
1435
+ levels,
1436
+ cx,
1437
+ cy,
1438
+ radius,
1439
+ angleStep
1440
+ }) {
1441
+ const lines = [];
1442
+ for (let level = 1; level <= levels; level++) {
1443
+ const r = radius * level / levels;
1444
+ const pts = [];
1445
+ for (let i = 0; i <= n; i++) {
1446
+ const angle = i * angleStep - Math.PI / 2;
1447
+ pts.push(`${cx + r * Math.cos(angle)},${cy + r * Math.sin(angle)}`);
1448
+ }
1449
+ lines.push(
1450
+ /* @__PURE__ */ jsx(
1451
+ "polygon",
1452
+ {
1453
+ points: pts.join(" "),
1454
+ fill: "none",
1455
+ stroke: "var(--msc-grid)",
1456
+ strokeWidth: 1
1457
+ },
1458
+ `level-${level}`
1459
+ )
1460
+ );
1461
+ }
1462
+ for (let i = 0; i < n; i++) {
1463
+ const angle = i * angleStep - Math.PI / 2;
1464
+ const x2 = cx + radius * Math.cos(angle);
1465
+ const y2 = cy + radius * Math.sin(angle);
1466
+ lines.push(
1467
+ /* @__PURE__ */ jsx(
1468
+ "line",
1469
+ {
1470
+ x1: cx,
1471
+ y1: cy,
1472
+ x2,
1473
+ y2,
1474
+ stroke: "var(--msc-grid)",
1475
+ strokeWidth: 1
1476
+ },
1477
+ `axis-${i}`
1478
+ )
1479
+ );
1480
+ }
1481
+ return /* @__PURE__ */ jsx("g", { children: lines });
1482
+ }
1483
+ function RadarPoint({
1484
+ pt,
1485
+ color,
1486
+ animate,
1487
+ duration,
1488
+ delay,
1489
+ tooltip
1490
+ }) {
1491
+ const [hovered, setHovered] = useState(false);
1492
+ const leaveTimeoutRef = useRef(null);
1493
+ const { innerWidth, innerHeight, svgRef, margin, registerClearTooltip, clearAllTooltips } = useChart();
1494
+ useEffect(() => {
1495
+ const clear = () => {
1496
+ if (leaveTimeoutRef.current) clearTimeout(leaveTimeoutRef.current);
1497
+ setHovered(false);
1498
+ };
1499
+ return registerClearTooltip(clear);
1500
+ }, [registerClearTooltip]);
1501
+ const handleEnter = () => {
1502
+ if (leaveTimeoutRef.current) clearTimeout(leaveTimeoutRef.current);
1503
+ clearAllTooltips();
1504
+ setHovered(true);
1505
+ };
1506
+ const handleLeave = () => {
1507
+ leaveTimeoutRef.current = setTimeout(() => setHovered(false), HOVER_LEAVE_DELAY7);
1508
+ };
1509
+ return /* @__PURE__ */ jsxs("g", { children: [
1510
+ /* @__PURE__ */ jsx(
1511
+ "circle",
1512
+ {
1513
+ cx: pt.x,
1514
+ cy: pt.y,
1515
+ r: 5,
1516
+ fill: color,
1517
+ stroke: "var(--msc-panel)",
1518
+ strokeWidth: 2,
1519
+ style: {
1520
+ cursor: tooltip ? "pointer" : void 0,
1521
+ ...animate ? { animation: `msc-marker-pop 400ms ease-out ${delay}ms both` } : {}
1522
+ },
1523
+ onMouseEnter: handleEnter,
1524
+ onMouseLeave: handleLeave
1525
+ }
1526
+ ),
1527
+ tooltip && hovered && /* @__PURE__ */ jsx(
1528
+ TooltipPortal,
1529
+ {
1530
+ anchorX: pt.x,
1531
+ anchorY: pt.y,
1532
+ containerWidth: innerWidth,
1533
+ containerHeight: innerHeight,
1534
+ svgRef,
1535
+ margin,
1536
+ children: /* @__PURE__ */ jsx(DefaultTooltip, { ...tooltip(pt.datum, pt.index) })
1537
+ }
1538
+ )
1539
+ ] });
1540
+ }
1541
+ var DEFAULT_COLORS4 = [
1542
+ "var(--msc-s1)",
1543
+ "var(--msc-s2)",
1544
+ "var(--msc-s3)",
1545
+ "var(--msc-s4)",
1546
+ "var(--msc-s5)"
1547
+ ];
1548
+ function PolarAreaChart({
1549
+ data,
1550
+ value,
1551
+ label,
1552
+ colors = DEFAULT_COLORS4,
1553
+ width = 280,
1554
+ height = 260,
1555
+ margin = { top: 16, right: 16, bottom: 16, left: 16 },
1556
+ showLegend = true,
1557
+ showValues = true,
1558
+ valueFormat = (v) => String(v),
1559
+ animate = true,
1560
+ defs,
1561
+ tooltip
1562
+ }) {
1563
+ const getColor = (i) => colors[i % colors.length] ?? colors[0] ?? "var(--msc-s1)";
1564
+ const legendItems = data.map((d, i) => ({
1565
+ label: label ? label(d, i) : `Item ${i + 1}`,
1566
+ value: showValues ? valueFormat(value(d, i)) : void 0,
1567
+ color: getColor(i)
1568
+ }));
1569
+ const chartMargin = {
1570
+ top: margin.top ?? 16,
1571
+ right: margin.right ?? 16,
1572
+ bottom: margin.bottom ?? 16,
1573
+ left: margin.left ?? 16
1574
+ };
1575
+ return /* @__PURE__ */ jsxs("div", { children: [
1576
+ /* @__PURE__ */ jsxs(Chart, { width, height, margin: chartMargin, children: [
1577
+ defs,
1578
+ /* @__PURE__ */ jsx(
1579
+ PolarAreaSeries,
1580
+ {
1581
+ data,
1582
+ value,
1583
+ colors,
1584
+ animate,
1585
+ tooltip
1586
+ }
1587
+ )
1588
+ ] }),
1589
+ showLegend && /* @__PURE__ */ jsx(Legend, { items: legendItems })
1590
+ ] });
1591
+ }
1592
+ function MultiaxisLineChart({
1593
+ data,
1594
+ x,
1595
+ leftLine,
1596
+ rightLine,
1597
+ leftLabel = "Left",
1598
+ rightLabel = "Right",
1599
+ leftStroke = "var(--msc-s1)",
1600
+ rightStroke = "var(--msc-s2)",
1601
+ width = 400,
1602
+ height = 240,
1603
+ margin = { top: 24, right: 48, bottom: 28, left: 48 },
1604
+ showMarkers = true,
1605
+ defs,
1606
+ leftTooltip,
1607
+ rightTooltip
1608
+ }) {
1609
+ const chartMargin = {
1610
+ top: margin.top ?? 24,
1611
+ right: margin.right ?? 48,
1612
+ bottom: margin.bottom ?? 28,
1613
+ left: margin.left ?? 48
1614
+ };
1615
+ const innerW = width - (chartMargin.left ?? 0) - (chartMargin.right ?? 0);
1616
+ const innerH = height - (chartMargin.top ?? 0) - (chartMargin.bottom ?? 0);
1617
+ const leftVals = data.map((d, i) => leftLine(d, i));
1618
+ const rightVals = data.map((d, i) => rightLine(d, i));
1619
+ const leftYScale = useMemo(
1620
+ () => scaleLinear().domain([Math.min(...leftVals, 0), Math.max(...leftVals)]).nice().range([innerH, 0]),
1621
+ [leftVals, innerH]
1622
+ );
1623
+ const rightYScale = useMemo(
1624
+ () => scaleLinear().domain([Math.min(...rightVals, 0), Math.max(...rightVals)]).nice().range([innerH, 0]),
1625
+ [rightVals, innerH]
1626
+ );
1627
+ const xScale = useMemo(() => {
1628
+ const labels = data.map((d, i) => String(x(d, i)));
1629
+ return scaleBand().domain(labels).range([0, innerW]).padding(0.25);
1630
+ }, [data, x, innerW]);
1631
+ const lineXScale = useMemo(() => {
1632
+ const domain = xScale.domain();
1633
+ const firstLabel = domain[0] ?? "";
1634
+ const lastLabel = domain[domain.length - 1] ?? firstLabel;
1635
+ const first = (xScale(firstLabel) ?? 0) + xScale.bandwidth() / 2;
1636
+ const last = (xScale(lastLabel) ?? first) + xScale.bandwidth() / 2;
1637
+ return scaleLinear().domain([0, data.length - 1]).range([first, last]);
1638
+ }, [xScale, data.length]);
1639
+ const bottomTicks = useMemo(
1640
+ () => data.map((d, i) => ({
1641
+ value: String(x(d, i)),
1642
+ x: (xScale(String(x(d, i))) ?? 0) + xScale.bandwidth() / 2,
1643
+ y: innerH
1644
+ })),
1645
+ [data, x, xScale, innerH]
1646
+ );
1647
+ const leftTicks = useMemo(
1648
+ () => leftYScale.ticks(5).map((v) => ({ value: String(v), x: 0, y: leftYScale(v) })),
1649
+ [leftYScale]
1650
+ );
1651
+ const rightTicks = useMemo(
1652
+ () => rightYScale.ticks(5).map((v) => ({
1653
+ value: String(v),
1654
+ x: innerW,
1655
+ y: rightYScale(v)
1656
+ })),
1657
+ [rightYScale, innerW]
1658
+ );
1659
+ const xTicks = xScale.domain().map((m) => (xScale(m) ?? 0) + xScale.bandwidth() / 2);
1660
+ const yTicks = leftYScale.ticks(5).map((v) => leftYScale(v));
1661
+ const defaultLeftTooltip = leftTooltip ?? ((d, i) => ({
1662
+ title: String(x(d, i)),
1663
+ rows: [{ label: leftLabel, value: String(leftLine(d, i)), color: leftStroke }]
1664
+ }));
1665
+ const defaultRightTooltip = rightTooltip ?? ((d, i) => ({
1666
+ title: String(x(d, i)),
1667
+ rows: [{ label: rightLabel, value: String(rightLine(d, i)), color: rightStroke }]
1668
+ }));
1669
+ return /* @__PURE__ */ jsxs(Chart, { width, height, margin: chartMargin, children: [
1670
+ defs,
1671
+ /* @__PURE__ */ jsx(Grid, { xTicks, yTicks }),
1672
+ /* @__PURE__ */ jsx(AxisLeft, { ticks: leftTicks }),
1673
+ /* @__PURE__ */ jsx(AxisRight, { ticks: rightTicks, x: innerW }),
1674
+ /* @__PURE__ */ jsx(AxisBottom, { ticks: bottomTicks }),
1675
+ /* @__PURE__ */ jsx(
1676
+ LineSeries,
1677
+ {
1678
+ data,
1679
+ x: (_, i) => i,
1680
+ y: leftLine,
1681
+ xScale: lineXScale,
1682
+ yScale: leftYScale,
1683
+ stroke: leftStroke,
1684
+ showMarkers,
1685
+ tooltip: defaultLeftTooltip
1686
+ }
1687
+ ),
1688
+ /* @__PURE__ */ jsx(
1689
+ LineSeries,
1690
+ {
1691
+ data,
1692
+ x: (_, i) => i,
1693
+ y: rightLine,
1694
+ xScale: lineXScale,
1695
+ yScale: rightYScale,
1696
+ stroke: rightStroke,
1697
+ showMarkers,
1698
+ tooltip: defaultRightTooltip
1699
+ }
1700
+ )
1701
+ ] });
1702
+ }
1703
+ var HOVER_LEAVE_DELAY8 = 150;
1704
+ function ScatterSeries({
1705
+ data,
1706
+ x,
1707
+ y,
1708
+ xScale,
1709
+ yScale,
1710
+ fill = "var(--msc-s1)",
1711
+ stroke = "var(--msc-panel)",
1712
+ strokeWidth = 2,
1713
+ radius = 5,
1714
+ animate = true,
1715
+ duration = 400,
1716
+ hoverDimOpacity = 0.5,
1717
+ tooltip
1718
+ }) {
1719
+ const [hoveredIndex, setHoveredIndex] = useState(null);
1720
+ const leaveTimeoutRef = useRef(null);
1721
+ const { innerWidth, innerHeight, svgRef, margin, registerClearTooltip, clearAllTooltips } = useChart();
1722
+ const clearTooltip = () => {
1723
+ if (leaveTimeoutRef.current) clearTimeout(leaveTimeoutRef.current);
1724
+ leaveTimeoutRef.current = null;
1725
+ setHoveredIndex(null);
1726
+ };
1727
+ useEffect(() => {
1728
+ return registerClearTooltip(clearTooltip);
1729
+ }, [registerClearTooltip]);
1730
+ const handleEnter = (i) => {
1731
+ if (leaveTimeoutRef.current) {
1732
+ clearTimeout(leaveTimeoutRef.current);
1733
+ leaveTimeoutRef.current = null;
1734
+ }
1735
+ clearAllTooltips();
1736
+ setHoveredIndex(i);
1737
+ };
1738
+ const handleLeave = () => {
1739
+ leaveTimeoutRef.current = setTimeout(clearTooltip, HOVER_LEAVE_DELAY8);
1740
+ };
1741
+ return /* @__PURE__ */ jsx("g", { children: data.map((d, i) => {
1742
+ const xx = xScale(x(d, i));
1743
+ const yy = yScale(y(d, i));
1744
+ if (!Number.isFinite(xx) || !Number.isFinite(yy)) return null;
1745
+ const isHovered = hoveredIndex === i;
1746
+ const opacity = hoveredIndex === null ? 0.92 : isHovered ? 1 : hoverDimOpacity;
1747
+ return /* @__PURE__ */ jsxs("g", { children: [
1748
+ /* @__PURE__ */ jsx(
1749
+ "circle",
1750
+ {
1751
+ cx: xx,
1752
+ cy: yy,
1753
+ r: radius,
1754
+ fill,
1755
+ stroke,
1756
+ strokeWidth,
1757
+ opacity,
1758
+ style: {
1759
+ transition: "opacity 0.2s ease",
1760
+ cursor: tooltip ? "pointer" : void 0,
1761
+ ...animate ? { animation: `msc-marker-pop ${duration}ms ease-out ${i * 50}ms both` } : {}
1762
+ },
1763
+ onMouseEnter: () => handleEnter(i),
1764
+ onMouseLeave: handleLeave
1765
+ }
1766
+ ),
1767
+ tooltip && isHovered && /* @__PURE__ */ jsx(
1768
+ TooltipPortal,
1769
+ {
1770
+ anchorX: xx,
1771
+ anchorY: yy,
1772
+ containerWidth: innerWidth,
1773
+ containerHeight: innerHeight,
1774
+ svgRef,
1775
+ margin,
1776
+ children: /* @__PURE__ */ jsx(DefaultTooltip, { ...tooltip(d, i) })
1777
+ }
1778
+ )
1779
+ ] }, i);
1780
+ }) });
1781
+ }
1782
+ var HOVER_LEAVE_DELAY9 = 150;
1783
+ var MIN_RADIUS = 4;
1784
+ var MAX_RADIUS = 24;
1785
+ function BubbleSeries({
1786
+ data,
1787
+ x,
1788
+ y,
1789
+ size,
1790
+ xScale,
1791
+ yScale,
1792
+ fill = "var(--msc-s1)",
1793
+ stroke = "var(--msc-panel)",
1794
+ strokeWidth = 2,
1795
+ fillOpacity = 0.7,
1796
+ animate = true,
1797
+ duration = 400,
1798
+ hoverDimOpacity = 0.5,
1799
+ tooltip
1800
+ }) {
1801
+ const [hoveredIndex, setHoveredIndex] = useState(null);
1802
+ const leaveTimeoutRef = useRef(null);
1803
+ const { innerWidth, innerHeight, svgRef, margin, registerClearTooltip, clearAllTooltips } = useChart();
1804
+ const sizeScale = useMemo(() => {
1805
+ const sizes = data.map((d, i) => size(d, i));
1806
+ const min = Math.min(...sizes);
1807
+ const max = Math.max(...sizes);
1808
+ return (v) => {
1809
+ if (max === min) return (MIN_RADIUS + MAX_RADIUS) / 2;
1810
+ const t = (v - min) / (max - min);
1811
+ return MIN_RADIUS + t * (MAX_RADIUS - MIN_RADIUS);
1812
+ };
1813
+ }, [data, size]);
1814
+ const clearTooltip = () => {
1815
+ if (leaveTimeoutRef.current) clearTimeout(leaveTimeoutRef.current);
1816
+ leaveTimeoutRef.current = null;
1817
+ setHoveredIndex(null);
1818
+ };
1819
+ useEffect(() => {
1820
+ return registerClearTooltip(clearTooltip);
1821
+ }, [registerClearTooltip]);
1822
+ const handleEnter = (i) => {
1823
+ if (leaveTimeoutRef.current) {
1824
+ clearTimeout(leaveTimeoutRef.current);
1825
+ leaveTimeoutRef.current = null;
1826
+ }
1827
+ clearAllTooltips();
1828
+ setHoveredIndex(i);
1829
+ };
1830
+ const handleLeave = () => {
1831
+ leaveTimeoutRef.current = setTimeout(clearTooltip, HOVER_LEAVE_DELAY9);
1832
+ };
1833
+ return /* @__PURE__ */ jsx("g", { children: data.map((d, i) => {
1834
+ const xx = xScale(x(d, i));
1835
+ const yy = yScale(y(d, i));
1836
+ if (!Number.isFinite(xx) || !Number.isFinite(yy)) return null;
1837
+ const r = sizeScale(size(d, i));
1838
+ const isHovered = hoveredIndex === i;
1839
+ const opacity = hoveredIndex === null ? fillOpacity : isHovered ? fillOpacity : hoverDimOpacity;
1840
+ return /* @__PURE__ */ jsxs("g", { children: [
1841
+ /* @__PURE__ */ jsx(
1842
+ "circle",
1843
+ {
1844
+ cx: xx,
1845
+ cy: yy,
1846
+ r,
1847
+ fill,
1848
+ stroke,
1849
+ strokeWidth,
1850
+ fillOpacity: opacity,
1851
+ style: {
1852
+ transition: "opacity 0.2s ease",
1853
+ cursor: tooltip ? "pointer" : void 0,
1854
+ ...animate ? { animation: `msc-marker-pop ${duration}ms ease-out ${i * 50}ms both` } : {}
1855
+ },
1856
+ onMouseEnter: () => handleEnter(i),
1857
+ onMouseLeave: handleLeave
1858
+ }
1859
+ ),
1860
+ tooltip && isHovered && /* @__PURE__ */ jsx(
1861
+ TooltipPortal,
1862
+ {
1863
+ anchorX: xx,
1864
+ anchorY: yy,
1865
+ containerWidth: innerWidth,
1866
+ containerHeight: innerHeight,
1867
+ svgRef,
1868
+ margin,
1869
+ children: /* @__PURE__ */ jsx(DefaultTooltip, { ...tooltip(d, i) })
1870
+ }
1871
+ )
1872
+ ] }, i);
1873
+ }) });
1874
+ }
1875
+ function interpolateColor(t, stops) {
1876
+ if (stops.length === 0) return "var(--msc-grid)";
1877
+ const first = stops[0];
1878
+ if (stops.length === 1 || !first) return first?.color ?? "var(--msc-grid)";
1879
+ t = Math.max(0, Math.min(1, t));
1880
+ for (let i = 0; i < stops.length - 1; i++) {
1881
+ const a = stops[i];
1882
+ const b = stops[i + 1];
1883
+ if (a && b && t >= a.offset && t <= b.offset) {
1884
+ const local = (t - a.offset) / (b.offset - a.offset || 1);
1885
+ return lerpColor(a.color, b.color, local);
1886
+ }
1887
+ }
1888
+ const last = stops[stops.length - 1];
1889
+ return last?.color ?? "var(--msc-grid)";
1890
+ }
1891
+ function lerpColor(a, b, t) {
1892
+ const parse = (hex) => {
1893
+ const m = hex.match(/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i);
1894
+ return m ? [parseInt(m[1] ?? "0", 16), parseInt(m[2] ?? "0", 16), parseInt(m[3] ?? "0", 16)] : [0, 0, 0];
1895
+ };
1896
+ const [r1, g1, b1] = parse(a);
1897
+ const [r2, g2, b2] = parse(b);
1898
+ const r = Math.round(r1 + (r2 - r1) * t);
1899
+ const g = Math.round(g1 + (g2 - g1) * t);
1900
+ const bl = Math.round(b1 + (b2 - b1) * t);
1901
+ return `rgb(${r},${g},${bl})`;
1902
+ }
1903
+ function HeatmapSeries({
1904
+ rows,
1905
+ columns,
1906
+ data,
1907
+ colorScale = ["#93c5fd", "#3b82f6", "#8b5cf6", "#7c3aed"],
1908
+ gradientStops,
1909
+ animate = true,
1910
+ duration = 300,
1911
+ hoverDimOpacity = 0.7,
1912
+ tooltip
1913
+ }) {
1914
+ const [hovered, setHovered] = useState(null);
1915
+ const leaveTimeoutRef = useRef(null);
1916
+ const { innerWidth, innerHeight, svgRef, margin, registerClearTooltip, clearAllTooltips } = useChart();
1917
+ const clearTooltip = () => {
1918
+ if (leaveTimeoutRef.current) clearTimeout(leaveTimeoutRef.current);
1919
+ leaveTimeoutRef.current = null;
1920
+ setHovered(null);
1921
+ };
1922
+ useEffect(() => {
1923
+ return registerClearTooltip(clearTooltip);
1924
+ }, [registerClearTooltip]);
1925
+ const handleEnter = (r, c) => {
1926
+ if (leaveTimeoutRef.current) {
1927
+ clearTimeout(leaveTimeoutRef.current);
1928
+ leaveTimeoutRef.current = null;
1929
+ }
1930
+ clearAllTooltips();
1931
+ setHovered({ r, c });
1932
+ };
1933
+ const handleLeave = () => {
1934
+ leaveTimeoutRef.current = setTimeout(clearTooltip, 150);
1935
+ };
1936
+ const { cellWidth, cellHeight, minVal, maxVal } = useMemo(() => {
1937
+ const cellW = innerWidth / Math.max(columns.length, 1);
1938
+ const cellH = innerHeight / Math.max(rows.length, 1);
1939
+ let min = Infinity;
1940
+ let max = -Infinity;
1941
+ data.forEach(
1942
+ (row) => row.forEach((cell) => {
1943
+ if (cell.value < min) min = cell.value;
1944
+ if (cell.value > max) max = cell.value;
1945
+ })
1946
+ );
1947
+ if (min === Infinity) min = 0;
1948
+ if (max === -Infinity) max = 1;
1949
+ return { cellWidth: cellW, cellHeight: cellH, minVal: min, maxVal: max };
1950
+ }, [innerWidth, innerHeight, columns.length, rows.length, data]);
1951
+ const getColor = (value) => {
1952
+ const t = maxVal === minVal ? 0 : (value - minVal) / (maxVal - minVal);
1953
+ if (gradientStops && gradientStops.length > 0) {
1954
+ return interpolateColor(t, gradientStops);
1955
+ }
1956
+ if (colorScale.length === 0) return "var(--msc-grid)";
1957
+ const idx = Math.min(
1958
+ Math.floor(t * (colorScale.length - 1)),
1959
+ colorScale.length - 1
1960
+ );
1961
+ return colorScale[idx];
1962
+ };
1963
+ return /* @__PURE__ */ jsxs("g", { children: [
1964
+ rows.map((rowLabel, r) => /* @__PURE__ */ jsx(
1965
+ "text",
1966
+ {
1967
+ x: -8,
1968
+ y: r * cellHeight + cellHeight / 2,
1969
+ textAnchor: "end",
1970
+ fontSize: 10,
1971
+ fill: "var(--msc-muted)",
1972
+ dy: "0.32em",
1973
+ children: rowLabel
1974
+ },
1975
+ `row-${r}`
1976
+ )),
1977
+ columns.map((colLabel, c) => /* @__PURE__ */ jsx(
1978
+ "text",
1979
+ {
1980
+ x: c * cellWidth + cellWidth / 2,
1981
+ y: innerHeight + 16,
1982
+ textAnchor: "middle",
1983
+ fontSize: 10,
1984
+ fill: "var(--msc-muted)",
1985
+ children: colLabel
1986
+ },
1987
+ `col-${c}`
1988
+ )),
1989
+ rows.map(
1990
+ (rowLabel, r) => columns.map((colLabel, c) => {
1991
+ const cell = data[r]?.[c] ?? { value: 0 };
1992
+ const x = c * cellWidth;
1993
+ const y = r * cellHeight;
1994
+ const isHovered = hovered?.r === r && hovered?.c === c;
1995
+ const opacity = hovered === null ? 1 : isHovered ? 1 : hoverDimOpacity;
1996
+ return /* @__PURE__ */ jsxs("g", { children: [
1997
+ /* @__PURE__ */ jsx(
1998
+ "rect",
1999
+ {
2000
+ x: x + 1,
2001
+ y: y + 1,
2002
+ width: cellWidth - 2,
2003
+ height: cellHeight - 2,
2004
+ fill: getColor(cell.value),
2005
+ opacity,
2006
+ rx: 2,
2007
+ style: {
2008
+ ...animate ? { animation: `msc-area-reveal ${duration}ms ease-out ${(r * columns.length + c) * 20}ms both` } : {},
2009
+ transition: "opacity 0.2s ease",
2010
+ cursor: tooltip ? "pointer" : void 0
2011
+ },
2012
+ onMouseEnter: () => handleEnter(r, c),
2013
+ onMouseLeave: handleLeave
2014
+ }
2015
+ ),
2016
+ tooltip && isHovered && /* @__PURE__ */ jsx(
2017
+ TooltipPortal,
2018
+ {
2019
+ anchorX: x + cellWidth / 2,
2020
+ anchorY: y + cellHeight / 2,
2021
+ containerWidth: innerWidth,
2022
+ containerHeight: innerHeight,
2023
+ svgRef,
2024
+ margin,
2025
+ children: /* @__PURE__ */ jsx(DefaultTooltip, { ...tooltip(rowLabel, colLabel, cell) })
2026
+ }
2027
+ )
2028
+ ] }, `${r}-${c}`);
2029
+ })
2030
+ )
2031
+ ] });
2032
+ }
2033
+ function useNearestPoint(data, xAccessor, xScale, yAccessor, yScale) {
2034
+ bisector((d) => xAccessor(d, 0)).center;
2035
+ return function findNearest(pointerX) {
2036
+ if (!data.length) return null;
2037
+ const lastDatum = data[data.length - 1];
2038
+ if (lastDatum === void 0) return null;
2039
+ const approxIndex = Math.round(pointerX / Math.max(xScale(xAccessor(lastDatum, data.length - 1)), 1) * (data.length - 1));
2040
+ const seed = Math.max(0, Math.min(data.length - 1, approxIndex));
2041
+ const idx = Math.max(0, Math.min(data.length - 1, seed));
2042
+ const d = data[idx];
2043
+ if (d === void 0) return null;
2044
+ const x = xScale(xAccessor(d, idx));
2045
+ const y = yScale(yAccessor(d, idx));
2046
+ const distance = Math.abs(pointerX - x);
2047
+ return { index: idx, datum: d, x, y, distance };
2048
+ };
2049
+ }
2050
+
2051
+ export { AreaSeries, AxisBottom, AxisLeft, AxisRight, BarSeries, BubbleSeries, Chart, ChartTitle, ComboChart, DefaultTooltip, Grid, GroupedBarSeries, HeatmapSeries, HorizontalBarSeries, Legend, LineSeries, LinearGradient, MultiaxisLineChart, PieChart, PieSeries, PolarAreaChart, PolarAreaSeries, RadarChart, RadialGradient, ScatterSeries, StackedBarSeries, ThemeProvider, ThresholdLine, TooltipPortal, computeTooltipPosition, useChart, useNearestPoint, useTheme };
2052
+ //# sourceMappingURL=index.js.map
2053
+ //# sourceMappingURL=index.js.map