radiant-charts-core 0.2.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/LICENSE +21 -0
- package/LICENSE.md +21 -0
- package/dist/index.d.mts +431 -0
- package/dist/index.d.ts +431 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +9 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +31 -0
- package/src/Declarative.tsx +503 -0
- package/src/RadiantChart.tsx +446 -0
- package/src/ResponsiveContainer.tsx +128 -0
- package/src/axes/CartesianAxis.ts +305 -0
- package/src/core/Animator.ts +119 -0
- package/src/core/ChartManager.ts +1062 -0
- package/src/core/CrosshairManager.ts +334 -0
- package/src/core/Legend.ts +269 -0
- package/src/core/ThemeManager.ts +98 -0
- package/src/index.ts +31 -0
- package/src/scale/Scale.ts +99 -0
- package/src/scene/Node.ts +183 -0
- package/src/scene/Scene.ts +197 -0
- package/src/scene/Shapes.ts +446 -0
- package/src/series/AreaSeries.ts +315 -0
- package/src/series/BarSeries.ts +502 -0
- package/src/series/LineSeries.ts +284 -0
- package/src/series/PieSeries.ts +203 -0
- package/src/series/ScatterSeries.ts +305 -0
- package/src/tooltip/TooltipContext.ts +22 -0
- package/src/tooltip/TooltipStore.ts +169 -0
- package/src/tooltip/__tests__/TooltipStore.test.ts +176 -0
- package/src/tooltip/coordUtils.ts +41 -0
- package/src/tooltip/index.ts +18 -0
- package/src/tooltip/types.ts +57 -0
- package/src/tooltip/useChartTooltip.ts +43 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/RadiantChart.tsx","../src/scene/Node.ts","../src/scene/Shapes.ts","../src/scene/Scene.ts","../src/scale/Scale.ts","../src/axes/CartesianAxis.ts","../src/core/Animator.ts","../src/series/BarSeries.ts","../src/series/LineSeries.ts","../src/series/PieSeries.ts","../src/series/AreaSeries.ts","../src/series/ScatterSeries.ts","../src/tooltip/types.ts","../src/tooltip/TooltipStore.ts","../src/core/ThemeManager.ts","../src/core/Legend.ts","../src/core/CrosshairManager.ts","../src/core/ChartManager.ts","../src/tooltip/TooltipContext.ts","../src/ResponsiveContainer.tsx","../src/Declarative.tsx","../src/tooltip/useChartTooltip.ts"],"sourcesContent":["'use client';\r\n\r\n// Radiant Charts - React Wrapper\r\n// Phase 1.1: Suspense skeleton, prefers-reduced-motion-aware, client boundary isolated\r\n\r\nimport React, { useRef, useEffect, useLayoutEffect, useState, useMemo, useImperativeHandle, forwardRef } from 'react';\r\nimport { ChartManager } from './core/ChartManager';\r\nimport { ThemeManager, ThemeOption } from './core/ThemeManager';\r\nimport { TooltipStoreContext } from './tooltip/TooltipContext';\r\nimport { TooltipStore } from './tooltip/TooltipStore';\r\nimport type { TooltipOptions } from './tooltip/types';\r\n\r\n// ─── Options Interface ────────────────────────────────────────────────────────\r\nexport interface DataLabelOptions {\r\n readonly enabled?: boolean;\r\n /** 'top' | 'bottom' | 'left' | 'right' | 'inside' | 'center' | 'outside' */\r\n readonly position?: string;\r\n readonly fontSize?: number;\r\n readonly fontFamily?: string;\r\n readonly fill?: string;\r\n readonly fontWeight?: string;\r\n readonly rotation?: number;\r\n}\r\n\r\nexport interface AnimationOptions {\r\n readonly enabled?: boolean;\r\n readonly duration?: number;\r\n readonly easing?: 'linear' | 'easeIn' | 'easeOut' | 'easeInOut' | 'easeInCubic' | 'easeOutCubic' | 'easeInOutCubic' | 'bounce' | 'elastic' | 'back';\r\n readonly type?: 'grow' | 'fade' | 'slide' | 'pop' | 'draw' | 'radial';\r\n readonly delay?: number;\r\n}\r\n\r\n// ─── Drop shadow ──────────────────────────────────────────────────────────────\r\nexport interface DropShadow {\r\n readonly enabled?: boolean;\r\n readonly color?: string;\r\n readonly xOffset?: number;\r\n readonly yOffset?: number;\r\n readonly blur?: number;\r\n}\r\n\r\n// ─── Marker (extended with shape variants) ────────────────────────────────────\r\nexport type MarkerShape = 'circle' | 'square' | 'cross' | 'diamond' | 'triangle' | 'plus';\r\n\r\nexport interface MarkerOptions {\r\n readonly enabled?: boolean;\r\n readonly shape?: MarkerShape;\r\n readonly size?: number;\r\n readonly fill?: string;\r\n readonly stroke?: string;\r\n readonly strokeWidth?: number;\r\n}\r\n\r\nexport interface RadiantChartOptions {\r\n readonly data: readonly any[];\r\n readonly animation?: AnimationOptions;\r\n readonly title?: { text: string; fontSize?: number; fill?: string };\r\n readonly subtitle?: { text: string; fontSize?: number; fill?: string };\r\n readonly legend?: {\r\n readonly enabled?: boolean;\r\n readonly position?: 'top' | 'bottom' | 'left' | 'right';\r\n readonly type?: 'discrete';\r\n readonly listeners?: {\r\n readonly legendItemClick?: (event: { seriesId: string; visible: boolean }) => void;\r\n readonly legendItemDoubleClick?: (event: { seriesId: string; isolated: boolean }) => void;\r\n };\r\n };\r\n /**\r\n * Node-level pointer event callbacks. Triggered when the user interacts with\r\n * an individual data point (bar / marker / sector / etc).\r\n */\r\n readonly listeners?: {\r\n readonly nodeClick?: (event: { seriesId: string; datum: any; xKey?: string; yKey?: string; type?: string }) => void;\r\n readonly nodeDoubleClick?: (event: { seriesId: string; datum: any; xKey?: string; yKey?: string; type?: string }) => void;\r\n };\r\n readonly showXAxis?: boolean;\r\n readonly showYAxis?: boolean;\r\n readonly showYAxisRight?: boolean;\r\n readonly xAxisFontSize?: number;\r\n readonly xAxisFontFamily?: string;\r\n readonly xAxisRotation?: number;\r\n readonly xAxisLabelAlignment?: 'start' | 'center' | 'end';\r\n readonly yAxisFontSize?: number;\r\n readonly yAxisFontFamily?: string;\r\n readonly yAxisRotation?: number;\r\n readonly yAxisLabelAlignment?: 'start' | 'center' | 'end';\r\n readonly yAxisRightFontSize?: number;\r\n readonly yAxisRightFontFamily?: string;\r\n readonly yAxisRightRotation?: number;\r\n readonly yAxisRightLabelAlignment?: 'start' | 'center' | 'end';\r\n readonly series: readonly {\r\n readonly type?: 'bar' | 'line' | 'pie' | 'donut' | 'area' | 'scatter';\r\n readonly animation?: AnimationOptions;\r\n readonly yAxisId?: 'left' | 'right';\r\n readonly xAxisKey?: string;\r\n readonly yAxisKey?: string;\r\n // Common keys\r\n readonly xKey?: string;\r\n readonly yKey?: string;\r\n readonly angleKey?: string;\r\n readonly labelKey?: string;\r\n readonly shadow?: DropShadow;\r\n readonly connectMissingData?: boolean;\r\n // Scatter\r\n readonly sizeKey?: string;\r\n readonly markerSize?: number;\r\n // Style\r\n readonly title?: string;\r\n readonly fill?: string;\r\n readonly stroke?: string;\r\n readonly strokeWidth?: number;\r\n readonly fills?: readonly string[];\r\n readonly innerRadius?: number;\r\n readonly outerRadius?: number;\r\n readonly startAngle?: number;\r\n readonly endAngle?: number;\r\n readonly padAngle?: number;\r\n readonly fillOpacity?: number;\r\n readonly cornerRadius?: number;\r\n // Behavior flags\r\n readonly grouped?: boolean;\r\n readonly stacked?: boolean;\r\n readonly normalized?: boolean;\r\n readonly direction?: 'vertical' | 'horizontal';\r\n readonly interpolation?: 'linear' | 'step' | 'smooth';\r\n /** @deprecated use interpolation:'step' */\r\n readonly step?: boolean;\r\n readonly marker?: MarkerOptions;\r\n readonly jitter?: number;\r\n readonly labels?: DataLabelOptions;\r\n }[];\r\n theme?: 'light' | 'dark' | 'system';\r\n padding?: { readonly top?: number; readonly right?: number; readonly bottom?: number; readonly left?: number; readonly inner?: number };\r\n crosshair?: { readonly x?: boolean; readonly y?: boolean };\r\n tooltip?: TooltipOptions;\r\n toolbar?: { readonly showExport?: boolean };\r\n /**\r\n * Callback triggered when keyboard navigation moves the internal focus index.\r\n * Used for synchronizing the virtualized accessibility table.\r\n */\r\n readonly onFocusChange?: (index: number | null) => void;\r\n}\r\n\r\n// ─── Accessibility helpers ────────────────────────────────────────────────────\r\n\r\n/**\r\n * Returns an ordered, deduplicated list of data keys referenced by the series.\r\n * Priority order: xKey first, then yKey, then other value-bearing keys.\r\n */\r\nconst VALUE_KEY_FIELDS = [\r\n 'xKey', 'yKey',\r\n 'labelKey', 'angleKey', 'sizeKey',\r\n] as const;\r\n\r\nfunction deriveTableKeys(series: RadiantChartOptions['series']): string[] {\r\n const seen = new Set<string>();\r\n for (const s of series) {\r\n for (const field of VALUE_KEY_FIELDS) {\r\n const val = (s as any)[field];\r\n if (typeof val === 'string') seen.add(val);\r\n }\r\n }\r\n return Array.from(seen);\r\n}\r\n\r\n// ─── Imperative handle ────────────────────────────────────────────────────────\r\n\r\nexport interface RadiantChartHandle {\r\n /**\r\n * Exports the current chart as a PNG and triggers a browser download.\r\n * @param filename Download filename. Defaults to 'chart.png'.\r\n */\r\n exportToPng(filename?: string): void;\r\n}\r\n\r\n// ─── Component ────────────────────────────────────────────────────────────────\r\n\r\ninterface RadiantChartProps {\r\n options: RadiantChartOptions;\r\n /**\r\n * Explicit width for the chart container. Number = px, string = CSS value.\r\n * Defaults to '100%'. For responsive sizing wrap with ResponsiveContainer.\r\n */\r\n width?: number | string;\r\n /**\r\n * Explicit height for the chart container. Number = px, string = CSS value.\r\n * Defaults to '100%'. When using '100%' the parent must have a defined height,\r\n * or wrap with ResponsiveContainer which handles this automatically.\r\n */\r\n height?: number | string;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n}\r\n\r\nconst RadiantChart = forwardRef<RadiantChartHandle, RadiantChartProps>(\r\nfunction RadiantChart({ options, width = '100%', height = '100%', className, style }, ref) {\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n const chartRef = useRef<ChartManager | null>(null);\r\n const tooltipStoreRef = useRef<TooltipStore | null>(null);\r\n const [mounted, setMounted] = useState(false);\r\n const [focusedIndex, setFocusedIndex] = useState<number | null>(null);\r\n\r\n useImperativeHandle(ref, () => ({\r\n exportToPng(filename?: string) {\r\n chartRef.current?.exportToPng(filename);\r\n },\r\n }), []);\r\n\r\n const resolvedOptions = useMemo<RadiantChartOptions>(() => {\r\n return {\r\n ...options,\r\n series: options.series || [],\r\n data: options.data || [],\r\n onFocusChange: (idx: number | null) => setFocusedIndex(idx),\r\n };\r\n }, [options]);\r\n\r\n // Phase 1.1 – Initialize chart engine on mount.\r\n // We deliberately do NOT call `setMounted(true)` here. Doing so synchronously\r\n // during the layout-commit phase scheduled an immediate re-render in the\r\n // same frame, and when a parent (e.g. the docs subtype switcher) rapidly\r\n // toggles a `key` prop forcing back-to-back unmount/remount cycles, those\r\n // synchronous setState calls stacked into \"Maximum update depth exceeded\".\r\n // The `mounted` flip is now handled by the dedicated `useEffect` below\r\n // which fires after paint, so the layout effect stays purely about\r\n // attaching/destroying the imperative engine.\r\n useLayoutEffect(() => {\r\n if (containerRef.current && !chartRef.current) {\r\n chartRef.current = new ChartManager(containerRef.current, {\r\n ...resolvedOptions,\r\n onFocusChange: (idx) => setFocusedIndex(idx),\r\n });\r\n tooltipStoreRef.current = chartRef.current.getTooltipStore();\r\n }\r\n return () => {\r\n chartRef.current?.destroy();\r\n chartRef.current = null;\r\n };\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, []);\r\n\r\n // Flip `mounted` after first paint via requestAnimationFrame so the\r\n // setState lands in a *separate* commit phase from the layout effect that\r\n // attached the engine. Without the rAF break, rapid key-driven remounts\r\n // (e.g. the docs subtype switcher composite-keying on\r\n // `${activeIndex}-${datasetType}`) stacked the synchronous setMounted\r\n // calls into a single React 18 commit and tripped the\r\n // \"Maximum update depth exceeded\" guard. The `if (!mounted)` guard keeps\r\n // the flip strictly idempotent so React never re-asserts the same value.\r\n useEffect(() => {\r\n if (mounted) return;\r\n if (typeof window === 'undefined') {\r\n setMounted(true);\r\n return;\r\n }\r\n let cancelled = false;\r\n const raf = window.requestAnimationFrame(() => {\r\n if (!cancelled) setMounted(true);\r\n });\r\n return () => {\r\n cancelled = true;\r\n window.cancelAnimationFrame(raf);\r\n };\r\n }, [mounted]);\r\n\r\n // Update chart when options change or after first paint (mounted).\r\n useEffect(() => {\r\n chartRef.current?.update(resolvedOptions);\r\n }, [resolvedOptions, mounted]);\r\n\r\n // When the theme prop transitions to or from 'system', ChartManager must attach\r\n // or detach its OS-level prefers-color-scheme listener. ChartManager.update()\r\n // (called above) already calls _syncMediaQueryListener() internally, so this\r\n // effect exists purely to make the contract explicit: any change to options.theme\r\n // guarantees a synchronous listener re-evaluation on the engine side.\r\n // If resolvedOptions hasn't changed for some other reason but theme has (e.g.\r\n // direct prop mutation in strict mode), the explicit update call here is a safety net.\r\n useEffect(() => {\r\n chartRef.current?.update(resolvedOptions);\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [options.theme]);\r\n\r\n // Resolve isDark once for the component's own UI (skeleton, container bg, toolbar).\r\n // For 'system' we read the live OS preference and subscribe to changes below.\r\n const [systemIsDark, setSystemIsDark] = useState(() => ThemeManager.resolveIsDark(options.theme as ThemeOption));\r\n\r\n // Re-render the React shell when the OS-level theme toggles while theme === 'system'.\r\n useEffect(() => {\r\n if (options.theme !== 'system' || typeof window === 'undefined') return;\r\n const mql = window.matchMedia('(prefers-color-scheme: dark)');\r\n const handler = () => setSystemIsDark(mql.matches);\r\n // Sync immediately in case it changed between render and effect\r\n setSystemIsDark(mql.matches);\r\n mql.addEventListener('change', handler);\r\n return () => mql.removeEventListener('change', handler);\r\n }, [options.theme]);\r\n\r\n const isDark = options.theme === 'system' ? systemIsDark : options.theme === 'dark';\r\n\r\n const tableKeys = useMemo(() => deriveTableKeys(resolvedOptions.series), [resolvedOptions.series]);\r\n\r\n const computedClassName = className || '';\r\n\r\n return (\r\n <TooltipStoreContext.Provider value={tooltipStoreRef.current}>\r\n <div\r\n ref={containerRef}\r\n data-radiant-chart\r\n className={computedClassName}\r\n style={{\r\n position: 'relative',\r\n width,\r\n height,\r\n minHeight: typeof height === 'number' ? undefined : '100px',\r\n display: 'block',\r\n overflow: 'hidden',\r\n backgroundColor: isDark ? '#020617' : '#ffffff',\r\n ...style,\r\n }}\r\n >\r\n {/* Pulse skeleton shown until canvas mounts */}\r\n {!mounted && (\r\n <div\r\n style={{\r\n position: 'absolute', inset: 0,\r\n display: 'flex', flexDirection: 'column',\r\n gap: 8, padding: '8px 10px 4px 4px',\r\n background: isDark ? '#020617' : '#ffffff',\r\n }}\r\n >\r\n {/* Title skeleton */}\r\n <div style={{ height: 14, width: '35%', borderRadius: 4, background: isDark ? '#1e293b' : '#f1f5f9', animation: 'radiant-pulse 1.4s ease-in-out infinite' }} />\r\n {/* Chart area skeleton */}\r\n <div style={{ flex: 1, display: 'flex', gap: 6, alignItems: 'flex-end', paddingTop: 8 }}>\r\n {[65, 45, 80, 55, 70, 40, 60].map((h, i) => (\r\n <div key={i} style={{ flex: 1, height: `${h}%`, borderRadius: '3px 3px 0 0', background: isDark ? '#1e293b' : '#f1f5f9', animation: `radiant-pulse 1.4s ease-in-out ${i * 0.1}s infinite` }} />\r\n ))}\r\n </div>\r\n {/* X-axis skeleton */}\r\n <div style={{ height: 8, borderRadius: 4, background: isDark ? '#1e293b' : '#f1f5f9', animation: 'radiant-pulse 1.4s ease-in-out infinite' }} />\r\n </div>\r\n )}\r\n <style>{`\r\n @keyframes radiant-pulse {\r\n 0%, 100% { opacity: 1; }\r\n 50% { opacity: 0.4; }\r\n }\r\n [data-radiant-chart] .radiant-toolbar { opacity: 0; transition: opacity 0.15s ease; }\r\n [data-radiant-chart]:hover .radiant-toolbar { opacity: 1; }\r\n `}</style>\r\n\r\n {/* Export toolbar — visible on container hover */}\r\n {options.toolbar?.showExport && (\r\n <div className=\"radiant-toolbar\" style={{ position: 'absolute', top: 8, right: 8, zIndex: 10, display: 'flex', gap: 4 }}>\r\n <button\r\n type=\"button\"\r\n title=\"Export as PNG\"\r\n aria-label=\"Export chart as PNG\"\r\n onClick={() => chartRef.current?.exportToPng(\r\n options.title?.text\r\n ? `${options.title.text.replace(/\\s+/g, '-').toLowerCase()}.png`\r\n : 'radiant-chart.png'\r\n )}\r\n style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n width: 28,\r\n height: 28,\r\n borderRadius: 6,\r\n border: isDark ? '1px solid rgba(255,255,255,0.12)' : '1px solid rgba(0,0,0,0.10)',\r\n background: isDark ? 'rgba(15,23,42,0.85)' : 'rgba(255,255,255,0.90)',\r\n color: isDark ? '#94a3b8' : '#64748b',\r\n cursor: 'pointer',\r\n backdropFilter: 'blur(4px)',\r\n boxShadow: isDark ? '0 1px 4px rgba(0,0,0,0.4)' : '0 1px 4px rgba(0,0,0,0.10)',\r\n padding: 0,\r\n transition: 'background 0.15s, color 0.15s',\r\n }}\r\n onMouseEnter={e => {\r\n (e.currentTarget as HTMLButtonElement).style.background = isDark ? 'rgba(30,41,59,0.95)' : 'rgba(241,245,249,0.98)';\r\n (e.currentTarget as HTMLButtonElement).style.color = isDark ? '#e2e8f0' : '#0f172a';\r\n }}\r\n onMouseLeave={e => {\r\n (e.currentTarget as HTMLButtonElement).style.background = isDark ? 'rgba(15,23,42,0.85)' : 'rgba(255,255,255,0.90)';\r\n (e.currentTarget as HTMLButtonElement).style.color = isDark ? '#94a3b8' : '#64748b';\r\n }}\r\n >\r\n {/* Download icon */}\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\r\n <path d=\"M8 1v9M5 7l3 3 3-3\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\r\n <path d=\"M2 12v1.5A1.5 1.5 0 003.5 15h9A1.5 1.5 0 0014 13.5V12\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n )}\r\n\r\n {/* Visually hidden data table for screen readers — virtualized for performance */}\r\n {tableKeys.length > 0 && resolvedOptions.data.length > 0 && (\r\n <table\r\n className=\"sr-only\"\r\n aria-label={options.title?.text ?? 'Chart data'}\r\n aria-rowcount={resolvedOptions.data.length + 1}\r\n >\r\n <thead>\r\n <tr aria-rowindex={1}>\r\n {tableKeys.map((key) => (\r\n <th key={key} scope=\"col\">{key}</th>\r\n ))}\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {(() => {\r\n // Virtualization logic: only render 10 rows around the focused index.\r\n // If nothing is focused, show the first 10 rows.\r\n const windowSize = 10;\r\n const totalItems = resolvedOptions.data.length;\r\n const start = focusedIndex === null \r\n ? 0 \r\n : Math.max(0, focusedIndex - Math.floor(windowSize / 2));\r\n const end = Math.min(totalItems, start + windowSize);\r\n \r\n return resolvedOptions.data.slice(start, end).map((row, i) => {\r\n const rowIndex = start + i;\r\n return (\r\n <tr \r\n key={rowIndex} \r\n aria-rowindex={rowIndex + 2}\r\n aria-selected={rowIndex === focusedIndex}\r\n >\r\n {tableKeys.map((key) => (\r\n <td key={key}>{row[key] ?? ''}</td>\r\n ))}\r\n </tr>\r\n );\r\n });\r\n })()}\r\n </tbody>\r\n </table>\r\n )}\r\n </div>\r\n </TooltipStoreContext.Provider>\r\n );\r\n});\r\n\r\nexport default RadiantChart;\r\n","export interface BBox {\r\n x: number;\r\n y: number;\r\n width: number;\r\n height: number;\r\n}\r\n\r\n/**\r\n * Base Node class for the Radiant Chart Scene Graph.\r\n */\r\nexport abstract class Node {\r\n id: string = Math.random().toString(36).substr(2, 9);\r\n x: number = 0;\r\n y: number = 0;\r\n visible: boolean = true;\r\n opacity: number = 1;\r\n translation: { x: number; y: number } = { x: 0, y: 0 };\r\n rotation: number = 0; // Rotation in radians\r\n scaling: { x: number; y: number } = { x: 1, y: 1 };\r\n \r\n parent: Node | null = null;\r\n children: Node[] = [];\r\n\r\n // Hit testing properties\r\n pointerEvents: boolean = true;\r\n\r\n // Clipping\r\n clipRect: BBox | null = null;\r\n\r\n // Data mapping\r\n datum: any = null;\r\n seriesId: string = '';\r\n\r\n /**\r\n * Optional drop shadow applied to this node before its shape paints.\r\n * Maps to canvas `shadow*` properties; reset automatically by the\r\n * surrounding save/restore so it never bleeds onto siblings.\r\n */\r\n shadow: { color?: string; blur?: number; offsetX?: number; offsetY?: number } | null = null;\r\n\r\n constructor() {}\r\n\r\n /**\r\n * Adds a child node.\r\n */\r\n add(child: Node) {\r\n if (child.parent) {\r\n child.parent.remove(child);\r\n }\r\n child.parent = this;\r\n this.children.push(child);\r\n }\r\n\r\n /**\r\n * Removes a child node.\r\n */\r\n remove(child: Node) {\r\n const index = this.children.indexOf(child);\r\n if (index !== -1) {\r\n this.children.splice(index, 1);\r\n child.parent = null;\r\n }\r\n }\r\n\r\n /**\r\n * Clears all children.\r\n */\r\n clear() {\r\n this.children.forEach(child => child.parent = null);\r\n this.children = [];\r\n }\r\n\r\n /**\r\n * Renders the node and its children.\r\n */\r\n render(ctx: CanvasRenderingContext2D) {\r\n if (!this.visible || this.opacity === 0) return;\r\n\r\n // Optimization: only save/restore if we have transformations, opacity change, or clipping.\r\n // This avoids overhead for thousands of simple nodes in large datasets.\r\n const hasTransform = (this.translation.x !== 0 || this.translation.y !== 0) || \r\n (this.rotation !== 0) || \r\n (this.scaling.x !== 1 || this.scaling.y !== 1);\r\n const hasShadow = this.shadow !== null;\r\n const hasEffect = (this.opacity !== 1) || (this.clipRect !== null) || hasShadow;\r\n\r\n if (!hasTransform && !hasEffect) {\r\n this.renderShape(ctx);\r\n for (const child of this.children) {\r\n child.render(ctx);\r\n }\r\n return;\r\n }\r\n\r\n ctx.save();\r\n \r\n // Apply transformations\r\n if (this.translation.x !== 0 || this.translation.y !== 0) {\r\n ctx.translate(this.translation.x, this.translation.y);\r\n }\r\n if (this.rotation !== 0) {\r\n ctx.rotate(this.rotation);\r\n }\r\n if (this.scaling.x !== 1 || this.scaling.y !== 1) {\r\n ctx.scale(this.scaling.x, this.scaling.y);\r\n }\r\n if (this.opacity !== 1) {\r\n ctx.globalAlpha *= this.opacity;\r\n }\r\n\r\n // Apply clipping if defined\r\n if (this.clipRect) {\r\n ctx.beginPath();\r\n ctx.rect(this.clipRect.x, this.clipRect.y, this.clipRect.width, this.clipRect.height);\r\n ctx.clip();\r\n }\r\n\r\n // Apply drop shadow before painting this node. We deliberately reset\r\n // before recursing into children so the shadow does not double-apply\r\n // to nested shapes (the canvas shadowColor is sticky across draw calls).\r\n if (this.shadow) {\r\n ctx.shadowColor = this.shadow.color ?? 'rgba(0,0,0,0.25)';\r\n ctx.shadowBlur = this.shadow.blur ?? 4;\r\n ctx.shadowOffsetX = this.shadow.offsetX ?? 0;\r\n ctx.shadowOffsetY = this.shadow.offsetY ?? 2;\r\n }\r\n\r\n // Abstract method to render the actual shape\r\n this.renderShape(ctx);\r\n\r\n if (this.shadow) {\r\n ctx.shadowColor = 'rgba(0,0,0,0)';\r\n ctx.shadowBlur = 0;\r\n ctx.shadowOffsetX = 0;\r\n ctx.shadowOffsetY = 0;\r\n }\r\n\r\n // Render children\r\n for (const child of this.children) {\r\n child.render(ctx);\r\n }\r\n\r\n ctx.restore();\r\n }\r\n\r\n /**\r\n * Hit testing: Returns the topmost node at (x, y) coordinates relative to this node.\r\n */\r\n pickNode(x: number, y: number): Node | null {\r\n if (!this.visible || !this.pointerEvents) return null;\r\n\r\n // Transform coordinates for children\r\n const localX = (x - this.translation.x) / this.scaling.x;\r\n const localY = (y - this.translation.y) / this.scaling.y;\r\n // Note: Rotation not handled in coordinate transform yet\r\n\r\n // Check children in reverse order (topmost first)\r\n for (let i = this.children.length - 1; i >= 0; i--) {\r\n const picked = this.children[i].pickNode(localX, localY);\r\n if (picked) return picked;\r\n }\r\n\r\n // Check this node\r\n if (this.isPointInNode(localX, localY)) {\r\n return this;\r\n }\r\n\r\n return null;\r\n }\r\n\r\n abstract renderShape(ctx: CanvasRenderingContext2D): void;\r\n\r\n /**\r\n * Hit testing: Returns true if the (x, y) coordinates (relative to parent) are within the node's bounds.\r\n */\r\n abstract isPointInNode(x: number, y: number): boolean;\r\n\r\n /**\r\n * Calculate bounding box (optional for now, but useful for layout).\r\n */\r\n abstract getBBox(): BBox;\r\n}\r\n\r\n","import { Node, BBox } from './Node';\n\n// ─── Group ────────────────────────────────────────────────────────────────────\n\nexport class Group extends Node {\n renderShape(_ctx: CanvasRenderingContext2D) {}\n\n isPointInNode(_x: number, _y: number): boolean {\n return false;\n }\n\n getBBox(): BBox {\n if (this.children.length === 0) return { x: 0, y: 0, width: 0, height: 0 };\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const child of this.children) {\n const b = child.getBBox();\n minX = Math.min(minX, b.x + child.translation.x);\n minY = Math.min(minY, b.y + child.translation.y);\n maxX = Math.max(maxX, b.x + b.width + child.translation.x);\n maxY = Math.max(maxY, b.y + b.height + child.translation.y);\n }\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n }\n}\n\n// ─── Rect ─────────────────────────────────────────────────────────────────────\n\nexport class Rect extends Node {\n width: number = 0;\n height: number = 0;\n fill: string = 'transparent';\n stroke: string = 'transparent';\n strokeWidth: number = 1;\n cornerRadius: number = 0;\n lineDash: number[] = [];\n\n renderShape(ctx: CanvasRenderingContext2D) {\n if (this.width <= 0 || this.height <= 0) return;\n\n ctx.beginPath();\n if (this.cornerRadius > 0) {\n const r = Math.min(this.cornerRadius, this.width / 2, this.height / 2);\n ctx.moveTo(this.x + r, this.y);\n ctx.arcTo(this.x + this.width, this.y, this.x + this.width, this.y + this.height, r);\n ctx.arcTo(this.x + this.width, this.y + this.height, this.x, this.y + this.height, r);\n ctx.arcTo(this.x, this.y + this.height, this.x, this.y, r);\n ctx.arcTo(this.x, this.y, this.x + this.width, this.y, r);\n } else {\n ctx.rect(this.x, this.y, this.width, this.height);\n }\n ctx.closePath();\n\n if (this.fill !== 'transparent') {\n ctx.fillStyle = this.fill;\n ctx.fill();\n }\n if (this.stroke !== 'transparent' && this.strokeWidth > 0) {\n ctx.strokeStyle = this.stroke;\n ctx.lineWidth = this.strokeWidth;\n if (this.lineDash.length > 0) ctx.setLineDash(this.lineDash);\n ctx.stroke();\n if (this.lineDash.length > 0) ctx.setLineDash([]);\n }\n }\n\n isPointInNode(x: number, y: number): boolean {\n const minX = Math.min(this.x, this.x + this.width);\n const maxX = Math.max(this.x, this.x + this.width);\n const minY = Math.min(this.y, this.y + this.height);\n const maxY = Math.max(this.y, this.y + this.height);\n return x >= minX && x <= maxX && y >= minY && y <= maxY;\n }\n\n getBBox(): BBox {\n return { x: this.x, y: this.y, width: this.width, height: this.height };\n }\n}\n\n// ─── Line ─────────────────────────────────────────────────────────────────────\n\nexport class Line extends Node {\n x1: number = 0;\n y1: number = 0;\n x2: number = 0;\n y2: number = 0;\n stroke: string = 'black';\n strokeWidth: number = 1;\n lineDash?: number[];\n\n renderShape(ctx: CanvasRenderingContext2D) {\n ctx.save();\n if (this.lineDash) ctx.setLineDash(this.lineDash);\n ctx.strokeStyle = this.stroke;\n ctx.lineWidth = this.strokeWidth;\n ctx.beginPath();\n ctx.moveTo(this.x1, this.y1);\n ctx.lineTo(this.x2, this.y2);\n ctx.stroke();\n ctx.restore();\n }\n\n isPointInNode(_x: number, _y: number): boolean { return false; }\n\n getBBox(): BBox {\n return {\n x: Math.min(this.x1, this.x2),\n y: Math.min(this.y1, this.y2),\n width: Math.abs(this.x2 - this.x1),\n height: Math.abs(this.y2 - this.y1),\n };\n }\n}\n\n// ─── Circle ───────────────────────────────────────────────────────────────────\n\nexport class Circle extends Node {\n centerX: number = 0;\n centerY: number = 0;\n radius: number = 5;\n fill: string = 'blue';\n stroke: string = 'transparent';\n strokeWidth: number = 1;\n\n renderShape(ctx: CanvasRenderingContext2D) {\n ctx.beginPath();\n ctx.arc(this.centerX, this.centerY, this.radius, 0, Math.PI * 2);\n ctx.closePath();\n if (this.fill !== 'transparent') { ctx.fillStyle = this.fill; ctx.fill(); }\n if (this.stroke !== 'transparent' && this.strokeWidth > 0) {\n ctx.strokeStyle = this.stroke;\n ctx.lineWidth = this.strokeWidth;\n ctx.stroke();\n }\n }\n\n isPointInNode(x: number, y: number): boolean {\n const dx = x - this.centerX, dy = y - this.centerY;\n return (dx * dx + dy * dy) <= this.radius * this.radius;\n }\n\n getBBox(): BBox {\n return { x: this.centerX - this.radius, y: this.centerY - this.radius, width: this.radius * 2, height: this.radius * 2 };\n }\n}\n\n// ─── Path ─────────────────────────────────────────────────────────────────────\n\nexport interface PathPoint {\n x: number;\n y: number;\n command: 'M' | 'L' | 'C';\n /** Bezier control point 1 (used when command === 'C') */\n cp1x?: number;\n cp1y?: number;\n /** Bezier control point 2 (used when command === 'C') */\n cp2x?: number;\n cp2y?: number;\n}\n\nexport class Path extends Node {\n pathData: PathPoint[] = [];\n fill: string = 'transparent';\n stroke: string = 'transparent';\n strokeWidth: number = 1;\n closed: boolean = false;\n lineDash?: number[];\n lineDashOffset: number = 0;\n\n renderShape(ctx: CanvasRenderingContext2D) {\n if (this.pathData.length === 0) return;\n\n ctx.save();\n if (this.lineDash) {\n ctx.setLineDash(this.lineDash);\n ctx.lineDashOffset = this.lineDashOffset;\n }\n\n ctx.beginPath();\n for (const p of this.pathData) {\n if (p.command === 'M') {\n ctx.moveTo(p.x, p.y);\n } else if (p.command === 'L') {\n ctx.lineTo(p.x, p.y);\n } else if (p.command === 'C' && p.cp1x !== undefined && p.cp2x !== undefined) {\n ctx.bezierCurveTo(p.cp1x, p.cp1y!, p.cp2x, p.cp2y!, p.x, p.y);\n }\n }\n\n if (this.closed) ctx.closePath();\n\n if (this.fill !== 'transparent') { ctx.fillStyle = this.fill; ctx.fill(); }\n if (this.stroke !== 'transparent' && this.strokeWidth > 0) {\n ctx.strokeStyle = this.stroke;\n ctx.lineWidth = this.strokeWidth;\n ctx.stroke();\n }\n ctx.restore();\n }\n\n isPointInNode(_x: number, _y: number): boolean { return false; }\n\n getBBox(): BBox {\n if (this.pathData.length === 0) return { x: 0, y: 0, width: 0, height: 0 };\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const p of this.pathData) {\n minX = Math.min(minX, p.x); minY = Math.min(minY, p.y);\n maxX = Math.max(maxX, p.x); maxY = Math.max(maxY, p.y);\n if (p.cp1x !== undefined) {\n minX = Math.min(minX, p.cp1x, p.cp2x!); minY = Math.min(minY, p.cp1y!, p.cp2y!);\n maxX = Math.max(maxX, p.cp1x, p.cp2x!); maxY = Math.max(maxY, p.cp1y!, p.cp2y!);\n }\n }\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n }\n}\n\n// ─── Marker ───────────────────────────────────────────────────────────────────\n// A polymorphic point marker. Drop-in replacement for Circle in series that\n// want to expose a `markerShape` option. Hit-testing uses the bounding box of\n// the marker square, which is plenty accurate for marker-sized targets.\n\nexport type MarkerShape = 'circle' | 'square' | 'cross' | 'diamond' | 'triangle' | 'plus';\n\nexport class Marker extends Node {\n centerX: number = 0;\n centerY: number = 0;\n radius: number = 5;\n fill: string = 'blue';\n stroke: string = 'transparent';\n strokeWidth: number = 1;\n shape: MarkerShape = 'circle';\n\n renderShape(ctx: CanvasRenderingContext2D) {\n const cx = this.centerX, cy = this.centerY, r = this.radius;\n if (r <= 0) return;\n\n ctx.beginPath();\n switch (this.shape) {\n case 'circle':\n ctx.arc(cx, cy, r, 0, Math.PI * 2);\n ctx.closePath();\n break;\n case 'square':\n ctx.rect(cx - r, cy - r, r * 2, r * 2);\n ctx.closePath();\n break;\n case 'diamond':\n ctx.moveTo(cx, cy - r);\n ctx.lineTo(cx + r, cy);\n ctx.lineTo(cx, cy + r);\n ctx.lineTo(cx - r, cy);\n ctx.closePath();\n break;\n case 'triangle':\n // Equilateral, point-up. Centred on (cx, cy).\n ctx.moveTo(cx, cy - r);\n ctx.lineTo(cx + r * 0.866, cy + r * 0.5);\n ctx.lineTo(cx - r * 0.866, cy + r * 0.5);\n ctx.closePath();\n break;\n case 'cross': {\n // Diagonal X — drawn with two thick lines fused into one path so the\n // shadow paints once. Width scales with radius.\n const w = r * 0.4;\n ctx.moveTo(cx - r, cy - r + w); ctx.lineTo(cx - r + w, cy - r);\n ctx.lineTo(cx, cy - w); ctx.lineTo(cx + r - w, cy - r);\n ctx.lineTo(cx + r, cy - r + w); ctx.lineTo(cx + w, cy);\n ctx.lineTo(cx + r, cy + r - w); ctx.lineTo(cx + r - w, cy + r);\n ctx.lineTo(cx, cy + w); ctx.lineTo(cx - r + w, cy + r);\n ctx.lineTo(cx - r, cy + r - w); ctx.lineTo(cx - w, cy);\n ctx.closePath();\n break;\n }\n case 'plus': {\n // Axis-aligned plus sign with arm thickness w.\n const w = r * 0.4;\n ctx.moveTo(cx - w, cy - r); ctx.lineTo(cx + w, cy - r);\n ctx.lineTo(cx + w, cy - w); ctx.lineTo(cx + r, cy - w);\n ctx.lineTo(cx + r, cy + w); ctx.lineTo(cx + w, cy + w);\n ctx.lineTo(cx + w, cy + r); ctx.lineTo(cx - w, cy + r);\n ctx.lineTo(cx - w, cy + w); ctx.lineTo(cx - r, cy + w);\n ctx.lineTo(cx - r, cy - w); ctx.lineTo(cx - w, cy - w);\n ctx.closePath();\n break;\n }\n }\n\n if (this.fill !== 'transparent') { ctx.fillStyle = this.fill; ctx.fill(); }\n if (this.stroke !== 'transparent' && this.strokeWidth > 0) {\n ctx.strokeStyle = this.stroke;\n ctx.lineWidth = this.strokeWidth;\n ctx.stroke();\n }\n }\n\n isPointInNode(x: number, y: number): boolean {\n const dx = x - this.centerX, dy = y - this.centerY;\n // Bounding-square hit test — sufficient for finger/cursor-sized markers.\n return Math.abs(dx) <= this.radius && Math.abs(dy) <= this.radius;\n }\n\n getBBox(): BBox {\n return {\n x: this.centerX - this.radius,\n y: this.centerY - this.radius,\n width: this.radius * 2,\n height: this.radius * 2,\n };\n }\n}\n\n// ─── Arc ──────────────────────────────────────────────────────────────────────\n\nexport class Arc extends Node {\n centerX: number = 0;\n centerY: number = 0;\n innerRadius: number = 0;\n outerRadius: number = 0;\n startAngle: number = 0;\n endAngle: number = 0;\n fill: string = 'blue';\n stroke: string = 'transparent';\n strokeWidth: number = 1;\n\n renderShape(ctx: CanvasRenderingContext2D) {\n ctx.beginPath();\n ctx.arc(this.centerX, this.centerY, this.outerRadius, this.startAngle, this.endAngle);\n if (this.innerRadius > 0) {\n ctx.arc(this.centerX, this.centerY, this.innerRadius, this.endAngle, this.startAngle, true);\n } else {\n ctx.lineTo(this.centerX, this.centerY);\n }\n ctx.closePath();\n if (this.fill !== 'transparent') { ctx.fillStyle = this.fill; ctx.fill(); }\n if (this.stroke !== 'transparent' && this.strokeWidth > 0) {\n ctx.strokeStyle = this.stroke; ctx.lineWidth = this.strokeWidth; ctx.stroke();\n }\n }\n\n isPointInNode(x: number, y: number): boolean {\n const dx = x - this.centerX, dy = y - this.centerY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n if (dist < this.innerRadius || dist > this.outerRadius) return false;\n let angle = Math.atan2(dy, dx);\n if (angle < 0) angle += Math.PI * 2;\n let s = this.startAngle % (Math.PI * 2); if (s < 0) s += Math.PI * 2;\n let e = this.endAngle % (Math.PI * 2); if (e < 0) e += Math.PI * 2;\n return s < e ? (angle >= s && angle <= e) : (angle >= s || angle <= e);\n }\n\n getBBox(): BBox {\n return { x: this.centerX - this.outerRadius, y: this.centerY - this.outerRadius, width: this.outerRadius * 2, height: this.outerRadius * 2 };\n }\n}\n\n// ─── Text ─────────────────────────────────────────────────────────────────────\n\nexport class Text extends Node {\n text: string = '';\n fontSize: number = 12;\n fontFamily: string = 'sans-serif';\n fontWeight: string = 'normal';\n fill: string = 'black';\n textAlign: CanvasTextAlign = 'start';\n textBaseline: CanvasTextBaseline = 'alphabetic';\n maxWidth?: number;\n shadowColor?: string;\n shadowBlur?: number;\n\n renderShape(ctx: CanvasRenderingContext2D) {\n ctx.font = `${this.fontWeight} ${this.fontSize}px ${this.fontFamily}`;\n ctx.fillStyle = this.fill;\n ctx.textAlign = this.textAlign;\n ctx.textBaseline = this.textBaseline;\n if (this.shadowColor) ctx.shadowColor = this.shadowColor;\n if (this.shadowBlur !== undefined) ctx.shadowBlur = this.shadowBlur;\n \n if (this.maxWidth !== undefined && this.maxWidth > 0) {\n ctx.fillText(this.text, this.x, this.y, this.maxWidth);\n } else {\n ctx.fillText(this.text, this.x, this.y);\n }\n \n if (this.shadowColor) ctx.shadowColor = 'transparent';\n if (this.shadowBlur !== undefined) ctx.shadowBlur = 0;\n }\n\n isPointInNode(_x: number, _y: number): boolean { return false; }\n\n getBBox(): BBox {\n return { x: this.x, y: this.y - this.fontSize, width: this.text.length * (this.fontSize * 0.55), height: this.fontSize };\n }\n}\n\n// ─── Polygon ──────────────────────────────────────────────────────────────────\n\nexport class Polygon extends Node {\n points: { x: number; y: number }[] = [];\n fill: string = 'transparent';\n stroke: string = 'transparent';\n strokeWidth: number = 1;\n closed: boolean = true;\n\n renderShape(ctx: CanvasRenderingContext2D) {\n if (this.points.length < 2) return;\n\n ctx.beginPath();\n ctx.moveTo(this.points[0].x, this.points[0].y);\n for (let i = 1; i < this.points.length; i++) {\n ctx.lineTo(this.points[i].x, this.points[i].y);\n }\n if (this.closed) ctx.closePath();\n\n if (this.fill !== 'transparent') {\n ctx.fillStyle = this.fill;\n ctx.fill();\n }\n if (this.stroke !== 'transparent' && this.strokeWidth > 0) {\n ctx.strokeStyle = this.stroke;\n ctx.lineWidth = this.strokeWidth;\n ctx.stroke();\n }\n }\n\n isPointInNode(x: number, y: number): boolean {\n // Basic ray-casting algorithm for point-in-polygon\n let inside = false;\n for (let i = 0, j = this.points.length - 1; i < this.points.length; j = i++) {\n const xi = this.points[i].x, yi = this.points[i].y;\n const xj = this.points[j].x, yj = this.points[j].y;\n const intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);\n if (intersect) inside = !inside;\n }\n return inside;\n }\n\n getBBox(): BBox {\n if (this.points.length === 0) return { x: 0, y: 0, width: 0, height: 0 };\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const p of this.points) {\n minX = Math.min(minX, p.x); minY = Math.min(minY, p.y);\n maxX = Math.max(maxX, p.x); maxY = Math.max(maxY, p.y);\n }\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n }\n}\n","import { Group } from './Shapes';\r\nimport { Node } from './Node';\r\n\r\n/**\r\n * Scene class: Manages the canvas element and the root of the scene graph.\r\n */\r\nexport class Scene {\r\n private container: HTMLElement;\r\n private canvas: HTMLCanvasElement;\r\n private ctx: CanvasRenderingContext2D;\r\n readonly root: Group = new Group();\r\n \r\n private width: number = 0;\r\n private height: number = 0;\r\n private pixelRatio: number = 1;\r\n\r\n onHover?: (node: any, event: MouseEvent) => void;\r\n onClick?: (node: any, event: MouseEvent) => void;\r\n onDblClick?: (node: any, event: MouseEvent) => void;\r\n onLongPress?: (node: any, event: MouseEvent) => void;\r\n\r\n private _longPressTimer: ReturnType<typeof setTimeout> | null = null;\r\n private _longPressFired = false;\r\n\r\n /** Background color painted before the scene graph on every render frame. */\r\n backgroundColor = '';\r\n\r\n constructor(container: HTMLElement) {\r\n this.container = container;\r\n this.canvas = document.createElement('canvas');\r\n this.canvas.style.position = 'absolute';\r\n this.canvas.style.top = '0';\r\n this.canvas.style.left = '0';\r\n this.canvas.style.width = '100%';\r\n this.canvas.style.height = '100%';\r\n this.canvas.style.display = 'block';\r\n this.canvas.style.zIndex = '1';\r\n \r\n container.appendChild(this.canvas);\r\n \r\n const ctx = this.canvas.getContext('2d');\r\n if (!ctx) {\r\n throw new Error('Could not get Canvas 2D context');\r\n }\r\n this.ctx = ctx;\r\n \r\n this.resize();\r\n this.setupEvents();\r\n }\r\n\r\n private setupEvents() {\r\n this.canvas.addEventListener('mousemove', (e) => {\r\n const rect = this.canvas.getBoundingClientRect();\r\n const x = e.clientX - rect.left;\r\n const y = e.clientY - rect.top;\r\n \r\n const node = this.root.pickNode(x, y);\r\n if (this.onHover) {\r\n this.onHover(node, e);\r\n }\r\n });\r\n\r\n this.canvas.addEventListener('mouseleave', (e) => {\r\n if (this.onHover) {\r\n this.onHover(null, e);\r\n }\r\n });\r\n\r\n this.canvas.addEventListener('click', (e) => {\r\n const rect = this.canvas.getBoundingClientRect();\r\n const x = e.clientX - rect.left;\r\n const y = e.clientY - rect.top;\r\n\r\n const node = this.root.pickNode(x, y);\r\n if (this.onClick) {\r\n this.onClick(node, e);\r\n }\r\n });\r\n\r\n this.canvas.addEventListener('dblclick', (e) => {\r\n const rect = this.canvas.getBoundingClientRect();\r\n const x = e.clientX - rect.left;\r\n const y = e.clientY - rect.top;\r\n\r\n const node = this.root.pickNode(x, y);\r\n if (this.onDblClick) {\r\n this.onDblClick(node, e);\r\n }\r\n });\r\n\r\n // Touch events — map to hover/click for tooltip on touch devices\r\n this.canvas.addEventListener('touchstart', (e) => {\r\n if (e.touches.length !== 1) return;\r\n const touch = e.touches[0];\r\n const rect = this.canvas.getBoundingClientRect();\r\n const x = touch.clientX - rect.left;\r\n const y = touch.clientY - rect.top;\r\n\r\n const node = this.root.pickNode(x, y);\r\n // Synthesize a mouse event for the hover/click handlers\r\n const syntheticMouse = new MouseEvent('mousemove', {\r\n clientX: touch.clientX,\r\n clientY: touch.clientY,\r\n });\r\n if (this.onHover) this.onHover(node, syntheticMouse);\r\n\r\n this._longPressFired = false;\r\n if (this._longPressTimer) clearTimeout(this._longPressTimer);\r\n this._longPressTimer = setTimeout(() => {\r\n this._longPressFired = true;\r\n const longPressMouse = new MouseEvent('click', {\r\n clientX: touch.clientX,\r\n clientY: touch.clientY,\r\n });\r\n if (this.onLongPress) this.onLongPress(node, longPressMouse);\r\n }, 500);\r\n }, { passive: true });\r\n\r\n this.canvas.addEventListener('touchend', (e) => {\r\n // Cancel long-press timer\r\n if (this._longPressTimer) { clearTimeout(this._longPressTimer); this._longPressTimer = null; }\r\n\r\n if (e.changedTouches.length !== 1) return;\r\n // Skip normal click if long-press already fired\r\n if (this._longPressFired) { this._longPressFired = false; return; }\r\n\r\n const touch = e.changedTouches[0];\r\n const rect = this.canvas.getBoundingClientRect();\r\n const x = touch.clientX - rect.left;\r\n const y = touch.clientY - rect.top;\r\n\r\n const node = this.root.pickNode(x, y);\r\n const syntheticMouse = new MouseEvent('click', {\r\n clientX: touch.clientX,\r\n clientY: touch.clientY,\r\n });\r\n if (this.onClick) this.onClick(node, syntheticMouse);\r\n }, { passive: true });\r\n\r\n this.canvas.addEventListener('touchmove', (e) => {\r\n // Cancel long-press on drag\r\n if (this._longPressTimer) { clearTimeout(this._longPressTimer); this._longPressTimer = null; }\r\n if (e.touches.length !== 1) return;\r\n const touch = e.touches[0];\r\n const rect = this.canvas.getBoundingClientRect();\r\n const x = touch.clientX - rect.left;\r\n const y = touch.clientY - rect.top;\r\n\r\n const node = this.root.pickNode(x, y);\r\n const syntheticMouse = new MouseEvent('mousemove', {\r\n clientX: touch.clientX,\r\n clientY: touch.clientY,\r\n });\r\n if (this.onHover) this.onHover(node, syntheticMouse);\r\n }, { passive: true });\r\n }\r\n\r\n resize() {\r\n const rect = this.container.getBoundingClientRect();\r\n this.width = rect.width;\r\n this.height = rect.height;\r\n \r\n if (this.width === 0 || this.height === 0) return;\r\n\r\n this.pixelRatio = window.devicePixelRatio || 1;\r\n\r\n this.canvas.width = this.width * this.pixelRatio;\r\n this.canvas.height = this.height * this.pixelRatio;\r\n \r\n this.ctx.resetTransform();\r\n this.ctx.scale(this.pixelRatio, this.pixelRatio);\r\n this.render();\r\n }\r\n\r\n render() {\r\n if (this.width === 0 || this.height === 0) return;\r\n\r\n this.ctx.clearRect(0, 0, this.width, this.height);\r\n\r\n if (this.backgroundColor) {\r\n this.ctx.fillStyle = this.backgroundColor;\r\n this.ctx.fillRect(0, 0, this.width, this.height);\r\n }\r\n\r\n this.root.render(this.ctx);\r\n }\r\n\r\n getCanvas(): HTMLCanvasElement { return this.canvas; }\r\n\r\n /** Exposes the 2D context so ChartManager can measure text before layout. */\r\n getContext(): CanvasRenderingContext2D { return this.ctx; }\r\n\r\n destroy() {\r\n if (this._longPressTimer) clearTimeout(this._longPressTimer);\r\n this.canvas.remove();\r\n }\r\n}","/**\r\n * Base Scale interface.\r\n */\r\nexport interface Scale<D, R> {\r\n domain: D[];\r\n range: R[];\r\n convert(value: D): R;\r\n invert(value: R): D;\r\n ticks?(count?: number): D[];\r\n}\r\n\r\n/**\r\n * LinearScale: domain [min, max] to range [minPixel, maxPixel].\r\n */\r\nexport class LinearScale implements Scale<number, number> {\r\n domain: number[] = [0, 1];\r\n range: number[] = [0, 1];\r\n\r\n convert(value: number): number {\r\n const [d0, d1] = this.domain;\r\n const [r0, r1] = this.range;\r\n if (d1 === d0) return r0;\r\n return r0 + ((value - d0) / (d1 - d0)) * (r1 - r0);\r\n }\r\n\r\n invert(value: number): number {\r\n const [d0, d1] = this.domain;\r\n const [r0, r1] = this.range;\r\n if (r1 === r0) return d0;\r\n return d0 + ((value - r0) / (r1 - r0)) * (d1 - d0);\r\n }\r\n\r\n /**\r\n * Generates \"nice\" ticks for the axis.\r\n */\r\n ticks(count: number = 5): number[] {\r\n const [d0, d1] = this.domain;\r\n const step = (d1 - d0) / count;\r\n const magnitude = Math.pow(10, Math.floor(Math.log10(step)));\r\n const normalizedStep = step / magnitude;\r\n\r\n let niceStep;\r\n if (normalizedStep < 1.5) niceStep = 1;\r\n else if (normalizedStep < 3) niceStep = 2;\r\n else if (normalizedStep < 7) niceStep = 5;\r\n else niceStep = 10;\r\n\r\n const finalStep = niceStep * magnitude;\r\n const start = Math.ceil(d0 / finalStep) * finalStep;\r\n const end = Math.floor(d1 / finalStep) * finalStep;\r\n\r\n const ticks = [];\r\n for (let t = start; t <= end; t += finalStep) {\r\n ticks.push(t);\r\n }\r\n return ticks;\r\n }\r\n}\r\n\r\n/**\r\n * BandScale: For categorical data.\r\n */\r\nexport class BandScale implements Scale<string, number> {\r\n domain: string[] = [];\r\n range: number[] = [0, 1];\r\n padding: number = 0.1;\r\n\r\n convert(value: string): number {\r\n const index = this.domain.indexOf(value);\r\n if (index === -1) return 0;\r\n \r\n const [r0, r1] = this.range;\r\n const step = (r1 - r0) / this.domain.length;\r\n return r0 + index * step + (step * this.padding) / 2;\r\n }\r\n\r\n invert(value: number): string {\r\n const [r0, r1] = this.range;\r\n const step = (r1 - r0) / this.domain.length;\r\n const index = Math.floor((value - r0) / step);\r\n return this.domain[index] || '';\r\n }\r\n\r\n getBandwidth(): number {\r\n const [r0, r1] = this.range;\r\n const step = (r1 - r0) / this.domain.length;\r\n return Math.abs(step * (1 - this.padding));\r\n }\r\n\r\n ticks(): string[] {\r\n return this.domain;\r\n }\r\n}\r\n\r\nexport function safeBandwidth(scale: Scale<any, number> | BandScale): number {\r\n return typeof (scale as any).getBandwidth === 'function'\r\n ? (scale as BandScale).getBandwidth()\r\n : 0;\r\n}\r\n","// Radiant Charts - CartesianAxis\r\n// Phase 1.2 + 5.2: Smart formatting, dashed grid lines, data-ink optimization\r\n// Phase 6: Dynamic axis sizing & configurable label offsets\r\n\r\nimport { Group, Line, Text } from '../scene/Shapes';\r\nimport { Scale } from '../scale/Scale';\r\nimport { Theme } from '../core/ThemeManager';\r\n\r\nexport interface AxisOptions {\r\n position: 'top' | 'bottom' | 'left' | 'right';\r\n title?: string;\r\n /** Show horizontal grid lines (default true for left/right axes) */\r\n gridLines?: boolean;\r\n /** Length (px) of the small tick mark on the X-axis. Default: 4 */\r\n tickLength?: number;\r\n /** Gap (px) between tick end and label start. Default: 2 */\r\n labelGap?: number;\r\n fontSize?: number;\r\n fontFamily?: string;\r\n rotation?: number;\r\n /** 'start' | 'center' | 'end' — only applicable for categorical (Band) scales */\r\n labelAlignment?: 'start' | 'center' | 'end';\r\n}\r\n\r\n/** Phase 5.2 – Smart axis label formatting */\r\nexport function formatAxisValue(val: unknown): string {\r\n if (val instanceof Date) {\r\n // Default Date formatting — short M/D/YY. Time scales with sub-day intervals\r\n // can override this via AxisConfig.label.formatter.\r\n return `${val.getMonth() + 1}/${val.getDate()}/${String(val.getFullYear()).slice(-2)}`;\r\n }\r\n if (typeof val !== 'number') return String(val);\r\n const abs = Math.abs(val);\r\n if (abs > 1e11 && abs < 1e14) { // Likely epoch milliseconds (between 1973 and 5138)\r\n const d = new Date(val);\r\n if (!isNaN(d.getTime())) {\r\n return `${d.getMonth() + 1}/${d.getDate()}/${String(d.getFullYear()).slice(-2)}`;\r\n }\r\n }\r\n if (abs >= 1e9) return (val / 1e9).toFixed(1).replace(/\\.0$/, '') + 'B';\r\n if (abs >= 1e6) return (val / 1e6).toFixed(1).replace(/\\.0$/, '') + 'M';\r\n if (abs >= 1e3) return (val / 1e3).toFixed(1).replace(/\\.0$/, '') + 'K';\r\n if (val % 1 !== 0) {\r\n // For small decimals (common in KDE / probability densities), preserve\r\n // significant digits — `toFixed(1)` would collapse 0.005 to \"0.0\".\r\n if (abs > 0 && abs < 1) {\r\n return Number(val.toPrecision(3)).toString();\r\n }\r\n return val.toFixed(1);\r\n }\r\n return String(val);\r\n}\r\n\r\n/**\r\n * Measures the required space for this axis given the current ticks and theme,\r\n * using the provided canvas context for accurate text measurement.\r\n */\r\nexport interface AxisSpaceInfo {\r\n /** Total pixels the axis needs perpendicular to its direction */\r\n size: number;\r\n}\r\n\r\nexport class CartesianAxis {\r\n private group = new Group();\r\n public scale: Scale<any, number>;\r\n private options: AxisOptions;\r\n private theme: Theme | null = null;\r\n private _measuredLabelMaxW: number = 0;\r\n private _layoutMaxWidth: number = 0;\r\n\r\n constructor(scale: Scale<any, number>, options: AxisOptions) {\r\n this.scale = scale;\r\n this.options = options;\r\n }\r\n\r\n setLayoutMaxWidth(max: number) {\r\n this._layoutMaxWidth = max;\r\n }\r\n\r\n getGroup() { return this.group; }\r\n\r\n setTheme(theme: Theme) { this.theme = theme; }\r\n\r\n updateOptions(options: Partial<AxisOptions>) {\r\n this.options = { ...this.options, ...options };\r\n }\r\n\r\n /**\r\n * Measures the exact space required for this axis perpendicular to its length.\r\n */\r\n getRequiredSpace(ctx: CanvasRenderingContext2D): AxisSpaceInfo {\r\n const { position, rotation = 0 } = this.options;\r\n const fontFamily = this.options.fontFamily || this.theme?.fontFamily || 'sans-serif';\r\n const fontSize = this.options.fontSize ?? 10;\r\n const tickLength = this.options.tickLength ?? 4;\r\n const labelGap = this.options.labelGap ?? 2;\r\n\r\n const tickCount: number | undefined = (this as any)._tickCount;\r\n const labelFormatter: ((p: { value: any; index: number }) => string) | undefined = (this as any)._labelFormatter;\r\n\r\n const ticks = this.scale.ticks ? this.scale.ticks(tickCount) : [];\r\n ctx.font = `${fontSize}px ${fontFamily}`;\r\n\r\n const rad = (rotation * Math.PI) / 180;\r\n const absCos = Math.abs(Math.cos(rad));\r\n const absSin = Math.abs(Math.sin(rad));\r\n\r\n if (position === 'bottom' || position === 'top') {\r\n let maxH = fontSize;\r\n if (rotation !== 0) {\r\n for (let i = 0; i < ticks.length; i++) {\r\n const tick = ticks[i];\r\n const text = labelFormatter\r\n ? labelFormatter({ value: tick, index: i })\r\n : formatAxisValue(tick);\r\n const w = ctx.measureText(text).width;\r\n const h = w * absSin + fontSize * absCos;\r\n if (h > maxH) maxH = h;\r\n }\r\n }\r\n let totalH = tickLength + labelGap + maxH + 4; // added 4px buffer\r\n if (this.options.title) totalH += 6 + 12; // increased gap and space\r\n return { size: Math.ceil(totalH) };\r\n }\r\n\r\n // left / right\r\n let maxW = 0;\r\n for (let i = 0; i < ticks.length; i++) {\r\n const tick = ticks[i];\r\n const text = labelFormatter\r\n ? labelFormatter({ value: tick, index: i })\r\n : formatAxisValue(tick);\r\n const w = ctx.measureText(text).width;\r\n const effectiveW = rotation !== 0 ? (w * absCos + fontSize * absSin) : w;\r\n if (effectiveW > maxW) maxW = effectiveW;\r\n }\r\n this._measuredLabelMaxW = Math.ceil(maxW);\r\n let totalW = labelGap + this._measuredLabelMaxW + 8; // increased from 6 to 8 for better label padding\r\n if (this.options.title) totalW += 8 + 14; // increased title buffer to ensure no clipping\r\n\r\n // Force a minimum width of 32px for side axes if they have labels,\r\n // preventing the chart from collapsing to 0px and causing rendering artifacts.\r\n if (ticks.length > 0) {\r\n totalW = Math.max(totalW, 32);\r\n }\r\n\r\n return { size: Math.ceil(totalW) };\r\n }\r\n\r\n update(length: number, gridLength: number = 0, showLabels: boolean = true, innerPad: number = 0, gridOffset: number = 0) {\r\n this.group.clear();\r\n const { position, rotation = 0 } = this.options;\r\n\r\n const textColor = this.theme?.subtextColor ?? '#6b7280';\r\n const gridColor = this.theme?.gridColor ?? 'rgba(107,114,128,0.12)';\r\n const axisColor = this.theme?.axisColor ?? '#d1d5db';\r\n const fontFamily = this.options.fontFamily || this.theme?.fontFamily || 'sans-serif';\r\n const fontSize = this.options.fontSize ?? 10;\r\n const tickLength = this.options.tickLength ?? 4;\r\n const labelGap = this.options.labelGap ?? 2;\r\n\r\n if (position === 'bottom' || position === 'top') {\r\n this.scale.range = [innerPad, length - innerPad];\r\n } else {\r\n this.scale.range = [length - innerPad, innerPad];\r\n }\r\n\r\n if (!showLabels) return;\r\n\r\n if (position === 'bottom' || position === 'top') {\r\n const axisLine = new Line();\r\n axisLine.x1 = 0; axisLine.y1 = 0; axisLine.x2 = length; axisLine.y2 = 0;\r\n axisLine.stroke = axisColor; axisLine.strokeWidth = 1;\r\n this.group.add(axisLine);\r\n }\r\n\r\n const tickCount: number | undefined = (this as any)._tickCount;\r\n const labelFormatter: ((p: { value: any; index: number }) => string) | undefined = (this as any)._labelFormatter;\r\n const gridStyleArr: ReadonlyArray<{ stroke?: string; lineDash?: readonly number[] }> | undefined = (this as any)._gridStyle;\r\n\r\n const ticks = this.scale.ticks ? this.scale.ticks(tickCount) : [];\r\n const showGrid = this.options.gridLines !== false;\r\n const { labelAlignment = 'center' } = this.options;\r\n\r\n const getBW = (this.scale as any).getBandwidth?.bind(this.scale);\r\n\r\n const isXAxis = position === 'bottom' || position === 'top';\r\n const isYAxis = position === 'left' || position === 'right';\r\n const labelMinGap = fontSize * 0.5;\r\n let lastLabelPos = isXAxis ? -Infinity : Infinity;\r\n\r\n ticks.forEach((tick, tIdx) => {\r\n let pos = this.scale.convert(tick);\r\n\r\n if (getBW) {\r\n const bw = getBW();\r\n const [br0, br1] = this.scale.range;\r\n const stepSign = br1 >= br0 ? 1 : -1;\r\n if (labelAlignment === 'center') pos += (stepSign * bw) / 2;\r\n else if (labelAlignment === 'end') pos += stepSign * bw;\r\n }\r\n\r\n const labelText = labelFormatter\r\n ? labelFormatter({ value: tick, index: tIdx })\r\n : formatAxisValue(tick);\r\n\r\n if (isXAxis && rotation === 0) {\r\n const estWidth = fontSize * 0.6 * labelText.length;\r\n const labelLeft = pos - estWidth / 2;\r\n if (labelLeft < lastLabelPos + labelMinGap) {\r\n if (position === 'bottom') {\r\n const tickLine = new Line();\r\n tickLine.x1 = pos; tickLine.y1 = 0; tickLine.x2 = pos; tickLine.y2 = tickLength;\r\n tickLine.stroke = axisColor; tickLine.strokeWidth = 1;\r\n this.group.add(tickLine);\r\n }\r\n return;\r\n }\r\n lastLabelPos = pos + estWidth / 2;\r\n }\r\n\r\n if (isYAxis) {\r\n if (Math.abs(pos - lastLabelPos) < fontSize + 2) {\r\n return;\r\n }\r\n lastLabelPos = pos;\r\n }\r\n\r\n const label = new Text();\r\n label.text = labelText;\r\n label.fontSize = fontSize;\r\n label.fill = textColor;\r\n label.fontFamily = fontFamily;\r\n \r\n const rad = (rotation * Math.PI) / 180;\r\n label.rotation = rad;\r\n\r\n if (position === 'bottom') {\r\n const tickLine = new Line();\r\n tickLine.x1 = pos; tickLine.y1 = 0; tickLine.x2 = pos; tickLine.y2 = tickLength;\r\n tickLine.stroke = axisColor; tickLine.strokeWidth = 1;\r\n this.group.add(tickLine);\r\n\r\n label.translation = { x: pos, y: tickLength + labelGap };\r\n label.x = 0; label.y = 0;\r\n\r\n if (rotation === 0) {\r\n label.textAlign = 'center';\r\n label.textBaseline = 'top';\r\n } else {\r\n label.textAlign = rotation > 0 ? 'left' : 'right';\r\n label.textBaseline = 'middle';\r\n }\r\n this.group.add(label);\r\n\r\n } else if (position === 'left' || position === 'right') {\r\n const isRight = position === 'right';\r\n const sign = isRight ? 1 : -1;\r\n\r\n label.textAlign = isRight ? 'left' : 'right';\r\n label.textBaseline = 'middle';\r\n label.maxWidth = this._layoutMaxWidth > 0 ? (this._layoutMaxWidth - labelGap - 8) : undefined;\r\n label.translation = { x: sign * labelGap, y: pos };\r\n label.x = 0; label.y = 0;\r\n this.group.add(label);\r\n\r\n if (showGrid && gridLength > 0 && position === 'left') {\r\n const gridLine = new Line();\r\n gridLine.x1 = gridOffset; gridLine.y1 = pos;\r\n gridLine.x2 = gridLength; gridLine.y2 = pos;\r\n const gs = gridStyleArr && gridStyleArr.length > 0 ? gridStyleArr[tIdx % gridStyleArr.length] : undefined;\r\n gridLine.stroke = gs?.stroke ?? gridColor;\r\n gridLine.strokeWidth = 1;\r\n gridLine.lineDash = gs?.lineDash ? [...gs.lineDash] : [4, 6];\r\n this.group.add(gridLine);\r\n }\r\n }\r\n });\r\n\r\n if (this.options.title) {\r\n const titleLabel = new Text();\r\n titleLabel.text = this.options.title;\r\n titleLabel.fontSize = 11;\r\n titleLabel.fill = textColor;\r\n titleLabel.fontFamily = fontFamily;\r\n if (position === 'bottom') {\r\n titleLabel.x = length / 2;\r\n titleLabel.y = tickLength + labelGap + this._measuredLabelMaxW + 12;\r\n titleLabel.textAlign = 'center';\r\n } else if (position === 'left') {\r\n titleLabel.x = -(labelGap + (this._layoutMaxWidth || this._measuredLabelMaxW) + 14);\r\n titleLabel.y = length / 2;\r\n titleLabel.rotation = -Math.PI / 2;\r\n titleLabel.textAlign = 'center';\r\n } else if (position === 'right') {\r\n titleLabel.x = labelGap + (this._layoutMaxWidth || this._measuredLabelMaxW) + 14;\r\n titleLabel.y = length / 2;\r\n titleLabel.rotation = Math.PI / 2;\r\n titleLabel.textAlign = 'center';\r\n }\r\n this.group.add(titleLabel);\r\n }\r\n }\r\n}\r\n\r\n","// Radiant Charts - Animator\r\n// Phase 6.1: Supports prefers-reduced-motion for accessibility\r\n\r\nfunction prefersReducedMotion(): boolean {\r\n if (typeof window === 'undefined') return false;\r\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\r\n}\r\n\r\nexport class Animator {\r\n private startTime: number = 0;\r\n private duration: number;\r\n private easing: (t: number) => number;\r\n private onUpdate: (progress: number) => void;\r\n private onComplete?: () => void;\r\n private requestId: number | null = null;\r\n\r\n // Easing presets\r\n static linear = (t: number): number => t;\r\n\r\n static easeInQuad = (t: number): number => t * t;\r\n static easeOutQuad = (t: number): number => t * (2 - t);\r\n static easeInOutQuad = (t: number): number =>\r\n t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;\r\n\r\n static easeInCubic = (t: number): number => t * t * t;\r\n static easeOutCubic = (t: number): number => (--t) * t * t + 1;\r\n static easeInOutCubic = (t: number): number =>\r\n t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;\r\n\r\n static easeInQuart = (t: number): number => t * t * t * t;\r\n static easeOutQuart = (t: number): number => 1 - (--t) * t * t * t;\r\n static easeInOutQuart = (t: number): number =>\r\n t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t;\r\n\r\n static easeOutBack = (t: number): number => {\r\n const c1 = 1.70158, c3 = c1 + 1;\r\n return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);\r\n };\r\n\r\n static easeOutBounce = (t: number): number => {\r\n const n1 = 7.5625;\r\n const d1 = 2.75;\r\n if (t < 1 / d1) return n1 * t * t;\r\n if (t < 2 / d1) return n1 * (t -= 1.5 / d1) * t + 0.75;\r\n if (t < 2.5 / d1) return n1 * (t -= 2.25 / d1) * t + 0.9375;\r\n return n1 * (t -= 2.625 / d1) * t + 0.984375;\r\n };\r\n\r\n static easeOutElastic = (t: number): number => {\r\n const c4 = (2 * Math.PI) / 3;\r\n return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;\r\n };\r\n\r\n static getEasing(name?: string): (t: number) => number {\r\n switch (name) {\r\n case 'linear': return Animator.linear;\r\n case 'easeIn': return Animator.easeInQuad;\r\n case 'easeOut': return Animator.easeOutQuad;\r\n case 'easeInOut': return Animator.easeInOutQuad;\r\n case 'easeInCubic': return Animator.easeInCubic;\r\n case 'easeOutCubic': return Animator.easeOutCubic;\r\n case 'easeInOutCubic': return Animator.easeInOutCubic;\r\n case 'easeInQuart': return Animator.easeInQuart;\r\n case 'easeOutQuart': return Animator.easeOutQuart;\r\n case 'easeInOutQuart': return Animator.easeInOutQuart;\r\n case 'bounce': return Animator.easeOutBounce;\r\n case 'elastic': return Animator.easeOutElastic;\r\n case 'back': return Animator.easeOutBack;\r\n default: return Animator.easeOutQuart;\r\n }\r\n }\r\n\r\n constructor(options: {\r\n duration?: number;\r\n easing?: (t: number) => number;\r\n onUpdate: (progress: number) => void;\r\n onComplete?: () => void;\r\n }) {\r\n this.duration = options.duration ?? 420;\r\n this.easing = options.easing ?? Animator.easeOutQuart;\r\n this.onUpdate = options.onUpdate;\r\n this.onComplete = options.onComplete;\r\n }\r\n\r\n start() {\r\n this.stop();\r\n\r\n // Phase 6.1 – Skip animation for users who prefer reduced motion\r\n if (prefersReducedMotion()) {\r\n this.onUpdate(1);\r\n this.onComplete?.();\r\n return;\r\n }\r\n\r\n this.startTime = performance.now();\r\n this.loop();\r\n }\r\n\r\n stop() {\r\n if (this.requestId !== null) {\r\n cancelAnimationFrame(this.requestId);\r\n this.requestId = null;\r\n }\r\n }\r\n\r\n private loop = () => {\r\n const now = performance.now();\r\n const progress = Math.min((now - this.startTime) / this.duration, 1);\r\n this.onUpdate(this.easing(progress));\r\n\r\n if (progress < 1) {\r\n this.requestId = requestAnimationFrame(this.loop);\r\n } else {\r\n this.requestId = null;\r\n this.onComplete?.();\r\n }\r\n };\r\n}\r\n\r\n","// Radiant Charts - BarSeries\r\n// Phase 2.2: Grouped, stacked, 100% normalized, horizontal, with corner radius\r\n\r\nimport { Node, BBox } from '../scene/Node';\r\nimport { Group, Rect, Text, Line } from '../scene/Shapes';\r\nimport { Scale, BandScale, safeBandwidth } from '../scale/Scale';\r\nimport { Animator } from '../core/Animator';\r\n\r\nexport interface BarSeriesOptions {\r\n xKey: string;\r\n yKey: string;\r\n title?: string;\r\n fill?: string;\r\n stroke?: string;\r\n grouped?: boolean;\r\n stacked?: boolean;\r\n /** 100% normalized stacking */\r\n normalized?: boolean;\r\n direction?: 'vertical' | 'horizontal';\r\n cornerRadius?: number;\r\n labels?: import('../RadiantChart').DataLabelOptions;\r\n animation?: import('../RadiantChart').AnimationOptions;\r\n shadow?: import('../RadiantChart').DropShadow;\r\n}\r\n\r\n/**\r\n * Optimized node for rendering thousands of bars in a single draw call.\r\n * Avoids the overhead of individual Scene Graph nodes and ctx.save/restore.\r\n */\r\nclass BarBatchNode extends Node {\r\n bars: { x: number; y: number; width: number; height: number; datum: any }[] = [];\r\n fill: string = '';\r\n stroke: string = 'transparent';\r\n cornerRadius: number = 0;\r\n\r\n renderShape(ctx: CanvasRenderingContext2D) {\r\n if (this.bars.length === 0) return;\r\n \r\n ctx.fillStyle = this.fill;\r\n ctx.beginPath();\r\n \r\n // Path batching: one beginPath and one fill for the whole dataset.\r\n for (const b of this.bars) {\r\n if (this.cornerRadius > 0 && b.width > 8 && b.height > 8) {\r\n const r = Math.min(this.cornerRadius, b.width / 2, b.height / 2);\r\n ctx.moveTo(b.x + r, b.y);\r\n ctx.arcTo(b.x + b.width, b.y, b.x + b.width, b.y + b.height, r);\r\n ctx.arcTo(b.x + b.width, b.y + b.height, b.x, b.y + b.height, r);\r\n ctx.arcTo(b.x, b.y + b.height, b.x, b.y, r);\r\n ctx.arcTo(b.x, b.y, b.x + b.width, b.y, r);\r\n } else {\r\n ctx.rect(b.x, b.y, b.width, b.height);\r\n }\r\n }\r\n \r\n ctx.fill();\r\n if (this.stroke !== 'transparent') {\r\n ctx.strokeStyle = this.stroke;\r\n ctx.stroke();\r\n }\r\n }\r\n\r\n isPointInNode(x: number, y: number): boolean {\r\n // Spatial search optimized for Cartesian layout (if we had scales). \r\n // Even O(N) is faster here than recursive pickNode.\r\n for (let i = this.bars.length - 1; i >= 0; i--) {\r\n const b = this.bars[i];\r\n if (x >= b.x && x <= b.x + b.width && y >= b.y && y <= b.y + b.height) {\r\n this.datum = b.datum;\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n getBBox(): BBox {\r\n if (this.bars.length === 0) return { x: 0, y: 0, width: 0, height: 0 };\r\n // Just return container bounds or compute from first/last\r\n return { x: 0, y: 0, width: 1000, height: 1000 };\r\n }\r\n}\r\n\r\nexport class BarSeries {\r\n private group = new Group();\r\n private xKey: string;\r\n private yKey: string;\r\n fill: string = '#4e79a7';\r\n private stroke: string = 'transparent';\r\n private grouped: boolean = false;\r\n private stacked: boolean = false;\r\n private normalized: boolean = false;\r\n private direction: 'vertical' | 'horizontal' = 'vertical';\r\n private cornerRadius: number = 3;\r\n private labelsOpts?: import('../RadiantChart').DataLabelOptions;\r\n private animationOpts?: import('../RadiantChart').AnimationOptions;\r\n private shadowOpts?: import('../RadiantChart').DropShadow;\r\n private animator?: Animator;\r\n private batchNode: BarBatchNode | null = null;\r\n private bars: {\r\n rect: Rect;\r\n label?: Text;\r\n rawY: number;\r\n targetY: number; targetHeight: number; startY: number; startHeight: number;\r\n targetX: number; targetWidth: number; startX: number; startWidth: number;\r\n targetOpacity: number; startOpacity: number;\r\n targetScaleX: number; startScaleX: number;\r\n targetScaleY: number; startScaleY: number;\r\n }[] = [];\r\n\r\n constructor(options: BarSeriesOptions) {\r\n this.xKey = options.xKey;\r\n this.yKey = options.yKey;\r\n this.grouped = options.grouped ?? false;\r\n this.stacked = options.stacked ?? false;\r\n this.normalized = options.normalized ?? false;\r\n this.direction = options.direction ?? 'vertical';\r\n this.cornerRadius = options.cornerRadius ?? 3;\r\n this.labelsOpts = options.labels;\r\n this.animationOpts = options.animation;\r\n this.shadowOpts = options.shadow;\r\n if (options.fill) this.fill = options.fill;\r\n if (options.stroke) this.stroke = options.stroke;\r\n }\r\n\r\n getGroup() { return this.group; }\r\n\r\n update(\r\n data: readonly any[],\r\n xScale: BandScale | Scale<any, number>,\r\n yScale: Scale<number, number>,\r\n seriesRect: { x: number; y: number; width: number; height: number },\r\n animate: boolean = true,\r\n seriesIndex: number = 0,\r\n totalSeries: number = 1,\r\n stackedOffsets?: number[],\r\n /** Column totals for 100% normalization */\r\n columnTotals?: number[],\r\n options?: BarSeriesOptions\r\n ) {\r\n if (options) {\r\n this.xKey = options.xKey;\r\n this.yKey = options.yKey;\r\n if (options.fill) this.fill = options.fill;\r\n if (options.stroke) this.stroke = options.stroke;\r\n if (options.grouped !== undefined) this.grouped = options.grouped;\r\n if (options.stacked !== undefined) this.stacked = options.stacked;\r\n if (options.normalized !== undefined) this.normalized = options.normalized;\r\n if (options.direction !== undefined) this.direction = options.direction;\r\n if (options.cornerRadius !== undefined) this.cornerRadius = options.cornerRadius;\r\n if (options.labels) this.labelsOpts = options.labels;\r\n if (options.animation) this.animationOpts = options.animation;\r\n if (options.shadow !== undefined) this.shadowOpts = options.shadow;\r\n }\r\n\r\n const isInitial = this.bars.length === 0;\r\n const isH = this.direction === 'horizontal';\r\n const animType = this.animationOpts?.type || 'grow';\r\n const oldLen = this.bars.length;\r\n const newLen = data.length;\r\n const isBigData = newLen > 1000;\r\n\r\n // ── Pre-Phase: Handle Big Data Fast Path ────────────────────────────\r\n if (isBigData) {\r\n this.group.clear();\r\n this.bars = []; // Drop the individual pool\r\n \r\n if (!this.batchNode) {\r\n this.batchNode = new BarBatchNode();\r\n }\r\n this.batchNode.fill = this.fill;\r\n this.batchNode.stroke = this.stroke;\r\n this.batchNode.cornerRadius = this.cornerRadius;\r\n this.batchNode.seriesId = this.yKey;\r\n this.batchNode.shadow = this.shadowOpts ?? null;\r\n \r\n this.group.add(this.batchNode);\r\n\r\n const batchBars: any[] = [];\r\n data.forEach((datum, i) => {\r\n let yVal = datum[this.yKey] as number;\r\n if (this.normalized && columnTotals && columnTotals[i]) {\r\n yVal = (yVal / columnTotals[i]) * 100;\r\n }\r\n\r\n const fullBW = safeBandwidth(xScale);\r\n if (!isH) {\r\n let bx = xScale.convert(datum[this.xKey]);\r\n let bw = fullBW;\r\n if (this.grouped && totalSeries > 1) {\r\n bw = fullBW / totalSeries;\r\n bx += seriesIndex * bw;\r\n }\r\n const ty = yScale.convert((this.stacked && stackedOffsets ? (stackedOffsets[i] ?? 0) : 0) + yVal);\r\n const th = yScale.convert(this.stacked && stackedOffsets ? (stackedOffsets[i] ?? 0) : 0) - ty;\r\n batchBars.push({ x: bx, y: ty, width: bw, height: th, datum });\r\n } else {\r\n // ... Horizontal logic similarly if needed, but keeping it simple for now\r\n let by = xScale.convert(datum[this.xKey]);\r\n let bh = fullBW;\r\n if (this.grouped && totalSeries > 1) {\r\n bh = fullBW / totalSeries;\r\n by += seriesIndex * bh;\r\n }\r\n const tx = yScale.convert(this.stacked && stackedOffsets ? (stackedOffsets[i] ?? 0) : 0);\r\n const tw = yScale.convert((this.stacked && stackedOffsets ? (stackedOffsets[i] ?? 0) : 0) + yVal) - tx;\r\n batchBars.push({ x: tx, y: by, width: tw, height: bh, datum });\r\n }\r\n });\r\n \r\n this.batchNode.bars = batchBars;\r\n\r\n // Sampled labels: render every Nth label so the high-density view still\r\n // carries context, without paying the full label-layout cost per bar.\r\n if (this.labelsOpts?.enabled) {\r\n const step = Math.max(1, Math.ceil(newLen / 100));\r\n for (let i = 0; i < batchBars.length; i += step) {\r\n const b = batchBars[i];\r\n const rect = new Rect();\r\n rect.x = b.x; rect.y = b.y; rect.width = b.width; rect.height = b.height;\r\n const lbl = new Text();\r\n this.group.add(lbl);\r\n this.placeLabel(lbl, rect, b.datum[this.yKey]);\r\n }\r\n }\r\n return;\r\n }\r\n\r\n // Individual node pool path (for < 500 rows)\r\n if (this.batchNode) {\r\n this.group.remove(this.batchNode);\r\n this.batchNode = null;\r\n }\r\n\r\n // ── Phase 1: Compute target geometry for every data point ────────────\r\n // We build an array of target values first, then reconcile with the pool.\r\n\r\n const targets: {\r\n datum: any; rawY: number;\r\n tx: number; ty: number; tw: number; th: number;\r\n }[] = [];\r\n\r\n data.forEach((datum, i) => {\r\n let yVal = datum[this.yKey] as number;\r\n\r\n // 100% normalization\r\n if (this.normalized && columnTotals && columnTotals[i]) {\r\n yVal = (yVal / columnTotals[i]) * 100;\r\n }\r\n\r\n const fullBW = safeBandwidth(xScale);\r\n let tx: number, ty: number, tw: number, th: number;\r\n\r\n if (!isH) {\r\n let bx = xScale.convert(datum[this.xKey]);\r\n let bw = fullBW;\r\n if (this.grouped && totalSeries > 1) {\r\n bw = fullBW / totalSeries;\r\n bx += seriesIndex * bw;\r\n }\r\n tx = bx; tw = bw;\r\n if (this.stacked && stackedOffsets) {\r\n const off = stackedOffsets[i] ?? 0;\r\n const normalOff = this.normalized && columnTotals?.[i] ? (off / columnTotals[i]) * 100 : off;\r\n ty = yScale.convert(normalOff + yVal);\r\n th = yScale.convert(normalOff) - ty;\r\n } else {\r\n ty = yScale.convert(yVal);\r\n th = yScale.convert(0) - ty;\r\n }\r\n } else {\r\n let by = xScale.convert(datum[this.xKey]);\r\n let bh = fullBW;\r\n if (this.grouped && totalSeries > 1) {\r\n bh = fullBW / totalSeries;\r\n by += seriesIndex * bh;\r\n }\r\n ty = by; th = bh;\r\n if (this.stacked && stackedOffsets) {\r\n const off = stackedOffsets[i] ?? 0;\r\n tx = yScale.convert(off);\r\n tw = yScale.convert(off + yVal) - tx;\r\n } else {\r\n tx = yScale.convert(0);\r\n tw = yScale.convert(yVal) - tx;\r\n }\r\n }\r\n\r\n targets.push({ datum, rawY: datum[this.yKey] as number, tx, ty, tw, th });\r\n });\r\n\r\n // ── Phase 2: Pool reconciliation ─────────────────────────────────────\r\n // Reuse existing Rects for indices that already have them, create new\r\n // ones for growth, and remove excess for shrinkage.\r\n\r\n // 2a. Remove excess bars when data shrinks\r\n if (newLen < oldLen) {\r\n for (let i = newLen; i < oldLen; i++) {\r\n const old = this.bars[i];\r\n this.group.remove(old.rect);\r\n if (old.label) this.group.remove(old.label);\r\n }\r\n this.bars.length = newLen;\r\n }\r\n\r\n // 2b. Reconcile each data index\r\n for (let i = 0; i < newLen; i++) {\r\n const { datum, rawY, tx, ty, tw, th } = targets[i];\r\n\r\n let barRect: Rect;\r\n let labelNode: Text | undefined;\r\n let sx: number, sy: number, sw: number, sh: number;\r\n let so = 1, to = 1;\r\n let ssx = 1, tsx = 1;\r\n let ssy = 1, tsy = 1;\r\n\r\n if (i < oldLen) {\r\n // ── Reuse existing Rect ──────────────────────────────────────────\r\n const existing = this.bars[i];\r\n barRect = existing.rect;\r\n labelNode = existing.label;\r\n\r\n // Capture the Rect's *current* pixel state as the animation start.\r\n // This is critical: if a previous animation is mid-flight the bar\r\n // will smoothly redirect from wherever it is right now, rather than\r\n // snapping to an old target or re-growing from zero.\r\n sx = barRect.x;\r\n sy = barRect.y;\r\n sw = barRect.width;\r\n sh = barRect.height;\r\n so = barRect.opacity;\r\n ssx = barRect.scaling.x;\r\n ssy = barRect.scaling.y;\r\n } else {\r\n // ── Create a new Rect (data grew) ────────────────────────────────\r\n barRect = new Rect();\r\n this.group.add(barRect);\r\n\r\n // Determine intro animation start\r\n sx = tx; sy = ty; sw = tw; sh = th;\r\n if (animType === 'grow') {\r\n if (!isH) { sy = seriesRect.height; sh = 0; }\r\n else { sx = 0; sw = 0; }\r\n } else if (animType === 'fade') {\r\n so = 0;\r\n } else if (animType === 'slide') {\r\n if (!isH) { sy = seriesRect.height + 50; }\r\n else { sx = -50; }\r\n } else if (animType === 'pop') {\r\n ssx = 0; ssy = 0;\r\n }\r\n\r\n // Create label if needed\r\n if (this.labelsOpts?.enabled) {\r\n labelNode = new Text();\r\n this.group.add(labelNode);\r\n }\r\n }\r\n\r\n // Apply visual properties (cheap, no allocation)\r\n barRect.fill = this.fill;\r\n barRect.stroke = this.stroke;\r\n barRect.cornerRadius = this.cornerRadius;\r\n barRect.datum = datum;\r\n barRect.seriesId = this.yKey;\r\n barRect.opacity = so;\r\n barRect.scaling = { x: ssx, y: ssy };\r\n barRect.shadow = this.shadowOpts ?? null;\r\n\r\n // For 'pop' animation, set translation to the bar's center so it\r\n // scales from the centre outward.\r\n let finalTX = tx, finalTY = ty;\r\n if (animType === 'pop') {\r\n barRect.translation = { x: tx + tw / 2, y: ty + th / 2 };\r\n finalTX = -tw / 2;\r\n finalTY = -th / 2;\r\n sx = -tw / 2;\r\n sy = -th / 2;\r\n } else {\r\n barRect.translation = { x: 0, y: 0 };\r\n }\r\n\r\n // Write back into the pool array (reuse the slot or push a new one)\r\n const entry = {\r\n rect: barRect, label: labelNode, rawY,\r\n targetY: finalTY, targetHeight: th, startY: sy, startHeight: sh,\r\n targetX: finalTX, targetWidth: tw, startX: sx, startWidth: sw,\r\n targetOpacity: to, startOpacity: so,\r\n targetScaleX: tsx, startScaleX: ssx,\r\n targetScaleY: tsy, startScaleY: ssy,\r\n };\r\n\r\n if (i < oldLen) {\r\n this.bars[i] = entry;\r\n } else {\r\n this.bars.push(entry);\r\n }\r\n }\r\n\r\n // ── Phase 3: Animate or snap ─────────────────────────────────────────\r\n if (animate && (this.animationOpts?.enabled !== false)) {\r\n this.animator?.stop();\r\n const duration = this.animationOpts?.duration ?? 500;\r\n const easing = Animator.getEasing(this.animationOpts?.easing);\r\n\r\n this.animator = new Animator({\r\n duration,\r\n easing,\r\n onUpdate: (progress) => {\r\n this.bars.forEach(b => {\r\n b.rect.y = b.startY + (b.targetY - b.startY) * progress;\r\n b.rect.height = b.startHeight + (b.targetHeight - b.startHeight) * progress;\r\n b.rect.x = b.startX + (b.targetX - b.startX) * progress;\r\n b.rect.width = b.startWidth + (b.targetWidth - b.startWidth) * progress;\r\n b.rect.opacity = b.startOpacity + (b.targetOpacity - b.startOpacity) * progress;\r\n b.rect.scaling = {\r\n x: b.startScaleX + (b.targetScaleX - b.startScaleX) * progress,\r\n y: b.startScaleY + (b.targetScaleY - b.startScaleY) * progress,\r\n };\r\n if (b.label) this.placeLabel(b.label, b.rect, b.rawY);\r\n });\r\n },\r\n });\r\n this.animator.start();\r\n } else {\r\n this.bars.forEach(b => {\r\n b.rect.y = b.targetY;\r\n b.rect.height = b.targetHeight;\r\n b.rect.x = b.targetX;\r\n b.rect.width = b.targetWidth;\r\n b.rect.opacity = b.targetOpacity;\r\n b.rect.scaling = { x: b.targetScaleX, y: b.targetScaleY };\r\n if (b.label) this.placeLabel(b.label, b.rect, b.rawY);\r\n });\r\n }\r\n }\r\n\r\n private placeLabel(txt: Text, rect: Rect, rawValue: number) {\r\n const pos = this.labelsOpts?.position || 'inside';\r\n const isH = this.direction === 'horizontal';\r\n \r\n // Formatting: abbreviate large numbers to prevent clutter\r\n let fv = String(rawValue);\r\n if (typeof rawValue === 'number') {\r\n const abs = Math.abs(rawValue);\r\n if (abs >= 1e9) fv = (rawValue / 1e9).toFixed(1).replace(/\\.0$/, '') + 'B';\r\n else if (abs >= 1e6) fv = (rawValue / 1e6).toFixed(1).replace(/\\.0$/, '') + 'M';\r\n else if (abs >= 1e3) fv = (rawValue / 1e3).toFixed(1).replace(/\\.0$/, '') + 'K';\r\n else fv = rawValue.toLocaleString();\r\n }\r\n \r\n txt.text = fv;\r\n txt.fontSize = this.labelsOpts?.fontSize || 10;\r\n txt.fontFamily = this.labelsOpts?.fontFamily || 'sans-serif';\r\n txt.fontWeight = this.labelsOpts?.fontWeight || '600';\r\n txt.rotation = ((this.labelsOpts?.rotation || 0) * Math.PI) / 180;\r\n // Inside a colored bar should ideally be white, outside should be dark/muted\r\n txt.fill = this.labelsOpts?.fill || (pos === 'inside' || pos === 'center' ? '#fff' : '#6b7280');\r\n txt.textAlign = 'center';\r\n txt.textBaseline = 'middle';\r\n\r\n let ax = 0, ay = 0;\r\n if (!isH) {\r\n ax = rect.x + rect.width / 2;\r\n if (pos === 'inside') {\r\n ay = rect.y + 12;\r\n } else if (pos === 'top' || pos === 'outside') {\r\n ay = rect.y - 8;\r\n txt.textBaseline = 'bottom';\r\n txt.fill = this.labelsOpts?.fill || '#6b7280';\r\n } else if (pos === 'center') {\r\n ay = rect.y + rect.height / 2;\r\n } else if (pos === 'bottom') {\r\n ay = rect.y + rect.height - 10;\r\n }\r\n } else {\r\n ay = rect.y + rect.height / 2;\r\n if (pos === 'inside') {\r\n ax = rect.x + rect.width - 12;\r\n txt.textAlign = 'right';\r\n } else if (pos === 'right' || pos === 'outside') {\r\n ax = rect.x + rect.width + 6;\r\n txt.textAlign = 'left';\r\n txt.fill = this.labelsOpts?.fill || '#6b7280';\r\n } else if (pos === 'center') {\r\n ax = rect.x + rect.width / 2;\r\n } else if (pos === 'left') {\r\n ax = rect.x + 8;\r\n txt.textAlign = 'left';\r\n }\r\n }\r\n \r\n txt.translation = { x: ax, y: ay };\r\n txt.x = 0;\r\n txt.y = 0;\r\n \r\n // Hide label if the bar is too thin to comfortably render text\r\n if (pos === 'inside' || pos === 'center') {\r\n if (!isH && (rect.width < 14 || rect.height < 14)) txt.text = '';\r\n if (isH && (rect.height < 14 || rect.width < 14)) txt.text = '';\r\n }\r\n }\r\n}\r\n","// Radiant Charts - LineSeries\r\n// Phase 2.1: Standard, Step, and Smooth (Catmull-Rom spline) line variants\r\n\r\nimport { Group, Path, Marker, PathPoint, Text } from '../scene/Shapes';\r\nimport { formatAxisValue } from '../axes/CartesianAxis';\r\nimport { Scale, BandScale, safeBandwidth } from '../scale/Scale';\r\nimport { Animator } from '../core/Animator';\r\n\r\nexport interface LineSeriesOptions {\r\n xKey: string;\r\n yKey: string;\r\n title?: string;\r\n stroke?: string;\r\n strokeWidth?: number;\r\n /** 'linear' | 'step' | 'smooth' */\r\n interpolation?: 'linear' | 'step' | 'smooth';\r\n /** @deprecated use interpolation:'step' */\r\n step?: boolean;\r\n marker?: {\r\n enabled?: boolean;\r\n size?: number;\r\n fill?: string;\r\n };\r\n labels?: import('../RadiantChart').DataLabelOptions;\r\n animation?: import('../RadiantChart').AnimationOptions;\r\n shadow?: import('../RadiantChart').DropShadow;\r\n /** When false, the line is severed at any null/NaN datapoint instead of bridging the gap. Default: true. */\r\n connectMissingData?: boolean;\r\n /** Configurable marker shape. Shape overrides the legacy dot-only renderer. */\r\n markerShape?: 'circle' | 'square' | 'cross' | 'diamond' | 'triangle' | 'plus';\r\n}\r\n\r\n/** Catmull-Rom → cubic Bezier control points (maintains C1 continuity) */\r\nfunction catmullRomToBezier(\r\n pts: { x: number; y: number }[]\r\n): PathPoint[] {\r\n if (pts.length === 0) return [];\r\n const result: PathPoint[] = [{ command: 'M', x: pts[0].x, y: pts[0].y }];\r\n\r\n for (let i = 1; i < pts.length; i++) {\r\n const p0 = pts[Math.max(i - 2, 0)];\r\n const p1 = pts[i - 1];\r\n const p2 = pts[i];\r\n const p3 = pts[Math.min(i + 1, pts.length - 1)];\r\n\r\n result.push({\r\n command: 'C',\r\n cp1x: p1.x + (p2.x - p0.x) / 6,\r\n cp1y: p1.y + (p2.y - p0.y) / 6,\r\n cp2x: p2.x - (p3.x - p1.x) / 6,\r\n cp2y: p2.y - (p3.y - p1.y) / 6,\r\n x: p2.x,\r\n y: p2.y,\r\n });\r\n }\r\n return result;\r\n}\r\n\r\nexport class LineSeries {\r\n private group = new Group();\r\n private xKey: string;\r\n private yKey: string;\r\n private stroke: string = '#4e79a7';\r\n private strokeWidth: number = 2;\r\n private interpolation: 'linear' | 'step' | 'smooth';\r\n private markerOpts = { enabled: true, size: 6, fill: '' };\r\n private labelsOpts?: import('../RadiantChart').DataLabelOptions;\r\n private animationOpts?: import('../RadiantChart').AnimationOptions;\r\n private shadowOpts?: import('../RadiantChart').DropShadow;\r\n private connectMissingData: boolean = true;\r\n private markerShape: 'circle' | 'square' | 'cross' | 'diamond' | 'triangle' | 'plus' = 'circle';\r\n private animator?: Animator;\r\n private linePath: Path = new Path();\r\n\r\n constructor(options: LineSeriesOptions) {\r\n this.xKey = options.xKey;\r\n this.yKey = options.yKey;\r\n // legacy 'step' boolean support\r\n const legacy = options.step ? 'step' : 'linear';\r\n this.interpolation = options.interpolation ?? legacy;\r\n if (options.stroke) this.stroke = options.stroke;\r\n if (options.strokeWidth) this.strokeWidth = options.strokeWidth;\r\n if (options.marker) this.markerOpts = { ...this.markerOpts, ...options.marker };\r\n this.markerOpts.fill = this.markerOpts.fill || this.stroke;\r\n this.labelsOpts = options.labels;\r\n this.animationOpts = options.animation;\r\n this.shadowOpts = options.shadow;\r\n this.connectMissingData = options.connectMissingData ?? true;\r\n this.markerShape = options.markerShape ?? 'circle';\r\n }\r\n\r\n getGroup() { return this.group; }\r\n\r\n update(\r\n data: readonly any[],\r\n xScale: BandScale | Scale<any, number>,\r\n yScale: Scale<number, number>,\r\n _seriesRect: { x: number; y: number; width: number; height: number },\r\n animate: boolean = true,\r\n options?: LineSeriesOptions\r\n ) {\r\n if (options) {\r\n this.xKey = options.xKey;\r\n this.yKey = options.yKey;\r\n if (options.stroke) this.stroke = options.stroke;\r\n if (options.strokeWidth !== undefined) this.strokeWidth = options.strokeWidth;\r\n if (options.interpolation) this.interpolation = options.interpolation;\r\n if (options.marker) this.markerOpts = { ...this.markerOpts, ...options.marker };\r\n if (options.labels) this.labelsOpts = options.labels;\r\n if (options.animation) this.animationOpts = options.animation;\r\n if (options.shadow !== undefined) this.shadowOpts = options.shadow;\r\n if (options.connectMissingData !== undefined) this.connectMissingData = options.connectMissingData;\r\n if (options.markerShape) this.markerShape = options.markerShape;\r\n }\r\n\r\n this.group.clear();\r\n if (data.length === 0) return;\r\n\r\n // Continuous X scales (LinearScale, TimeScale) — used by grid-sync mode —\r\n // don't implement getBandwidth(). safeBandwidth() returns 0 for those so\r\n // points center directly at the converted X pixel; BandScale still gets\r\n // its half-band offset.\r\n const pts = data.map(d => {\r\n const raw = d[this.yKey];\r\n const missing = raw === null || raw === undefined || (typeof raw === 'number' && isNaN(raw));\r\n const bw = safeBandwidth(xScale);\r\n return {\r\n x: (xScale as Scale<any, number>).convert(d[this.xKey]) + bw / 2,\r\n y: yScale.convert(missing ? 0 : raw),\r\n datum: d,\r\n missing,\r\n };\r\n });\r\n\r\n // ─ Build path ─\r\n const path = this.linePath;\r\n path.pathData = [];\r\n path.stroke = this.stroke;\r\n path.strokeWidth = this.strokeWidth;\r\n path.shadow = this.shadowOpts ?? null;\r\n\r\n // Split into contiguous non-missing runs when gap-skipping is requested.\r\n // Each run becomes its own sub-path (started by an 'M' command) so the\r\n // line is visually severed at any null/NaN datum.\r\n const runs: typeof pts[] = [];\r\n if (this.connectMissingData) {\r\n runs.push(pts.filter(p => !p.missing));\r\n } else {\r\n let current: typeof pts = [];\r\n pts.forEach(p => {\r\n if (p.missing) {\r\n if (current.length > 0) { runs.push(current); current = []; }\r\n } else {\r\n current.push(p);\r\n }\r\n });\r\n if (current.length > 0) runs.push(current);\r\n }\r\n\r\n runs.forEach(run => {\r\n if (run.length === 0) return;\r\n if (this.interpolation === 'smooth') {\r\n path.pathData.push(...catmullRomToBezier(run));\r\n } else if (this.interpolation === 'step') {\r\n run.forEach((p, i) => {\r\n if (i === 0) {\r\n path.pathData.push({ command: 'M', x: p.x, y: p.y });\r\n } else {\r\n const prev = path.pathData[path.pathData.length - 1];\r\n path.pathData.push({ command: 'L', x: p.x, y: prev.y });\r\n path.pathData.push({ command: 'L', x: p.x, y: p.y });\r\n }\r\n });\r\n } else {\r\n run.forEach((p, i) =>\r\n path.pathData.push({ command: i === 0 ? 'M' : 'L', x: p.x, y: p.y })\r\n );\r\n }\r\n });\r\n\r\n this.group.add(path);\r\n\r\n // ─ Markers & Labels (wrapped in a group for collective opacity) ─\r\n const markersGroup = new Group();\r\n this.group.add(markersGroup);\r\n\r\n if (this.markerOpts.enabled || this.labelsOpts?.enabled) {\r\n pts.forEach(p => {\r\n if (p.missing) return;\r\n if (this.markerOpts.enabled) {\r\n const marker = new Marker();\r\n marker.centerX = p.x;\r\n marker.centerY = p.y;\r\n marker.radius = (this.markerOpts.size || 6) / 2;\r\n marker.shape = this.markerShape;\r\n marker.fill = this.markerOpts.fill || this.stroke;\r\n marker.stroke = '#fff';\r\n marker.strokeWidth = 1.5;\r\n marker.shadow = this.shadowOpts ?? null;\r\n marker.datum = p.datum;\r\n marker.seriesId = this.yKey;\r\n markersGroup.add(marker);\r\n }\r\n\r\n if (this.labelsOpts?.enabled) {\r\n const lbl = new Text();\r\n lbl.text = formatAxisValue(p.datum[this.yKey]);\r\n lbl.fontSize = this.labelsOpts.fontSize || 10;\r\n lbl.fontFamily = this.labelsOpts.fontFamily || 'sans-serif';\r\n lbl.fontWeight = this.labelsOpts.fontWeight || '600';\r\n lbl.rotation = ((this.labelsOpts.rotation || 0) * Math.PI) / 180;\r\n lbl.fill = this.labelsOpts.fill || this.stroke;\r\n \r\n const pos = this.labelsOpts.position || 'top';\r\n const offset = (this.markerOpts.enabled ? this.markerOpts.size || 6 : 0) / 2 + 5;\r\n\r\n let ax = p.x, ay = p.y;\r\n if (pos === 'top') {\r\n ay = p.y - offset;\r\n lbl.textAlign = 'center'; lbl.textBaseline = 'bottom';\r\n } else if (pos === 'bottom') {\r\n ay = p.y + offset + 2;\r\n lbl.textAlign = 'center'; lbl.textBaseline = 'top';\r\n } else if (pos === 'left') {\r\n ax = p.x - offset - 4;\r\n lbl.textAlign = 'right'; lbl.textBaseline = 'middle';\r\n } else if (pos === 'right') {\r\n ax = p.x + offset + 4;\r\n lbl.textAlign = 'left'; lbl.textBaseline = 'middle';\r\n } else {\r\n lbl.textAlign = 'center'; lbl.textBaseline = 'middle';\r\n if (this.markerOpts.enabled) lbl.fill = '#fff';\r\n }\r\n lbl.translation = { x: ax, y: ay };\r\n lbl.x = 0; lbl.y = 0;\r\n markersGroup.add(lbl);\r\n }\r\n });\r\n }\r\n\r\n if (animate && this.animationOpts?.enabled !== false) {\r\n this.animator?.stop();\r\n const animType = this.animationOpts?.type || 'draw';\r\n const duration = this.animationOpts?.duration ?? 800;\r\n const easing = Animator.getEasing(this.animationOpts?.easing);\r\n\r\n if (animType === 'draw') {\r\n // Approximate path length for drawing effect\r\n let length = 0;\r\n for (let i = 1; i < pts.length; i++) {\r\n length += Math.sqrt(Math.pow(pts[i].x - pts[i-1].x, 2) + Math.pow(pts[i].y - pts[i-1].y, 2));\r\n }\r\n if (this.interpolation === 'step') length *= 1.5; // padding for steps\r\n\r\n path.lineDash = [length, length];\r\n path.lineDashOffset = length;\r\n markersGroup.opacity = 0;\r\n\r\n this.animator = new Animator({\r\n duration,\r\n easing,\r\n onUpdate: (p) => {\r\n path.lineDashOffset = length * (1 - p);\r\n if (p > 0.8) markersGroup.opacity = (p - 0.8) * 5;\r\n },\r\n onComplete: () => {\r\n path.lineDash = undefined;\r\n markersGroup.opacity = 1;\r\n }\r\n });\r\n } else {\r\n // Default fade\r\n this.group.opacity = 0;\r\n this.animator = new Animator({\r\n duration,\r\n easing,\r\n onUpdate: (p) => { this.group.opacity = p; }\r\n });\r\n }\r\n this.animator.start();\r\n }\r\n }\r\n}\r\n\r\n","// Radiant Charts - PieSeries\r\n// Phase 2.4: Pie, Donut, Half-Donut / Semi-Circle with entrance animation\r\n\r\nimport { Group, Arc, Text } from '../scene/Shapes';\r\nimport { Animator } from '../core/Animator';\r\n\r\nexport interface PieSeriesOptions {\r\n angleKey: string;\r\n labelKey: string;\r\n innerRadius?: number;\r\n outerRadius?: number;\r\n fills?: string[];\r\n strokes?: string[];\r\n /** Start angle in degrees (default -90 = top). Use 180 for half-donut */\r\n startAngle?: number;\r\n /** End angle in degrees (default 270 = full circle). Use 360 for half-donut */\r\n endAngle?: number;\r\n /** Gap between slices in radians */\r\n padAngle?: number;\r\n labels?: import('../RadiantChart').DataLabelOptions;\r\n animation?: import('../RadiantChart').AnimationOptions;\r\n}\r\n\r\nconst DEG = Math.PI / 180;\r\n\r\nexport class PieSeries {\r\n private group = new Group();\r\n private angleKey: string;\r\n private labelKey: string;\r\n private innerRadius: number = 0;\r\n private outerRadius?: number;\r\n private fills: string[] = ['#4e79a7','#f28e2c','#e15759','#76b7b2','#59a14f','#edc948','#b07aa1','#ff9da7','#9c755f','#bab0ac'];\r\n private strokes: string[] = ['#fff'];\r\n private startAngleDeg: number = -90;\r\n private endAngleDeg: number = 270;\r\n private padAngle: number = 0.008;\r\n private labelsOpts?: import('../RadiantChart').DataLabelOptions;\r\n private animationOpts?: import('../RadiantChart').AnimationOptions;\r\n private animator?: Animator;\r\n private slices: { arc: Arc, targetStart: number, targetEnd: number, label?: Text }[] = [];\r\n\r\n constructor(options: PieSeriesOptions) {\r\n this.angleKey = options.angleKey;\r\n this.labelKey = options.labelKey;\r\n if (options.innerRadius !== undefined) this.innerRadius = options.innerRadius;\r\n if (options.outerRadius !== undefined) this.outerRadius = options.outerRadius;\r\n if (options.fills) this.fills = options.fills;\r\n if (options.strokes) this.strokes = options.strokes;\r\n if (options.startAngle !== undefined) this.startAngleDeg = options.startAngle;\r\n if (options.endAngle !== undefined) this.endAngleDeg = options.endAngle;\r\n if (options.padAngle !== undefined) this.padAngle = options.padAngle;\r\n this.labelsOpts = options.labels;\r\n this.animationOpts = options.animation;\r\n }\r\n\r\n getGroup() { return this.group; }\r\n\r\n update(data: readonly any[], seriesRect: { x: number; y: number; width: number; height: number }, animate: boolean = true, options?: PieSeriesOptions) {\r\n if (options) {\r\n this.angleKey = options.angleKey;\r\n this.labelKey = options.labelKey;\r\n if (options.innerRadius !== undefined) this.innerRadius = options.innerRadius;\r\n if (options.outerRadius !== undefined) this.outerRadius = options.outerRadius;\r\n if (options.fills) this.fills = options.fills;\r\n if (options.strokes) this.strokes = options.strokes;\r\n if (options.startAngle !== undefined) this.startAngleDeg = options.startAngle;\r\n if (options.endAngle !== undefined) this.endAngleDeg = options.endAngle;\r\n if (options.padAngle !== undefined) this.padAngle = options.padAngle;\r\n if (options.labels) this.labelsOpts = options.labels;\r\n if (options.animation) this.animationOpts = options.animation;\r\n }\r\n this.group.clear();\r\n if (!data || data.length === 0) return;\r\n\r\n const total = data.reduce((s, d) => s + (d[this.angleKey] || 0), 0);\r\n if (total === 0) return;\r\n\r\n const cx = seriesRect.x + seriesRect.width / 2;\r\n const cy = seriesRect.y + seriesRect.height / 2;\r\n const marginFactor = this.labelsOpts?.enabled !== false ? 0.72 : 0.88;\r\n const outerR = this.outerRadius ?? (Math.min(seriesRect.width, seriesRect.height) / 2 * marginFactor);\r\n // innerRadius ≤ 1.0 is treated as a fraction of outerR (e.g. 0.5 → 50% of outerR)\r\n const innerR = this.innerRadius > 0 && this.innerRadius <= 1.0 ? this.innerRadius * outerR : this.innerRadius;\r\n\r\n const startRad = this.startAngleDeg * DEG;\r\n const totalArcRad = (this.endAngleDeg - this.startAngleDeg) * DEG;\r\n\r\n this.slices = [];\r\n let currentAngle = startRad;\r\n\r\n data.forEach((datum, i) => {\r\n const val = datum[this.angleKey] || 0;\r\n const sliceAngle = (val / total) * totalArcRad - this.padAngle;\r\n\r\n const slice = new Arc();\r\n slice.centerX = cx;\r\n slice.centerY = cy;\r\n slice.innerRadius = innerR;\r\n slice.outerRadius = outerR;\r\n slice.startAngle = currentAngle;\r\n slice.endAngle = currentAngle + sliceAngle;\r\n slice.fill = this.fills[i % this.fills.length];\r\n slice.stroke = this.strokes[i % this.strokes.length];\r\n slice.strokeWidth = 2;\r\n slice.datum = datum;\r\n slice.seriesId = this.angleKey;\r\n this.group.add(slice);\r\n\r\n let labelNode: Text | undefined;\r\n // Label\r\n if (this.labelsOpts?.enabled !== false) {\r\n const labelAngle = currentAngle + sliceAngle / 2;\r\n const pos = this.labelsOpts?.position || 'outside';\r\n const isInside = pos === 'inside' || pos === 'center';\r\n \r\n const labelR = isInside ? innerR + (outerR - innerR) / 2 : outerR + 18;\r\n const lx = cx + Math.cos(labelAngle) * labelR;\r\n const ly = cy + Math.sin(labelAngle) * labelR;\r\n \r\n labelNode = new Text();\r\n labelNode.text = String(datum[this.labelKey] ?? '');\r\n labelNode.fontSize = this.labelsOpts?.fontSize || 10;\r\n labelNode.fontFamily = this.labelsOpts?.fontFamily || 'sans-serif';\r\n labelNode.fontWeight = this.labelsOpts?.fontWeight || 'normal';\r\n labelNode.rotation = ((this.labelsOpts?.rotation || 0) * Math.PI) / 180;\r\n labelNode.fill = this.labelsOpts?.fill || (isInside ? '#fff' : '#6b7280');\r\n \r\n // Dynamically adjust text alignment and max width to prevent container overflow\r\n const cos = Math.cos(labelAngle);\r\n labelNode.textAlign = isInside ? 'center' : (cos > 0.05 ? 'start' : cos < -0.05 ? 'end' : 'center');\r\n labelNode.textBaseline = 'middle';\r\n labelNode.translation = { x: lx, y: ly };\r\n labelNode.x = 0;\r\n labelNode.y = 0;\r\n \r\n // Anti-collision: truncate long labels that would bleed off-canvas\r\n if (!isInside) {\r\n const availableWidth = cos > 0 \r\n ? seriesRect.x + seriesRect.width - lx - 10\r\n : lx - seriesRect.x - 10;\r\n labelNode.maxWidth = Math.max(40, Math.min(availableWidth, seriesRect.width / 3));\r\n }\r\n\r\n if (isInside && sliceAngle < 0.1) labelNode.text = '';\r\n this.group.add(labelNode);\r\n }\r\n\r\n this.slices.push({ arc: slice, targetStart: currentAngle, targetEnd: currentAngle + sliceAngle, label: labelNode });\r\n currentAngle += sliceAngle + this.padAngle;\r\n });\r\n\r\n if (animate && this.animationOpts?.enabled !== false) {\r\n this.animator?.stop();\r\n const animType = this.animationOpts?.type || 'grow';\r\n const duration = this.animationOpts?.duration ?? 600;\r\n const easing = Animator.getEasing(this.animationOpts?.easing || (animType === 'grow' ? 'back' : 'easeOut'));\r\n\r\n if (animType === 'grow') {\r\n this.slices.forEach(s => { s.arc.outerRadius = 0; if (s.label) s.label.opacity = 0; });\r\n this.animator = new Animator({\r\n duration, easing,\r\n onUpdate: (p) => {\r\n this.slices.forEach(s => { \r\n s.arc.outerRadius = outerR * p; \r\n if (s.label && p > 0.8) s.label.opacity = (p - 0.8) * 5;\r\n });\r\n }\r\n });\r\n } else if (animType === 'radial') {\r\n this.slices.forEach(s => { s.arc.endAngle = s.arc.startAngle; if (s.label) s.label.opacity = 0; });\r\n this.animator = new Animator({\r\n duration, easing,\r\n onUpdate: (p) => {\r\n this.slices.forEach(s => {\r\n const fullAngle = s.targetEnd - s.targetStart;\r\n s.arc.endAngle = s.targetStart + fullAngle * p;\r\n if (s.label && p > 0.8) s.label.opacity = (p - 0.8) * 5;\r\n });\r\n }\r\n });\r\n } else {\r\n this.group.opacity = 0;\r\n this.animator = new Animator({\r\n duration, easing,\r\n onUpdate: (p) => { this.group.opacity = p; }\r\n });\r\n }\r\n this.animator.start();\r\n }\r\n }\r\n\r\n getLegendData(theme: any, data: readonly any[]): import('../core/Legend').LegendItem[] {\r\n if (!data) return [];\r\n return data.map((d, i) => ({\r\n id: `${this.angleKey}-${i}`,\r\n label: String(d[this.labelKey] ?? `Item ${i + 1}`),\r\n fill: this.fills[i % this.fills.length],\r\n markerType: 'square'\r\n }));\r\n }\r\n}\r\n\r\n\r\n","// Radiant Charts - AreaSeries\r\n// Phase 2.3: Standard, stacked, step, and smooth curve variants\r\n\r\nimport { Group, Path, Marker, PathPoint, Text } from '../scene/Shapes';\r\nimport { formatAxisValue } from '../axes/CartesianAxis';\r\nimport { Scale, BandScale, safeBandwidth } from '../scale/Scale';\r\nimport { Animator } from '../core/Animator';\r\n\r\nexport interface AreaSeriesOptions {\r\n xKey: string;\r\n yKey: string;\r\n title?: string;\r\n fill?: string;\r\n stroke?: string;\r\n strokeWidth?: number;\r\n fillOpacity?: number;\r\n stacked?: boolean;\r\n /** When true, the stack is rescaled so each column sums to 100% — yielding a 100% stacked area chart. */\r\n normalized?: boolean;\r\n interpolation?: 'linear' | 'step' | 'smooth';\r\n marker?: { enabled?: boolean; shape?: 'circle' | 'square' | 'cross' | 'diamond' | 'triangle' | 'plus'; size?: number; fill?: string; stroke?: string; strokeWidth?: number };\r\n /** When false, the area path is severed at any null/NaN datapoint instead of bridging the gap. Default: true. */\r\n connectMissingData?: boolean;\r\n labels?: import('../RadiantChart').DataLabelOptions;\r\n animation?: import('../RadiantChart').AnimationOptions;\r\n shadow?: import('../RadiantChart').DropShadow;\r\n}\r\n\r\nfunction catmullRomBezier(pts: { x: number; y: number }[]): PathPoint[] {\r\n if (pts.length === 0) return [];\r\n const out: PathPoint[] = [{ command: 'M', x: pts[0].x, y: pts[0].y }];\r\n for (let i = 1; i < pts.length; i++) {\r\n const p0 = pts[Math.max(i - 2, 0)];\r\n const p1 = pts[i - 1];\r\n const p2 = pts[i];\r\n const p3 = pts[Math.min(i + 1, pts.length - 1)];\r\n out.push({\r\n command: 'C',\r\n cp1x: p1.x + (p2.x - p0.x) / 6,\r\n cp1y: p1.y + (p2.y - p0.y) / 6,\r\n cp2x: p2.x - (p3.x - p1.x) / 6,\r\n cp2y: p2.y - (p3.y - p1.y) / 6,\r\n x: p2.x,\r\n y: p2.y,\r\n });\r\n }\r\n return out;\r\n}\r\n\r\nexport class AreaSeries {\r\n private group = new Group();\r\n private xKey: string;\r\n private yKey: string;\r\n fill: string = '#4e79a7';\r\n private stroke: string = '#4e79a7';\r\n private strokeWidth: number = 2;\r\n private fillOpacity: number = 0.25;\r\n private stacked: boolean = false;\r\n private normalized: boolean = false;\r\n private connectMissingData: boolean = true;\r\n private interpolation: 'linear' | 'step' | 'smooth';\r\n private markerOpts = { enabled: false, size: 6, fill: '' };\r\n private labelsOpts?: import('../RadiantChart').DataLabelOptions;\r\n private animationOpts?: import('../RadiantChart').AnimationOptions;\r\n private shadowOpts?: import('../RadiantChart').DropShadow;\r\n private animator?: Animator;\r\n private path = new Path();\r\n private markers: Marker[] = [];\r\n private points: {\r\n x: number;\r\n targetY: number; startY: number; currentY: number;\r\n targetBottomY: number; startBottomY: number; currentBottomY: number;\r\n label?: Text;\r\n datum: any;\r\n /** True when the underlying y value is null / NaN — used to break the path. */\r\n missing?: boolean;\r\n }[] = [];\r\n\r\n constructor(options: AreaSeriesOptions) {\r\n this.xKey = options.xKey;\r\n this.yKey = options.yKey;\r\n this.stacked = options.stacked ?? false;\r\n this.normalized = options.normalized ?? false;\r\n this.connectMissingData = options.connectMissingData ?? true;\r\n this.interpolation = options.interpolation ?? 'linear';\r\n if (options.fill) this.fill = options.fill;\r\n if (options.stroke) this.stroke = options.stroke;\r\n if (options.strokeWidth !== undefined) this.strokeWidth = options.strokeWidth;\r\n if (options.fillOpacity !== undefined) this.fillOpacity = options.fillOpacity;\r\n if (options.marker) this.markerOpts = { ...this.markerOpts, ...options.marker };\r\n this.markerOpts.fill = this.markerOpts.fill || this.fill;\r\n this.labelsOpts = options.labels;\r\n this.animationOpts = options.animation;\r\n this.shadowOpts = options.shadow;\r\n }\r\n\r\n getGroup() { return this.group; }\r\n\r\n update(\r\n data: readonly any[],\r\n xScale: BandScale | Scale<any, number>,\r\n yScale: Scale<number, number>,\r\n seriesRect: { x: number; y: number; width: number; height: number },\r\n animate: boolean = true,\r\n stackedOffsets?: number[],\r\n options?: AreaSeriesOptions,\r\n columnTotals?: number[],\r\n ) {\r\n if (options) {\r\n this.xKey = options.xKey;\r\n this.yKey = options.yKey;\r\n if (options.fill) this.fill = options.fill;\r\n if (options.stroke) this.stroke = options.stroke;\r\n if (options.strokeWidth !== undefined) this.strokeWidth = options.strokeWidth;\r\n if (options.fillOpacity !== undefined) this.fillOpacity = options.fillOpacity;\r\n if (options.stacked !== undefined) this.stacked = options.stacked;\r\n if (options.normalized !== undefined) this.normalized = options.normalized;\r\n if (options.connectMissingData !== undefined) this.connectMissingData = options.connectMissingData;\r\n if (options.interpolation) this.interpolation = options.interpolation;\r\n if (options.marker) this.markerOpts = { ...this.markerOpts, ...options.marker };\r\n if (options.labels) this.labelsOpts = options.labels;\r\n if (options.animation) this.animationOpts = options.animation;\r\n if (options.shadow !== undefined) this.shadowOpts = options.shadow;\r\n }\r\n\r\n const isInitial = this.points.length === 0;\r\n this.group.clear();\r\n if (data.length === 0) return;\r\n\r\n this.path = new Path();\r\n this.path.fill = this.fill;\r\n this.path.stroke = this.stroke;\r\n this.path.strokeWidth = this.strokeWidth;\r\n this.path.opacity = this.fillOpacity;\r\n this.path.shadow = this.shadowOpts ?? null;\r\n this.group.add(this.path);\r\n\r\n const newPts: typeof this.points = [];\r\n this.markers = [];\r\n\r\n data.forEach((datum, i) => {\r\n const x = xScale.convert(datum[this.xKey]) + safeBandwidth(xScale) / 2;\r\n let yVal = datum[this.yKey];\r\n const isMissing = yVal === null || yVal === undefined || (typeof yVal === 'number' && isNaN(yVal));\r\n\r\n let targetY: number, targetBottomY: number;\r\n if (this.stacked && stackedOffsets) {\r\n const off = stackedOffsets[i] ?? 0;\r\n const total = columnTotals?.[i] ?? 0;\r\n if (this.normalized && total > 0) {\r\n // Normalize the running offset and current value into a 0..100 stack.\r\n const normOff = (off / total) * 100;\r\n const normVal = ((yVal ?? 0) / total) * 100;\r\n targetBottomY = yScale.convert(normOff);\r\n targetY = yScale.convert(normOff + normVal);\r\n } else {\r\n targetBottomY = yScale.convert(off);\r\n targetY = yScale.convert(off + (yVal ?? 0));\r\n }\r\n } else {\r\n targetY = yScale.convert(yVal ?? 0);\r\n targetBottomY = yScale.convert(0);\r\n }\r\n\r\n const startY = isInitial ? yScale.convert(0) : (this.points[i]?.currentY ?? yScale.convert(0));\r\n const startBottomY = isInitial ? yScale.convert(0) : (this.points[i]?.currentBottomY ?? yScale.convert(0));\r\n \r\n let label: Text | undefined;\r\n if (this.labelsOpts?.enabled) {\r\n label = new Text();\r\n this.group.add(label);\r\n }\r\n\r\n newPts.push({ x, targetY, startY, currentY: startY, targetBottomY, startBottomY, currentBottomY: startBottomY, label, datum, missing: isMissing });\r\n\r\n if (this.markerOpts.enabled) {\r\n const m = new Marker();\r\n m.shape = (this.markerOpts as any).shape || 'circle';\r\n m.centerX = x; m.centerY = targetY;\r\n m.radius = (this.markerOpts.size || 6) / 2;\r\n m.fill = this.markerOpts.fill;\r\n if ((this.markerOpts as any).stroke) m.stroke = (this.markerOpts as any).stroke;\r\n if ((this.markerOpts as any).strokeWidth !== undefined) m.strokeWidth = (this.markerOpts as any).strokeWidth;\r\n m.shadow = this.shadowOpts ?? null;\r\n m.datum = datum; m.seriesId = this.yKey;\r\n this.markers.push(m);\r\n this.group.add(m);\r\n }\r\n });\r\n\r\n this.points = newPts;\r\n\r\n if (animate && this.animationOpts?.enabled !== false) {\r\n this.animator?.stop();\r\n const animType = this.animationOpts?.type || 'grow';\r\n const duration = this.animationOpts?.duration ?? 500;\r\n const easing = Animator.getEasing(this.animationOpts?.easing);\r\n\r\n if (animType === 'fade') {\r\n this.group.opacity = 0;\r\n this.animator = new Animator({\r\n duration, easing,\r\n onUpdate: (p) => { \r\n this.buildPath(1);\r\n this.group.opacity = p * this.fillOpacity;\r\n if (this.labelsOpts?.enabled) this.renderLabels();\r\n }\r\n });\r\n } else {\r\n // Default grow\r\n this.animator = new Animator({\r\n duration,\r\n easing,\r\n onUpdate: (p) => {\r\n this.buildPath(p);\r\n if (this.labelsOpts?.enabled) this.renderLabels();\r\n },\r\n });\r\n }\r\n this.animator.start();\r\n } else {\r\n this.points.forEach((p, i) => {\r\n p.label = newPts[i].label; // sync new label node\r\n p.targetY = newPts[i].targetY; p.targetBottomY = newPts[i].targetBottomY;\r\n p.startY = p.currentY; p.startBottomY = p.currentBottomY;\r\n });\r\n this.buildPath(1);\r\n if (this.labelsOpts?.enabled) this.renderLabels();\r\n }\r\n }\r\n\r\n private renderLabels() {\r\n this.points.forEach(p => {\r\n if (!p.label) return;\r\n const lbl = p.label;\r\n lbl.text = formatAxisValue(p.datum[this.yKey]);\r\n lbl.fontSize = this.labelsOpts?.fontSize || 10;\r\n lbl.fontFamily = this.labelsOpts?.fontFamily || 'sans-serif';\r\n lbl.fontWeight = this.labelsOpts?.fontWeight || '600';\r\n lbl.rotation = ((this.labelsOpts?.rotation || 0) * Math.PI) / 180;\r\n lbl.fill = this.labelsOpts?.fill || this.stroke;\r\n lbl.textAlign = 'center';\r\n lbl.textBaseline = 'bottom';\r\n lbl.translation = { x: p.x, y: p.currentY - 8 };\r\n lbl.x = 0;\r\n lbl.y = 0;\r\n });\r\n }\r\n\r\n private buildPath(progress: number) {\r\n // Update interpolated coordinates first so contiguous-segment splitting\r\n // below can read currentY / currentBottomY directly.\r\n this.points.forEach((p, i) => {\r\n p.currentY = p.startY + (p.targetY - p.startY) * progress;\r\n p.currentBottomY = p.startBottomY + (p.targetBottomY - p.startBottomY) * progress;\r\n if (this.markers[i]) this.markers[i].centerY = p.currentY;\r\n });\r\n\r\n // Split the points into contiguous, non-missing runs when gap-skipping\r\n // is requested. A run is rendered as one closed sub-path so the visual\r\n // area is severed at any null/NaN.\r\n const runs: typeof this.points[] = [];\r\n if (this.connectMissingData) {\r\n runs.push(this.points);\r\n } else {\r\n let current: typeof this.points = [];\r\n this.points.forEach(p => {\r\n if (p.missing) {\r\n if (current.length > 0) { runs.push(current); current = []; }\r\n } else {\r\n current.push(p);\r\n }\r\n });\r\n if (current.length > 0) runs.push(current);\r\n }\r\n\r\n const allPath: PathPoint[] = [];\r\n runs.forEach(run => {\r\n const topPts = run.map(p => ({ x: p.x, y: p.currentY }));\r\n if (topPts.length === 0) return;\r\n\r\n let topPath: PathPoint[];\r\n if (this.interpolation === 'smooth') {\r\n topPath = catmullRomBezier(topPts);\r\n } else if (this.interpolation === 'step') {\r\n topPath = [];\r\n topPts.forEach((p, i) => {\r\n if (i === 0) { topPath.push({ command: 'M', x: p.x, y: p.y }); }\r\n else {\r\n const prev = topPath[topPath.length - 1];\r\n topPath.push({ command: 'L', x: p.x, y: prev.y });\r\n topPath.push({ command: 'L', x: p.x, y: p.y });\r\n }\r\n });\r\n } else {\r\n topPath = topPts.map((p, i) => ({ command: (i === 0 ? 'M' : 'L') as 'M' | 'L', x: p.x, y: p.y }));\r\n }\r\n\r\n // Trace the run's bottom in reverse to close the polygon.\r\n const bottomPath: PathPoint[] = [];\r\n for (let i = run.length - 1; i >= 0; i--) {\r\n bottomPath.push({ command: 'L', x: run[i].x, y: run[i].currentBottomY });\r\n }\r\n // Close this run by returning to its first top point so each sub-path\r\n // is independently fillable.\r\n bottomPath.push({ command: 'L', x: topPts[0].x, y: topPts[0].y });\r\n\r\n allPath.push(...topPath, ...bottomPath);\r\n });\r\n\r\n this.path.pathData = allPath;\r\n this.path.closed = true;\r\n }\r\n}\r\n\r\n","import { Group, Circle, Marker, MarkerShape, Text } from '../scene/Shapes';\nimport { formatAxisValue } from '../axes/CartesianAxis';\nimport { Scale, BandScale, safeBandwidth } from '../scale/Scale';\nimport { Animator } from '../core/Animator';\n\nexport interface ScatterSeriesOptions {\n xKey: string;\n yKey: string;\n sizeKey?: string;\n fill?: string;\n stroke?: string;\n strokeWidth?: number;\n marker?: {\n size?: number;\n fill?: string;\n };\n jitter?: number; // 0 to 1, fraction of bandwidth to jitter (default 0)\n labels?: import('../RadiantChart').DataLabelOptions;\n animation?: import('../RadiantChart').AnimationOptions;\n shadow?: import('../RadiantChart').DropShadow;\n markerShape?: 'circle' | 'square' | 'cross' | 'diamond' | 'triangle' | 'plus';\n}\n\n/**\n * Point animation state: start and target values for a single marker.\n */\ninterface PointState {\n startX: number; targetX: number;\n startY: number; targetY: number;\n startRadius: number; targetRadius: number;\n startOpacity: number; targetOpacity: number;\n}\n\n/**\n * ScatterSeries: Renders individual points (Scatter or Bubble charts).\n *\n * Uses an object-pool / diff strategy: existing Circle shapes are reused and\n * their target positions are updated in-place, so the scene graph is not torn\n * down and rebuilt on every update call. This makes streaming / real-time data\n * significantly cheaper — only shape creation/removal happens at the boundary.\n */\nexport class ScatterSeries {\n private group = new Group();\n private xKey: string;\n private yKey: string;\n private sizeKey?: string;\n private fill: string = '#4e79a7';\n private stroke: string = '#fff';\n private strokeWidth: number = 1;\n private markerSize: number = 8;\n private labelsOpts?: import('../RadiantChart').DataLabelOptions;\n private animationOpts?: import('../RadiantChart').AnimationOptions;\n private shadowOpts?: import('../RadiantChart').DropShadow;\n\n private animator?: Animator;\n\n /** Pooled marker nodes — one per data point, in data order. Polymorphic so\n * the markerShape option can switch between dot/square/cross/etc. */\n private markers: Marker[] = [];\n private markerShape: MarkerShape = 'circle';\n /** Pooled label Text nodes (only populated when labelsOpts.enabled is true). */\n private labelTexts: Text[] = [];\n /** Per-marker animation state, parallel to this.markers. */\n private points: PointState[] = [];\n\n private jitter: number = 0;\n /**\n * Stable per-index jitter offsets so points don't jump laterally when data\n * updates. Grown on demand; shrunk by truncation to preserve existing offsets.\n */\n private jitterOffsets: number[] = [];\n\n constructor(options: ScatterSeriesOptions) {\n this.xKey = options.xKey;\n this.yKey = options.yKey;\n this.sizeKey = options.sizeKey;\n this.jitter = options.jitter ?? 0;\n if (options.fill) this.fill = options.fill;\n if (options.stroke) this.stroke = options.stroke;\n if (options.strokeWidth !== undefined) this.strokeWidth = options.strokeWidth;\n if (options.marker?.size !== undefined) this.markerSize = options.marker.size;\n this.labelsOpts = options.labels;\n this.animationOpts = options.animation;\n this.shadowOpts = options.shadow;\n if (options.markerShape) this.markerShape = options.markerShape;\n }\n\n getGroup() {\n return this.group;\n }\n\n update(\n data: readonly any[],\n xScale: Scale<any, number>,\n yScale: Scale<number, number>,\n seriesRect: { x: number; y: number; width: number; height: number },\n animate: boolean = true,\n options?: ScatterSeriesOptions\n ) {\n if (options) {\n this.xKey = options.xKey;\n this.yKey = options.yKey;\n if (options.sizeKey !== undefined) this.sizeKey = options.sizeKey;\n if (options.fill) this.fill = options.fill;\n if (options.stroke) this.stroke = options.stroke;\n if (options.strokeWidth !== undefined) this.strokeWidth = options.strokeWidth;\n if (options.marker?.size !== undefined) this.markerSize = options.marker.size;\n if (options.jitter !== undefined) this.jitter = options.jitter;\n if (options.labels) this.labelsOpts = options.labels;\n if (options.animation) this.animationOpts = options.animation;\n if (options.shadow !== undefined) this.shadowOpts = options.shadow;\n if (options.markerShape) this.markerShape = options.markerShape;\n }\n\n // Stop any in-flight animation before reading current positions so the\n // start values we capture reflect where each point actually is on screen.\n if (this.animator) this.animator.stop();\n\n if (data.length === 0) {\n for (const m of this.markers) this.group.remove(m);\n for (const l of this.labelTexts) this.group.remove(l);\n this.markers = [];\n this.labelTexts = [];\n this.points = [];\n return;\n }\n\n // ── Jitter offsets: grow if needed, shrink by truncation ─────────────────\n while (this.jitterOffsets.length < data.length) {\n this.jitterOffsets.push((Math.random() - 0.5) * 2);\n }\n if (this.jitterOffsets.length > data.length) {\n this.jitterOffsets.length = data.length;\n }\n\n // ── Size scale for bubble charts ─────────────────────────────────────────\n let sizeScale = (_val: number) => this.markerSize / 2;\n if (this.sizeKey) {\n const sizes = data.map(d => d[this.sizeKey!] || 0);\n const maxSize = Math.max(...sizes);\n sizeScale = (val: number) => (val / (maxSize || 1)) * this.markerSize;\n }\n\n const animType = this.animationOpts?.type || 'pop';\n const isInitial = this.points.length === 0;\n const newPoints: PointState[] = [];\n\n // ── Diff pass: update existing markers, create new ones ──────────────────\n data.forEach((datum, i) => {\n const xVal = datum[this.xKey];\n const yVal = datum[this.yKey];\n const sVal = this.sizeKey ? datum[this.sizeKey] : 0;\n\n // Target pixel position\n let tx: number;\n if ('getBandwidth' in xScale) {\n const bw = safeBandwidth(xScale);\n const joff = this.jitterOffsets[i] * (bw * this.jitter / 2);\n tx = (xScale as BandScale).convert(xVal) + bw / 2 + joff;\n } else {\n tx = xScale.convert(xVal);\n }\n const ty = yScale.convert(yVal);\n const tr = sizeScale(sVal);\n\n let marker: Marker;\n let sx: number, sy: number, sr: number, so: number;\n\n if (i < this.markers.length) {\n // ── Reuse existing marker ────────────────────────────────────────────\n // Capture current rendered position as the animation start so that a\n // mid-flight transition begins smoothly from where the dot actually is.\n marker = this.markers[i];\n sx = marker.centerX;\n sy = marker.centerY;\n sr = marker.radius;\n so = marker.opacity;\n\n // Update non-animated style properties\n marker.fill = this.fill;\n marker.stroke = this.stroke;\n marker.strokeWidth = this.strokeWidth;\n marker.shape = this.markerShape;\n marker.datum = datum;\n marker.seriesId = this.yKey;\n marker.shadow = this.shadowOpts ?? null;\n } else {\n // ── Create and pool a new marker (enter transition) ──────────────────\n marker = new Marker();\n marker.fill = this.fill;\n marker.stroke = this.stroke;\n marker.strokeWidth = this.strokeWidth;\n marker.shape = this.markerShape;\n marker.datum = datum;\n marker.seriesId = this.yKey;\n marker.shadow = this.shadowOpts ?? null;\n this.markers.push(marker);\n this.group.add(marker);\n\n // Entry start state — new points animate in from their entry position\n if (isInitial && animType === 'grow') {\n sx = tx; sy = seriesRect.height; sr = tr; so = 1;\n } else if (isInitial && animType === 'fade') {\n sx = tx; sy = ty; sr = tr; so = 0;\n } else if (isInitial && animType === 'slide') {\n sx = tx; sy = seriesRect.height + 20; sr = tr; so = 1;\n } else {\n // 'pop' (default) — and for new points added to an existing series\n sx = tx; sy = ty; sr = 0; so = 0;\n }\n\n marker.centerX = sx;\n marker.centerY = sy;\n marker.radius = sr;\n marker.opacity = so;\n }\n\n newPoints.push({\n startX: sx, targetX: tx,\n startY: sy, targetY: ty,\n startRadius: sr, targetRadius: tr,\n startOpacity: so, targetOpacity: 1,\n });\n });\n\n // ── Remove excess markers from the pool ──────────────────────────────────\n if (this.markers.length > data.length) {\n for (let i = data.length; i < this.markers.length; i++) {\n this.group.remove(this.markers[i]);\n }\n this.markers.length = data.length;\n }\n\n // ── Sync label pool (parallel logic to markers) ───────────────────────────\n const labelsEnabled = this.labelsOpts?.enabled ?? false;\n\n if (labelsEnabled) {\n // Grow label pool\n while (this.labelTexts.length < data.length) {\n const lbl = new Text();\n lbl.textAlign = 'center';\n lbl.textBaseline = 'bottom';\n lbl.x = 0;\n lbl.y = 0;\n this.labelTexts.push(lbl);\n this.group.add(lbl);\n }\n // Shrink label pool\n if (this.labelTexts.length > data.length) {\n for (let i = data.length; i < this.labelTexts.length; i++) {\n this.group.remove(this.labelTexts[i]);\n }\n this.labelTexts.length = data.length;\n }\n // Apply label style (may have changed with options update)\n this.labelTexts.forEach((lbl, i) => {\n const yVal = data[i][this.yKey];\n lbl.text = formatAxisValue(yVal);\n lbl.fontSize = this.labelsOpts?.fontSize ?? 10;\n lbl.fontFamily = this.labelsOpts?.fontFamily ?? 'sans-serif';\n lbl.fontWeight = this.labelsOpts?.fontWeight ?? '600';\n lbl.rotation = ((this.labelsOpts?.rotation ?? 0) * Math.PI) / 180;\n lbl.fill = this.labelsOpts?.fill ?? this.fill;\n });\n } else {\n // Labels disabled — clear the pool if it had items\n if (this.labelTexts.length > 0) {\n for (const l of this.labelTexts) this.group.remove(l);\n this.labelTexts = [];\n }\n }\n\n this.points = newPoints;\n\n // ── Animate or snap to target ─────────────────────────────────────────────\n const applyProgress = (p: number) => {\n this.points.forEach((pt, i) => {\n const marker = this.markers[i];\n if (!marker) return;\n const cx = pt.startX + (pt.targetX - pt.startX) * p;\n const cy = pt.startY + (pt.targetY - pt.startY) * p;\n const cr = pt.startRadius + (pt.targetRadius - pt.startRadius) * p;\n marker.centerX = cx;\n marker.centerY = cy;\n marker.radius = cr;\n marker.opacity = pt.startOpacity + (pt.targetOpacity - pt.startOpacity) * p;\n\n if (labelsEnabled && this.labelTexts[i]) {\n this.labelTexts[i].translation = { x: cx, y: cy - (cr + 5) };\n }\n });\n };\n\n if (animate && this.animationOpts?.enabled !== false) {\n const duration = this.animationOpts?.duration ?? 600;\n const easing = Animator.getEasing(\n this.animationOpts?.easing ?? (animType === 'pop' ? 'back' : 'easeOut')\n );\n this.animator = new Animator({ duration, easing, onUpdate: applyProgress });\n this.animator.start();\n } else {\n applyProgress(1);\n }\n }\n}\n","// Radiant Charts — Tooltip System Types\n\nexport type TooltipTrigger = 'hover' | 'none';\nexport type TooltipMode = 'shared' | 'item';\nexport type TooltipPositionMode = 'follow-pointer' | 'snap-to-data' | 'fixed';\n\nexport interface TooltipDatumEntry {\n seriesIndex: number;\n seriesId: string;\n seriesType: string;\n title: string;\n color: string;\n datum: Record<string, any>;\n dataIndex: number;\n xValue: any;\n yValue: any;\n}\n\nexport interface TooltipState {\n active: boolean;\n /** Raw mouse position — viewport-relative (clientX/Y) */\n pointerX: number;\n pointerY: number;\n /** Snapped data-point position — viewport-relative, used as portal anchor */\n anchorX: number;\n anchorY: number;\n /** Chart-local coordinates (relative to container top-left) */\n localX: number;\n localY: number;\n /** Active data entries */\n entries: TooltipDatumEntry[];\n /** Shared X-axis label (for shared mode) */\n sharedLabel: string | null;\n}\n\nexport interface TooltipOptions {\n enabled?: boolean;\n trigger?: TooltipTrigger;\n mode?: TooltipMode;\n positionMode?: TooltipPositionMode;\n delay?: { show?: number; hide?: number };\n offset?: { x?: number; y?: number };\n snap?: boolean;\n shared?: boolean;\n}\n\nexport const DEFAULT_TOOLTIP_STATE: TooltipState = {\n active: false,\n pointerX: 0,\n pointerY: 0,\n anchorX: 0,\n anchorY: 0,\n localX: 0,\n localY: 0,\n entries: [],\n sharedLabel: null,\n};\n","// Radiant Charts — Tooltip State Store\n// Framework-agnostic pub/sub store consumable by React (useSyncExternalStore) and the canvas engine.\n\nimport { TooltipState, TooltipOptions, TooltipDatumEntry, DEFAULT_TOOLTIP_STATE } from './types';\n\ntype Listener = () => void;\n\nexport class TooltipStore {\n private _state: TooltipState = { ...DEFAULT_TOOLTIP_STATE };\n private _listeners = new Set<Listener>();\n private _options: TooltipOptions = {};\n private _showTimer: ReturnType<typeof setTimeout> | null = null;\n private _hideTimer: ReturnType<typeof setTimeout> | null = null;\n private _pendingActivation: (() => void) | null = null;\n\n // ── Public API ──────────────────────────────────────────────────────────────\n\n getState(): TooltipState {\n return this._state;\n }\n\n getOptions(): TooltipOptions {\n return this._options;\n }\n\n setOptions(options: TooltipOptions) {\n this._options = options;\n }\n\n subscribe(listener: Listener): () => void {\n this._listeners.add(listener);\n return () => { this._listeners.delete(listener); };\n }\n\n /**\n * Activate the tooltip with the given entries and position.\n * Respects delay.show if configured.\n */\n activate(\n entries: TooltipDatumEntry[],\n pointer: { x: number; y: number },\n anchor: { x: number; y: number },\n local: { x: number; y: number },\n sharedLabel: string | null,\n ) {\n if (this._options.enabled === false) return;\n\n this._clearHideTimer();\n\n const doActivate = () => {\n this._setState({\n active: true,\n pointerX: pointer.x,\n pointerY: pointer.y,\n anchorX: anchor.x,\n anchorY: anchor.y,\n localX: local.x,\n localY: local.y,\n entries,\n sharedLabel,\n });\n };\n\n const showDelay = this._options.delay?.show ?? 0;\n if (showDelay > 0) {\n this._clearShowTimer();\n this._pendingActivation = doActivate;\n this._showTimer = setTimeout(() => {\n this._pendingActivation?.();\n this._pendingActivation = null;\n this._showTimer = null;\n }, showDelay);\n } else {\n doActivate();\n }\n }\n\n /**\n * Deactivate the tooltip. Respects delay.hide if configured.\n */\n deactivate() {\n this._clearShowTimer();\n this._pendingActivation = null;\n\n const hideDelay = this._options.delay?.hide ?? 0;\n if (hideDelay > 0 && this._state.active) {\n this._hideTimer = setTimeout(() => {\n this._doDeactivate();\n this._hideTimer = null;\n }, hideDelay);\n } else {\n this._doDeactivate();\n }\n }\n\n /**\n * Update only the pointer position (for follow-pointer mode).\n */\n updatePointer(x: number, y: number) {\n if (!this._state.active) return;\n this._setState({\n ...this._state,\n pointerX: x,\n pointerY: y,\n });\n }\n\n /**\n * Notify subscribers that the chart has resized.\n * The portal will recompute its position on next paint.\n */\n notifyResize() {\n if (this._state.active) {\n this._notify();\n }\n }\n\n /**\n * Force-hide the tooltip regardless of state.\n */\n hide() {\n this._clearShowTimer();\n this._clearHideTimer();\n this._pendingActivation = null;\n this._doDeactivate(true);\n }\n\n /**\n * Clean up timers and listeners.\n */\n destroy() {\n this.hide();\n this._listeners.clear();\n }\n\n // ── Private ─────────────────────────────────────────────────────────────────\n\n private _setState(next: TooltipState) {\n this._state = next;\n this._notify();\n }\n\n private _notify() {\n for (const listener of this._listeners) {\n listener();\n }\n }\n\n private _doDeactivate(force = false) {\n if (!this._state.active && !force) return;\n this._setState({\n ...DEFAULT_TOOLTIP_STATE,\n });\n }\n\n private _clearShowTimer() {\n if (this._showTimer !== null) {\n clearTimeout(this._showTimer);\n this._showTimer = null;\n }\n }\n\n private _clearHideTimer() {\n if (this._hideTimer !== null) {\n clearTimeout(this._hideTimer);\n this._hideTimer = null;\n }\n }\n}\n","// Radiant Charts - ThemeManager\n// Phase 1.2: Global Theming System with semantic palettes\n\nexport interface ThemePalettes {\n categorical: string[];\n}\n\nexport interface Theme {\n backgroundColor: string;\n textColor: string;\n subtextColor: string;\n axisColor: string;\n gridColor: string;\n /** Default palette (categorical) */\n palette: string[];\n palettes: ThemePalettes;\n fontFamily: string;\n}\n\n// ─── Palettes ────────────────────────────────────────────────────────────────\n\nconst CATEGORICAL_LIGHT = [\n '#4e79a7', '#f28e2c', '#e15759', '#76b7b2',\n '#59a14f', '#edc948', '#b07aa1', '#ff9da7',\n '#9c755f', '#bab0ac',\n];\nconst CATEGORICAL_DARK = [\n '#80b1d3', '#fdb462', '#fb8072', '#bebada',\n '#b3de69', '#fccde5', '#8dd3c7', '#ffffb3',\n '#bc80bd', '#ccebc5',\n];\n// ─── Built-in Themes ─────────────────────────────────────────────────────────\n\nexport const lightTheme: Theme = {\n backgroundColor: '#ffffff',\n textColor: '#1a1a2e',\n subtextColor: '#6b7280',\n axisColor: '#d1d5db',\n gridColor: 'rgba(107,114,128,0.12)',\n palette: CATEGORICAL_LIGHT,\n palettes: {\n categorical: CATEGORICAL_LIGHT,\n },\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n};\n\nexport const darkTheme: Theme = {\n backgroundColor: '#020617',\n textColor: '#e2e8f0',\n subtextColor: '#94a3b8',\n axisColor: '#334155',\n gridColor: 'rgba(148,163,184,0.08)',\n palette: CATEGORICAL_DARK,\n palettes: {\n categorical: CATEGORICAL_DARK,\n },\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n};\n\n// ─── ThemeManager ─────────────────────────────────────────────────────────────\n\nexport type ThemeOption = 'light' | 'dark' | 'system' | Theme;\n\n/**\n * Detects whether the OS/browser is currently in dark mode.\n * Returns false in SSR or when the API is unavailable.\n */\nfunction systemPrefersDark(): boolean {\n if (typeof window === 'undefined') return false;\n return window.matchMedia('(prefers-color-scheme: dark)').matches;\n}\n\nexport class ThemeManager {\n private currentTheme: Theme = lightTheme;\n\n setTheme(name: ThemeOption) {\n if (name === 'light') this.currentTheme = lightTheme;\n else if (name === 'dark') this.currentTheme = darkTheme;\n else if (name === 'system') this.currentTheme = systemPrefersDark() ? darkTheme : lightTheme;\n else this.currentTheme = name as Theme;\n }\n\n get theme(): Theme {\n return this.currentTheme;\n }\n\n /**\n * Resolves whether the given theme option evaluates to dark mode right now.\n * Useful for UI layers that need an `isDark` boolean without holding a\n * ThemeManager instance.\n */\n static resolveIsDark(option: ThemeOption | undefined): boolean {\n if (option === 'dark') return true;\n if (option === 'system') return systemPrefersDark();\n return false;\n }\n}\n\n","import { Group, Rect, Text, Circle, Line } from '../scene/Shapes';\nimport { Theme } from './ThemeManager';\n\nexport interface LegendItem {\n id: string;\n label: string;\n fill: string;\n markerType?: 'square' | 'circle' | 'line';\n}\n\n/**\n * Legend: Renders the chart legend with interactive toggle and pagination support.\n *\n * Items are wrapped into rows then split into pages so the legend never grows\n * taller than ~20 % of the chart height. When multiple pages exist, ◀ / ▶\n * buttons are rendered in a nav row at the bottom of the legend group.\n *\n * ## Click flow\n * - Series item group → `seriesId` = the series ID → ChartManager toggles visibility\n * - Arrow button group → `seriesId` = '__legend_prev__' | '__legend_next__'\n * → ChartManager calls `legend.paginate(±1)`\n *\n * ## Hit-testing note\n * `Text.isPointInNode` always returns false, so arrow buttons wrap the text in\n * a Group that also contains a transparent Rect that absorbs pointer events.\n */\nexport class Legend {\n private group = new Group();\n private items: LegendItem[] = [];\n private theme?: Theme;\n\n /** Series IDs that the user has toggled off via legend click. */\n hiddenSeries: string[] = [];\n\n // ── Pagination state ────────────────────────────────────────────────────────\n private pages: LegendItem[][] = [];\n private currentPage = 0;\n\n // ── Layout constants ────────────────────────────────────────────────────────\n private readonly ROW_H = 24; // px per item row\n private readonly NAV_H = 22; // px for the ◀/▶ row\n private readonly MARKER = 12; // marker square/circle size\n private readonly GAP = 6; // gap between marker and label\n private readonly SPACING = 20; // gap between items on the same row\n private readonly CHAR_W = 7.5; // estimated px per label character\n\n // Captured in update() and reused by _renderCurrentPage()\n private lastMaxWidth = 0;\n private lastMaxRows = 2;\n\n // ── Public API ──────────────────────────────────────────────────────────────\n\n getGroup() { return this.group; }\n\n setHiddenSeries(ids: string[]) { this.hiddenSeries = ids; }\n getHiddenSeries(): string[] { return this.hiddenSeries; }\n\n update(items: LegendItem[], theme: Theme, maxWidth: number, maxHeight: number, position: string = 'bottom') {\n this.items = items;\n this.theme = theme;\n this.lastMaxWidth = maxWidth;\n\n const isVertical = position === 'left' || position === 'right';\n const verticalLimitFrac = 0.85; // Reserve up to 85% for side legends\n const horizontalLimitFrac = 0.25; // Reserve up to 25% for top/bottom legends\n\n // Reserve space based on orientation; side legends can grow much taller.\n this.lastMaxRows = Math.max(1, Math.floor((maxHeight * (isVertical ? verticalLimitFrac : horizontalLimitFrac)) / this.ROW_H));\n\n this.pages = this._buildPages(items, maxWidth, this.lastMaxRows);\n // Clamp in case items were removed and pages count dropped\n this.currentPage = Math.min(this.currentPage, Math.max(0, this.pages.length - 1));\n\n this._renderCurrentPage();\n }\n\n /**\n * Advance (+1) or retreat (−1) one page and re-render.\n * Called by ChartManager when the ◀ / ▶ arrow is clicked.\n */\n paginate(delta: 1 | -1) {\n this.currentPage = Math.max(0, Math.min(this.pages.length - 1, this.currentPage + delta));\n this._renderCurrentPage();\n }\n\n getBBox() { return this.group.getBBox(); }\n\n // ── Private helpers ─────────────────────────────────────────────────────────\n\n /**\n * Wrap items into rows then chunk rows into pages.\n *\n * Two-stage layout:\n * 1. Pack items left-to-right; start a new row when the current row overflows.\n * 2. Split the resulting rows into pages of `maxRows` rows each.\n */\n private _buildPages(items: LegendItem[], maxWidth: number, maxRows: number): LegendItem[][] {\n // Stage 1: row-wrap\n const rows: LegendItem[][] = [];\n let currentRow: LegendItem[] = [];\n let currentX = 0;\n\n for (const item of items) {\n const itemW = this.MARKER + this.GAP + item.label.length * this.CHAR_W + this.SPACING;\n if (currentX + itemW > maxWidth && currentRow.length > 0) {\n rows.push(currentRow);\n currentRow = [];\n currentX = 0;\n }\n currentRow.push(item);\n currentX += itemW;\n }\n if (currentRow.length > 0) rows.push(currentRow);\n\n // Stage 2: page-chunk\n const pages: LegendItem[][] = [];\n for (let i = 0; i < rows.length; i += maxRows) {\n pages.push(rows.slice(i, i + maxRows).flat());\n }\n return pages.length > 0 ? pages : [[]];\n }\n\n /** Rebuild the group's children for the active page. */\n private _renderCurrentPage() {\n this.group.clear();\n if (!this.theme) return;\n\n const theme = this.theme;\n const items = this.pages[this.currentPage] ?? [];\n const multiPage = this.pages.length > 1;\n\n // ── Series item rows ────────────────────────────────────────────────────\n let currentX = 0;\n let currentY = 0;\n\n for (const item of items) {\n const labelW = item.label.length * this.CHAR_W;\n const totalW = this.MARKER + this.GAP + labelW;\n\n if (currentX + totalW > this.lastMaxWidth && currentX > 0) {\n currentX = 0;\n currentY += this.ROW_H;\n }\n\n const itemGroup = new Group();\n itemGroup.translation = { x: currentX, y: currentY };\n itemGroup.seriesId = item.id;\n itemGroup.opacity = this.hiddenSeries.includes(item.id) ? 0.4 : 1;\n itemGroup.pointerEvents = true;\n\n if (item.markerType === 'circle') {\n const marker = new Circle();\n marker.centerX = this.MARKER / 2;\n marker.centerY = this.MARKER / 2;\n marker.radius = this.MARKER / 2;\n marker.fill = item.fill;\n itemGroup.add(marker);\n } else if (item.markerType === 'line') {\n const marker = new Line();\n marker.x1 = 0;\n marker.y1 = this.MARKER / 2;\n marker.x2 = this.MARKER;\n marker.y2 = this.MARKER / 2;\n marker.stroke = item.fill;\n marker.strokeWidth = 3;\n itemGroup.add(marker);\n } else {\n const marker = new Rect();\n marker.width = this.MARKER;\n marker.height = this.MARKER;\n marker.fill = item.fill;\n marker.cornerRadius = 2;\n itemGroup.add(marker);\n }\n\n const label = new Text();\n label.text = item.label;\n label.x = this.MARKER + this.GAP;\n label.y = this.MARKER / 2;\n label.fontSize = 11;\n label.fontFamily = theme.fontFamily;\n label.fill = theme.textColor;\n label.textBaseline = 'middle';\n itemGroup.add(label);\n\n this.group.add(itemGroup);\n currentX += totalW + this.SPACING;\n }\n\n // ── Navigation row ──────────────────────────────────────────────────────\n if (!multiPage) return;\n\n const navY = currentY + (items.length > 0 ? this.ROW_H : 0);\n const muted = theme.subtextColor;\n const btnH = this.NAV_H;\n const btnW = 28; // clickable width for each arrow button\n\n // ◀ prev\n if (this.currentPage > 0) {\n this.group.add(this._makeNavButton('◀', '__legend_prev__', 0, navY, btnW, btnH, muted, theme, 'start'));\n }\n\n // \"2 / 5\" page indicator (non-interactive)\n const pageIndicator = new Text();\n pageIndicator.text = `${this.currentPage + 1} / ${this.pages.length}`;\n pageIndicator.x = this.lastMaxWidth / 2;\n pageIndicator.y = navY + btnH / 2;\n pageIndicator.fontSize = 10;\n pageIndicator.fontFamily = theme.fontFamily;\n pageIndicator.fill = muted;\n pageIndicator.textAlign = 'center';\n pageIndicator.textBaseline = 'middle';\n pageIndicator.pointerEvents = false;\n this.group.add(pageIndicator);\n\n // ▶ next\n if (this.currentPage < this.pages.length - 1) {\n this.group.add(\n this._makeNavButton('▶', '__legend_next__', this.lastMaxWidth - btnW, navY, btnW, btnH, muted, theme, 'end'),\n );\n }\n }\n\n /**\n * Creates a clickable arrow button: an invisible hit-area Rect behind a Text\n * arrow glyph, wrapped in a Group tagged with the special seriesId.\n *\n * The `Rect` provides a reliably hittable area because `Text.isPointInNode`\n * always returns false in this scene-graph implementation.\n */\n private _makeNavButton(\n glyph: string,\n actionId: '__legend_prev__' | '__legend_next__',\n x: number,\n y: number,\n w: number,\n h: number,\n color: string,\n theme: Theme,\n align: CanvasTextAlign,\n ): Group {\n const btn = new Group();\n btn.translation = { x, y };\n btn.seriesId = actionId;\n btn.pointerEvents = true;\n\n // Transparent hit-area so the full button region is clickable\n const hitRect = new Rect();\n hitRect.x = 0;\n hitRect.y = 0;\n hitRect.width = w;\n hitRect.height = h;\n hitRect.fill = 'transparent';\n btn.add(hitRect);\n\n const label = new Text();\n label.text = glyph;\n label.x = align === 'end' ? w : 0;\n label.y = h / 2;\n label.fontSize = 11;\n label.fontFamily = theme.fontFamily;\n label.fill = color;\n label.textAlign = align;\n label.textBaseline = 'middle';\n btn.add(label);\n\n return btn;\n }\n}\n","// Radiant Charts - CrosshairRenderer (formerly CrosshairManager)\n// Enhanced: snap dots per series, band highlighting, spike lines, lerp animation\n\nimport { Group, Line, Circle, Rect, Text } from '../scene/Shapes';\nimport { Theme } from './ThemeManager';\nimport { BandScale, safeBandwidth } from '../scale/Scale';\n\n\n/** @deprecated Use `CrosshairRenderer` */\nexport type CrosshairManager = CrosshairRenderer;\n\nexport class CrosshairRenderer {\n private group = new Group();\n private xLine = new Line();\n private yLine = new Line();\n private snapDot = new Circle();\n private bandHighlight = new Rect();\n private enabledX = false;\n private enabledY = false;\n\n /** Pooled per-series snap dots for shared mode */\n private seriesSnapDots: Circle[] = [];\n /** Target radii for snap dot scale animation (0 = hidden, 4 = full) */\n private seriesSnapTargets: number[] = [];\n /** Spike line axis labels */\n private spikeXLabel = new Text();\n private spikeYLabel = new Text();\n private spikeXBg = new Rect();\n private spikeYBg = new Rect();\n\n /** Lerp animation state — target vs current positions */\n private _targetX = 0;\n private _targetY = 0;\n private _currentX = 0;\n private _currentY = 0;\n private _lerpActive = false;\n private static readonly LERP_SPEED = 0.25; // 0–1, higher = faster convergence\n /** Skip lerp animation when user prefers reduced motion */\n private _reducedMotion = typeof window !== 'undefined'\n && window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;\n\n constructor() {\n this.group.visible = false;\n\n this.xLine.strokeWidth = 1;\n this.yLine.strokeWidth = 1;\n\n this.snapDot.radius = 5;\n this.snapDot.fill = 'transparent';\n this.snapDot.strokeWidth = 2;\n\n this.bandHighlight.fill = 'rgba(128,128,128,0.06)';\n this.bandHighlight.visible = false;\n\n // Spike label defaults\n this.spikeXLabel.fontSize = 10;\n this.spikeXLabel.textAlign = 'center';\n this.spikeXLabel.textBaseline = 'top';\n this.spikeXLabel.visible = false;\n this.spikeXBg.cornerRadius = 3;\n this.spikeXBg.visible = false;\n\n this.spikeYLabel.fontSize = 10;\n this.spikeYLabel.textAlign = 'right';\n this.spikeYLabel.textBaseline = 'middle';\n this.spikeYLabel.visible = false;\n this.spikeYBg.cornerRadius = 3;\n this.spikeYBg.visible = false;\n\n this.group.add(this.bandHighlight);\n this.group.add(this.xLine);\n this.group.add(this.yLine);\n this.group.add(this.snapDot);\n this.group.add(this.spikeXBg);\n this.group.add(this.spikeXLabel);\n this.group.add(this.spikeYBg);\n this.group.add(this.spikeYLabel);\n }\n\n getGroup() { return this.group; }\n\n updateOptions(options: { x?: boolean; y?: boolean }) {\n this.enabledX = options.x ?? false;\n this.enabledY = options.y ?? false;\n }\n\n /**\n * Show crosshair lines and snap to nearest data point.\n * If xScale (BandScale) and data are provided, the vertical line snaps to\n * the nearest category center instead of following the raw mouse X.\n */\n show(\n x: number,\n y: number,\n bounds: { x: number; y: number; width: number; height: number },\n theme: Theme,\n xScale?: BandScale,\n data?: readonly any[],\n xKey?: string\n ) {\n if (!this.enabledX && !this.enabledY) {\n this.group.visible = false;\n return;\n }\n\n this.group.visible = true;\n const color = theme.axisColor;\n\n // Snap x to nearest category center\n let snappedX = x;\n let snappedY = y;\n this.snapDot.visible = false;\n this.bandHighlight.visible = false;\n\n if (xScale && data && xKey) {\n let minDist = Infinity;\n let closestX = x;\n let closestBandX = 0;\n for (const d of data) {\n const catX = xScale.convert(d[xKey]) + safeBandwidth(xScale) / 2;\n const absX = catX + bounds.x;\n const dist = Math.abs(absX - x);\n if (dist < minDist) {\n minDist = dist;\n closestX = absX;\n closestBandX = xScale.convert(d[xKey]);\n }\n }\n snappedX = closestX;\n\n // Band highlight for BandScale charts\n if (this.enabledX) {\n this.bandHighlight.visible = true;\n this.bandHighlight.x = closestBandX + bounds.x;\n this.bandHighlight.y = bounds.y;\n this.bandHighlight.width = safeBandwidth(xScale);\n this.bandHighlight.height = bounds.height;\n const isDark = theme.backgroundColor.includes('2') || theme.backgroundColor.includes('0');\n this.bandHighlight.fill = isDark ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.04)';\n }\n\n // Show snap dot on the crosshair intersection\n if (this.enabledX) {\n this.snapDot.visible = true;\n this.snapDot.centerX = snappedX;\n this.snapDot.centerY = y;\n this.snapDot.fill = theme.backgroundColor;\n this.snapDot.stroke = color;\n }\n }\n\n // Set targets for lerp animation\n this._targetX = snappedX;\n this._targetY = snappedY;\n\n // On first show, snap immediately (no lerp from 0,0)\n if (!this._lerpActive && this._currentX === 0 && this._currentY === 0) {\n this._currentX = snappedX;\n this._currentY = snappedY;\n } else {\n this._lerpActive = true;\n }\n\n if (this.enabledX) {\n this.xLine.visible = true;\n this.xLine.x1 = this._currentX; this.xLine.y1 = bounds.y;\n this.xLine.x2 = this._currentX; this.xLine.y2 = bounds.y + bounds.height;\n this.xLine.stroke = color;\n this.xLine.lineDash = [4, 4];\n } else {\n this.xLine.visible = false;\n }\n\n if (this.enabledY) {\n this.yLine.visible = true;\n this.yLine.x1 = bounds.x; this.yLine.y1 = this._currentY;\n this.yLine.x2 = bounds.x + bounds.width; this.yLine.y2 = this._currentY;\n this.yLine.stroke = color;\n this.yLine.lineDash = [4, 4];\n } else {\n this.yLine.visible = false;\n }\n\n // Hide spike labels by default (they're shown via showSeriesSnaps)\n this.spikeXLabel.visible = false;\n this.spikeXBg.visible = false;\n this.spikeYLabel.visible = false;\n this.spikeYBg.visible = false;\n }\n\n /**\n * Show spike line axis labels at the crosshair intersection with each axis.\n */\n showSpikeLabels(\n xLabel: string,\n yLabel: string,\n snappedX: number,\n snappedY: number,\n bounds: { x: number; y: number; width: number; height: number },\n theme: Theme,\n ) {\n const isDark = theme.backgroundColor.includes('2') || theme.backgroundColor.includes('0');\n\n // X-axis spike label\n if (xLabel && this.enabledX) {\n this.spikeXLabel.visible = true;\n this.spikeXLabel.text = xLabel;\n this.spikeXLabel.x = snappedX;\n this.spikeXLabel.y = bounds.y + bounds.height + 4;\n this.spikeXLabel.fill = isDark ? '#e2e8f0' : '#1e293b';\n this.spikeXLabel.fontFamily = theme.fontFamily;\n\n // Background badge\n const tw = xLabel.length * 6 + 12;\n this.spikeXBg.visible = true;\n this.spikeXBg.x = snappedX - tw / 2;\n this.spikeXBg.y = bounds.y + bounds.height + 2;\n this.spikeXBg.width = tw;\n this.spikeXBg.height = 18;\n this.spikeXBg.fill = isDark ? '#1e293b' : '#f1f5f9';\n this.spikeXBg.stroke = theme.axisColor;\n this.spikeXBg.strokeWidth = 1;\n }\n\n // Y-axis spike label\n if (yLabel && this.enabledY) {\n this.spikeYLabel.visible = true;\n this.spikeYLabel.text = yLabel;\n this.spikeYLabel.x = bounds.x - 4;\n this.spikeYLabel.y = snappedY;\n this.spikeYLabel.fill = isDark ? '#e2e8f0' : '#1e293b';\n this.spikeYLabel.fontFamily = theme.fontFamily;\n\n const tw = yLabel.length * 6 + 12;\n this.spikeYBg.visible = true;\n this.spikeYBg.x = bounds.x - tw - 4;\n this.spikeYBg.y = snappedY - 9;\n this.spikeYBg.width = tw;\n this.spikeYBg.height = 18;\n this.spikeYBg.fill = isDark ? '#1e293b' : '#f1f5f9';\n this.spikeYBg.stroke = theme.axisColor;\n this.spikeYBg.strokeWidth = 1;\n }\n }\n\n /**\n * Tick the lerp interpolation one step. Called each RAF frame by ChartManager.\n * Returns true if the crosshair position changed (scene needs re-render).\n */\n tick(): boolean {\n if (!this.group.visible) return false;\n // Check if there are any animating snap dots\n const hasSnapAnim = this.seriesSnapDots.some((d, i) =>\n Math.abs((this.seriesSnapTargets[i] ?? 0) - d.radius) > 0.2\n );\n if (!this._lerpActive && !hasSnapAnim) return false;\n\n // Skip animation when user prefers reduced motion — snap instantly\n if (this._reducedMotion) {\n this._currentX = this._targetX;\n this._currentY = this._targetY;\n this._lerpActive = false;\n if (this.enabledX) { this.xLine.x1 = this._currentX; this.xLine.x2 = this._currentX; }\n if (this.enabledY) { this.yLine.y1 = this._currentY; this.yLine.y2 = this._currentY; }\n for (let i = 0; i < this.seriesSnapDots.length; i++) {\n const dot = this.seriesSnapDots[i];\n const target = this.seriesSnapTargets[i] ?? 0;\n dot.radius = target;\n if (target === 0) dot.visible = false;\n }\n return true;\n }\n\n const speed = CrosshairRenderer.LERP_SPEED;\n const dx = this._targetX - this._currentX;\n const dy = this._targetY - this._currentY;\n\n // Snap when close enough (sub-pixel)\n if (Math.abs(dx) < 0.5 && Math.abs(dy) < 0.5) {\n this._currentX = this._targetX;\n this._currentY = this._targetY;\n this._lerpActive = false;\n } else {\n this._currentX += dx * speed;\n this._currentY += dy * speed;\n }\n\n // Apply interpolated position to the crosshair lines\n if (this.enabledX) {\n this.xLine.x1 = this._currentX;\n this.xLine.x2 = this._currentX;\n }\n if (this.enabledY) {\n this.yLine.y1 = this._currentY;\n this.yLine.y2 = this._currentY;\n }\n\n // Animate snap dot radii (scale in/out)\n for (let i = 0; i < this.seriesSnapDots.length; i++) {\n const dot = this.seriesSnapDots[i];\n const target = this.seriesSnapTargets[i] ?? 0;\n const diff = target - dot.radius;\n if (Math.abs(diff) < 0.2) {\n dot.radius = target;\n if (target === 0) dot.visible = false;\n } else {\n dot.radius += diff * 0.35;\n }\n }\n\n return true;\n }\n\n /** Hide all series snap dots (animated scale-out via tick()) */\n hideSeriesSnaps() {\n for (let i = 0; i < this.seriesSnapDots.length; i++) {\n this.seriesSnapTargets[i] = 0;\n }\n }\n\n hide() {\n this.group.visible = false;\n this.bandHighlight.visible = false;\n this.hideSeriesSnaps();\n this.spikeXLabel.visible = false;\n this.spikeXBg.visible = false;\n this.spikeYLabel.visible = false;\n this.spikeYBg.visible = false;\n // Reset lerp so next show starts fresh\n this._lerpActive = false;\n this._currentX = 0;\n this._currentY = 0;\n }\n}\n","import { Scene } from '../scene/Scene';\r\nimport { Group, Rect, Text } from '../scene/Shapes';\r\nimport { RadiantChartOptions } from '../RadiantChart';\r\nimport { BandScale, LinearScale, Scale } from '../scale/Scale';\r\nimport { CartesianAxis } from '../axes/CartesianAxis';\r\nimport { BarSeries } from '../series/BarSeries';\r\nimport { LineSeries } from '../series/LineSeries';\r\nimport { PieSeries } from '../series/PieSeries';\r\nimport { AreaSeries } from '../series/AreaSeries';\r\nimport { ScatterSeries } from '../series/ScatterSeries';\r\nimport { TooltipStore } from '../tooltip/TooltipStore';\r\nimport { ThemeManager, ThemeOption } from './ThemeManager';\r\nimport { Legend, LegendItem } from './Legend';\r\nimport { CrosshairRenderer } from './CrosshairManager';\r\n\r\nconst NON_CARTESIAN = new Set([\r\n 'pie',\r\n]);\r\n\r\nexport class ChartManager {\r\n private container: HTMLElement;\r\n private options: RadiantChartOptions;\r\n private scene: Scene;\r\n private tooltipStore = new TooltipStore();\r\n private themeManager = new ThemeManager();\r\n private legend = new Legend();\r\n private legendProxy?: HTMLElement;\r\n private crosshair = new CrosshairRenderer();\r\n private resizeObserver: ResizeObserver;\r\n\r\n // ── System theme media query listener ──────────────────────────────────────\r\n private mediaQuery: MediaQueryList | null = null;\r\n private _onSystemThemeChange = () => {\r\n // Only react if the user's option is 'system'; ignore for explicit themes.\r\n if (this.options.theme !== 'system') return;\r\n // Re-resolve the theme and re-render the chart with the new palette.\r\n this.themeManager.setTheme('system');\r\n const bg = this.themeManager.theme.backgroundColor;\r\n this.container.style.backgroundColor = bg;\r\n this.scene.backgroundColor = bg;\r\n this.processData();\r\n this.performLayout();\r\n this.render();\r\n };\r\n\r\n private titleGroup = new Group();\r\n private subtitleGroup = new Group();\r\n private legendGroup = new Group();\r\n private seriesGroup = new Group();\r\n private axesGroup = new Group();\r\n private crosshairGroup = new Group();\r\n private emptyGroup = new Group();\r\n\r\n private categoryScale: Scale<any, number> = new BandScale();\r\n private valueScale: Scale<any, number> = new LinearScale();\r\n private valueScaleRight: Scale<any, number> = new LinearScale();\r\n private xAxis?: CartesianAxis;\r\n private yAxis?: CartesianAxis;\r\n private yAxisRight?: CartesianAxis;\r\n\r\n private series: any[] = [];\r\n private seriesInstances = new Map<string, any>();\r\n private isCartesian = true;\r\n private seriesRect = { x: 0, y: 0, width: 0, height: 0 };\r\n private initialized = false;\r\n private animRafId: number | null = null;\r\n private hoveredSeriesId: string | null = null;\r\n private hiddenSeries: string[] = [];\r\n private minY: number = 0;\r\n private maxY: number = 0;\r\n\r\n private lastDataRef: readonly any[] | null = null;\r\n\r\n /** Keyboard navigation index for tooltip accessibility */\r\n private _kbIndex = -1;\r\n private readonly _onKeyDown: (e: KeyboardEvent) => void;\r\n private readonly _onPointerLeave: (e: PointerEvent) => void;\r\n\r\n constructor(container: HTMLElement, options: RadiantChartOptions) {\r\n this.container = container;\r\n this.options = options;\r\n this.scene = new Scene(container);\r\n this.tooltipStore.setOptions(options.tooltip ?? {});\r\n\r\n // Keyboard navigation for tooltip accessibility\r\n this.container.setAttribute('tabindex', '0');\r\n this._onKeyDown = this._handleKeyboard.bind(this);\r\n this.container.addEventListener('keydown', this._onKeyDown);\r\n\r\n this._onPointerLeave = () => {\r\n this.tooltipStore.deactivate();\r\n this.crosshair.hide();\r\n this.crosshair.hideSeriesSnaps();\r\n this.hoveredSeriesId = null;\r\n this.series.forEach(s => { s.getGroup().opacity = 1; });\r\n };\r\n this.container.addEventListener('pointerleave', this._onPointerLeave);\r\n\r\n this.scene.root.add(this.titleGroup);\r\n this.scene.root.add(this.subtitleGroup);\r\n this.scene.root.add(this.axesGroup);\r\n this.scene.root.add(this.seriesGroup);\r\n // Legend must render AFTER seriesGroup so it paints on top of chart content\r\n // (prevents occlusion for full-area charts like Pie, etc.)\r\n this.scene.root.add(this.legendGroup);\r\n this.scene.root.add(this.crosshairGroup);\r\n this.scene.root.add(this.emptyGroup);\r\n \r\n this.legendGroup.add(this.legend.getGroup());\r\n this.crosshairGroup.add(this.crosshair.getGroup());\r\n\r\n // DOM proxy for the legend — allows external CSS/DOM targeting while\r\n // the legend itself is rendered to the canvas for performance.\r\n this.legendProxy = document.createElement('div');\r\n this.legendProxy.className = 'radiant-chart-legend';\r\n this.legendProxy.style.position = 'absolute';\r\n this.legendProxy.style.pointerEvents = 'none';\r\n this.legendProxy.style.display = 'none';\r\n this.container.appendChild(this.legendProxy);\r\n\r\n this.setupInteractivity();\r\n this.startLoop();\r\n\r\n this.resizeObserver = new ResizeObserver(entries => {\r\n for (const e of entries) {\r\n if (e.contentRect.width > 0 && e.contentRect.height > 0) {\r\n this.scene.resize();\r\n this.performLayout();\r\n this.render();\r\n this.initialized = true;\r\n // Notify tooltip portal to recompute position after resize\r\n this.tooltipStore.notifyResize();\r\n }\r\n }\r\n });\r\n this.resizeObserver.observe(container);\r\n\r\n // Listen for OS-level theme toggles only when the user explicitly opts in to 'system'.\r\n // _syncMediaQueryListener() handles attaching / detaching on every update() call.\r\n this._syncMediaQueryListener();\r\n\r\n this.update(options);\r\n }\r\n\r\n private startLoop() {\r\n const loop = () => {\r\n this.crosshair.tick();\r\n this.render();\r\n this.animRafId = requestAnimationFrame(loop);\r\n };\r\n this.animRafId = requestAnimationFrame(loop);\r\n }\r\n\r\n private stopLoop() {\r\n if (this.animRafId !== null) { cancelAnimationFrame(this.animRafId); this.animRafId = null; }\r\n }\r\n\r\n private setupInteractivity() {\r\n this.scene.onHover = (node, event) => {\r\n if (!this.initialized) return;\r\n\r\n if (node === null) {\r\n this.tooltipStore.deactivate();\r\n this.crosshair.hide();\r\n this.crosshair.hideSeriesSnaps();\r\n this.hoveredSeriesId = null;\r\n this.series.forEach(s => { s.getGroup().opacity = 1; });\r\n return;\r\n }\r\n\r\n const rect = this.container.getBoundingClientRect();\r\n const mx = event.clientX - rect.left;\r\n const my = event.clientY - rect.top;\r\n const theme = this.themeManager.theme;\r\n const sr = this.seriesRect;\r\n const palette = theme.palette;\r\n\r\n // Snap-to-data crosshair\r\n if (this.isCartesian && mx >= sr.x && mx <= sr.x + sr.width && my >= sr.y && my <= sr.y + sr.height) {\r\n const xOpt = this.options.series[0]?.xKey;\r\n this.crosshair.show(\r\n mx, my, sr, theme,\r\n xOpt ? (this.categoryScale as BandScale) : undefined,\r\n xOpt ? this.options.data : undefined,\r\n xOpt\r\n );\r\n } else {\r\n this.crosshair.hide();\r\n }\r\n\r\n if (this.options.tooltip?.enabled !== false) {\r\n if (this.isCartesian && mx >= sr.x && mx <= sr.x + sr.width && my >= sr.y && my <= sr.y + sr.height) {\r\n // Emit raw hover data for external tooltip implementations\r\n this.tooltipStore.activate(\r\n [],\r\n { x: event.clientX, y: event.clientY },\r\n { x: event.clientX, y: event.clientY },\r\n { x: mx, y: my },\r\n null,\r\n );\r\n } else if (node?.datum && !this.isCartesian) {\r\n this.tooltipStore.activate(\r\n [],\r\n { x: event.clientX, y: event.clientY },\r\n { x: event.clientX, y: event.clientY },\r\n { x: mx, y: my },\r\n null,\r\n );\r\n } else {\r\n this.tooltipStore.deactivate();\r\n this.crosshair.hide();\r\n this.crosshair.hideSeriesSnaps();\r\n }\r\n }\r\n\r\n // Focus dimming\r\n const seriesId = node?.seriesId ?? null;\r\n if (node?.datum && seriesId !== this.hoveredSeriesId) {\r\n this.hoveredSeriesId = seriesId;\r\n this.series.forEach((s, i) => {\r\n const id = this.options.series[i]?.yKey ?? this.options.series[i]?.angleKey ?? `s${i}`;\r\n s.getGroup().opacity = (id === seriesId || this.series.length === 1) ? 1 : 0.15;\r\n });\r\n } else if (!node?.datum && this.hoveredSeriesId !== null) {\r\n this.hoveredSeriesId = null;\r\n this.series.forEach(s => { s.getGroup().opacity = 1; });\r\n }\r\n };\r\n\r\n // ── Click handler for legend toggle ────────────────────────────────\r\n this.scene.onClick = (node, _event) => {\r\n if (!node) return;\r\n\r\n // Walk up the scene graph and check if the clicked node (or any\r\n // ancestor) lives inside the legendGroup. If it does, the first\r\n // non-empty seriesId we encounter on the way up is the toggle target.\r\n let current = node;\r\n let seriesId: string | null = null;\r\n let insideLegend = false;\r\n\r\n while (current) {\r\n if (current.seriesId && !seriesId) {\r\n seriesId = current.seriesId;\r\n }\r\n if (current === this.legendGroup || current === this.legend.getGroup()) {\r\n insideLegend = true;\r\n break;\r\n }\r\n current = current.parent;\r\n }\r\n\r\n // ── User-supplied node click listener ─────────────────────────────────\r\n // Fires for any clicked data node outside the legend that carries a\r\n // datum payload — bars, markers, sectors, tiles, etc. The seriesId is\r\n // resolved by walking up the scene graph above.\r\n if (!insideLegend && node.datum && this.options.listeners?.nodeClick) {\r\n const seriesOpt = this.options.series.find(\r\n so => (so.yKey ?? so.angleKey ?? '') === seriesId\r\n );\r\n this.options.listeners.nodeClick({\r\n seriesId: seriesId ?? '',\r\n datum: node.datum,\r\n xKey: seriesOpt?.xKey,\r\n yKey: seriesOpt?.yKey,\r\n type: seriesOpt?.type,\r\n });\r\n }\r\n\r\n if (!insideLegend || !seriesId) return;\r\n\r\n // ── Pagination arrows ──────────────────────────────────────────────────\r\n if (seriesId === '__legend_prev__' || seriesId === '__legend_next__') {\r\n this.legend.paginate(seriesId === '__legend_next__' ? 1 : -1);\r\n this.performLayout();\r\n this.render();\r\n return;\r\n }\r\n\r\n // ── Series toggle ──────────────────────────────────────────────────────\r\n const idx = this.hiddenSeries.indexOf(seriesId);\r\n if (idx >= 0) {\r\n this.hiddenSeries.splice(idx, 1);\r\n } else {\r\n this.hiddenSeries.push(seriesId);\r\n }\r\n\r\n // ── User-supplied legend item click listener ──────────────────────────\r\n this.options.legend?.listeners?.legendItemClick?.({\r\n seriesId,\r\n visible: !this.hiddenSeries.includes(seriesId),\r\n });\r\n\r\n // Sync state to the Legend renderer and re-process everything so the\r\n // value-scale domain is recalculated without the hidden series.\r\n this.legend.setHiddenSeries([...this.hiddenSeries]);\r\n this.processData();\r\n this.performLayout();\r\n this.render();\r\n };\r\n\r\n // ── Double-click handler ──────────────────────────────────────────────\r\n // Two responsibilities:\r\n // 1. Inside the legend → isolate the dbl-clicked series (hide all others;\r\n // if already isolated, restore the full set). Fires the user-supplied\r\n // legendItemDoubleClick callback.\r\n // 2. Outside the legend on a data node → fire nodeDoubleClick.\r\n this.scene.onDblClick = (node, _event) => {\r\n if (!node) return;\r\n\r\n let current = node;\r\n let seriesId: string | null = null;\r\n let insideLegend = false;\r\n while (current) {\r\n if (current.seriesId && !seriesId) seriesId = current.seriesId;\r\n if (current === this.legendGroup || current === this.legend.getGroup()) {\r\n insideLegend = true;\r\n break;\r\n }\r\n current = current.parent;\r\n }\r\n\r\n if (insideLegend) {\r\n if (!seriesId || seriesId === '__legend_prev__' || seriesId === '__legend_next__') return;\r\n\r\n // Build the full set of series IDs the same way the legend item builder did.\r\n const allIds = this.options.series.map((s, i) => s.yKey ?? s.angleKey ?? `s${i}`);\r\n const others = allIds.filter(id => id !== seriesId);\r\n // Already isolated when every \"other\" series is currently hidden.\r\n const isIsolated = others.every(id => this.hiddenSeries.includes(id));\r\n\r\n if (isIsolated) {\r\n this.hiddenSeries = []; // restore everything\r\n } else {\r\n this.hiddenSeries = others; // hide every other series\r\n }\r\n\r\n this.options.legend?.listeners?.legendItemDoubleClick?.({\r\n seriesId,\r\n isolated: !isIsolated,\r\n });\r\n\r\n this.legend.setHiddenSeries([...this.hiddenSeries]);\r\n this.processData();\r\n this.performLayout();\r\n this.render();\r\n return;\r\n }\r\n\r\n if (node.datum && this.options.listeners?.nodeDoubleClick) {\r\n const seriesOpt = this.options.series.find(\r\n so => (so.yKey ?? so.angleKey ?? '') === seriesId\r\n );\r\n this.options.listeners.nodeDoubleClick({\r\n seriesId: seriesId ?? '',\r\n datum: node.datum,\r\n xKey: seriesOpt?.xKey,\r\n yKey: seriesOpt?.yKey,\r\n type: seriesOpt?.type,\r\n });\r\n }\r\n };\r\n }\r\n\r\n /** Public accessor for the tooltip state store (consumed by React wrappers). */\r\n getTooltipStore(): TooltipStore { return this.tooltipStore; }\r\n\r\n /**\r\n * Keyboard navigation handler for tooltip accessibility.\r\n * ArrowLeft/Right cycle through X-axis data points.\r\n */\r\n private _handleKeyboard(e: KeyboardEvent) {\r\n if (!this.initialized || !this.isCartesian) return;\r\n const data = this.options.data;\r\n if (!data?.length) return;\r\n\r\n const xKey = this.options.series[0]?.xKey;\r\n if (!xKey) return;\r\n\r\n if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') {\r\n e.preventDefault();\r\n const delta = e.key === 'ArrowRight' ? 1 : -1;\r\n this._kbIndex = Math.max(0, Math.min(data.length - 1, this._kbIndex + delta));\r\n\r\n const sr = this.seriesRect;\r\n const theme = this.themeManager.theme;\r\n const palette = theme.palette;\r\n\r\n this.crosshair.show(\r\n sr.x + sr.width / 2, sr.y + sr.height / 2, sr, theme,\r\n this.categoryScale instanceof BandScale ? this.categoryScale : undefined,\r\n data, xKey,\r\n );\r\n this.options.onFocusChange?.(this._kbIndex);\r\n } else if (e.key === 'Escape') {\r\n e.preventDefault();\r\n this.tooltipStore.deactivate();\r\n this.crosshair.hide();\r\n this.crosshair.hideSeriesSnaps();\r\n this._kbIndex = -1;\r\n this.options.onFocusChange?.(null);\r\n } else if (e.key === 'Home') {\r\n e.preventDefault();\r\n this._kbIndex = 0;\r\n // Re-trigger via synthetic ArrowRight at index 0\r\n this._handleKeyboard(new KeyboardEvent('keydown', { key: 'ArrowLeft' }));\r\n this._kbIndex = 0;\r\n } else if (e.key === 'End') {\r\n e.preventDefault();\r\n this._kbIndex = data.length - 1;\r\n this._handleKeyboard(new KeyboardEvent('keydown', { key: 'ArrowRight' }));\r\n this._kbIndex = data.length - 1;\r\n }\r\n }\r\n\r\n update(options: RadiantChartOptions) {\r\n const dataChanged = options.data !== this.lastDataRef;\r\n this.lastDataRef = options.data;\r\n\r\n this.options = options;\r\n if (options.theme) this.themeManager.setTheme(options.theme as ThemeOption);\r\n const themeBackground = this.themeManager.theme.backgroundColor;\r\n this.container.style.backgroundColor = themeBackground;\r\n this.scene.backgroundColor = themeBackground;\r\n this.container.style.transition = 'background-color 0.3s';\r\n this.crosshair.updateOptions(options.crosshair ?? {});\r\n this.tooltipStore.setOptions(options.tooltip ?? {});\r\n this._syncMediaQueryListener();\r\n this.processData();\r\n this.performLayout(dataChanged);\r\n this.render();\r\n }\r\n\r\n /**\r\n * Attaches the `prefers-color-scheme` listener when theme is 'system', or\r\n * removes it when the theme has changed away from 'system'. Safe to call\r\n * repeatedly — it is idempotent (won't double-attach).\r\n */\r\n private _syncMediaQueryListener() {\r\n if (typeof window === 'undefined') return;\r\n\r\n const needsListener = this.options.theme === 'system';\r\n\r\n if (needsListener && !this.mediaQuery) {\r\n this.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\r\n this.mediaQuery.addEventListener('change', this._onSystemThemeChange);\r\n } else if (!needsListener && this.mediaQuery) {\r\n this.mediaQuery.removeEventListener('change', this._onSystemThemeChange);\r\n this.mediaQuery = null;\r\n }\r\n }\r\n\r\n private processData() {\r\n // Normalize series types to avoid fallback rendering\r\n const series = (this.options.series || []).map(s => {\r\n const type = (s.type || '').toLowerCase().replace(/[-_ ]/g, '');\r\n let yAxisId = s.yAxisId;\r\n if (!yAxisId && type === 'line' && s.yKey && /percent|cumulative|pareto/i.test(s.yKey)) {\r\n yAxisId = 'right';\r\n }\r\n return { ...s, type, yAxisId };\r\n });\r\n this.options = { ...this.options, series: series as any };\r\n const { data } = this.options;\r\n this.emptyGroup.clear();\r\n\r\n if (!data?.length || !series?.length) {\r\n this.isCartesian = false;\r\n this.initialized = true;\r\n this.axesGroup.visible = false;\r\n this.seriesGroup.clear();\r\n // Hide the legend when there is no data — prevents stale legend items\r\n // from persisting after a data clear (e.g. Interactive Editor removes\r\n // the `data` key and clicks \"Run\").\r\n this.legendGroup.visible = false;\r\n this.legend.getGroup().visible = false;\r\n this.series = [];\r\n this.seriesInstances.clear();\r\n return;\r\n }\r\n\r\n this.isCartesian = series.every(s => !NON_CARTESIAN.has(s.type ?? ''));\r\n\r\n if (this.isCartesian) {\r\n const xKeys = new Set<any>();\r\n this.minY = Infinity;\r\n this.maxY = -Infinity;\r\n\r\n const isContinuousX = series.some(s => s.type === 'scatter');\r\n if (isContinuousX) {\r\n this.categoryScale = new LinearScale();\r\n this.valueScale = new LinearScale();\r\n } else {\r\n this.categoryScale = new BandScale();\r\n this.valueScale = new LinearScale();\r\n }\r\n\r\n const stackedBars = series.filter(s => s.type === 'bar' && (s.stacked || s.normalized));\r\n const stackedAreas = series.filter(s => s.type === 'area' && (s.stacked || s.normalized));\r\n const colTotals = data.map(d => stackedBars.reduce((t, s) => t + (d[s.yKey!] ?? 0), 0));\r\n const areaColTotals = data.map(d => stackedAreas.reduce((t, s) => t + (d[s.yKey!] ?? 0), 0));\r\n\r\n if (stackedBars.length > 0) {\r\n if (series.some(s => s.type === 'bar' && s.normalized)) this.maxY = 100;\r\n else {\r\n data.forEach((_, i) => { this.maxY = Math.max(this.maxY, colTotals[i]); });\r\n }\r\n }\r\n if (stackedAreas.length > 0) {\r\n if (series.some(s => s.type === 'area' && s.normalized)) {\r\n this.maxY = Math.max(this.maxY, 100);\r\n } else {\r\n data.forEach((_, i) => { this.maxY = Math.max(this.maxY, areaColTotals[i]); });\r\n }\r\n }\r\n\r\n const xKeyFields = new Set<string>();\r\n const yKeyFields = new Set<string>();\r\n series.forEach(s => {\r\n if (s.xKey) xKeyFields.add(s.xKey);\r\n });\r\n\r\n series.forEach((s, sIdx) => {\r\n const seriesId = s.yKey ?? s.angleKey ?? `s${sIdx}`;\r\n const isHidden = this.hiddenSeries.includes(seriesId);\r\n if (!isHidden && s.yKey && !s.stacked && !s.normalized && s.type !== 'histogram') {\r\n yKeyFields.add(s.yKey);\r\n }\r\n });\r\n\r\n data.forEach(d => {\r\n xKeyFields.forEach(k => { if (d[k] !== undefined) xKeys.add(d[k]); });\r\n yKeyFields.forEach(k => {\r\n const v = d[k];\r\n if (v > this.maxY) this.maxY = v;\r\n if (v < this.minY) this.minY = v;\r\n });\r\n });\r\n\r\n if (this.categoryScale instanceof BandScale) {\r\n this.categoryScale.domain = Array.from(xKeys);\r\n } else {\r\n const numericX = Array.from(xKeys).map(v => typeof v === 'number' ? v : Number(new Date(v))).filter(v => !isNaN(v));\r\n if (numericX.length > 0) {\r\n const minX = Math.min(...numericX);\r\n const maxX = Math.max(...numericX);\r\n this.categoryScale.domain = [minX, maxX];\r\n }\r\n }\r\n\r\n if (this.valueScale instanceof BandScale) {\r\n const yKeys = new Set<any>();\r\n series.forEach(s => {\r\n if (s.yKey) data.forEach(d => yKeys.add(d[s.yKey!]));\r\n });\r\n this.valueScale.domain = Array.from(yKeys);\r\n } else {\r\n const mustStartAtZero = series.some(s => s.type === 'bar' || s.type === 'area');\r\n const dMin = mustStartAtZero ? Math.min(0, this.minY) : this.minY;\r\n const dMax = this.maxY === -Infinity ? 100 : this.maxY;\r\n this.valueScale.domain = [dMin * (dMin < 0 ? 1.1 : 0.98), dMax * 1.05];\r\n }\r\n const hasRightAxis = series.some(s => s.yAxisId === 'right');\r\n if (hasRightAxis) {\r\n let minYRight = 0, maxYRight = -Infinity;\r\n series.forEach(s => {\r\n if (s.yAxisId === 'right' && s.yKey) {\r\n data.forEach(d => {\r\n const v = d[s.yKey!];\r\n if (v > maxYRight) maxYRight = v;\r\n if (v < minYRight) minYRight = v;\r\n });\r\n }\r\n });\r\n this.valueScaleRight.domain = [minYRight, (maxYRight === -Infinity ? 100 : maxYRight) * 1.12];\r\n }\r\n\r\n const isH = series.some(s =>\r\n (s.type === 'bar' && s.direction === 'horizontal')\r\n );\r\n const theme = this.themeManager.theme;\r\n this.axesGroup.clear();\r\n\r\n if (!isH) {\r\n this.xAxis = new CartesianAxis(this.categoryScale, { \r\n position: 'bottom',\r\n fontSize: this.options.xAxisFontSize,\r\n fontFamily: this.options.xAxisFontFamily,\r\n rotation: this.options.xAxisRotation,\r\n labelAlignment: this.options.xAxisLabelAlignment\r\n });\r\n this.yAxis = new CartesianAxis(this.valueScale, { \r\n position: 'left',\r\n fontSize: this.options.yAxisFontSize,\r\n fontFamily: this.options.yAxisFontFamily,\r\n rotation: this.options.yAxisRotation,\r\n labelAlignment: this.options.yAxisLabelAlignment\r\n });\r\n if (series.some(s => s.yAxisId === 'right')) {\r\n this.yAxisRight = new CartesianAxis(this.valueScaleRight, {\r\n position: 'right',\r\n fontSize: this.options.yAxisRightFontSize ?? this.options.yAxisFontSize,\r\n fontFamily: this.options.yAxisRightFontFamily ?? this.options.yAxisFontFamily,\r\n rotation: this.options.yAxisRightRotation ?? this.options.yAxisRotation,\r\n labelAlignment: this.options.yAxisRightLabelAlignment ?? this.options.yAxisLabelAlignment\r\n });\r\n } else {\r\n this.yAxisRight = undefined;\r\n }\r\n } else {\r\n this.xAxis = new CartesianAxis(this.valueScale, { \r\n position: 'bottom',\r\n fontSize: this.options.xAxisFontSize,\r\n fontFamily: this.options.xAxisFontFamily,\r\n rotation: this.options.xAxisRotation,\r\n labelAlignment: this.options.xAxisLabelAlignment\r\n });\r\n this.yAxis = new CartesianAxis(this.categoryScale, { \r\n position: 'left',\r\n fontSize: this.options.yAxisFontSize,\r\n fontFamily: this.options.yAxisFontFamily,\r\n rotation: this.options.yAxisRotation,\r\n labelAlignment: this.options.yAxisLabelAlignment\r\n });\r\n this.yAxisRight = undefined;\r\n }\r\n this.xAxis.setTheme(theme); this.yAxis.setTheme(theme);\r\n this.axesGroup.add(this.xAxis.getGroup());\r\n this.axesGroup.add(this.yAxis.getGroup());\r\n if (this.yAxisRight) {\r\n this.yAxisRight.setTheme(theme);\r\n this.axesGroup.add(this.yAxisRight.getGroup());\r\n }\r\n this.axesGroup.visible = true;\r\n } else {\r\n this.axesGroup.visible = false;\r\n }\r\n }\r\n\r\n private createSeriesInstance(s: any, i: number): any {\r\n const palette = this.themeManager.theme.palette;\r\n const color = s.fill ?? palette[i % palette.length];\r\n const animation = { ...this.options.animation, ...s.animation };\r\n const base = { ...s, fill: color, stroke: s.stroke ?? color, animation };\r\n\r\n switch (s.type) {\r\n case 'bar': return new BarSeries(base as any);\r\n case 'line': return new LineSeries(base as any);\r\n case 'pie': return new PieSeries({ ...s, fills: s.fills ?? palette } as any);\r\n case 'donut': return new PieSeries({ ...s, fills: s.fills ?? palette, innerRadius: s.innerRadius ?? 0.6 } as any);\r\n case 'area': return new AreaSeries(base as any);\r\n case 'scatter': return new ScatterSeries({ ...base, jitter: s.jitter } as any);\r\n default: return null;\r\n }\r\n }\r\n\r\n private renderEmpty() {\r\n const { width, height } = this.container.getBoundingClientRect();\r\n if (!width || !height) return;\r\n const theme = this.themeManager.theme;\r\n\r\n const icon = new Text();\r\n icon.text = '⬜';\r\n icon.x = width / 2; icon.y = height / 2 - 20;\r\n icon.fontSize = 26; icon.fill = theme.axisColor;\r\n icon.textAlign = 'center'; icon.textBaseline = 'middle';\r\n this.emptyGroup.add(icon);\r\n\r\n const msg = new Text();\r\n msg.text = 'No data available';\r\n msg.x = width / 2; msg.y = height / 2 + 16;\r\n msg.fontSize = 13; msg.fill = theme.subtextColor;\r\n msg.fontFamily = theme.fontFamily;\r\n msg.textAlign = 'center'; msg.textBaseline = 'middle';\r\n this.emptyGroup.add(msg);\r\n }\r\n\r\n private performLayout(shouldAnimate: boolean = false) {\r\n const { width, height } = this.container.getBoundingClientRect();\r\n if (!width || !height) return;\r\n\r\n this.axesGroup.opacity = 1;\r\n this.seriesGroup.opacity = 1;\r\n\r\n // Default padding is intentionally minimal so charts fill their container.\r\n // When the user sets padding these defaults are replaced entirely.\r\n const pad = this.options.padding ?? { top: 4, right: 4, bottom: 0, left: 4 };\r\n let top = pad.top ?? 4;\r\n let bottom = height - (pad.bottom ?? 0);\r\n let left = pad.left ?? 4;\r\n let right = width - (pad.right ?? 4);\r\n const innerPad = (pad as any).inner ?? 0;\r\n\r\n const theme = this.themeManager.theme;\r\n\r\n // Title / subtitle\r\n this.titleGroup.clear(); this.subtitleGroup.clear();\r\n if (this.options.title) {\r\n const t = new Text();\r\n t.text = this.options.title.text; t.fontSize = this.options.title.fontSize ?? 16;\r\n t.fontWeight = '600'; t.fill = theme.textColor; t.fontFamily = theme.fontFamily;\r\n t.x = width / 2; t.y = top + t.fontSize; t.textAlign = 'center';\r\n this.titleGroup.add(t);\r\n top += t.fontSize + 8;\r\n }\r\n if (this.options.subtitle) {\r\n const s = new Text();\r\n s.text = this.options.subtitle.text; s.fontSize = this.options.subtitle.fontSize ?? 12;\r\n s.fill = theme.subtextColor; s.fontFamily = theme.fontFamily;\r\n s.x = width / 2; s.y = top + s.fontSize; s.textAlign = 'center';\r\n this.subtitleGroup.add(s);\r\n top += s.fontSize + 6;\r\n }\r\n\r\n // Legend\r\n const legendOpt = this.options.legend;\r\n const showLegend = legendOpt?.enabled !== false && this.options.series.length > 1;\r\n\r\n\r\n if (showLegend) {\r\n let items: LegendItem[] = [];\r\n // Chart types that live in the non-Cartesian performLayout branch and\r\n // therefore store their series instance under the `${type}-${i}-null`\r\n // key. When we have to create an instance ahead of the layout pass to\r\n // build the legend, we cache it under the same key so the real render\r\n // re-uses it instead of throwing away our temp and losing its config.\r\n const NON_CARTESIAN_TYPES = new Set(NON_CARTESIAN);\r\n\r\n this.options.series.forEach((sOpt, i) => {\r\n // Try to find an existing instance to delegate legend item generation\r\n let instance: any = null;\r\n for (const [key, inst] of this.seriesInstances.entries()) {\r\n if (key.startsWith(`${sOpt.type}-${i}-`)) {\r\n instance = inst;\r\n break;\r\n }\r\n }\r\n\r\n // If no instance exists (first render), create one and cache it so the\r\n // downstream performLayout pass finds the same object. Previously the\r\n // temp instance was discarded, which — combined with performLayout\r\n // re-creating its own instance — could leave the legend items out of\r\n // sync with the series config on the first paint.\r\n if (!instance) {\r\n instance = this.createSeriesInstance(sOpt, i);\r\n if (instance && NON_CARTESIAN_TYPES.has(sOpt.type as string)) {\r\n this.seriesInstances.set(`${sOpt.type}-${i}-null`, instance);\r\n }\r\n }\r\n\r\n if (instance && typeof instance.getLegendData === 'function') {\r\n const legendItems = instance.getLegendData(theme, this.options.data);\r\n if (Array.isArray(legendItems) && legendItems.length > 0) {\r\n items.push(...legendItems);\r\n } else {\r\n items.push({\r\n id: sOpt.yKey ?? sOpt.angleKey ?? `s${i}`,\r\n label: sOpt.title ?? sOpt.yKey ?? sOpt.angleKey ?? `Series ${i + 1}`,\r\n fill: sOpt.fill ?? theme.palette[i % theme.palette.length],\r\n markerType: (sOpt.type === 'line' || sOpt.type === 'scatter') ? 'circle' : 'square',\r\n });\r\n }\r\n } else {\r\n items.push({\r\n id: sOpt.yKey ?? sOpt.angleKey ?? `s${i}`,\r\n label: sOpt.title ?? sOpt.yKey ?? sOpt.angleKey ?? `Series ${i + 1}`,\r\n fill: sOpt.fill ?? theme.palette[i % theme.palette.length],\r\n markerType: (sOpt.type === 'line' || sOpt.type === 'scatter') ? 'circle' : 'square',\r\n });\r\n }\r\n });\r\n\r\n this.legend.setHiddenSeries([...this.hiddenSeries]);\r\n\r\n const position = legendOpt?.position ?? 'bottom';\r\n const isVertical = position === 'left' || position === 'right';\r\n // For vertical legend, limit width to 30% of container or 200px.\r\n const legendMaxWidth = isVertical ? Math.min(width * 0.3, 200) : width;\r\n\r\n this.legend.update(items, theme, legendMaxWidth, height, position);\r\n // Ensure the legend layer is visible — a previous pass may have hidden\r\n // it if it was empty, and opacity defaults can drift from context.\r\n this.legendGroup.visible = true;\r\n this.legendGroup.opacity = 1;\r\n const legendGroupNode = this.legend.getGroup();\r\n legendGroupNode.visible = true;\r\n legendGroupNode.opacity = 1;\r\n\r\n const lb = this.legend.getBBox();\r\n if (lb.width > 0 && lb.height > 0) {\r\n let lx = 0, ly = 0;\r\n if (position === 'bottom') {\r\n lx = (width - lb.width) / 2 - lb.x;\r\n ly = bottom - lb.height - lb.y;\r\n bottom -= lb.height + 10;\r\n } else if (position === 'top') {\r\n lx = (width - lb.width) / 2 - lb.x;\r\n ly = top - lb.y;\r\n top += lb.height + 10;\r\n } else if (position === 'left') {\r\n lx = left - lb.x;\r\n ly = (height - lb.height) / 2 - lb.y;\r\n left += lb.width + 10;\r\n } else if (position === 'right') {\r\n lx = right - lb.width - lb.x;\r\n ly = (height - lb.height) / 2 - lb.y;\r\n right -= lb.width + 10;\r\n }\r\n\r\n legendGroupNode.translation = { x: lx, y: ly };\r\n\r\n // Update DOM proxy — allows external CSS/DOM targeting (e.g. for\r\n // accessibility tools or CSS-based layout verification) while the\r\n // legend itself remains canvas-rendered for high performance.\r\n if (this.legendProxy) {\r\n this.legendProxy.style.display = 'block';\r\n this.legendProxy.style.left = `${lx + lb.x}px`;\r\n this.legendProxy.style.top = `${ly + lb.y}px`;\r\n this.legendProxy.style.width = `${lb.width}px`;\r\n this.legendProxy.style.height = `${lb.height}px`;\r\n }\r\n } else {\r\n // Fallback for empty/zero bbox\r\n if (position === 'bottom') {\r\n legendGroupNode.translation = { x: 0, y: bottom - 24 };\r\n bottom -= 24;\r\n } else if (position === 'top') {\r\n legendGroupNode.translation = { x: 0, y: top };\r\n top += 24;\r\n }\r\n if (this.legendProxy) this.legendProxy.style.display = 'none';\r\n }\r\n } else {\r\n this.legendGroup.visible = false;\r\n if (this.legendProxy) this.legendProxy.style.display = 'none';\r\n }\r\n\r\n // Axis visibility — default true; false collapses the reserved space to 0\r\n // so the plot fills the full edge with no dead zone.\r\n const showXAxis = this.options.showXAxis !== false;\r\n const showYAxis = this.options.showYAxis !== false;\r\n const showYAxisRight = this.options.showYAxisRight !== false;\r\n\r\n // Dynamic axis sizing — ask each axis how much space its labels actually need.\r\n const ctx = this.scene.getContext();\r\n let yAxisW = 0;\r\n let yAxisRightW = 0;\r\n let xAxisH = 0;\r\n let topAxisH = 0;\r\n const Y_LABEL_DATA_GAP = 12;\r\n\r\n if (this.isCartesian && this.yAxis && showYAxis) {\r\n this.yAxis.setTheme(theme);\r\n this.yAxis.updateOptions({\r\n fontSize: this.options.yAxisFontSize,\r\n fontFamily: this.options.yAxisFontFamily,\r\n rotation: this.options.yAxisRotation,\r\n labelAlignment: this.options.yAxisLabelAlignment\r\n });\r\n yAxisW = this.yAxis.getRequiredSpace(ctx).size + Y_LABEL_DATA_GAP;\r\n // Cap Y-axis width to 40% of container to prevent pushing the chart to oblivion on mobile\r\n const maxYWidth = width * 0.4;\r\n if (yAxisW > maxYWidth) {\r\n yAxisW = maxYWidth;\r\n this.yAxis.setLayoutMaxWidth(yAxisW - Y_LABEL_DATA_GAP);\r\n } else {\r\n this.yAxis.setLayoutMaxWidth(0); // clear any previous cap\r\n }\r\n }\r\n if (this.isCartesian && this.yAxisRight && showYAxisRight) {\r\n this.yAxisRight.setTheme(theme);\r\n this.yAxisRight.updateOptions({\r\n fontSize: this.options.yAxisRightFontSize ?? this.options.yAxisFontSize,\r\n fontFamily: this.options.yAxisRightFontFamily ?? this.options.yAxisFontFamily,\r\n rotation: this.options.yAxisRightRotation ?? this.options.yAxisRotation,\r\n labelAlignment: this.options.yAxisRightLabelAlignment ?? this.options.yAxisLabelAlignment\r\n });\r\n yAxisRightW = this.yAxisRight.getRequiredSpace(ctx).size + Y_LABEL_DATA_GAP;\r\n }\r\n if (this.isCartesian && this.xAxis && showXAxis) {\r\n this.xAxis.setTheme(theme);\r\n this.xAxis.updateOptions({\r\n fontSize: this.options.xAxisFontSize,\r\n fontFamily: this.options.xAxisFontFamily,\r\n rotation: this.options.xAxisRotation,\r\n labelAlignment: this.options.xAxisLabelAlignment\r\n });\r\n xAxisH = this.xAxis.getRequiredSpace(ctx).size;\r\n }\r\n\r\n this.seriesRect = {\r\n x: left + yAxisW,\r\n y: top + topAxisH,\r\n width: right - left - yAxisW - yAxisRightW,\r\n height: bottom - top - xAxisH - topAxisH,\r\n };\r\n const sr = this.seriesRect;\r\n\r\n // Inner plot area (shrunk by innerPad)\r\n const ip = {\r\n x: sr.x + innerPad,\r\n y: sr.y + innerPad,\r\n width: sr.width - innerPad * 2,\r\n height: sr.height - innerPad * 2,\r\n };\r\n\r\n if (this.isCartesian && this.xAxis && this.yAxis) {\r\n this.xAxis.setTheme(theme); this.yAxis.setTheme(theme);\r\n\r\n this.xAxis.getGroup().translation = { x: sr.x, y: sr.y + sr.height };\r\n // Range the axis to include the inner padding\r\n this.xAxis.update(sr.width, 0, showXAxis, innerPad);\r\n this.yAxis.getGroup().translation = { x: sr.x - Y_LABEL_DATA_GAP, y: sr.y };\r\n this.yAxis.update(sr.height, sr.width + Y_LABEL_DATA_GAP, showYAxis, innerPad, Y_LABEL_DATA_GAP);\r\n\r\n if (this.yAxisRight) {\r\n this.yAxisRight.getGroup().translation = { x: sr.x + sr.width + Y_LABEL_DATA_GAP, y: sr.y };\r\n this.yAxisRight.update(sr.height, sr.width + Y_LABEL_DATA_GAP, showYAxisRight, innerPad);\r\n }\r\n\r\n this.seriesGroup.translation = { x: sr.x, y: sr.y };\r\n this.seriesGroup.clipRect = { x: 0, y: 0, width: sr.width, height: sr.height };\r\n\r\n this.seriesGroup.clear();\r\n const usedSeries: any[] = [];\r\n const fData = this.options.data;\r\n\r\n this.options.series.forEach((sOpt, sIdx) => {\r\n const sId = sOpt.yKey ?? sOpt.angleKey ?? `s${sIdx}`;\r\n if (this.hiddenSeries.includes(sId)) return;\r\n\r\n const isH = (sOpt.type === 'bar' && sOpt.direction === 'horizontal');\r\n let catScale: any = isH ? this.yAxis?.scale : this.xAxis?.scale;\r\n let valScale: any = sOpt.yAxisId === 'right' && this.yAxisRight ? this.yAxisRight.scale : (isH ? this.xAxis?.scale : this.yAxis?.scale);\r\n\r\n const decimationType = sOpt.type === 'line' || sOpt.type === 'area';\r\n\r\n const instanceKey = `${sOpt.type}-${sIdx}-null`;\r\n let s = this.seriesInstances.get(instanceKey);\r\n if (!s) {\r\n s = this.createSeriesInstance(sOpt, sIdx);\r\n if (s) this.seriesInstances.set(instanceKey, s);\r\n }\r\n if (!s) return;\r\n usedSeries.push(s);\r\n\r\n this.seriesGroup.add(s.getGroup());\r\n\r\n const subRect = { x: 0, y: 0, width: sr.width, height: sr.height };\r\n\r\n const seriesOptForUpdate: any = decimationType && fData.length > 1000\r\n ? { ...(sOpt as any), marker: { ...(sOpt as any).marker, enabled: false } }\r\n : (sOpt as any);\r\n\r\n if (s instanceof BarSeries) {\r\n const allBars = this.options.series.filter(so => so.type === 'bar');\r\n let barOffsets: number[] | undefined;\r\n let barTotals: number[] | undefined;\r\n\r\n if (sOpt.stacked || sOpt.normalized) {\r\n const allStackedBars = allBars.filter(so => so.stacked || so.normalized);\r\n const myIdx = allStackedBars.indexOf(sOpt);\r\n barOffsets = fData.map(d =>\r\n allStackedBars.slice(0, myIdx).reduce((acc, so) => acc + (d[so.yKey!] ?? 0), 0)\r\n );\r\n barTotals = fData.map(d =>\r\n allStackedBars.reduce((acc, so) => acc + (d[so.yKey!] ?? 0), 0)\r\n );\r\n }\r\n\r\n s.update(fData, catScale as BandScale, valScale, subRect, true, sIdx, allBars.length, barOffsets, barTotals, sOpt as any);\r\n } else if (s instanceof AreaSeries) {\r\n let areaOffsets: number[] | undefined;\r\n let areaTotals: number[] | undefined;\r\n if (sOpt.stacked || sOpt.normalized) {\r\n const allStackedAreas = this.options.series.filter(\r\n so => so.type === 'area' && (so.stacked || so.normalized)\r\n );\r\n const myIdx = allStackedAreas.indexOf(sOpt);\r\n areaOffsets = fData.map(d =>\r\n allStackedAreas.slice(0, myIdx).reduce((acc, so) => acc + (d[so.yKey!] ?? 0), 0)\r\n );\r\n areaTotals = fData.map(d =>\r\n allStackedAreas.reduce((acc, so) => acc + (d[so.yKey!] ?? 0), 0)\r\n );\r\n }\r\n s.update(fData, catScale as BandScale, valScale, subRect, true, areaOffsets, seriesOptForUpdate, areaTotals);\r\n } else if (\r\n s instanceof LineSeries ||\r\n s instanceof ScatterSeries\r\n ) {\r\n s.update(fData, catScale as any, valScale, subRect, true, seriesOptForUpdate);\r\n }\r\n });\r\n this.series = usedSeries;\r\n } else {\r\n this.seriesGroup.translation = { x: 0, y: 0 };\r\n this.seriesGroup.clipRect = { x: sr.x - innerPad, y: sr.y - innerPad, width: sr.width + innerPad * 2, height: sr.height + innerPad * 2 };\r\n this.seriesGroup.clear();\r\n const usedSeries: any[] = [];\r\n this.options.series.forEach((sOpt, i) => {\r\n // Skip hidden series in non-cartesian rendering.\r\n const sId = sOpt.yKey ?? sOpt.angleKey ?? `s${i}`;\r\n if (this.hiddenSeries.includes(sId)) return;\r\n\r\n const instanceKey = `${sOpt.type}-${i}-null`;\r\n let s = this.seriesInstances.get(instanceKey);\r\n if (!s) {\r\n s = this.createSeriesInstance(sOpt, i);\r\n if (s) this.seriesInstances.set(instanceKey, s);\r\n }\r\n if (!s) return;\r\n usedSeries.push(s);\r\n\r\n this.seriesGroup.add(s.getGroup());\r\n if (s instanceof PieSeries) {\r\n s.update(this.options.data, sr, shouldAnimate, sOpt as any);\r\n }\r\n });\r\n this.series = usedSeries;\r\n }\r\n\r\n }\r\n\r\n private render() {\r\n this.scene.render();\r\n }\r\n\r\n /**\r\n * Exports the current chart as a PNG file and triggers a browser download.\r\n *\r\n * @param filename Download filename. Defaults to 'chart.png'.\r\n */\r\n exportToPng(filename = 'chart.png') {\r\n const canvas = this.scene.getCanvas();\r\n const dataUrl = canvas.toDataURL('image/png');\r\n const a = document.createElement('a');\r\n a.href = dataUrl;\r\n a.download = filename;\r\n document.body.appendChild(a);\r\n a.click();\r\n document.body.removeChild(a);\r\n }\r\n\r\n\r\n destroy() {\r\n this.stopLoop();\r\n this.resizeObserver.disconnect();\r\n // Clean up the OS-level color-scheme listener\r\n if (this.mediaQuery) {\r\n this.mediaQuery.removeEventListener('change', this._onSystemThemeChange);\r\n this.mediaQuery = null;\r\n }\r\n this.container.removeEventListener('keydown', this._onKeyDown);\r\n this.container.removeEventListener('pointerleave', this._onPointerLeave);\r\n this.scene.destroy();\r\n this.tooltipStore.destroy();\r\n if (this.legendProxy) {\r\n this.legendProxy.remove();\r\n this.legendProxy = undefined;\r\n }\r\n }\r\n}\r\n","// Radiant Charts — Tooltip React Context\n// Provides the TooltipStore to the React component tree.\n\nimport { createContext, useContext } from 'react';\nimport { TooltipStore } from './TooltipStore';\n\nexport const TooltipStoreContext = createContext<TooltipStore | null>(null);\n\n/**\n * Internal hook to read the TooltipStore from context.\n * Throws if used outside of a TooltipStoreContext provider.\n */\nexport function useTooltipStore(): TooltipStore {\n const store = useContext(TooltipStoreContext);\n if (!store) {\n throw new Error(\n 'useTooltipStore must be used within a RadiantChart or Chart component. ' +\n 'Make sure your component is wrapped in a chart provider.'\n );\n }\n return store;\n}\n","'use client';\r\n\r\n// Radiant Charts - ResponsiveContainer\r\n// High-performance container that measures available space and provides\r\n// explicit pixel dimensions to children so canvas charts render correctly.\r\n\r\nimport React, { useRef, useLayoutEffect, useState, useCallback } from 'react';\r\n\r\nexport interface ResponsiveContainerProps {\r\n /**\r\n * Width of the container. Number = pixels, string = CSS value (e.g. '100%').\r\n * Default: '100%'\r\n */\r\n width?: number | string;\r\n /**\r\n * Height of the container. Number = pixels, string = CSS value (e.g. '100%').\r\n * When '100%' the container observes its parent and fills it.\r\n * Default: 300\r\n */\r\n height?: number | string;\r\n /** Minimum height in px applied as a CSS floor. Default: 100 */\r\n minHeight?: number;\r\n /** Minimum width in px applied as a CSS floor. Default: 0 */\r\n minWidth?: number;\r\n /**\r\n * Aspect ratio (width ÷ height). When set, height is derived from the\r\n * measured container width and this ratio. Overrides `height`.\r\n */\r\n aspect?: number;\r\n /**\r\n * Debounce resize callbacks by N ms to avoid excessive re-renders.\r\n * Default: 0 (no debounce)\r\n */\r\n debounce?: number;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n children: React.ReactNode;\r\n}\r\n\r\nconst ResponsiveContainer: React.FC<ResponsiveContainerProps> = ({\r\n width = '100%',\r\n height = 300,\r\n minHeight = 100,\r\n minWidth = 0,\r\n aspect,\r\n debounce = 0,\r\n className,\r\n style,\r\n children,\r\n}) => {\r\n const wrapperRef = useRef<HTMLDivElement>(null);\r\n const [containerSize, setContainerSize] = useState<{ width: number; height: number } | null>(null);\r\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\r\n\r\n const applySize = useCallback((w: number, h: number) => {\r\n setContainerSize({ width: w, height: h });\r\n }, []);\r\n\r\n const handleEntries = useCallback((entries: ResizeObserverEntry[]) => {\r\n for (const entry of entries) {\r\n const { width: w, height: h } = entry.contentRect;\r\n if (w === 0 && h === 0) continue;\r\n if (debounce > 0) {\r\n if (debounceTimer.current) clearTimeout(debounceTimer.current);\r\n debounceTimer.current = setTimeout(() => applySize(w, h), debounce);\r\n } else {\r\n applySize(w, h);\r\n }\r\n }\r\n }, [debounce, applySize]);\r\n\r\n useLayoutEffect(() => {\r\n const el = wrapperRef.current;\r\n if (!el) return;\r\n\r\n // Seed with current size immediately so the first render isn't 0×0\r\n const rect = el.getBoundingClientRect();\r\n if (rect.width > 0 || rect.height > 0) {\r\n applySize(rect.width, rect.height);\r\n }\r\n\r\n const ro = new ResizeObserver(handleEntries);\r\n ro.observe(el);\r\n return () => {\r\n ro.disconnect();\r\n if (debounceTimer.current) clearTimeout(debounceTimer.current);\r\n };\r\n }, [handleEntries, applySize]);\r\n\r\n // Resolve the effective height for the wrapper div:\r\n // - aspect ratio wins if provided\r\n // - a number height is used directly\r\n // - a string height ('100%' etc.) is used as-is; the ResizeObserver on\r\n // the wrapper will then report the pixel size to children\r\n const effectiveHeight: number | string = aspect && containerSize\r\n ? Math.max(minHeight, containerSize.width / aspect)\r\n : height;\r\n\r\n return (\r\n <div\r\n ref={wrapperRef}\r\n className={className}\r\n style={{\r\n position: 'relative',\r\n width,\r\n height: effectiveHeight,\r\n minHeight,\r\n minWidth,\r\n overflow: 'hidden',\r\n ...style,\r\n }}\r\n >\r\n {/*\r\n Inner div is absolutely positioned to fill the wrapper. This ensures\r\n that when `height` is a percentage string, the children receive a\r\n concrete pixel-sized parent (the wrapper is measured by ResizeObserver\r\n and re-renders with an explicit pixel height on the next tick, but the\r\n absolute fill guarantees no CLS even on the first render).\r\n */}\r\n <div style={{ position: 'absolute', inset: 0 }}>\r\n {children}\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\nexport default ResponsiveContainer;\r\n\r\n","'use client';\n\n/**\n * Radiant Charts — Declarative JSX API\n *\n * Provides a composable, JSX-first interface that React developers expect.\n * Children register their configuration with the parent <Chart> via context;\n * the parent assembles a standard RadiantChartOptions object and renders a\n * single imperative RadiantChart under the hood.\n *\n * @example\n * ```tsx\n * import { Chart, Bar, Line, XAxis, YAxis, Title, Legend } from 'radiant-charts/Declarative';\n *\n * const data = [\n * { month: 'Jan', sales: 120, target: 100 },\n * { month: 'Feb', sales: 150, target: 130 },\n * { month: 'Mar', sales: 135, target: 140 },\n * ];\n *\n * export default function Revenue() {\n * return (\n * <Chart data={data} theme=\"dark\" height={400}>\n * <Title text=\"Monthly Revenue\" />\n * <Legend position=\"bottom\" />\n * <XAxis fontSize={11} rotation={-45} />\n * <YAxis show={false} />\n * <Bar xKey=\"month\" yKey=\"sales\" fill=\"#4e79a7\" cornerRadius={4} />\n * <Line xKey=\"month\" yKey=\"target\" stroke=\"#e15759\" />\n * </Chart>\n * );\n * }\n * ```\n */\n\nimport React, {\n createContext,\n useContext,\n useCallback,\n useRef,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport RadiantChart, {\n RadiantChartOptions,\n AnimationOptions,\n DataLabelOptions,\n RadiantChartHandle,\n} from './RadiantChart';\nimport type { TooltipOptions } from './tooltip/types';\n\n// ─── Internal Registration Types ──────────────────────────────────────────────\n\n/** Every series child resolves to one of these registration entries. */\ninterface SeriesRegistration {\n id: string;\n /** The props as-is from the JSX component, minus React children. */\n props: Record<string, any>;\n}\n\ninterface AxisRegistration {\n axis: 'x' | 'y' | 'y-right';\n props: Record<string, any>;\n}\n\ninterface TitleRegistration {\n kind: 'title' | 'subtitle';\n props: { text: string; fontSize?: number; fill?: string };\n}\n\ninterface LegendRegistration {\n enabled?: boolean;\n position?: 'top' | 'bottom' | 'left' | 'right';\n}\n\ninterface ChartContextValue {\n registerSeries: (id: string, props: Record<string, any>) => void;\n unregisterSeries: (id: string) => void;\n registerAxis: (id: string, axis: AxisRegistration) => void;\n unregisterAxis: (id: string) => void;\n registerTitle: (id: string, reg: TitleRegistration) => void;\n unregisterTitle: (id: string) => void;\n registerLegend: (id: string, reg: LegendRegistration) => void;\n unregisterLegend: (id: string) => void;\n}\n\nconst ChartContext = createContext<ChartContextValue | null>(null);\n\nfunction useChartContext(): ChartContextValue {\n const ctx = useContext(ChartContext);\n if (!ctx) throw new Error('Radiant declarative components must be children of <Chart>.');\n return ctx;\n}\n\n// ─── ID Generator ─────────────────────────────────────────────────────────────\n\nlet _nextId = 0;\nfunction useStableId(prefix: string): string {\n const ref = useRef<string>('');\n if (ref.current === '') ref.current = `${prefix}-${_nextId++}`;\n return ref.current;\n}\n\n// ─── <Chart> ──────────────────────────────────────────────────────────────────\n\nexport interface ChartProps {\n /** The data array shared by all series children. */\n data: readonly any[];\n /** Color theme. Accepts 'light', 'dark', or 'system'. */\n theme?: 'light' | 'dark' | 'system';\n /** Chart width. Number = px, string = CSS value. Default '100%'. */\n width?: number | string;\n /** Chart height. Number = px, string = CSS value. Default '100%'. */\n height?: number | string;\n /** Global animation options applied to all series. */\n animation?: AnimationOptions;\n /** Padding around the plot area. */\n padding?: {\n top?: number;\n right?: number;\n bottom?: number;\n left?: number;\n inner?: number;\n };\n /** Crosshair configuration. */\n crosshair?: { x?: boolean; y?: boolean };\n /** Tooltip configuration. */\n tooltip?: TooltipOptions;\n /** Show the export toolbar in the top-right corner. */\n showExport?: boolean;\n /** Additional class name applied to the container. */\n className?: string;\n /** Inline style applied to the container. */\n style?: React.CSSProperties;\n /** Access the imperative chart handle (e.g. exportToPng). */\n chartRef?: React.Ref<RadiantChartHandle>;\n /** Declarative series, axis, title, legend, and annotation children. */\n children?: React.ReactNode;\n}\n\nexport const Chart: React.FC<ChartProps> = ({\n data,\n theme,\n width,\n height,\n animation,\n padding,\n crosshair,\n tooltip,\n showExport,\n className,\n style,\n chartRef,\n children,\n}) => {\n // ── Mutable registries (writes don't trigger re-render) ───────────────\n const seriesMap = useRef(new Map<string, Record<string, any>>());\n const axisMap = useRef(new Map<string, AxisRegistration>());\n const titleMap = useRef(new Map<string, TitleRegistration>());\n const legendMap = useRef(new Map<string, LegendRegistration>());\n // Incremented to signal a rebuild of the options object.\n const [rev, setRev] = useState(0);\n const bump = useCallback(() => setRev(r => r + 1), []);\n\n // ── Context value (stable across renders) ─────────────────────────────\n const ctx = useMemo<ChartContextValue>(() => ({\n registerSeries: (id, props) => { seriesMap.current.set(id, props); bump(); },\n unregisterSeries: (id) => { seriesMap.current.delete(id); bump(); },\n registerAxis: (id, a) => { axisMap.current.set(id, a); bump(); },\n unregisterAxis: (id) => { axisMap.current.delete(id); bump(); },\n registerTitle: (id, t) => { titleMap.current.set(id, t); bump(); },\n unregisterTitle: (id) => { titleMap.current.delete(id); bump(); },\n registerLegend: (id, l) => { legendMap.current.set(id, l); bump(); },\n unregisterLegend: (id) => { legendMap.current.delete(id); bump(); },\n }), [bump]);\n\n // ── Build RadiantChartOptions from all registrations ──────────────────\n const options = useMemo<RadiantChartOptions>(() => {\n // --- Series ---\n const series: any[] = [];\n seriesMap.current.forEach(props => {\n series.push(props);\n });\n // Guarantee at least one series entry so the engine doesn't error.\n if (series.length === 0) {\n series.push({ type: 'bar', xKey: 'x', yKey: 'y' });\n }\n\n // --- Axes ---\n let showXAxis: boolean | undefined;\n let showYAxis: boolean | undefined;\n let showYAxisRight: boolean | undefined;\n let xAxisFontSize: number | undefined;\n let xAxisFontFamily: string | undefined;\n let xAxisRotation: number | undefined;\n let xAxisLabelAlignment: 'start' | 'center' | 'end' | undefined;\n let yAxisFontSize: number | undefined;\n let yAxisFontFamily: string | undefined;\n let yAxisRotation: number | undefined;\n let yAxisLabelAlignment: 'start' | 'center' | 'end' | undefined;\n let yAxisRightFontSize: number | undefined;\n let yAxisRightFontFamily: string | undefined;\n let yAxisRightRotation: number | undefined;\n let yAxisRightLabelAlignment: 'start' | 'center' | 'end' | undefined;\n\n axisMap.current.forEach(({ axis, props }) => {\n if (axis === 'x') {\n showXAxis = props.show ?? true;\n xAxisFontSize = props.fontSize;\n xAxisFontFamily = props.fontFamily;\n xAxisRotation = props.rotation;\n xAxisLabelAlignment = props.labelAlignment;\n } else if (axis === 'y') {\n showYAxis = props.show ?? true;\n yAxisFontSize = props.fontSize;\n yAxisFontFamily = props.fontFamily;\n yAxisRotation = props.rotation;\n yAxisLabelAlignment = props.labelAlignment;\n } else if (axis === 'y-right') {\n showYAxisRight = props.show ?? true;\n yAxisRightFontSize = props.fontSize;\n yAxisRightFontFamily = props.fontFamily;\n yAxisRightRotation = props.rotation;\n yAxisRightLabelAlignment = props.labelAlignment;\n }\n });\n\n // --- Title / Subtitle ---\n let title: RadiantChartOptions['title'];\n let subtitle: RadiantChartOptions['subtitle'];\n titleMap.current.forEach(t => {\n if (t.kind === 'title') title = t.props;\n else subtitle = t.props;\n });\n\n // --- Legend ---\n let legend: RadiantChartOptions['legend'];\n legendMap.current.forEach(l => {\n legend = { enabled: l.enabled ?? true, position: l.position };\n });\n\n // --- Tooltip ---\n // Scanned directly from the JSX children tree rather than the registry,\n // because these are lightweight config markers — no mount side-effects needed.\n let tooltipFromChild: TooltipOptions | undefined;\n React.Children.forEach(children, (child) => {\n if (React.isValidElement(child) && child.type === Tooltip) {\n tooltipFromChild = child.props as TooltipOptions;\n }\n });\n\n return {\n data,\n theme,\n animation,\n padding,\n crosshair,\n tooltip: tooltipFromChild ? { ...tooltip, ...tooltipFromChild } : tooltip,\n toolbar: showExport ? { showExport: true } : undefined,\n title,\n subtitle,\n legend,\n showXAxis,\n showYAxis,\n showYAxisRight,\n xAxisFontSize,\n xAxisFontFamily,\n xAxisRotation,\n xAxisLabelAlignment,\n yAxisFontSize,\n yAxisFontFamily,\n yAxisRotation,\n yAxisLabelAlignment,\n yAxisRightFontSize,\n yAxisRightFontFamily,\n yAxisRightRotation,\n yAxisRightLabelAlignment,\n series,\n };\n // rev is the rebuild signal — it isn't used in the body but must be in\n // the dependency array so useMemo re-runs when children register/unregister.\n // children is included so Tooltip prop changes are picked up immediately.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [data, theme, animation, padding, crosshair, tooltip, showExport, children, rev]);\n\n return (\n <ChartContext.Provider value={ctx}>\n {/* Render children so their effects fire and register with ctx */}\n {children}\n <RadiantChart\n ref={chartRef}\n options={options}\n width={width}\n height={height}\n className={className}\n style={style}\n />\n </ChartContext.Provider>\n );\n};\n\n// ─── Series Components ────────────────────────────────────────────────────────\n//\n// Each component is a \"config-only\" node: it renders nothing visible.\n// On mount it registers its props with the parent <Chart> context;\n// on unmount it unregisters. Prop changes trigger a re-registration.\n\n/** Shared props accepted by every series component. */\ninterface CommonSeriesProps {\n xKey?: string;\n yKey?: string;\n fill?: string;\n stroke?: string;\n strokeWidth?: number;\n fillOpacity?: number;\n cornerRadius?: number;\n title?: string;\n grouped?: boolean;\n stacked?: boolean;\n normalized?: boolean;\n direction?: 'vertical' | 'horizontal';\n interpolation?: 'linear' | 'step' | 'smooth';\n marker?: { enabled?: boolean; size?: number; fill?: string };\n labels?: DataLabelOptions;\n animation?: AnimationOptions;\n yAxisId?: 'left' | 'right';\n /** Any additional props are forwarded verbatim to the engine. */\n [key: string]: any;\n}\n\nfunction createSeriesComponent(seriesType: string, displayName: string) {\n const Component: React.FC<CommonSeriesProps> = (props) => {\n const id = useStableId(seriesType);\n const ctx = useChartContext();\n\n // Build the full props blob including `type`.\n const blob = useMemo(\n () => ({ type: seriesType, ...props }),\n // Fast-path: serialise props to catch deep changes without a manual dep list.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [JSON.stringify(props)],\n );\n\n useEffect(() => {\n ctx.registerSeries(id, blob);\n return () => ctx.unregisterSeries(id);\n }, [ctx, id, blob]);\n\n return null; // Config-only — no DOM output\n };\n Component.displayName = displayName;\n return Component;\n}\n\n// ── Primary series ────────────────────────────────────────────────────────────\n\nexport const Bar = createSeriesComponent('bar', 'Bar');\nexport const Line = createSeriesComponent('line', 'Line');\nexport const Area = createSeriesComponent('area', 'Area');\nexport const Scatter = createSeriesComponent('scatter', 'Scatter');\nexport const Pie = createSeriesComponent('pie', 'Pie');\nexport const Donut = createSeriesComponent('donut', 'Donut');\n\n\n// ─── Axis Components ──────────────────────────────────────────────────────────\n\nexport interface AxisProps {\n /** Show or hide this axis. Default: true. */\n show?: boolean;\n /** Font size for axis labels in px. */\n fontSize?: number;\n /** Font family for axis labels. */\n fontFamily?: string;\n /** Label rotation in degrees. */\n rotation?: number;\n /** Label alignment. */\n labelAlignment?: 'start' | 'center' | 'end';\n}\n\nexport const XAxis: React.FC<AxisProps> = (props) => {\n const id = useStableId('x-axis');\n const ctx = useChartContext();\n const blob = useMemo(() => ({ axis: 'x' as const, props }), [JSON.stringify(props)]); // eslint-disable-line react-hooks/exhaustive-deps\n useEffect(() => {\n ctx.registerAxis(id, blob);\n return () => ctx.unregisterAxis(id);\n }, [ctx, id, blob]);\n return null;\n};\nXAxis.displayName = 'XAxis';\n\nexport const YAxis: React.FC<AxisProps> = (props) => {\n const id = useStableId('y-axis');\n const ctx = useChartContext();\n const blob = useMemo(() => ({ axis: 'y' as const, props }), [JSON.stringify(props)]); // eslint-disable-line react-hooks/exhaustive-deps\n useEffect(() => {\n ctx.registerAxis(id, blob);\n return () => ctx.unregisterAxis(id);\n }, [ctx, id, blob]);\n return null;\n};\nYAxis.displayName = 'YAxis';\n\nexport const YAxisRight: React.FC<AxisProps> = (props) => {\n const id = useStableId('y-axis-right');\n const ctx = useChartContext();\n const blob = useMemo(() => ({ axis: 'y-right' as const, props }), [JSON.stringify(props)]); // eslint-disable-line react-hooks/exhaustive-deps\n useEffect(() => {\n ctx.registerAxis(id, blob);\n return () => ctx.unregisterAxis(id);\n }, [ctx, id, blob]);\n return null;\n};\nYAxisRight.displayName = 'YAxisRight';\n\n// ─── Title & Subtitle ─────────────────────────────────────────────────────────\n\nexport interface TitleProps {\n text: string;\n fontSize?: number;\n fill?: string;\n}\n\nexport const Title: React.FC<TitleProps> = (props) => {\n const id = useStableId('title');\n const ctx = useChartContext();\n const blob = useMemo(\n () => ({ kind: 'title' as const, props }),\n [JSON.stringify(props)], // eslint-disable-line react-hooks/exhaustive-deps\n );\n useEffect(() => {\n ctx.registerTitle(id, blob);\n return () => ctx.unregisterTitle(id);\n }, [ctx, id, blob]);\n return null;\n};\nTitle.displayName = 'Title';\n\nexport const Subtitle: React.FC<TitleProps> = (props) => {\n const id = useStableId('subtitle');\n const ctx = useChartContext();\n const blob = useMemo(\n () => ({ kind: 'subtitle' as const, props }),\n [JSON.stringify(props)], // eslint-disable-line react-hooks/exhaustive-deps\n );\n useEffect(() => {\n ctx.registerTitle(id, blob);\n return () => ctx.unregisterTitle(id);\n }, [ctx, id, blob]);\n return null;\n};\nSubtitle.displayName = 'Subtitle';\n\n// ─── Legend ───────────────────────────────────────────────────────────────────\n\nexport interface LegendProps {\n /** Show or hide the legend. Default: true. */\n enabled?: boolean;\n /** Legend placement. */\n position?: 'top' | 'bottom' | 'left' | 'right';\n}\n\nexport const Legend: React.FC<LegendProps> = (props) => {\n const id = useStableId('legend');\n const ctx = useChartContext();\n const blob = useMemo(\n () => ({ enabled: props.enabled, position: props.position }),\n [props.enabled, props.position],\n );\n useEffect(() => {\n ctx.registerLegend(id, blob);\n return () => ctx.unregisterLegend(id);\n }, [ctx, id, blob]);\n return null;\n};\nLegend.displayName = 'Legend';\n\n// ─── Tooltip (declarative config-only component) ─────────────────────────────\n\nexport interface TooltipProps extends TooltipOptions {}\n\n/**\n * Configure the tooltip system declaratively as a child of `<Chart>`.\n * This is a config-only component — it renders nothing.\n * Props are passed through to the chart's tooltip options.\n *\n * @example\n * <Chart data={data}>\n * <Tooltip\n * mode=\"shared\"\n * snap\n * sticky\n * bulletShape=\"circle\"\n * bodyTemplate=\"Revenue: ${revenue}\"\n * footerTemplate=\"Source: ${source}\"\n * style={{ background: '#1a1a2e', borderRadius: 12 }}\n * />\n * <Bar xKey=\"month\" yKey=\"sales\" />\n * </Chart>\n */\nexport const Tooltip: React.FC<TooltipProps> = () => null;\nTooltip.displayName = 'Tooltip';\n","// Radiant Charts — Public useChartTooltip Hook\n\nimport { useSyncExternalStore, useCallback } from 'react';\nimport { useTooltipStore } from './TooltipContext';\nimport { TooltipDatumEntry } from './types';\n\nexport interface ChartTooltipContext {\n active: boolean;\n entries: TooltipDatumEntry[];\n sharedLabel: string | null;\n pointerX: number;\n pointerY: number;\n anchorX: number;\n anchorY: number;\n localX: number;\n localY: number;\n hide: () => void;\n}\n\nexport function useChartTooltip(): ChartTooltipContext {\n const store = useTooltipStore();\n\n const state = useSyncExternalStore(\n store.subscribe.bind(store),\n store.getState.bind(store),\n () => store.getState(),\n );\n\n const hide = useCallback(() => store.hide(), [store]);\n\n return {\n active: state.active,\n entries: state.entries,\n sharedLabel: state.sharedLabel,\n pointerX: state.pointerX,\n pointerY: state.pointerY,\n anchorX: state.anchorX,\n anchorY: state.anchorY,\n localX: state.localX,\n localY: state.localY,\n hide,\n };\n}\n"],"mappings":"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","names":["React","useRef","useEffect","useLayoutEffect","useState","useMemo","useImperativeHandle","forwardRef","Node","child","index","ctx","hasTransform","hasShadow","hasEffect","x","y","localX","localY","i","picked","Group","Node","_ctx","_x","_y","minX","minY","maxX","maxY","child","b","Rect","ctx","r","x","y","Line","Circle","dx","dy","Path","p","Marker","cx","cy","w","Arc","dist","angle","s","e","Text","Scene","container","Group","ctx","e","rect","x","y","node","touch","syntheticMouse","longPressMouse","LinearScale","value","d0","d1","r0","r1","count","step","magnitude","normalizedStep","niceStep","finalStep","start","end","ticks","t","BandScale","index","safeBandwidth","scale","formatAxisValue","val","abs","d","CartesianAxis","scale","options","Group","max","theme","ctx","position","rotation","fontFamily","fontSize","tickLength","labelGap","tickCount","labelFormatter","ticks","rad","absCos","absSin","maxH","i","tick","text","h","totalH","maxW","w","effectiveW","totalW","length","gridLength","showLabels","innerPad","gridOffset","textColor","gridColor","axisColor","axisLine","Line","gridStyleArr","showGrid","labelAlignment","getBW","isXAxis","isYAxis","labelMinGap","lastLabelPos","tIdx","pos","bw","br0","br1","stepSign","labelText","estWidth","tickLine","label","Text","isRight","sign","gridLine","gs","titleLabel","prefersReducedMotion","_Animator","options","now","progress","name","c4","Animator","BarBatchNode","Node","ctx","b","r","x","y","i","BarSeries","options","Group","data","xScale","yScale","seriesRect","animate","seriesIndex","totalSeries","stackedOffsets","columnTotals","isInitial","isH","animType","oldLen","newLen","batchBars","datum","yVal","fullBW","safeBandwidth","by","bh","tx","tw","bx","bw","ty","th","step","rect","Rect","lbl","Text","targets","off","normalOff","old","rawY","barRect","labelNode","sx","sy","sw","sh","so","to","ssx","tsx","ssy","tsy","existing","finalTX","finalTY","entry","duration","easing","Animator","progress","txt","rawValue","pos","fv","abs","ax","ay","catmullRomToBezier","pts","result","i","p0","p1","p2","p3","LineSeries","options","Group","Path","legacy","data","xScale","yScale","_seriesRect","animate","d","raw","missing","bw","safeBandwidth","path","runs","p","current","run","prev","markersGroup","marker","Marker","lbl","Text","formatAxisValue","pos","offset","ax","ay","animType","duration","easing","Animator","length","DEG","PieSeries","options","Group","data","seriesRect","animate","total","s","d","cx","cy","marginFactor","outerR","innerR","startRad","totalArcRad","currentAngle","datum","i","sliceAngle","slice","Arc","labelNode","labelAngle","pos","isInside","labelR","lx","ly","Text","cos","availableWidth","animType","duration","easing","Animator","p","fullAngle","theme","catmullRomBezier","pts","out","i","p0","p1","p2","p3","AreaSeries","options","Group","Path","data","xScale","yScale","seriesRect","animate","stackedOffsets","columnTotals","isInitial","newPts","datum","x","safeBandwidth","yVal","isMissing","targetY","targetBottomY","off","total","normOff","normVal","startY","startBottomY","label","Text","m","Marker","animType","duration","easing","Animator","p","lbl","formatAxisValue","progress","runs","current","allPath","run","topPts","topPath","prev","bottomPath","ScatterSeries","options","Group","data","xScale","yScale","seriesRect","animate","m","l","sizeScale","_val","sizes","d","maxSize","val","animType","isInitial","newPoints","datum","i","xVal","yVal","sVal","tx","bw","safeBandwidth","joff","ty","tr","marker","sx","sy","sr","so","Marker","labelsEnabled","lbl","Text","formatAxisValue","applyProgress","pt","cx","cy","cr","duration","easing","Animator","DEFAULT_TOOLTIP_STATE","TooltipStore","DEFAULT_TOOLTIP_STATE","options","listener","entries","pointer","anchor","local","sharedLabel","doActivate","showDelay","hideDelay","x","y","next","force","CATEGORICAL_LIGHT","CATEGORICAL_DARK","lightTheme","darkTheme","systemPrefersDark","ThemeManager","name","option","Legend","Group","ids","items","theme","maxWidth","maxHeight","position","isVertical","verticalLimitFrac","horizontalLimitFrac","delta","maxRows","rows","currentRow","currentX","item","itemW","pages","i","multiPage","currentY","labelW","totalW","itemGroup","marker","Circle","Line","Rect","label","Text","navY","muted","btnH","btnW","pageIndicator","glyph","actionId","x","y","w","h","color","align","btn","hitRect","_CrosshairRenderer","Group","Line","Circle","Rect","Text","options","x","y","bounds","theme","xScale","data","xKey","color","snappedX","snappedY","minDist","closestX","closestBandX","d","absX","safeBandwidth","dist","isDark","xLabel","yLabel","tw","hasSnapAnim","i","dot","target","speed","dx","dy","diff","CrosshairRenderer","NON_CARTESIAN","ChartManager","container","options","TooltipStore","ThemeManager","Legend","CrosshairRenderer","bg","Group","BandScale","LinearScale","Scene","s","entries","e","loop","node","event","rect","mx","my","theme","sr","palette","xOpt","seriesId","i","id","_event","current","insideLegend","seriesOpt","so","idx","others","isIsolated","data","xKey","delta","dataChanged","themeBackground","needsListener","series","type","yAxisId","xKeys","stackedBars","stackedAreas","colTotals","d","t","areaColTotals","_","xKeyFields","yKeyFields","sIdx","k","v","numericX","minX","maxX","yKeys","dMin","dMax","minYRight","maxYRight","isH","CartesianAxis","color","animation","base","BarSeries","LineSeries","PieSeries","AreaSeries","ScatterSeries","width","height","icon","Text","msg","shouldAnimate","pad","top","bottom","left","right","innerPad","legendOpt","items","NON_CARTESIAN_TYPES","sOpt","instance","key","inst","legendItems","position","legendMaxWidth","legendGroupNode","lb","lx","ly","showXAxis","showYAxis","showYAxisRight","ctx","yAxisW","yAxisRightW","xAxisH","topAxisH","Y_LABEL_DATA_GAP","maxYWidth","ip","usedSeries","fData","sId","catScale","valScale","decimationType","instanceKey","subRect","seriesOptForUpdate","allBars","barOffsets","barTotals","allStackedBars","myIdx","acc","areaOffsets","areaTotals","allStackedAreas","filename","dataUrl","a","createContext","useContext","TooltipStoreContext","useTooltipStore","store","VALUE_KEY_FIELDS","deriveTableKeys","series","seen","s","field","val","RadiantChart","forwardRef","options","width","height","className","style","ref","containerRef","useRef","chartRef","tooltipStoreRef","mounted","setMounted","useState","focusedIndex","setFocusedIndex","useImperativeHandle","filename","resolvedOptions","useMemo","idx","useLayoutEffect","ChartManager","useEffect","cancelled","raf","systemIsDark","setSystemIsDark","ThemeManager","mql","handler","isDark","tableKeys","computedClassName","React","TooltipStoreContext","h","i","e","key","totalItems","start","end","row","rowIndex","RadiantChart_default","React","useRef","useLayoutEffect","useState","useCallback","ResponsiveContainer","width","height","minHeight","minWidth","aspect","debounce","className","style","children","wrapperRef","containerSize","setContainerSize","debounceTimer","applySize","w","h","handleEntries","entries","entry","el","rect","ro","effectiveHeight","ResponsiveContainer_default","React","createContext","useContext","useCallback","useRef","useEffect","useMemo","useState","ChartContext","createContext","useChartContext","ctx","useContext","_nextId","useStableId","prefix","ref","useRef","Chart","data","theme","width","height","animation","padding","crosshair","tooltip","showExport","className","style","chartRef","children","seriesMap","axisMap","titleMap","legendMap","rev","setRev","useState","bump","useCallback","r","useMemo","id","props","a","t","l","options","series","showXAxis","showYAxis","showYAxisRight","xAxisFontSize","xAxisFontFamily","xAxisRotation","xAxisLabelAlignment","yAxisFontSize","yAxisFontFamily","yAxisRotation","yAxisLabelAlignment","yAxisRightFontSize","yAxisRightFontFamily","yAxisRightRotation","yAxisRightLabelAlignment","axis","title","subtitle","legend","tooltipFromChild","React","child","Tooltip","RadiantChart_default","createSeriesComponent","seriesType","displayName","Component","blob","useEffect","Bar","Line","Area","Scatter","Pie","Donut","XAxis","YAxis","YAxisRight","Title","Subtitle","Legend","useSyncExternalStore","useCallback","useChartTooltip","store","useTooltipStore","state","useSyncExternalStore","hide","useCallback"]}
|