chartifypdf 0.2.0 → 0.4.0
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/README.md +192 -10
- package/dist/components/ExportButton.d.ts +16 -0
- package/dist/hooks/useZoom.d.ts +1 -0
- package/dist/index.d.ts +18 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/types/chart.types.d.ts +9 -0
- package/dist/utils/exportPdf.d.ts +5 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
# ChartifyPDF
|
|
2
2
|
|
|
3
|
-
A zero-dependency React line chart component built with pure SVG. Supports zoom,
|
|
3
|
+
A zero-dependency React line chart component built with pure SVG. Supports semantic zoom, smooth curves, hover highlight, peak markers, context menu, export to PDF/PNG/SVG, and more.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **Pure SVG** — no external charting libraries
|
|
8
8
|
- **TypeScript** — fully typed props and exports
|
|
9
9
|
- **Responsive** — auto-resizes via ResizeObserver, or set fixed dimensions
|
|
10
|
-
- **Zoom
|
|
10
|
+
- **Semantic Zoom** — domain-based zoom with Ctrl+scroll, labels auto-update granularity
|
|
11
|
+
- **Smooth Curves** — monotone cubic (Fritsch-Carlson) and natural cubic spline
|
|
12
|
+
- **Hover Highlight** — hovered series stays bright, others dim with smooth transition
|
|
13
|
+
- **Peak Markers** — configurable icons (arrow/diamond/star) at peak data points
|
|
14
|
+
- **Right-Click Context Menu** — data table popover showing all series values
|
|
15
|
+
- **Export** — export chart as PDF, PNG, or SVG with one click
|
|
16
|
+
- **Click to Zoom** — click a data point to zoom in, double-click to reset
|
|
11
17
|
- **Tooltips** — hover to see data values, with custom formatters and renderers
|
|
12
18
|
- **Multi-series** — plot multiple data lines on one chart
|
|
13
19
|
- **Customizable** — colors, axes, grid lines, fonts, margins, and more
|
|
@@ -67,6 +73,10 @@ function App() {
|
|
|
67
73
|
| `className` | `string` | — | CSS class for container div |
|
|
68
74
|
| `onPointClick` | `(point, series) => void` | — | Click handler for data points |
|
|
69
75
|
| `ariaLabel` | `string` | `"Line chart"` | Accessibility label |
|
|
76
|
+
| `curveType` | `CurveType` | `"linear"` | Global curve type: `"linear"` \| `"monotone"` \| `"natural"` |
|
|
77
|
+
| `peaks` | `PeakConfig[]` | — | Peak date markers |
|
|
78
|
+
| `contextMenu` | `ContextMenuConfig` | — | Right-click context menu config |
|
|
79
|
+
| `export` | `ExportConfig` | — | Export button config |
|
|
70
80
|
|
|
71
81
|
### `DataSeries`
|
|
72
82
|
|
|
@@ -80,6 +90,7 @@ function App() {
|
|
|
80
90
|
| `strokeDasharray` | `string` | — | SVG dash pattern (e.g. `"5 3"`) |
|
|
81
91
|
| `showDots` | `boolean` | `false` | Show circles at data points |
|
|
82
92
|
| `dotRadius` | `number` | `3.5` | Dot circle radius |
|
|
93
|
+
| `curveType` | `CurveType` | — | Per-series curve override |
|
|
83
94
|
|
|
84
95
|
### `AxisConfig`
|
|
85
96
|
|
|
@@ -92,6 +103,7 @@ function App() {
|
|
|
92
103
|
| `max` | `number` | auto | Override axis maximum |
|
|
93
104
|
| `gridLines` | `boolean` | Y: `true`, X: `false` | Show grid lines |
|
|
94
105
|
| `gridLineColor` | `string` | `"#e0e0e0"` | Grid line color |
|
|
106
|
+
| `integerTicks` | `boolean` | `false` | Force integer-only ticks (useful for date timelines) |
|
|
95
107
|
|
|
96
108
|
### `TooltipConfig`
|
|
97
109
|
|
|
@@ -115,6 +127,35 @@ function App() {
|
|
|
115
127
|
| `controlsPosition` | `string` | `"top-right"` | `"top-left"` \| `"top-right"` \| `"bottom-left"` \| `"bottom-right"` |
|
|
116
128
|
| `enableWheel` | `boolean` | `true` | Zoom with mouse wheel |
|
|
117
129
|
| `enablePan` | `boolean` | `true` | Pan by dragging |
|
|
130
|
+
| `requireCtrlKey` | `boolean` | `true` | Require Ctrl/Cmd key for wheel zoom (prevents accidental page scroll) |
|
|
131
|
+
| `enableClickZoom` | `boolean` | `false` | Click to zoom into a data point, double-click to reset |
|
|
132
|
+
|
|
133
|
+
### `PeakConfig`
|
|
134
|
+
|
|
135
|
+
| Field | Type | Default | Description |
|
|
136
|
+
|-------|------|---------|-------------|
|
|
137
|
+
| `x` | `number` | *required* | X position of the peak |
|
|
138
|
+
| `label` | `string` | — | Label text above the marker |
|
|
139
|
+
| `color` | `string` | `"#ef4444"` | Marker color |
|
|
140
|
+
| `icon` | `string` | `"arrow"` | `"arrow"` \| `"diamond"` \| `"star"` |
|
|
141
|
+
|
|
142
|
+
### `ContextMenuConfig`
|
|
143
|
+
|
|
144
|
+
| Field | Type | Default | Description |
|
|
145
|
+
|-------|------|---------|-------------|
|
|
146
|
+
| `enabled` | `boolean` | `false` | Enable right-click context menu |
|
|
147
|
+
| `backgroundColor` | `string` | `"#ffffff"` | Menu background color |
|
|
148
|
+
| `textColor` | `string` | `"#1f2937"` | Menu text color |
|
|
149
|
+
| `borderColor` | `string` | `"#e5e7eb"` | Menu border color |
|
|
150
|
+
|
|
151
|
+
### `ExportConfig`
|
|
152
|
+
|
|
153
|
+
| Field | Type | Default | Description |
|
|
154
|
+
|-------|------|---------|-------------|
|
|
155
|
+
| `enabled` | `boolean` | `false` | Show export button |
|
|
156
|
+
| `buttonPosition` | `string` | `"top-right"` | `"top-left"` \| `"top-right"` \| `"bottom-left"` \| `"bottom-right"` |
|
|
157
|
+
| `fileName` | `string` | `"chart"` | Exported file name (without extension) |
|
|
158
|
+
| `format` | `string` | `"pdf"` | `"pdf"` \| `"png"` \| `"svg"` |
|
|
118
159
|
|
|
119
160
|
### `ChartStyle`
|
|
120
161
|
|
|
@@ -144,6 +185,31 @@ function App() {
|
|
|
144
185
|
|
|
145
186
|
The chart fills its parent container's width and updates on resize.
|
|
146
187
|
|
|
188
|
+
### Smooth Curved Lines
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
<LineChart
|
|
192
|
+
data={data}
|
|
193
|
+
curveType="monotone"
|
|
194
|
+
width={800}
|
|
195
|
+
height={400}
|
|
196
|
+
/>
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Available curve types:
|
|
200
|
+
- `"linear"` — straight lines (default)
|
|
201
|
+
- `"monotone"` — Fritsch-Carlson monotone cubic, no overshoot (best for data)
|
|
202
|
+
- `"natural"` — natural cubic spline, smoother but may overshoot
|
|
203
|
+
|
|
204
|
+
Per-series override:
|
|
205
|
+
|
|
206
|
+
```tsx
|
|
207
|
+
const data = [
|
|
208
|
+
{ id: "a", name: "Smooth", data: [...], curveType: "monotone" },
|
|
209
|
+
{ id: "b", name: "Linear", data: [...], curveType: "linear" },
|
|
210
|
+
];
|
|
211
|
+
```
|
|
212
|
+
|
|
147
213
|
### Multi-series with Custom Colors
|
|
148
214
|
|
|
149
215
|
```tsx
|
|
@@ -167,19 +233,91 @@ const data = [
|
|
|
167
233
|
<LineChart data={data} width={800} height={400} />
|
|
168
234
|
```
|
|
169
235
|
|
|
170
|
-
|
|
236
|
+
Hover over any line to highlight it — the hovered series stays at full opacity while others dim to 20%.
|
|
237
|
+
|
|
238
|
+
### Semantic Zoom with Integer Timeline
|
|
171
239
|
|
|
172
240
|
```tsx
|
|
173
241
|
<LineChart
|
|
174
242
|
data={data}
|
|
175
243
|
width={800}
|
|
176
244
|
height={400}
|
|
177
|
-
xAxis={{
|
|
178
|
-
|
|
179
|
-
|
|
245
|
+
xAxis={{
|
|
246
|
+
label: "Day",
|
|
247
|
+
integerTicks: true,
|
|
248
|
+
tickFormat: (v) => `Day ${v}`,
|
|
249
|
+
}}
|
|
250
|
+
zoom={{
|
|
251
|
+
enabled: true,
|
|
252
|
+
maxScale: 5,
|
|
253
|
+
requireCtrlKey: true,
|
|
254
|
+
enableClickZoom: true,
|
|
255
|
+
}}
|
|
180
256
|
/>
|
|
181
257
|
```
|
|
182
258
|
|
|
259
|
+
- **Ctrl + scroll** to zoom — page scrolls normally without Ctrl
|
|
260
|
+
- **Click** a data point to zoom 2x centered at that point
|
|
261
|
+
- **Double-click** to reset zoom
|
|
262
|
+
- X-axis labels automatically update granularity when zoomed
|
|
263
|
+
- `integerTicks: true` prevents decimal values on date timelines
|
|
264
|
+
|
|
265
|
+
### Peak Markers
|
|
266
|
+
|
|
267
|
+
```tsx
|
|
268
|
+
<LineChart
|
|
269
|
+
data={data}
|
|
270
|
+
peaks={[
|
|
271
|
+
{ x: 3, label: "Peak", icon: "star", color: "#ef4444" },
|
|
272
|
+
{ x: 7, label: "ATH", icon: "arrow" },
|
|
273
|
+
]}
|
|
274
|
+
/>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Right-Click Context Menu
|
|
278
|
+
|
|
279
|
+
```tsx
|
|
280
|
+
<LineChart
|
|
281
|
+
data={data}
|
|
282
|
+
contextMenu={{
|
|
283
|
+
enabled: true,
|
|
284
|
+
backgroundColor: "#1a1a2e",
|
|
285
|
+
textColor: "#eee",
|
|
286
|
+
borderColor: "#333",
|
|
287
|
+
}}
|
|
288
|
+
/>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Right-click anywhere on the chart to see a data table showing all series values at the nearest X position. Press Escape or click outside to close.
|
|
292
|
+
|
|
293
|
+
### Export to PDF/PNG/SVG
|
|
294
|
+
|
|
295
|
+
```tsx
|
|
296
|
+
<LineChart
|
|
297
|
+
data={data}
|
|
298
|
+
export={{
|
|
299
|
+
enabled: true,
|
|
300
|
+
format: "png",
|
|
301
|
+
fileName: "my-chart",
|
|
302
|
+
buttonPosition: "top-right",
|
|
303
|
+
}}
|
|
304
|
+
/>
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
A download button appears in the chart. Click to export.
|
|
308
|
+
|
|
309
|
+
For programmatic export:
|
|
310
|
+
|
|
311
|
+
```tsx
|
|
312
|
+
import { exportChart, exportChartAsPdf, exportChartAsPng, exportChartAsSvg } from "chartifypdf";
|
|
313
|
+
|
|
314
|
+
// Using a ref to the SVG element
|
|
315
|
+
const svgElement = document.querySelector("svg");
|
|
316
|
+
await exportChart(svgElement, "pdf", "my-chart");
|
|
317
|
+
await exportChartAsPng(svgElement, "my-chart");
|
|
318
|
+
await exportChartAsSvg(svgElement, "my-chart");
|
|
319
|
+
```
|
|
320
|
+
|
|
183
321
|
### Custom Tooltip
|
|
184
322
|
|
|
185
323
|
```tsx
|
|
@@ -231,20 +369,63 @@ const data = [
|
|
|
231
369
|
|
|
232
370
|
Note: Set `showDots: true` on the series to make points clickable.
|
|
233
371
|
|
|
372
|
+
### Full-featured Example
|
|
373
|
+
|
|
374
|
+
```tsx
|
|
375
|
+
<LineChart
|
|
376
|
+
data={data}
|
|
377
|
+
width={900}
|
|
378
|
+
height={500}
|
|
379
|
+
curveType="monotone"
|
|
380
|
+
xAxis={{ label: "Date", integerTicks: true, gridLines: true }}
|
|
381
|
+
yAxis={{ label: "Value ($)", tickFormat: (v) => `$${v}` }}
|
|
382
|
+
zoom={{
|
|
383
|
+
enabled: true,
|
|
384
|
+
maxScale: 8,
|
|
385
|
+
requireCtrlKey: true,
|
|
386
|
+
enableClickZoom: true,
|
|
387
|
+
}}
|
|
388
|
+
peaks={[{ x: 15, label: "Peak", icon: "star" }]}
|
|
389
|
+
contextMenu={{ enabled: true }}
|
|
390
|
+
export={{ enabled: true, format: "png", fileName: "report" }}
|
|
391
|
+
animation={{ enabled: true }}
|
|
392
|
+
/>
|
|
393
|
+
```
|
|
394
|
+
|
|
234
395
|
## Exported Hooks
|
|
235
396
|
|
|
236
397
|
For advanced usage, you can import the hooks directly:
|
|
237
398
|
|
|
238
399
|
```tsx
|
|
239
|
-
import {
|
|
400
|
+
import {
|
|
401
|
+
useChartDimensions,
|
|
402
|
+
useDataDomain,
|
|
403
|
+
useScales,
|
|
404
|
+
useZoom,
|
|
405
|
+
useTooltip,
|
|
406
|
+
} from "chartifypdf";
|
|
240
407
|
```
|
|
241
408
|
|
|
242
409
|
| Hook | Purpose |
|
|
243
410
|
|------|---------|
|
|
244
411
|
| `useChartDimensions` | Responsive container measurement via ResizeObserver |
|
|
245
|
-
| `
|
|
246
|
-
| `
|
|
247
|
-
| `
|
|
412
|
+
| `useDataDomain` | Extract full X/Y domain from data series |
|
|
413
|
+
| `useScales` | Compute linear scales, ticks, and domains (supports view domain override) |
|
|
414
|
+
| `useZoom` | Domain-based semantic zoom/pan state and event handlers |
|
|
415
|
+
| `useTooltip` | Track mouse position and find nearest data point with Y-proximity detection |
|
|
416
|
+
|
|
417
|
+
## Exported Utilities
|
|
418
|
+
|
|
419
|
+
```tsx
|
|
420
|
+
import { exportChart, exportChartAsPdf, exportChartAsPng, exportChartAsSvg } from "chartifypdf";
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
| Utility | Description |
|
|
424
|
+
|---------|-------------|
|
|
425
|
+
| `exportChart(svg, format, fileName)` | Export SVG element as PDF, PNG, or SVG |
|
|
426
|
+
| `exportChartAsPdf(svg, fileName)` | Export as PDF (opens print dialog) |
|
|
427
|
+
| `exportChartAsPng(svg, fileName)` | Export as PNG (2x resolution) |
|
|
428
|
+
| `exportChartAsSvg(svg, fileName)` | Export as SVG file |
|
|
248
429
|
|
|
249
430
|
## Browser Support
|
|
250
431
|
|
|
@@ -252,6 +433,7 @@ Works in all modern browsers that support:
|
|
|
252
433
|
- SVG
|
|
253
434
|
- ResizeObserver
|
|
254
435
|
- CSS transitions (for animation)
|
|
436
|
+
- Canvas API (for PNG/PDF export)
|
|
255
437
|
|
|
256
438
|
## License
|
|
257
439
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { ExportConfig } from "../types/chart.types";
|
|
3
|
+
interface ExportButtonProps {
|
|
4
|
+
config?: ExportConfig;
|
|
5
|
+
svgRef: React.RefObject<SVGSVGElement | null>;
|
|
6
|
+
svgWidth: number;
|
|
7
|
+
svgHeight: number;
|
|
8
|
+
margin: {
|
|
9
|
+
top: number;
|
|
10
|
+
right: number;
|
|
11
|
+
bottom: number;
|
|
12
|
+
left: number;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export declare const ExportButton: React.FC<ExportButtonProps>;
|
|
16
|
+
export {};
|
package/dist/hooks/useZoom.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export interface ZoomState {
|
|
|
8
8
|
zoomIn: () => void;
|
|
9
9
|
zoomOut: () => void;
|
|
10
10
|
resetZoom: () => void;
|
|
11
|
+
zoomToPoint: (dataX: number, dataY: number) => void;
|
|
11
12
|
handleWheel: (e: React.WheelEvent) => void;
|
|
12
13
|
handlePanStart: (e: React.MouseEvent) => void;
|
|
13
14
|
handlePanMove: (e: React.MouseEvent) => void;
|
package/dist/index.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ interface AxisConfig {
|
|
|
25
25
|
max?: number;
|
|
26
26
|
gridLines?: boolean;
|
|
27
27
|
gridLineColor?: string;
|
|
28
|
+
integerTicks?: boolean;
|
|
28
29
|
}
|
|
29
30
|
interface TooltipConfig {
|
|
30
31
|
enabled?: boolean;
|
|
@@ -43,6 +44,7 @@ interface ZoomConfig {
|
|
|
43
44
|
enableWheel?: boolean;
|
|
44
45
|
enablePan?: boolean;
|
|
45
46
|
requireCtrlKey?: boolean;
|
|
47
|
+
enableClickZoom?: boolean;
|
|
46
48
|
}
|
|
47
49
|
interface ChartMargin {
|
|
48
50
|
top: number;
|
|
@@ -74,6 +76,12 @@ interface ContextMenuConfig {
|
|
|
74
76
|
textColor?: string;
|
|
75
77
|
borderColor?: string;
|
|
76
78
|
}
|
|
79
|
+
interface ExportConfig {
|
|
80
|
+
enabled?: boolean;
|
|
81
|
+
buttonPosition?: "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
|
82
|
+
fileName?: string;
|
|
83
|
+
format?: "pdf" | "png" | "svg";
|
|
84
|
+
}
|
|
77
85
|
interface LineChartProps {
|
|
78
86
|
data: DataSeries[];
|
|
79
87
|
width?: number;
|
|
@@ -92,6 +100,7 @@ interface LineChartProps {
|
|
|
92
100
|
curveType?: CurveType;
|
|
93
101
|
peaks?: PeakConfig[];
|
|
94
102
|
contextMenu?: ContextMenuConfig;
|
|
103
|
+
export?: ExportConfig;
|
|
95
104
|
}
|
|
96
105
|
|
|
97
106
|
declare const LineChart: React$1.FC<LineChartProps>;
|
|
@@ -126,6 +135,7 @@ interface ZoomState {
|
|
|
126
135
|
zoomIn: () => void;
|
|
127
136
|
zoomOut: () => void;
|
|
128
137
|
resetZoom: () => void;
|
|
138
|
+
zoomToPoint: (dataX: number, dataY: number) => void;
|
|
129
139
|
handleWheel: (e: React.WheelEvent) => void;
|
|
130
140
|
handlePanStart: (e: React.MouseEvent) => void;
|
|
131
141
|
handlePanMove: (e: React.MouseEvent) => void;
|
|
@@ -145,5 +155,11 @@ interface TooltipState {
|
|
|
145
155
|
}
|
|
146
156
|
declare function useTooltip(svgRef: RefObject<SVGSVGElement | null>, data: DataSeries[], xScale: (v: number) => number, yScale: (v: number) => number, marginLeft: number, marginTop: number, plotWidth: number, _config?: TooltipConfig): TooltipState;
|
|
147
157
|
|
|
148
|
-
|
|
149
|
-
|
|
158
|
+
type ExportFormat = "pdf" | "png" | "svg";
|
|
159
|
+
declare function exportChartAsSvg(svgElement: SVGSVGElement, fileName?: string): Promise<void>;
|
|
160
|
+
declare function exportChartAsPng(svgElement: SVGSVGElement, fileName?: string): Promise<void>;
|
|
161
|
+
declare function exportChartAsPdf(svgElement: SVGSVGElement, fileName?: string): Promise<void>;
|
|
162
|
+
declare function exportChart(svgElement: SVGSVGElement, format?: ExportFormat, fileName?: string): Promise<void>;
|
|
163
|
+
|
|
164
|
+
export { LineChart, exportChart, exportChartAsPdf, exportChartAsPng, exportChartAsSvg, useChartDimensions, useDataDomain, useScales, useTooltip, useZoom };
|
|
165
|
+
export type { AnimationConfig, AxisConfig, ChartMargin, ChartStyle, ContextMenuConfig, CurveType, DataPoint, DataSeries, ExportConfig, LineChartProps, PeakConfig, TooltipConfig, ZoomConfig };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("react/jsx-runtime"),t=require("react");const n=["#4e79a7","#f28e2b","#e15759","#76b7b2","#59a14f","#edc948","#b07aa1","#ff9da7","#9c755f","#bab0ac"];function o(e,n,o){const[i,r]=t.useState({width:n??0,height:o??0}),s=void 0!==n&&void 0!==o;return t.useLayoutEffect(()=>{if(s)return void r({width:n,height:o});const t=e.current;if(!t)return;const i=()=>{const e=t.getBoundingClientRect();r({width:e.width,height:e.height})};i();const l=new ResizeObserver(()=>{i()});return l.observe(t),()=>l.disconnect()},[e,s,n,o]),i}function i(e,t,n){return Math.min(Math.max(e,t),n)}function r(e,t,n){return e+(t-e)*n}function s(e,t){const n=Math.floor(Math.log10(e)),o=e/Math.pow(10,n);let i;return i=t?o<1.5?1:o<3?2:o<7?5:10:o<=1?1:o<=2?2:o<=5?5:10,i*Math.pow(10,n)}function l(e,t,n){if(e===t){const n=0===e?1:.1*Math.abs(e);e-=n,t+=n}const o=s(t-e,!1),i=s(o/(n-1),!0);return{niceMin:Math.floor(e/i)*i,niceMax:Math.ceil(t/i)*i,tickStep:i}}function a(e,t,n,o){return i=>{if(t===e)return(n+o)/2;const s=function(e,t,n){return e===t?0:(n-e)/(t-e)}(e,t,i);return r(n,o,s)}}function c(e,t,n){const o=[];for(let i=e;i<=t+.5*n;i+=n)o.push(parseFloat(i.toPrecision(12)));return o}function d(e,n,o){return t.useMemo(()=>{let t=1/0,i=-1/0,r=1/0,s=-1/0;for(const n of e)for(const e of n.data)e.x<t&&(t=e.x),e.x>i&&(i=e.x),e.y<r&&(r=e.y),e.y>s&&(s=e.y);isFinite(t)||(t=0,i=1,r=0,s=1),void 0!==n?.min&&(t=n.min),void 0!==n?.max&&(i=n.max),void 0!==o?.min&&(r=o.min),void 0!==o?.max&&(s=o.max);const a=n?.tickCount??6,c=o?.tickCount??6,d=l(t,i,a),u=l(r,s,c);return{fullXDomain:[d.niceMin,d.niceMax],fullYDomain:[u.niceMin,u.niceMax]}},[e,n,o])}function u(e,n,o,i,r,s,d){return t.useMemo(()=>{let t=1/0,u=-1/0,x=1/0,f=-1/0;for(const n of e)for(const e of n.data)e.x<t&&(t=e.x),e.x>u&&(u=e.x),e.y<x&&(x=e.y),e.y>f&&(f=e.y);isFinite(t)||(t=0,u=1,x=0,f=1),void 0!==i?.min&&(t=i.min),void 0!==i?.max&&(u=i.max),void 0!==r?.min&&(x=r.min),void 0!==r?.max&&(f=r.max);const h=i?.tickCount??6,y=r?.tickCount??6;let m,p,g,b;if(s)m=s[0],p=s[1];else{const e=l(t,u,h);m=e.niceMin,p=e.niceMax}if(d)g=d[0],b=d[1];else{const e=l(x,f,y);g=e.niceMin,b=e.niceMax}const k=l(m,p,h),v=l(g,b,y);return{xScale:a(m,p,0,n),yScale:a(g,b,o,0),xTicks:c(k.niceMin,k.niceMax,k.tickStep).filter(e=>e>=m&&e<=p),yTicks:c(v.niceMin,v.niceMax,v.tickStep).filter(e=>e>=g&&e<=b),xDomain:[m,p],yDomain:[g,b]}},[e,n,o,i,r,s,d])}function x(e,n,o,s,l){const a=e?.enabled??!1,c=e?.maxScale??10,d=e?.step??.5,u=e?.enableWheel??!0,x=e?.enablePan??!0,f=e?.requireCtrlKey??!0,[h,y]=t.useState(n),[m,p]=t.useState(o),[g,b]=t.useState(!1),[k,v]=t.useState(!1),C=t.useRef({x:0,y:0,xDomain:n,yDomain:o}),S=t.useRef(null),j=t.useRef({x:n,y:o});n[0]===j.current.x[0]&&n[1]===j.current.x[1]&&o[0]===j.current.y[0]&&o[1]===j.current.y[1]||(j.current={x:n,y:o},y(n),p(o));const M=n[1]-n[0],$=h[1]-h[0],w=M>0&&$>0?M/$:1,D=t.useCallback((e,t)=>{const n=e[1]-e[0];if(n>=t[1]-t[0])return t;let o=e[0],i=e[1];return o<t[0]&&(o=t[0],i=o+n),i>t[1]&&(i=t[1],o=i-n),[o,i]},[]),W=t.useCallback(()=>{S.current&&clearTimeout(S.current),v(!0),S.current=setTimeout(()=>v(!1),2e3)},[]),T=t.useCallback((e,t,i)=>{if(!a)return;const s=t??.5,l=i??.5;y(t=>{const o=(t[1]-t[0])/e,i=M/c,l=Math.max(o,i),a=Math.min(l,M),d=r(t[0],t[1],s)-a*s;return D([d,d+a],n)}),p(t=>{const n=t[1]-t[0],i=o[1]-o[0],s=n/e,a=i/c,d=Math.max(s,a),u=Math.min(d,i),x=r(t[0],t[1],l)-u*l;return D([x,x+u],o)})},[a,n,o,M,c,D]),P=t.useCallback(()=>{T(1+d)},[d,T]),L=t.useCallback(()=>{T(1/(1+d))},[d,T]),X=t.useCallback(()=>{y(n),p(o)},[n,o]),A=t.useCallback(e=>{if(!a||!u)return;if(f&&!e.ctrlKey&&!e.metaKey)return void W();e.preventDefault();const t=e.currentTarget.getBoundingClientRect(),n=e.clientX-t.left,o=e.clientY-t.top,r=i(n/(t.width||1),0,1),s=i(o/(t.height||1),0,1),l=e.deltaY<0?1+d:1/(1+d);T(l,r,s)},[a,u,f,d,W,T]),z=t.useCallback(e=>{!a||!x||w<=1||0===e.button&&(b(!0),C.current={x:e.clientX,y:e.clientY,xDomain:h,yDomain:m})},[a,x,w,h,m]),N=t.useCallback(e=>{if(!g)return;const t=e.clientX-C.current.x,i=e.clientY-C.current.y,r=C.current.xDomain,a=C.current.yDomain,c=r[1]-r[0],d=a[1]-a[0],u=-t/s*c,x=i/l*d,f=[r[0]+u,r[1]+u],h=[a[0]+x,a[1]+x];y(D(f,n)),p(D(h,o))},[g,s,l,n,o,D]),R=t.useCallback(()=>{b(!1)},[]);return{viewXDomain:h,viewYDomain:m,scale:w,isPanning:g,showZoomHint:k,zoomIn:P,zoomOut:L,resetZoom:X,handleWheel:A,handlePanStart:z,handlePanMove:N,handlePanEnd:R}}function f(e,t,n){if(0===e.length)return null;let o=0,i=e.length-1;for(;o<i;){const r=Math.floor((o+i)/2);n(e[r].x)<t?o=r+1:i=r}let r=e[o],s=Math.abs(n(r.x)-t);if(o>0){const i=Math.abs(n(e[o-1].x)-t);i<s&&(s=i,r=e[o-1])}return r}function h(e,n,o,i,r,s,l,a){const[c,d]=t.useState(!1),[u,x]=t.useState(0),[h,y]=t.useState(0),[m,p]=t.useState(null),[g,b]=t.useState(null),[k,v]=t.useState(null);return{tooltipVisible:c,tooltipX:u,tooltipY:h,activePoint:m,activeSeries:g,activeSeriesId:k,handleMouseMove:t.useCallback(t=>{const s=e.current;if(!s)return;const a=s.getBoundingClientRect(),c=t.clientX-a.left-r;if(c<0||c>l)return d(!1),void v(null);let u=null,h=null,m=1/0;for(const e of n){const t=f(e.data,c,o);if(!t)continue;const n=Math.abs(o(t.x)-c);n<m&&(m=n,u=t,h=e)}u&&h&&(x(o(u.x)),y(i(u.y)),p(u),b(h),v(h.id),d(!0))},[e,n,o,i,r,l]),handleMouseLeave:t.useCallback(()=>{d(!1),p(null),b(null),v(null)},[])}}const y=e=>Math.abs(e)>=1e6?`${(e/1e6).toFixed(1)}M`:Math.abs(e)>=1e3?`${(e/1e3).toFixed(1)}K`:Number.isInteger(e)?e.toString():e.toFixed(1),m=t.memo(({xTicks:t,yTicks:n,xScale:o,yScale:i,plotWidth:r,plotHeight:s,xAxisConfig:l,yAxisConfig:a,style:c})=>{const d=c?.axisColor??"#333",u=c?.tickColor??"#666",x=c?.fontFamily??"sans-serif",f=c?.fontSize??11,h=l?.tickFormat??y,m=a?.tickFormat??y;return e.jsxs("g",{className:"chartifypdf-axes",children:[e.jsx("line",{x1:0,y1:s,x2:r,y2:s,stroke:d,strokeWidth:1}),t.map(t=>{const n=o(t);return e.jsxs("g",{children:[e.jsx("line",{x1:n,y1:s,x2:n,y2:s+6,stroke:d,strokeWidth:1}),e.jsx("text",{x:n,y:s+18,textAnchor:"middle",fill:u,fontFamily:x,fontSize:f,children:h(t)})]},`x-tick-${t}`)}),l?.label&&e.jsx("text",{x:r/2,y:s+38,textAnchor:"middle",fill:d,fontFamily:x,fontSize:f+1,fontWeight:"bold",children:l.label}),e.jsx("line",{x1:0,y1:0,x2:0,y2:s,stroke:d,strokeWidth:1}),n.map(t=>{const n=i(t);return e.jsxs("g",{children:[e.jsx("line",{x1:-6,y1:n,x2:0,y2:n,stroke:d,strokeWidth:1}),e.jsx("text",{x:-10,y:n,textAnchor:"end",dominantBaseline:"middle",fill:u,fontFamily:x,fontSize:f,children:m(t)})]},`y-tick-${t}`)}),a?.label&&e.jsx("text",{x:0,y:0,textAnchor:"middle",fill:d,fontFamily:x,fontSize:f+1,fontWeight:"bold",transform:`translate(-40, ${s/2}) rotate(-90)`,children:a.label})]})});m.displayName="Axes";const p=t.memo(({xTicks:t,yTicks:n,xScale:o,yScale:i,plotWidth:r,plotHeight:s,showXGrid:l,showYGrid:a,xGridColor:c="#e0e0e0",yGridColor:d="#e0e0e0"})=>e.jsxs("g",{className:"chartifypdf-grid",children:[a&&n.map(t=>{const n=i(t);return e.jsx("line",{x1:0,y1:n,x2:r,y2:n,stroke:d,strokeDasharray:"4 4",strokeOpacity:.5},`y-grid-${t}`)}),l&&t.map(t=>{const n=o(t);return e.jsx("line",{x1:n,y1:0,x2:n,y2:s,stroke:c,strokeDasharray:"4 4",strokeOpacity:.5},`x-grid-${t}`)})]}));function g(e){if(0===e.length)return"";const[t,...n]=e;return`M${t.x},${t.y}`+n.map(e=>`L${e.x},${e.y}`).join("")}function b(e,t){switch(t){case"monotone":return function(e){const t=e.length;if(t<2)return g(e);if(2===t)return g(e);const n=[],o=[],i=[];for(let r=0;r<t-1;r++)n.push(e[r+1].x-e[r].x),o.push(e[r+1].y-e[r].y),i.push(0===n[r]?0:o[r]/n[r]);const r=new Array(t);r[0]=i[0],r[t-1]=i[t-2];for(let e=1;e<t-1;e++)i[e-1]*i[e]<=0?r[e]=0:r[e]=2/(1/i[e-1]+1/i[e]);for(let e=0;e<t-1;e++)if(0===i[e])r[e]=0,r[e+1]=0;else{const t=r[e]/i[e],n=r[e+1]/i[e],o=t*t+n*n;if(o>9){const s=3/Math.sqrt(o);r[e]=s*t*i[e],r[e+1]=s*n*i[e]}}let s=`M${e[0].x},${e[0].y}`;for(let o=0;o<t-1;o++){const t=n[o]/3;s+=`C${e[o].x+t},${e[o].y+r[o]*t},${e[o+1].x-t},${e[o+1].y-r[o+1]*t},${e[o+1].x},${e[o+1].y}`}return s}(e);case"natural":return function(e){const t=e.length;if(t<2)return g(e);if(2===t)return g(e);function n(e){const t=e.length-1,n=new Array(t),o=new Array(t),i=new Array(t);n[0]=0,o[0]=2,i[0]=e[0]+2*e[1];for(let r=1;r<t-1;r++)n[r]=1,o[r]=4,i[r]=4*e[r]+2*e[r+1];n[t-1]=2,o[t-1]=7,i[t-1]=8*e[t-1]+e[t];for(let e=1;e<t;e++){const t=n[e]/o[e-1];o[e]-=t,i[e]-=t*i[e-1]}const r=new Array(t);r[t-1]=i[t-1]/o[t-1];for(let e=t-2;e>=0;e--)r[e]=(i[e]-r[e+1])/o[e];const s=new Array(t);for(let n=0;n<t-1;n++)s[n]=2*e[n+1]-r[n+1];s[t-1]=(e[t]+r[t-1])/2;const l=[];for(let e=0;e<t;e++)l.push({cp1:r[e],cp2:s[e]});return l}const o=e.map(e=>e.x),i=e.map(e=>e.y),r=n(o),s=n(i);let l=`M${e[0].x},${e[0].y}`;for(let n=0;n<t-1;n++)l+=`C${r[n].cp1},${s[n].cp1},${r[n].cp2},${s[n].cp2},${e[n+1].x},${e[n+1].y}`;return l}(e);default:return g(e)}}p.displayName="GridLines";const k=t.memo(({series:n,xScale:o,yScale:i,color:r,animation:s,onPointClick:l,curveType:a,highlightOpacity:c})=>{const d=t.useRef(null),[u,x]=t.useState(0),[f,h]=t.useState(!s?.enabled),y=n.strokeWidth??2,m=n.showDots??!1,p=n.dotRadius??3.5,k=n.curveType??a??"linear",v=c??1,C=n.data.map(e=>({x:o(e.x),y:i(e.y)})),S="linear"===k?g(C):b(C,k);t.useEffect(()=>{if(s?.enabled&&d.current){const e=d.current.getTotalLength();x(e),h(!1);const t=setTimeout(()=>{h(!0)},s.duration??800);return()=>clearTimeout(t)}},[S,s?.enabled,s?.duration]);const j=s?.enabled&&u>0?{strokeDasharray:u,strokeDashoffset:f?0:u,transition:`stroke-dashoffset ${s.duration??800}ms ${s.easing??"ease-in-out"}`}:{};return e.jsxs("g",{className:"chartifypdf-line-path",style:{opacity:v,transition:"opacity 150ms ease"},children:[e.jsx("path",{ref:d,d:S,fill:"none",stroke:r,strokeWidth:y,strokeDasharray:n.strokeDasharray,strokeLinecap:"round",strokeLinejoin:"round",style:j}),m&&n.data.map((t,s)=>e.jsx("circle",{cx:o(t.x),cy:i(t.y),r:p,fill:r,stroke:"#fff",strokeWidth:1.5,style:{cursor:l?"pointer":"default"},onClick:l?()=>l(t,n):void 0},`dot-${n.id}-${s}`))]})});k.displayName="LinePath";const v=t.memo(({visible:t,x:n,y:o,point:i,series:r,plotHeight:s,plotWidth:l,config:a,seriesColor:c})=>{if(!t||!i||!r)return null;const d=a?.backgroundColor??"rgba(0, 0, 0, 0.8)",u=a?.textColor??"#fff";let x;if(a?.renderCustom)x=a.renderCustom(i,r);else{x=a?.formatter?a.formatter(i,r):`${r.name}: (${i.x}, ${i.y})`}let f=n+12,h=o-40-8;return f+140>l&&(f=n-140-12),h<0&&(h=o+12),e.jsxs("g",{className:"chartifypdf-tooltip",pointerEvents:"none",children:[e.jsx("line",{x1:n,y1:0,x2:n,y2:s,stroke:"#999",strokeWidth:1,strokeDasharray:"4 4",opacity:.6}),e.jsx("circle",{cx:n,cy:o,r:5,fill:c,stroke:"#fff",strokeWidth:2}),e.jsx("foreignObject",{x:f,y:h,width:140,height:60,overflow:"visible",children:e.jsx("div",{style:{backgroundColor:d,color:u,padding:"6px 10px",borderRadius:"4px",fontSize:"12px",fontFamily:"sans-serif",whiteSpace:"nowrap",lineHeight:1.4,boxShadow:"0 2px 6px rgba(0,0,0,0.2)"},children:x})})]})});v.displayName="Tooltip";const C=t.memo(({config:t,svgWidth:n,svgHeight:o,margin:i,scale:r,onZoomIn:s,onZoomOut:l,onReset:a})=>{if(!t?.enabled||!1===t.showControls)return null;const c=t.controlsPosition??"top-right",d=24;let u,x;switch(c){case"top-left":u=i.left+8,x=i.top+8;break;case"bottom-left":u=i.left+8,x=o-i.bottom-24-8;break;case"bottom-right":u=n-i.right-80-8,x=o-i.bottom-24-8;break;default:u=n-i.right-80-8,x=i.top+8}const f=r>1?[{label:"+",onClick:s},{label:"−",onClick:l},{label:"↺",onClick:a}]:[{label:"+",onClick:s},{label:"−",onClick:l}];return e.jsx("g",{className:"chartifypdf-zoom-controls",transform:`translate(${u}, ${x})`,children:f.map((t,n)=>e.jsxs("g",{transform:`translate(${28*n}, 0)`,onClick:t.onClick,style:{cursor:"pointer"},children:[e.jsx("rect",{width:d,height:d,rx:4,fill:"rgba(255,255,255,0.9)",stroke:"#ccc",strokeWidth:1}),e.jsx("text",{x:12,y:12,textAnchor:"middle",dominantBaseline:"central",fontSize:14,fontFamily:"sans-serif",fill:"#333",fontWeight:"bold",children:t.label})]},t.label))})});function S({x:t,y:n,color:o}){return e.jsx("polygon",{points:`${t},${n} ${t-5},${n-10} ${t+5},${n-10}`,fill:o})}function j({x:t,y:n,color:o}){return e.jsx("polygon",{points:`${t},${n-6} ${t+5},${n} ${t},${n+6} ${t-5},${n}`,fill:o})}function M({x:t,y:n,color:o}){const i=[];for(let e=0;e<5;e++){const o=(72*e-90)*(Math.PI/180),r=(72*e+36-90)*(Math.PI/180);i.push(`${t+6*Math.cos(o)},${n+6*Math.sin(o)}`),i.push(`${t+3*Math.cos(r)},${n+3*Math.sin(r)}`)}return e.jsx("polygon",{points:i.join(" "),fill:o})}C.displayName="ZoomControls";const $=t.memo(({peaks:t,data:n,xScale:o,yScale:i})=>e.jsx("g",{className:"chartifypdf-peak-markers",children:t.map((t,r)=>{const s=function(e,t){let n=-1/0,o=-1;for(let i=0;i<e.length;i++){const r=e[i];let s=r.data[0],l=1/0;for(const e of r.data){const n=Math.abs(e.x-t);n<l&&(l=n,s=e)}s&&s.y>n&&(n=s.y,o=i)}return-1===o?null:{y:n,seriesIndex:o}}(n,t.x);if(!s)return null;const l=o(t.x),a=i(s.y),c=t.color??"#ef4444",d=t.icon??"arrow",u=t.label,x=a-14;return e.jsxs("g",{children:[e.jsx("line",{x1:l,y1:a,x2:l,y2:x+6,stroke:c,strokeWidth:1,strokeDasharray:"3 2",opacity:.6}),"arrow"===d&&e.jsx(S,{x:l,y:x,color:c}),"diamond"===d&&e.jsx(j,{x:l,y:x,color:c}),"star"===d&&e.jsx(M,{x:l,y:x,color:c}),u&&e.jsx("text",{x:l,y:x-8,textAnchor:"middle",fill:c,fontSize:11,fontWeight:600,children:u})]},`peak-${r}`)})}));$.displayName="PeakMarkers";const w=({visible:n,x:o,y:i,nearestX:r,data:s,config:l,getSeriesColor:a,onClose:c})=>{const d=t.useRef(null);if(t.useEffect(()=>{if(!n)return;const e=e=>{d.current&&!d.current.contains(e.target)&&c()},t=e=>{"Escape"===e.key&&c()},o=setTimeout(()=>{document.addEventListener("mousedown",e),document.addEventListener("keydown",t)},0);return()=>{clearTimeout(o),document.removeEventListener("mousedown",e),document.removeEventListener("keydown",t)}},[n,c]),!n)return null;const u=l?.backgroundColor??"#ffffff",x=l?.textColor??"#1f2937",f=l?.borderColor??"#e5e7eb",h=s.map((e,t)=>{const n=function(e,t){if(0===e.data.length)return null;let n=e.data[0],o=Math.abs(n.x-t);for(const i of e.data){const e=Math.abs(i.x-t);e<o&&(o=e,n=i)}return n.y}(e,r);return{name:e.name,color:e.color??a(t),x:r,y:n}});return e.jsxs("div",{ref:d,style:{position:"fixed",left:o,top:i,zIndex:9999,backgroundColor:u,color:x,border:`1px solid ${f}`,borderRadius:6,boxShadow:"0 4px 12px rgba(0,0,0,0.15)",padding:"8px 0",minWidth:200,fontSize:12,fontFamily:"system-ui, -apple-system, sans-serif"},children:[e.jsxs("div",{style:{padding:"4px 12px 8px",fontWeight:600,fontSize:11,color:x,opacity:.6,borderBottom:`1px solid ${f}`,marginBottom:4},children:["Data at X = ","number"==typeof r?r.toLocaleString():r]}),e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse"},children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{style:{textAlign:"left",padding:"4px 12px",fontWeight:600,opacity:.7},children:"Series"}),e.jsx("th",{style:{textAlign:"right",padding:"4px 12px",fontWeight:600,opacity:.7},children:"Y"})]})}),e.jsx("tbody",{children:h.map((t,n)=>e.jsxs("tr",{style:{borderTop:n>0?`1px solid ${f}`:void 0},children:[e.jsxs("td",{style:{padding:"4px 12px",display:"flex",alignItems:"center",gap:6},children:[e.jsx("span",{style:{display:"inline-block",width:8,height:8,borderRadius:"50%",backgroundColor:t.color,flexShrink:0}}),t.name]}),e.jsx("td",{style:{padding:"4px 12px",textAlign:"right",fontVariantNumeric:"tabular-nums"},children:null!==t.y?t.y.toLocaleString():"—"})]},n))})]})]})};w.displayName="ContextMenu";const D={top:20,right:20,bottom:50,left:60},W=({data:i,width:r,height:s,margin:l,xAxis:a,yAxis:c,tooltip:f,zoom:y,style:g,animation:b,colorPalette:S,className:j,onPointClick:M,ariaLabel:W,curveType:T,peaks:P,contextMenu:L})=>{const X=t.useRef(null),A=t.useRef(null),z=t.useId(),N={...D,...l},R=o(X,r,s??400),{width:F,height:Y}=R,I=Math.max(0,F-N.left-N.right),E=Math.max(0,Y-N.top-N.bottom),{fullXDomain:H,fullYDomain:O}=d(i,a,c),Z=x(y,H,O,I,E),G=y?.enabled??!1,{xScale:B,yScale:q,xTicks:K,yTicks:V}=u(i,I,E,a,c,G?Z.viewXDomain:void 0,G?Z.viewYDomain:void 0),U=!1!==f?.enabled,J=h(A,i,B,q,N.left,N.top,I),Q=J.activeSeriesId,_=J.tooltipVisible&&null!==Q,ee=e=>_?e===Q?1:.2:1,[te,ne]=t.useState({visible:!1,clientX:0,clientY:0,nearestX:0}),oe=t.useCallback(e=>{if(!L?.enabled)return;e.preventDefault();const t=A.current;if(!t)return;const n=t.getBoundingClientRect(),o=e.clientX-n.left-N.left;if(o<0||o>I)return;let r=0,s=1/0;for(const e of i)for(const t of e.data){const e=B(t.x),n=Math.abs(e-o);n<s&&(s=n,r=t.x)}ne({visible:!0,clientX:e.clientX,clientY:e.clientY,nearestX:r})},[L?.enabled,i,B,N.left,I]),ie=t.useCallback(()=>{ne(e=>({...e,visible:!1}))},[]),re=a?.gridLines??!1,se=c?.gridLines??!0,le=e=>function(e,t){const o=t??n;return o[e%o.length]}(e,S);return 0===F||0===Y?e.jsx("div",{ref:X,className:j,style:{width:r??"100%",height:s??400,backgroundColor:g?.backgroundColor}}):e.jsxs("div",{ref:X,className:j,style:{width:r??"100%",height:s??400,backgroundColor:g?.backgroundColor,position:"relative"},children:[e.jsxs("svg",{ref:A,width:F,height:Y,role:"img","aria-label":W??"Line chart",onMouseMove:U&&!Z.isPanning?J.handleMouseMove:void 0,onMouseLeave:U?J.handleMouseLeave:void 0,onWheel:G?Z.handleWheel:void 0,onMouseDown:G?Z.handlePanStart:void 0,onMouseUp:G?Z.handlePanEnd:void 0,onContextMenu:oe,style:{userSelect:Z.isPanning?"none":void 0,cursor:Z.isPanning?"grabbing":G&&Z.scale>1?"grab":void 0},children:[e.jsx("defs",{children:e.jsx("clipPath",{id:z,children:e.jsx("rect",{width:I,height:E})})}),e.jsxs("g",{transform:`translate(${N.left}, ${N.top})`,children:[e.jsx(m,{xTicks:K,yTicks:V,xScale:B,yScale:q,plotWidth:I,plotHeight:E,xAxisConfig:a,yAxisConfig:c,style:g}),e.jsx(p,{xTicks:K,yTicks:V,xScale:B,yScale:q,plotWidth:I,plotHeight:E,showXGrid:re,showYGrid:se,xGridColor:a?.gridLineColor,yGridColor:c?.gridLineColor}),e.jsxs("g",{clipPath:`url(#${z})`,children:[G?e.jsx("g",{onMouseMove:Z.handlePanMove,children:i.map((t,n)=>e.jsx(k,{series:t,xScale:B,yScale:q,color:t.color??le(n),animation:b,onPointClick:M,curveType:T,highlightOpacity:ee(t.id)},t.id))}):i.map((t,n)=>e.jsx(k,{series:t,xScale:B,yScale:q,color:t.color??le(n),animation:b,onPointClick:M,curveType:T,highlightOpacity:ee(t.id)},t.id)),P&&P.length>0&&e.jsx($,{peaks:P,data:i,xScale:B,yScale:q,colorPalette:S})]}),U&&e.jsx(v,{visible:J.tooltipVisible,x:J.tooltipX,y:J.tooltipY,point:J.activePoint,series:J.activeSeries,plotHeight:E,plotWidth:I,config:f,seriesColor:J.activeSeries?.color??le(i.findIndex(e=>e.id===J.activeSeries?.id))})]}),e.jsx(C,{config:y,svgWidth:F,svgHeight:Y,margin:N,scale:Z.scale,onZoomIn:Z.zoomIn,onZoomOut:Z.zoomOut,onReset:Z.resetZoom})]}),Z.showZoomHint&&e.jsx("div",{style:{position:"absolute",top:"50%",left:"50%",transform:"translate(-50%, -50%)",background:"rgba(0, 0, 0, 0.7)",color:"#fff",padding:"8px 16px",borderRadius:6,fontSize:13,fontFamily:"system-ui, -apple-system, sans-serif",pointerEvents:"none",whiteSpace:"nowrap",zIndex:10},children:"Hold Ctrl + scroll to zoom"}),L?.enabled&&e.jsx(w,{visible:te.visible,x:te.clientX,y:te.clientY,nearestX:te.nearestX,data:i,config:L,getSeriesColor:le,onClose:ie})]})};W.displayName="LineChart",exports.LineChart=W,exports.useChartDimensions=o,exports.useDataDomain=d,exports.useScales=u,exports.useTooltip=h,exports.useZoom=x;
|
|
1
|
+
"use strict";var e=require("react/jsx-runtime"),t=require("react");const n=["#4e79a7","#f28e2b","#e15759","#76b7b2","#59a14f","#edc948","#b07aa1","#ff9da7","#9c755f","#bab0ac"];function o(e,n,o){const[i,r]=t.useState({width:n??0,height:o??0}),s=void 0!==n&&void 0!==o;return t.useLayoutEffect(()=>{if(s)return void r({width:n,height:o});const t=e.current;if(!t)return;const i=()=>{const e=t.getBoundingClientRect();r({width:e.width,height:e.height})};i();const a=new ResizeObserver(()=>{i()});return a.observe(t),()=>a.disconnect()},[e,s,n,o]),i}function i(e,t,n){return Math.min(Math.max(e,t),n)}function r(e,t,n){return e+(t-e)*n}function s(e,t){const n=Math.floor(Math.log10(e)),o=e/Math.pow(10,n);let i;return i=t?o<1.5?1:o<3?2:o<7?5:10:o<=1?1:o<=2?2:o<=5?5:10,i*Math.pow(10,n)}function a(e,t,n){if(e===t){const n=0===e?1:.1*Math.abs(e);e-=n,t+=n}const o=s(t-e,!1),i=s(o/(n-1),!0);return{niceMin:Math.floor(e/i)*i,niceMax:Math.ceil(t/i)*i,tickStep:i}}function l(e,t,n,o){return i=>{if(t===e)return(n+o)/2;const s=function(e,t,n){return e===t?0:(n-e)/(t-e)}(e,t,i);return r(n,o,s)}}function c(e,t,n){const o=[];for(let i=e;i<=t+.5*n;i+=n)o.push(parseFloat(i.toPrecision(12)));return o}function d(e,n,o){return t.useMemo(()=>{let t=1/0,i=-1/0,r=1/0,s=-1/0;for(const n of e)for(const e of n.data)e.x<t&&(t=e.x),e.x>i&&(i=e.x),e.y<r&&(r=e.y),e.y>s&&(s=e.y);isFinite(t)||(t=0,i=1,r=0,s=1),void 0!==n?.min&&(t=n.min),void 0!==n?.max&&(i=n.max),void 0!==o?.min&&(r=o.min),void 0!==o?.max&&(s=o.max);const l=n?.tickCount??6,c=o?.tickCount??6,d=a(t,i,l),u=a(r,s,c);return{fullXDomain:[d.niceMin,d.niceMax],fullYDomain:[u.niceMin,u.niceMax]}},[e,n,o])}function u(e,n,o,i,r,s,d){return t.useMemo(()=>{let t=1/0,u=-1/0,h=1/0,f=-1/0;for(const n of e)for(const e of n.data)e.x<t&&(t=e.x),e.x>u&&(u=e.x),e.y<h&&(h=e.y),e.y>f&&(f=e.y);isFinite(t)||(t=0,u=1,h=0,f=1),void 0!==i?.min&&(t=i.min),void 0!==i?.max&&(u=i.max),void 0!==r?.min&&(h=r.min),void 0!==r?.max&&(f=r.max);const x=i?.tickCount??6,m=r?.tickCount??6;let p,g,y,b;if(s)p=s[0],g=s[1];else{const e=a(t,u,x);p=e.niceMin,g=e.niceMax}if(d)y=d[0],b=d[1];else{const e=a(h,f,m);y=e.niceMin,b=e.niceMax}const k=a(p,g,x),v=a(y,b,m),w=l(p,g,0,n),C=l(y,b,o,0);let M=k.tickStep,S=k.niceMin,j=k.niceMax;i?.integerTicks&&(M=Math.max(1,Math.ceil(M)),S=Math.ceil(p),j=Math.floor(g));let $=v.tickStep,L=v.niceMin,P=v.niceMax;r?.integerTicks&&($=Math.max(1,Math.ceil($)),L=Math.ceil(y),P=Math.floor(b));return{xScale:w,yScale:C,xTicks:c(S,j,M).filter(e=>e>=p&&e<=g).filter(e=>!i?.integerTicks||Number.isInteger(e)),yTicks:c(L,P,$).filter(e=>e>=y&&e<=b).filter(e=>!r?.integerTicks||Number.isInteger(e)),xDomain:[p,g],yDomain:[y,b]}},[e,n,o,i,r,s,d])}function h(e,n,o,s,a){const l=e?.enabled??!1,c=e?.maxScale??10,d=e?.step??.5,u=e?.enableWheel??!0,h=e?.enablePan??!0,f=e?.requireCtrlKey??!0,[x,m]=t.useState(n),[p,g]=t.useState(o),[y,b]=t.useState(!1),[k,v]=t.useState(!1),w=t.useRef({x:0,y:0,xDomain:n,yDomain:o}),C=t.useRef(null),M=t.useRef({x:n,y:o});n[0]===M.current.x[0]&&n[1]===M.current.x[1]&&o[0]===M.current.y[0]&&o[1]===M.current.y[1]||(M.current={x:n,y:o},m(n),g(o));const S=n[1]-n[0],j=x[1]-x[0],$=S>0&&j>0?S/j:1,L=t.useCallback((e,t)=>{const n=e[1]-e[0];if(n>=t[1]-t[0])return t;let o=e[0],i=e[1];return o<t[0]&&(o=t[0],i=o+n),i>t[1]&&(i=t[1],o=i-n),[o,i]},[]),P=t.useCallback(()=>{C.current&&clearTimeout(C.current),v(!0),C.current=setTimeout(()=>v(!1),2e3)},[]),D=t.useCallback((e,t,i)=>{if(!l)return;const s=t??.5,a=i??.5;m(t=>{const o=(t[1]-t[0])/e,i=S/c,a=Math.max(o,i),l=Math.min(a,S),d=r(t[0],t[1],s)-l*s;return L([d,d+l],n)}),g(t=>{const n=t[1]-t[0],i=o[1]-o[0],s=n/e,l=i/c,d=Math.max(s,l),u=Math.min(d,i),h=r(t[0],t[1],a)-u*a;return L([h,h+u],o)})},[l,n,o,S,c,L]),T=t.useCallback(()=>{D(1+d)},[d,D]),R=t.useCallback(()=>{D(1/(1+d))},[d,D]),W=t.useCallback(()=>{m(n),g(o)},[n,o]),A=t.useCallback((e,t)=>{if(!l)return;m(t=>{const o=(t[1]-t[0])/2,i=S/c,r=Math.max(o,i),s=Math.min(r,S),a=e-s/2;return L([a,a+s],n)}),g(e=>{const n=e[1]-e[0],i=o[1]-o[0],r=n/2,s=i/c,a=Math.max(r,s),l=Math.min(a,i),d=t-l/2;return L([d,d+l],o)})},[l,n,o,S,c,L]),z=t.useCallback(e=>{if(!l||!u)return;if(f&&!e.ctrlKey&&!e.metaKey)return void P();e.preventDefault();const t=e.currentTarget.getBoundingClientRect(),n=e.clientX-t.left,o=e.clientY-t.top,r=i(n/(t.width||1),0,1),s=i(o/(t.height||1),0,1),a=e.deltaY<0?1+d:1/(1+d);D(a,r,s)},[l,u,f,d,P,D]),N=t.useCallback(e=>{!l||!h||$<=1||0===e.button&&(b(!0),w.current={x:e.clientX,y:e.clientY,xDomain:x,yDomain:p})},[l,h,$,x,p]),X=t.useCallback(e=>{if(!y)return;const t=e.clientX-w.current.x,i=e.clientY-w.current.y,r=w.current.xDomain,l=w.current.yDomain,c=r[1]-r[0],d=l[1]-l[0],u=-t/s*c,h=i/a*d,f=[r[0]+u,r[1]+u],x=[l[0]+h,l[1]+h];m(L(f,n)),g(L(x,o))},[y,s,a,n,o,L]),E=t.useCallback(()=>{b(!1)},[]);return{viewXDomain:x,viewYDomain:p,scale:$,isPanning:y,showZoomHint:k,zoomIn:T,zoomOut:R,resetZoom:W,zoomToPoint:A,handleWheel:z,handlePanStart:N,handlePanMove:X,handlePanEnd:E}}function f(e,t,n){if(0===e.length)return null;let o=0,i=e.length-1;for(;o<i;){const r=Math.floor((o+i)/2);n(e[r].x)<t?o=r+1:i=r}let r=e[o],s=Math.abs(n(r.x)-t);if(o>0){const i=Math.abs(n(e[o-1].x)-t);i<s&&(s=i,r=e[o-1])}return r}function x(e,n,o,i,r,s,a,l){const[c,d]=t.useState(!1),[u,h]=t.useState(0),[x,m]=t.useState(0),[p,g]=t.useState(null),[y,b]=t.useState(null),[k,v]=t.useState(null);return{tooltipVisible:c,tooltipX:u,tooltipY:x,activePoint:p,activeSeries:y,activeSeriesId:k,handleMouseMove:t.useCallback(t=>{const l=e.current;if(!l)return;const c=l.getBoundingClientRect(),u=t.clientX-c.left-r,x=t.clientY-c.top-s;if(u<0||u>a)return d(!1),void v(null);let p=0,y=1/0;for(const e of n){const t=f(e.data,u,o);if(!t)continue;const n=Math.abs(o(t.x)-u);n<y&&(y=n,p=t.x)}let k=null,w=null,C=1/0;for(const e of n){let t=null,n=1/0;for(const o of e.data){const e=Math.abs(o.x-p);e<n&&(n=e,t=o)}if(!t)continue;const o=i(t.y),r=Math.abs(o-x);r<C&&(C=r,k=t,w=e)}k&&w&&(h(o(k.x)),m(i(k.y)),g(k),b(w),v(w.id),d(!0))},[e,n,o,i,r,s,a]),handleMouseLeave:t.useCallback(()=>{d(!1),g(null),b(null),v(null)},[])}}const m=e=>Math.abs(e)>=1e6?`${(e/1e6).toFixed(1)}M`:Math.abs(e)>=1e3?`${(e/1e3).toFixed(1)}K`:Number.isInteger(e)?e.toString():e.toFixed(1),p=t.memo(({xTicks:t,yTicks:n,xScale:o,yScale:i,plotWidth:r,plotHeight:s,xAxisConfig:a,yAxisConfig:l,style:c})=>{const d=c?.axisColor??"#333",u=c?.tickColor??"#666",h=c?.fontFamily??"sans-serif",f=c?.fontSize??11,x=a?.tickFormat??m,p=l?.tickFormat??m;return e.jsxs("g",{className:"chartifypdf-axes",children:[e.jsx("line",{x1:0,y1:s,x2:r,y2:s,stroke:d,strokeWidth:1}),t.map(t=>{const n=o(t);return e.jsxs("g",{children:[e.jsx("line",{x1:n,y1:s,x2:n,y2:s+6,stroke:d,strokeWidth:1}),e.jsx("text",{x:n,y:s+18,textAnchor:"middle",fill:u,fontFamily:h,fontSize:f,children:x(t)})]},`x-tick-${t}`)}),a?.label&&e.jsx("text",{x:r/2,y:s+38,textAnchor:"middle",fill:d,fontFamily:h,fontSize:f+1,fontWeight:"bold",children:a.label}),e.jsx("line",{x1:0,y1:0,x2:0,y2:s,stroke:d,strokeWidth:1}),n.map(t=>{const n=i(t);return e.jsxs("g",{children:[e.jsx("line",{x1:-6,y1:n,x2:0,y2:n,stroke:d,strokeWidth:1}),e.jsx("text",{x:-10,y:n,textAnchor:"end",dominantBaseline:"middle",fill:u,fontFamily:h,fontSize:f,children:p(t)})]},`y-tick-${t}`)}),l?.label&&e.jsx("text",{x:0,y:0,textAnchor:"middle",fill:d,fontFamily:h,fontSize:f+1,fontWeight:"bold",transform:`translate(-40, ${s/2}) rotate(-90)`,children:l.label})]})});p.displayName="Axes";const g=t.memo(({xTicks:t,yTicks:n,xScale:o,yScale:i,plotWidth:r,plotHeight:s,showXGrid:a,showYGrid:l,xGridColor:c="#e0e0e0",yGridColor:d="#e0e0e0"})=>e.jsxs("g",{className:"chartifypdf-grid",children:[l&&n.map(t=>{const n=i(t);return e.jsx("line",{x1:0,y1:n,x2:r,y2:n,stroke:d,strokeDasharray:"4 4",strokeOpacity:.5},`y-grid-${t}`)}),a&&t.map(t=>{const n=o(t);return e.jsx("line",{x1:n,y1:0,x2:n,y2:s,stroke:c,strokeDasharray:"4 4",strokeOpacity:.5},`x-grid-${t}`)})]}));function y(e){if(0===e.length)return"";const[t,...n]=e;return`M${t.x},${t.y}`+n.map(e=>`L${e.x},${e.y}`).join("")}function b(e,t){switch(t){case"monotone":return function(e){const t=e.length;if(t<2)return y(e);if(2===t)return y(e);const n=[],o=[],i=[];for(let r=0;r<t-1;r++)n.push(e[r+1].x-e[r].x),o.push(e[r+1].y-e[r].y),i.push(0===n[r]?0:o[r]/n[r]);const r=new Array(t);r[0]=i[0],r[t-1]=i[t-2];for(let e=1;e<t-1;e++)i[e-1]*i[e]<=0?r[e]=0:r[e]=2/(1/i[e-1]+1/i[e]);for(let e=0;e<t-1;e++)if(0===i[e])r[e]=0,r[e+1]=0;else{const t=r[e]/i[e],n=r[e+1]/i[e],o=t*t+n*n;if(o>9){const s=3/Math.sqrt(o);r[e]=s*t*i[e],r[e+1]=s*n*i[e]}}let s=`M${e[0].x},${e[0].y}`;for(let o=0;o<t-1;o++){const t=n[o]/3;s+=`C${e[o].x+t},${e[o].y+r[o]*t},${e[o+1].x-t},${e[o+1].y-r[o+1]*t},${e[o+1].x},${e[o+1].y}`}return s}(e);case"natural":return function(e){const t=e.length;if(t<2)return y(e);if(2===t)return y(e);function n(e){const t=e.length-1,n=new Array(t),o=new Array(t),i=new Array(t);n[0]=0,o[0]=2,i[0]=e[0]+2*e[1];for(let r=1;r<t-1;r++)n[r]=1,o[r]=4,i[r]=4*e[r]+2*e[r+1];n[t-1]=2,o[t-1]=7,i[t-1]=8*e[t-1]+e[t];for(let e=1;e<t;e++){const t=n[e]/o[e-1];o[e]-=t,i[e]-=t*i[e-1]}const r=new Array(t);r[t-1]=i[t-1]/o[t-1];for(let e=t-2;e>=0;e--)r[e]=(i[e]-r[e+1])/o[e];const s=new Array(t);for(let n=0;n<t-1;n++)s[n]=2*e[n+1]-r[n+1];s[t-1]=(e[t]+r[t-1])/2;const a=[];for(let e=0;e<t;e++)a.push({cp1:r[e],cp2:s[e]});return a}const o=e.map(e=>e.x),i=e.map(e=>e.y),r=n(o),s=n(i);let a=`M${e[0].x},${e[0].y}`;for(let n=0;n<t-1;n++)a+=`C${r[n].cp1},${s[n].cp1},${r[n].cp2},${s[n].cp2},${e[n+1].x},${e[n+1].y}`;return a}(e);default:return y(e)}}g.displayName="GridLines";const k=t.memo(({series:n,xScale:o,yScale:i,color:r,animation:s,onPointClick:a,curveType:l,highlightOpacity:c})=>{const d=t.useRef(null),[u,h]=t.useState(0),[f,x]=t.useState(!s?.enabled),m=n.strokeWidth??2,p=n.showDots??!1,g=n.dotRadius??3.5,k=n.curveType??l??"linear",v=c??1,w=n.data.map(e=>({x:o(e.x),y:i(e.y)})),C="linear"===k?y(w):b(w,k);t.useEffect(()=>{if(s?.enabled&&d.current){const e=d.current.getTotalLength();h(e),x(!1);const t=setTimeout(()=>{x(!0)},s.duration??800);return()=>clearTimeout(t)}},[C,s?.enabled,s?.duration]);const M=s?.enabled&&u>0?{strokeDasharray:u,strokeDashoffset:f?0:u,transition:`stroke-dashoffset ${s.duration??800}ms ${s.easing??"ease-in-out"}`}:{};return e.jsxs("g",{className:"chartifypdf-line-path",style:{opacity:v,transition:"opacity 150ms ease"},children:[e.jsx("path",{ref:d,d:C,fill:"none",stroke:r,strokeWidth:m,strokeDasharray:n.strokeDasharray,strokeLinecap:"round",strokeLinejoin:"round",style:M}),p&&n.data.map((t,s)=>e.jsx("circle",{cx:o(t.x),cy:i(t.y),r:g,fill:r,stroke:"#fff",strokeWidth:1.5,style:{cursor:a?"pointer":"default"},onClick:a?()=>a(t,n):void 0},`dot-${n.id}-${s}`))]})});k.displayName="LinePath";const v=t.memo(({visible:t,x:n,y:o,point:i,series:r,plotHeight:s,plotWidth:a,config:l,seriesColor:c})=>{if(!t||!i||!r)return null;const d=l?.backgroundColor??"rgba(0, 0, 0, 0.8)",u=l?.textColor??"#fff";let h;if(l?.renderCustom)h=l.renderCustom(i,r);else{h=l?.formatter?l.formatter(i,r):`${r.name}: (${i.x}, ${i.y})`}let f=n+12,x=o-40-8;return f+140>a&&(f=n-140-12),x<0&&(x=o+12),e.jsxs("g",{className:"chartifypdf-tooltip",pointerEvents:"none",children:[e.jsx("line",{x1:n,y1:0,x2:n,y2:s,stroke:"#999",strokeWidth:1,strokeDasharray:"4 4",opacity:.6}),e.jsx("circle",{cx:n,cy:o,r:5,fill:c,stroke:"#fff",strokeWidth:2}),e.jsx("foreignObject",{x:f,y:x,width:140,height:60,overflow:"visible",children:e.jsx("div",{style:{backgroundColor:d,color:u,padding:"6px 10px",borderRadius:"4px",fontSize:"12px",fontFamily:"sans-serif",whiteSpace:"nowrap",lineHeight:1.4,boxShadow:"0 2px 6px rgba(0,0,0,0.2)"},children:h})})]})});v.displayName="Tooltip";const w=t.memo(({config:t,svgWidth:n,svgHeight:o,margin:i,scale:r,onZoomIn:s,onZoomOut:a,onReset:l})=>{if(!t?.enabled||!1===t.showControls)return null;const c=t.controlsPosition??"top-right",d=24;let u,h;switch(c){case"top-left":u=i.left+8,h=i.top+8;break;case"bottom-left":u=i.left+8,h=o-i.bottom-24-8;break;case"bottom-right":u=n-i.right-80-8,h=o-i.bottom-24-8;break;default:u=n-i.right-80-8,h=i.top+8}const f=r>1?[{label:"+",onClick:s},{label:"−",onClick:a},{label:"↺",onClick:l}]:[{label:"+",onClick:s},{label:"−",onClick:a}];return e.jsx("g",{className:"chartifypdf-zoom-controls",transform:`translate(${u}, ${h})`,children:f.map((t,n)=>e.jsxs("g",{transform:`translate(${28*n}, 0)`,onClick:t.onClick,style:{cursor:"pointer"},children:[e.jsx("rect",{width:d,height:d,rx:4,fill:"rgba(255,255,255,0.9)",stroke:"#ccc",strokeWidth:1}),e.jsx("text",{x:12,y:12,textAnchor:"middle",dominantBaseline:"central",fontSize:14,fontFamily:"sans-serif",fill:"#333",fontWeight:"bold",children:t.label})]},t.label))})});function C({x:t,y:n,color:o}){return e.jsx("polygon",{points:`${t},${n} ${t-5},${n-10} ${t+5},${n-10}`,fill:o})}function M({x:t,y:n,color:o}){return e.jsx("polygon",{points:`${t},${n-6} ${t+5},${n} ${t},${n+6} ${t-5},${n}`,fill:o})}function S({x:t,y:n,color:o}){const i=[];for(let e=0;e<5;e++){const o=(72*e-90)*(Math.PI/180),r=(72*e+36-90)*(Math.PI/180);i.push(`${t+6*Math.cos(o)},${n+6*Math.sin(o)}`),i.push(`${t+3*Math.cos(r)},${n+3*Math.sin(r)}`)}return e.jsx("polygon",{points:i.join(" "),fill:o})}w.displayName="ZoomControls";const j=t.memo(({peaks:t,data:n,xScale:o,yScale:i})=>e.jsx("g",{className:"chartifypdf-peak-markers",children:t.map((t,r)=>{const s=function(e,t){let n=-1/0,o=-1;for(let i=0;i<e.length;i++){const r=e[i];let s=r.data[0],a=1/0;for(const e of r.data){const n=Math.abs(e.x-t);n<a&&(a=n,s=e)}s&&s.y>n&&(n=s.y,o=i)}return-1===o?null:{y:n,seriesIndex:o}}(n,t.x);if(!s)return null;const a=o(t.x),l=i(s.y),c=t.color??"#ef4444",d=t.icon??"arrow",u=t.label,h=l-14;return e.jsxs("g",{children:[e.jsx("line",{x1:a,y1:l,x2:a,y2:h+6,stroke:c,strokeWidth:1,strokeDasharray:"3 2",opacity:.6}),"arrow"===d&&e.jsx(C,{x:a,y:h,color:c}),"diamond"===d&&e.jsx(M,{x:a,y:h,color:c}),"star"===d&&e.jsx(S,{x:a,y:h,color:c}),u&&e.jsx("text",{x:a,y:h-8,textAnchor:"middle",fill:c,fontSize:11,fontWeight:600,children:u})]},`peak-${r}`)})}));j.displayName="PeakMarkers";const $=({visible:n,x:o,y:i,nearestX:r,data:s,config:a,getSeriesColor:l,onClose:c})=>{const d=t.useRef(null);if(t.useEffect(()=>{if(!n)return;const e=e=>{d.current&&!d.current.contains(e.target)&&c()},t=e=>{"Escape"===e.key&&c()},o=setTimeout(()=>{document.addEventListener("mousedown",e),document.addEventListener("keydown",t)},0);return()=>{clearTimeout(o),document.removeEventListener("mousedown",e),document.removeEventListener("keydown",t)}},[n,c]),!n)return null;const u=a?.backgroundColor??"#ffffff",h=a?.textColor??"#1f2937",f=a?.borderColor??"#e5e7eb",x=s.map((e,t)=>{const n=function(e,t){if(0===e.data.length)return null;let n=e.data[0],o=Math.abs(n.x-t);for(const i of e.data){const e=Math.abs(i.x-t);e<o&&(o=e,n=i)}return n.y}(e,r);return{name:e.name,color:e.color??l(t),x:r,y:n}});return e.jsxs("div",{ref:d,style:{position:"fixed",left:o,top:i,zIndex:9999,backgroundColor:u,color:h,border:`1px solid ${f}`,borderRadius:6,boxShadow:"0 4px 12px rgba(0,0,0,0.15)",padding:"8px 0",minWidth:200,fontSize:12,fontFamily:"system-ui, -apple-system, sans-serif"},children:[e.jsxs("div",{style:{padding:"4px 12px 8px",fontWeight:600,fontSize:11,color:h,opacity:.6,borderBottom:`1px solid ${f}`,marginBottom:4},children:["Data at X = ","number"==typeof r?r.toLocaleString():r]}),e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse"},children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{style:{textAlign:"left",padding:"4px 12px",fontWeight:600,opacity:.7},children:"Series"}),e.jsx("th",{style:{textAlign:"right",padding:"4px 12px",fontWeight:600,opacity:.7},children:"Y"})]})}),e.jsx("tbody",{children:x.map((t,n)=>e.jsxs("tr",{style:{borderTop:n>0?`1px solid ${f}`:void 0},children:[e.jsxs("td",{style:{padding:"4px 12px",display:"flex",alignItems:"center",gap:6},children:[e.jsx("span",{style:{display:"inline-block",width:8,height:8,borderRadius:"50%",backgroundColor:t.color,flexShrink:0}}),t.name]}),e.jsx("td",{style:{padding:"4px 12px",textAlign:"right",fontVariantNumeric:"tabular-nums"},children:null!==t.y?t.y.toLocaleString():"—"})]},n))})]})]})};function L(e){const t=e.cloneNode(!0),n=e.getBoundingClientRect();t.setAttribute("width",String(n.width)),t.setAttribute("height",String(n.height)),t.setAttribute("xmlns","http://www.w3.org/2000/svg"),t.setAttribute("xmlns:xlink","http://www.w3.org/1999/xlink");const o=e.querySelectorAll("*"),i=t.querySelectorAll("*");for(let e=0;e<o.length;e++){const t=o[e],n=i[e];if(!n.style)continue;const r=window.getComputedStyle(t),s=["fill","stroke","stroke-width","stroke-dasharray","opacity","font-family","font-size","font-weight","text-anchor","dominant-baseline","visibility","display"];for(const e of s){const t=r.getPropertyValue(e);t&&n.style.setProperty(e,t)}}return t}function P(e,t){const n=URL.createObjectURL(e),o=document.createElement("a");o.href=n,o.download=t,document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(n)}async function D(e,t=2){const n=e.getBoundingClientRect(),o=n.width*t,i=n.height*t,r=document.createElement("canvas");r.width=o,r.height=i;const s=r.getContext("2d");if(!s)throw new Error("Cannot get canvas 2d context");s.scale(t,t);const a=function(e){const t=L(e),n=(new XMLSerializer).serializeToString(t),o=new Blob([n],{type:"image/svg+xml;charset=utf-8"});return URL.createObjectURL(o)}(e);return new Promise((e,t)=>{const o=new Image;o.onload=()=>{s.fillStyle="#ffffff",s.fillRect(0,0,n.width,n.height),s.drawImage(o,0,0,n.width,n.height),URL.revokeObjectURL(a),e(r)},o.onerror=()=>{URL.revokeObjectURL(a),t(new Error("Failed to load SVG as image"))},o.src=a})}async function T(e,t="chart"){const n=L(e),o=(new XMLSerializer).serializeToString(n);P(new Blob([o],{type:"image/svg+xml;charset=utf-8"}),`${t}.svg`)}async function R(e,t="chart"){const n=await D(e);P(await new Promise((e,t)=>{n.toBlob(n=>n?e(n):t(new Error("Canvas toBlob failed")),"image/png")}),`${t}.png`)}async function W(e,t="chart"){const n=(await D(e)).toDataURL("image/png"),o=e.getBoundingClientRect(),i=window.open("","_blank");if(!i)throw new Error("Popup blocked. Please allow popups to export PDF.");i.document.write(`\n <!DOCTYPE html>\n <html>\n <head>\n <title>${t}</title>\n <style>\n @page { size: landscape; margin: 10mm; }\n body { margin: 0; display: flex; justify-content: center; align-items: center; min-height: 100vh; }\n img { max-width: 100%; height: auto; }\n </style>\n </head>\n <body>\n <img src="${n}" width="${o.width}" height="${o.height}" />\n <script>\n window.onload = function() {\n setTimeout(function() { window.print(); window.close(); }, 300);\n };\n <\/script>\n </body>\n </html>\n `),i.document.close()}async function A(e,t="pdf",n="chart"){switch(t){case"svg":return T(e,n);case"png":return R(e,n);case"pdf":return W(e,n)}}$.displayName="ContextMenu";const z=t.memo(({config:n,svgRef:o,svgWidth:i,svgHeight:r,margin:s})=>{if(!n?.enabled)return null;let a,l;switch(n.buttonPosition??"top-right"){case"top-left":a=s.left+8,l=s.top+8+24+8;break;case"bottom-left":a=s.left+8,l=r-s.bottom-24-8;break;case"bottom-right":a=i-s.right-28-8,l=r-s.bottom-24-8;break;default:a=i-s.right-28-8,l=s.top+8+24+8}const c=t.useCallback(()=>{const e=o.current;if(!e)return;A(e,n?.format??"pdf",n?.fileName??"chart")},[o,n?.format,n?.fileName]);return e.jsxs("g",{className:"chartifypdf-export-button",transform:`translate(${a}, ${l})`,onClick:c,style:{cursor:"pointer"},children:[e.jsx("rect",{width:28,height:24,rx:4,fill:"rgba(255,255,255,0.9)",stroke:"#ccc",strokeWidth:1}),e.jsx("g",{transform:"translate(7, 4)",children:e.jsx("path",{d:"M7,2 L7,10 L4,7 M7,10 L10,7 M3,13 L11,13",fill:"none",stroke:"#333",strokeWidth:1.5,strokeLinecap:"round",strokeLinejoin:"round"})})]})});z.displayName="ExportButton";const N={top:20,right:20,bottom:50,left:60},X=({data:i,width:r,height:s,margin:a,xAxis:l,yAxis:c,tooltip:f,zoom:m,style:y,animation:b,colorPalette:C,className:M,onPointClick:S,ariaLabel:L,curveType:P,peaks:D,contextMenu:T,export:R})=>{const W=t.useRef(null),A=t.useRef(null),X=t.useId(),E={...N,...a},Y=o(W,r,s??400),{width:F,height:I}=Y,B=Math.max(0,F-E.left-E.right),O=Math.max(0,I-E.top-E.bottom),{fullXDomain:H,fullYDomain:U}=d(i,l,c),Z=h(m,H,U,B,O),G=m?.enabled??!1,q=m?.enableClickZoom??!1,{xScale:K,yScale:V,xTicks:_,yTicks:J}=u(i,B,O,l,c,G?Z.viewXDomain:void 0,G?Z.viewYDomain:void 0),Q=!1!==f?.enabled,ee=x(A,i,K,V,E.left,E.top,B),te=ee.activeSeriesId,ne=ee.tooltipVisible&&null!==te,oe=e=>ne?e===te?1:.2:1,ie=m?.requireCtrlKey??!0,re=m?.enableWheel??!0;t.useEffect(()=>{const e=A.current;if(!e||!G||!re)return;const t=e=>{ie?(e.ctrlKey||e.metaKey)&&e.preventDefault():e.preventDefault()};return e.addEventListener("wheel",t,{passive:!1}),()=>e.removeEventListener("wheel",t)},[G,re,ie]);const se=t.useCallback(e=>{if(!G||!q)return;if(Z.isPanning)return;const t=A.current;if(!t)return;const n=t.getBoundingClientRect(),o=e.clientX-n.left-E.left,r=e.clientY-n.top-E.top;if(o<0||o>B||r<0||r>O)return;let s=0,a=0,l=1/0;for(const e of i)for(const t of e.data){const e=K(t.x),n=V(t.y),i=Math.hypot(e-o,n-r);i<l&&(l=i,s=t.x,a=t.y)}Z.zoomToPoint(s,a)},[G,q,Z,i,K,V,E.left,E.top,B,O]),ae=t.useCallback(()=>{G&&q&&Z.resetZoom()},[G,q,Z]),[le,ce]=t.useState({visible:!1,clientX:0,clientY:0,nearestX:0}),de=t.useCallback(e=>{if(!T?.enabled)return;e.preventDefault();const t=A.current;if(!t)return;const n=t.getBoundingClientRect(),o=e.clientX-n.left-E.left;if(o<0||o>B)return;let r=0,s=1/0;for(const e of i)for(const t of e.data){const e=K(t.x),n=Math.abs(e-o);n<s&&(s=n,r=t.x)}ce({visible:!0,clientX:e.clientX,clientY:e.clientY,nearestX:r})},[T?.enabled,i,K,E.left,B]),ue=t.useCallback(()=>{ce(e=>({...e,visible:!1}))},[]),he=l?.gridLines??!1,fe=c?.gridLines??!0,xe=e=>function(e,t){const o=t??n;return o[e%o.length]}(e,C);return 0===F||0===I?e.jsx("div",{ref:W,className:M,style:{width:r??"100%",height:s??400,backgroundColor:y?.backgroundColor}}):e.jsxs("div",{ref:W,className:M,style:{width:r??"100%",height:s??400,backgroundColor:y?.backgroundColor,position:"relative"},children:[e.jsxs("svg",{ref:A,width:F,height:I,role:"img","aria-label":L??"Line chart",onMouseMove:Q&&!Z.isPanning?ee.handleMouseMove:void 0,onMouseLeave:Q?ee.handleMouseLeave:void 0,onWheel:G?Z.handleWheel:void 0,onMouseDown:G?Z.handlePanStart:void 0,onMouseUp:G?Z.handlePanEnd:void 0,onClick:se,onDoubleClick:ae,onContextMenu:de,style:{userSelect:Z.isPanning?"none":void 0,cursor:Z.isPanning?"grabbing":G&&Z.scale>1?"grab":void 0},children:[e.jsx("defs",{children:e.jsx("clipPath",{id:X,children:e.jsx("rect",{width:B,height:O})})}),e.jsxs("g",{transform:`translate(${E.left}, ${E.top})`,children:[e.jsx(p,{xTicks:_,yTicks:J,xScale:K,yScale:V,plotWidth:B,plotHeight:O,xAxisConfig:l,yAxisConfig:c,style:y}),e.jsx(g,{xTicks:_,yTicks:J,xScale:K,yScale:V,plotWidth:B,plotHeight:O,showXGrid:he,showYGrid:fe,xGridColor:l?.gridLineColor,yGridColor:c?.gridLineColor}),e.jsxs("g",{clipPath:`url(#${X})`,children:[G?e.jsx("g",{onMouseMove:Z.handlePanMove,children:i.map((t,n)=>e.jsx(k,{series:t,xScale:K,yScale:V,color:t.color??xe(n),animation:b,onPointClick:S,curveType:P,highlightOpacity:oe(t.id)},t.id))}):i.map((t,n)=>e.jsx(k,{series:t,xScale:K,yScale:V,color:t.color??xe(n),animation:b,onPointClick:S,curveType:P,highlightOpacity:oe(t.id)},t.id)),D&&D.length>0&&e.jsx(j,{peaks:D,data:i,xScale:K,yScale:V,colorPalette:C})]}),Q&&e.jsx(v,{visible:ee.tooltipVisible,x:ee.tooltipX,y:ee.tooltipY,point:ee.activePoint,series:ee.activeSeries,plotHeight:O,plotWidth:B,config:f,seriesColor:ee.activeSeries?.color??xe(i.findIndex(e=>e.id===ee.activeSeries?.id))})]}),e.jsx(w,{config:m,svgWidth:F,svgHeight:I,margin:E,scale:Z.scale,onZoomIn:Z.zoomIn,onZoomOut:Z.zoomOut,onReset:Z.resetZoom}),e.jsx(z,{config:R,svgRef:A,svgWidth:F,svgHeight:I,margin:E})]}),Z.showZoomHint&&e.jsx("div",{style:{position:"absolute",top:"50%",left:"50%",transform:"translate(-50%, -50%)",background:"rgba(0, 0, 0, 0.7)",color:"#fff",padding:"8px 16px",borderRadius:6,fontSize:13,fontFamily:"system-ui, -apple-system, sans-serif",pointerEvents:"none",whiteSpace:"nowrap",zIndex:10},children:"Hold Ctrl + scroll to zoom"}),T?.enabled&&e.jsx($,{visible:le.visible,x:le.clientX,y:le.clientY,nearestX:le.nearestX,data:i,config:T,getSeriesColor:xe,onClose:ue})]})};X.displayName="LineChart",exports.LineChart=X,exports.exportChart=A,exports.exportChartAsPdf=W,exports.exportChartAsPng=R,exports.exportChartAsSvg=T,exports.useChartDimensions=o,exports.useDataDomain=d,exports.useScales=u,exports.useTooltip=x,exports.useZoom=h;
|
|
2
2
|
//# sourceMappingURL=index.js.map
|