@vielzeug/prism 2.2.5 → 3.0.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.
Files changed (97) hide show
  1. package/README.md +19 -40
  2. package/dist/_dev.cjs +1 -1
  3. package/dist/_dev.cjs.map +1 -1
  4. package/dist/_dev.js +1 -2
  5. package/dist/_dev.js.map +1 -1
  6. package/dist/axes/axis.cjs +1 -1
  7. package/dist/axes/axis.cjs.map +1 -1
  8. package/dist/axes/axis.d.ts +1 -0
  9. package/dist/axes/axis.d.ts.map +1 -1
  10. package/dist/axes/axis.js +15 -11
  11. package/dist/axes/axis.js.map +1 -1
  12. package/dist/charts/area/area-chart.cjs +1 -1
  13. package/dist/charts/area/area-chart.cjs.map +1 -1
  14. package/dist/charts/area/area-chart.d.ts +2 -2
  15. package/dist/charts/area/area-chart.d.ts.map +1 -1
  16. package/dist/charts/area/area-chart.js +31 -31
  17. package/dist/charts/area/area-chart.js.map +1 -1
  18. package/dist/charts/area/area-renderer.cjs +1 -1
  19. package/dist/charts/area/area-renderer.cjs.map +1 -1
  20. package/dist/charts/area/area-renderer.d.ts +2 -2
  21. package/dist/charts/area/area-renderer.d.ts.map +1 -1
  22. package/dist/charts/area/area-renderer.js +14 -14
  23. package/dist/charts/area/area-renderer.js.map +1 -1
  24. package/dist/charts/bar/bar-chart.cjs +1 -1
  25. package/dist/charts/bar/bar-chart.cjs.map +1 -1
  26. package/dist/charts/bar/bar-chart.d.ts +2 -2
  27. package/dist/charts/bar/bar-chart.d.ts.map +1 -1
  28. package/dist/charts/bar/bar-chart.js +58 -56
  29. package/dist/charts/bar/bar-chart.js.map +1 -1
  30. package/dist/charts/bar/bar-hit-test.cjs +1 -1
  31. package/dist/charts/bar/bar-hit-test.cjs.map +1 -1
  32. package/dist/charts/bar/bar-hit-test.js +5 -4
  33. package/dist/charts/bar/bar-hit-test.js.map +1 -1
  34. package/dist/charts/bar/bar-renderer.cjs +1 -1
  35. package/dist/charts/bar/bar-renderer.js +24 -24
  36. package/dist/charts/line/line-chart.cjs +1 -1
  37. package/dist/charts/line/line-chart.cjs.map +1 -1
  38. package/dist/charts/line/line-chart.d.ts +2 -2
  39. package/dist/charts/line/line-chart.d.ts.map +1 -1
  40. package/dist/charts/line/line-chart.js +31 -31
  41. package/dist/charts/line/line-chart.js.map +1 -1
  42. package/dist/charts/line/line-renderer.cjs +1 -1
  43. package/dist/charts/line/line-renderer.cjs.map +1 -1
  44. package/dist/charts/line/line-renderer.d.ts +2 -2
  45. package/dist/charts/line/line-renderer.d.ts.map +1 -1
  46. package/dist/charts/line/line-renderer.js +34 -34
  47. package/dist/charts/line/line-renderer.js.map +1 -1
  48. package/dist/charts/pie/pie-chart.cjs +1 -1
  49. package/dist/charts/pie/pie-chart.cjs.map +1 -1
  50. package/dist/charts/pie/pie-chart.d.ts +2 -2
  51. package/dist/charts/pie/pie-chart.d.ts.map +1 -1
  52. package/dist/charts/pie/pie-chart.js +118 -109
  53. package/dist/charts/pie/pie-chart.js.map +1 -1
  54. package/dist/charts/sparkline/sparkline.cjs +1 -1
  55. package/dist/charts/sparkline/sparkline.cjs.map +1 -1
  56. package/dist/charts/sparkline/sparkline.d.ts +2 -2
  57. package/dist/charts/sparkline/sparkline.d.ts.map +1 -1
  58. package/dist/charts/sparkline/sparkline.js +119 -117
  59. package/dist/charts/sparkline/sparkline.js.map +1 -1
  60. package/dist/core/chart-base.cjs +1 -1
  61. package/dist/core/chart-base.cjs.map +1 -1
  62. package/dist/core/chart-base.d.ts +2 -4
  63. package/dist/core/chart-base.d.ts.map +1 -1
  64. package/dist/core/chart-base.js +21 -30
  65. package/dist/core/chart-base.js.map +1 -1
  66. package/dist/core/chart-scaffold.cjs +1 -1
  67. package/dist/core/chart-scaffold.cjs.map +1 -1
  68. package/dist/core/chart-scaffold.d.ts +9 -10
  69. package/dist/core/chart-scaffold.d.ts.map +1 -1
  70. package/dist/core/chart-scaffold.js +31 -43
  71. package/dist/core/chart-scaffold.js.map +1 -1
  72. package/dist/core/layout.cjs +1 -1
  73. package/dist/core/layout.cjs.map +1 -1
  74. package/dist/core/layout.js +1 -1
  75. package/dist/core/layout.js.map +1 -1
  76. package/dist/index.cjs +1 -1
  77. package/dist/index.d.ts +2 -6
  78. package/dist/index.d.ts.map +1 -1
  79. package/dist/index.js +11 -12
  80. package/dist/interaction/legend.cjs +1 -1
  81. package/dist/interaction/legend.cjs.map +1 -1
  82. package/dist/interaction/legend.js +1 -1
  83. package/dist/interaction/legend.js.map +1 -1
  84. package/dist/interaction/tooltip.cjs +1 -1
  85. package/dist/interaction/tooltip.cjs.map +1 -1
  86. package/dist/interaction/tooltip.d.ts.map +1 -1
  87. package/dist/interaction/tooltip.js +29 -29
  88. package/dist/interaction/tooltip.js.map +1 -1
  89. package/dist/prism.cjs +1 -1
  90. package/dist/prism.cjs.map +1 -1
  91. package/dist/prism.iife.js +1 -1
  92. package/dist/prism.iife.js.map +1 -1
  93. package/dist/prism.js +1 -1
  94. package/dist/prism.js.map +1 -1
  95. package/dist/types.d.ts +24 -48
  96. package/dist/types.d.ts.map +1 -1
  97. package/package.json +8 -9
@@ -1 +1 @@
1
- {"version":3,"file":"pie-chart.cjs","names":[],"sources":["../../../src/charts/pie/pie-chart.ts"],"sourcesContent":["import { isReactive } from '@vielzeug/ripple';\nimport { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { tweenNumber } from '../../animation/tween';\nimport type { ChartEventHandlers } from '../../core/chart-scaffold';\nimport { createRadialScaffold } from '../../core/chart-scaffold';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport { seriesColor } from '../../theme';\nimport type { ChartHandle, PieChartConfig, PieSliceConfig } from '../../types';\nimport { type Arc, arcCentroid, arcPath, computeArcs } from './pie-renderer';\n\nconst TWO_PI = 2 * Math.PI;\n\nconst SEMI_START = -Math.PI / 2; // -90° = 9-o'clock (left)\nconst SEMI_END = Math.PI / 2; // +90° = 3-o'clock (right) → true 180° half-circle\n\nfunction semiAngles(variant: PieChartConfig['variant']): { end: number; start: number } {\n return variant === 'semi' ? { end: SEMI_END, start: SEMI_START } : { end: TWO_PI, start: 0 };\n}\n\nexport function createPieChart(container: HTMLElement, config: PieChartConfig): ChartHandle {\n const variant = config.variant ?? 'pie';\n const padPixels = config.padPixels ?? (variant === 'pie' ? 0 : 8);\n const cornerRadius = config.cornerRadius ?? (variant === 'pie' ? 0 : 8);\n\n // Pie SVG elements live directly on the SVG (not inside chartArea groups).\n // We create them once and reuse across renders.\n const bgCircle = createSvgElement('circle', { class: 'prism-pie-bg', 'pointer-events': 'none' });\n const pieGroup = createSvgElement('g', {\n class: 'prism-pie-slices',\n 'shape-rendering': 'geometricPrecision',\n });\n const labelGroup = createSvgElement('g', { class: 'prism-pie-labels', 'pointer-events': 'none' });\n\n // Current arcs shared between renderFn and event handlers via closure.\n let currentArcs: Arc[] = [];\n let activeRaf: number | null = null;\n\n function renderLabels(slices: PieSliceConfig[]): void {\n while (labelGroup.children.length > currentArcs.length) labelGroup.removeChild(labelGroup.lastChild!);\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n const slice = slices[i];\n\n if (!slice?.label) continue;\n\n const { x, y } = arcCentroid(arc);\n let text = labelGroup.children[i] as SVGTextElement | undefined;\n\n if (!text) {\n text = createSvgElement('text', { class: 'prism-pie-label' });\n labelGroup.appendChild(text);\n }\n\n setAttributes(text, {\n 'dominant-baseline': 'middle',\n fill: 'var(--prism-pie-label-color, #fff)',\n 'font-family': 'var(--prism-font-family, system-ui)',\n 'font-size': 'var(--prism-pie-label-size, 12px)',\n 'text-anchor': 'middle',\n x,\n y,\n });\n\n text.textContent = slice.label;\n }\n }\n\n const handle = createRadialScaffold(\n container,\n {\n a11y: config.a11y,\n legend: config.legend,\n plugins: config.plugins,\n tooltip: config.tooltip,\n },\n (ctx): ChartEventHandlers => {\n const { legend, svg, tooltip } = ctx;\n\n // Append pie groups to SVG on first render (idempotent).\n if (!svg.contains(bgCircle)) {\n svg.appendChild(bgCircle);\n svg.appendChild(pieGroup);\n svg.appendChild(labelGroup);\n }\n\n const { height: h, width: w } = ctx.dimensions.value;\n const isSemi = variant === 'semi';\n const cx = w / 2;\n const cy = isSemi ? h * 0.85 : h / 2;\n const padding = 8;\n const outer = isSemi ? Math.min(cx, cy) - padding : Math.min(w, h) / 2 - padding;\n const defaultInner = variant === 'pie' ? 0 : Math.round(outer * 0.55);\n const inner = config.innerRadius !== undefined ? config.innerRadius : defaultInner;\n const outerR = Math.max(inner + 1, outer);\n\n const slices = isReactive(config.data) ? config.data.value : config.data;\n const { end, start } = semiAngles(variant);\n\n currentArcs = computeArcs(\n slices,\n cx,\n cy,\n outerR,\n inner,\n start,\n end,\n padPixels,\n cornerRadius,\n (i) => seriesColor(i),\n false,\n );\n\n setAttributes(bgCircle, { cx, cy, r: inner > 0 ? inner : 0 });\n bgCircle.setAttribute('style', 'fill:var(--prism-bg,#fff)');\n\n while (pieGroup.children.length > currentArcs.length) pieGroup.removeChild(pieGroup.lastChild!);\n\n while (labelGroup.children.length > currentArcs.length) labelGroup.removeChild(labelGroup.lastChild!);\n\n const motion = resolveMotion(config.transition, 0);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n let path = pieGroup.children[i] as SVGPathElement | undefined;\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-pie-slice' });\n pieGroup.appendChild(path);\n }\n\n path.setAttribute('fill', arc.color);\n path.setAttribute('stroke', 'none');\n path.style.cursor = config.onClick || config.onHover ? 'pointer' : '';\n }\n\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n if (dur > 0) {\n let rafStart: number | null = null;\n\n const frame = (ts: number) => {\n if (rafStart === null) rafStart = ts;\n\n const t = easing(Math.min(1, (ts - rafStart) / dur));\n const revealAngle = tweenNumber(start, end, t);\n\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (!el) continue;\n\n if (revealAngle <= a.startAngle) {\n setAttributes(el, { d: '' });\n } else {\n const visibleEnd = Math.min(a.endAngle, revealAngle);\n\n setAttributes(el, { d: arcPath({ ...a, endAngle: visibleEnd }) });\n }\n }\n\n if (t < 1) {\n activeRaf = requestAnimationFrame(frame);\n } else {\n activeRaf = null;\n renderLabels(slices);\n }\n };\n\n activeRaf = requestAnimationFrame(frame);\n } else {\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (el) setAttributes(el, { d: arcPath(a) });\n }\n\n renderLabels(slices);\n }\n\n legend?.update(currentArcs.map((arc) => ({ color: arc.color, name: arc.slice.label ?? '' })));\n tooltip?.hide();\n\n const onMouseMove = (e: MouseEvent): void => {\n const svgRect = svg.getBoundingClientRect();\n const mx = e.clientX - svgRect.left;\n const my = e.clientY - svgRect.top;\n const hit = hitTestArc(currentArcs, mx, my, variant);\n\n if (hit >= 0) {\n const arc = currentArcs[hit];\n\n config.onHover?.(arc.slice, hit);\n\n const { x, y } = arcCentroid(arc);\n const contR = container.getBoundingClientRect();\n\n tooltip?.show(\n x + (svgRect.left - contR.left),\n y + (svgRect.top - contR.top),\n { key: hit, value: arc.slice.value },\n { color: arc.color, data: [], name: arc.slice.label ?? '' },\n );\n } else {\n config.onHover?.(null, null);\n tooltip?.hide();\n }\n };\n\n const onMouseLeave = (): void => {\n config.onHover?.(null, null);\n tooltip?.hide();\n };\n\n const onClick = (e: MouseEvent): void => {\n if (!config.onClick) return;\n\n const svgRect = svg.getBoundingClientRect();\n const mx = e.clientX - svgRect.left;\n const my = e.clientY - svgRect.top;\n const hit = hitTestArc(currentArcs, mx, my, variant);\n\n if (hit >= 0) config.onClick(currentArcs[hit].slice, hit);\n };\n\n return { onClick, onMouseLeave, onMouseMove };\n },\n );\n\n return {\n get disposalSignal(): AbortSignal {\n return handle.disposalSignal;\n },\n\n dispose() {\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n handle.dispose();\n },\n\n get disposed(): boolean {\n return handle.disposed;\n },\n\n el: handle.el,\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n}\n\nfunction hitTestArc(arcs: Arc[], mx: number, my: number, variant: PieChartConfig['variant']): number {\n for (let i = 0; i < arcs.length; i++) {\n const arc = arcs[i];\n const dx = mx - arc.centerX;\n const dy = my - arc.centerY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n if (dist < arc.outerRadius && dist >= arc.innerRadius) {\n const rawAngle = Math.atan2(dx, -dy);\n\n if (variant === 'semi') {\n if (rawAngle >= arc.startAngle - 1e-9 && rawAngle <= arc.endAngle + 1e-9) return i;\n } else {\n const angle = rawAngle < 0 ? rawAngle + TWO_PI : rawAngle;\n\n if (angle >= arc.startAngle - 1e-9 && angle <= arc.endAngle + 1e-9) return i;\n }\n }\n }\n\n return -1;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pie-chart.cjs","names":[],"sources":["../../../src/charts/pie/pie-chart.ts"],"sourcesContent":["import { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { tweenNumber } from '../../animation/tween';\nimport type { ChartEventHandlers } from '../../core/chart-scaffold';\nimport { createRadialScaffold } from '../../core/chart-scaffold';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport { seriesColor } from '../../theme';\nimport type { ChartHandle, PieChartConfig, PieSliceConfig } from '../../types';\nimport { type Arc, arcCentroid, arcPath, computeArcs } from './pie-renderer';\n\nconst TWO_PI = 2 * Math.PI;\n\nconst SEMI_START = -Math.PI / 2; // -90° = 9-o'clock (left)\nconst SEMI_END = Math.PI / 2; // +90° = 3-o'clock (right) → true 180° half-circle\n\nfunction semiAngles(variant: PieChartConfig['variant']): { end: number; start: number } {\n return variant === 'semi' ? { end: SEMI_END, start: SEMI_START } : { end: TWO_PI, start: 0 };\n}\n\nexport function createPieChart(container: HTMLElement, config: PieChartConfig): ChartHandle<PieSliceConfig[]> {\n const variant = config.variant ?? 'pie';\n const padPixels = config.padPixels ?? (variant === 'pie' ? 0 : 8);\n const cornerRadius = config.cornerRadius ?? (variant === 'pie' ? 0 : 8);\n let data = config.data;\n\n // Pie SVG elements live directly on the SVG (not inside chartArea groups).\n // We create them once and reuse across renders.\n const bgCircle = createSvgElement('circle', { class: 'prism-pie-bg', 'pointer-events': 'none' });\n const pieGroup = createSvgElement('g', {\n class: 'prism-pie-slices',\n 'shape-rendering': 'geometricPrecision',\n });\n const labelGroup = createSvgElement('g', { class: 'prism-pie-labels', 'pointer-events': 'none' });\n\n // Current arcs shared between renderFn and event handlers via closure.\n let currentArcs: Arc[] = [];\n let activeRaf: number | null = null;\n\n function renderLabels(slices: PieSliceConfig[]): void {\n labelGroup.replaceChildren();\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n const slice = slices[i];\n\n if (!slice?.label) continue;\n\n const { x, y } = arcCentroid(arc);\n const text = createSvgElement('text', { class: 'prism-pie-label' });\n\n setAttributes(text, {\n 'dominant-baseline': 'middle',\n fill: 'var(--prism-pie-label-color, #fff)',\n 'font-family': 'var(--prism-font-family, system-ui)',\n 'font-size': 'var(--prism-pie-label-size, 12px)',\n 'text-anchor': 'middle',\n x,\n y,\n });\n\n text.textContent = slice.label;\n labelGroup.appendChild(text);\n }\n }\n\n let handle: ChartHandle<PieSliceConfig[]> | undefined;\n\n try {\n handle = createRadialScaffold(\n container,\n {\n a11y: config.a11y,\n legend: config.legend,\n tooltip: config.tooltip,\n },\n (ctx): ChartEventHandlers => {\n const { legend, svg, tooltip } = ctx;\n\n // Append pie groups to SVG on first render (idempotent).\n if (!svg.contains(bgCircle)) {\n svg.appendChild(bgCircle);\n svg.appendChild(pieGroup);\n svg.appendChild(labelGroup);\n }\n\n const { height: h, width: w } = ctx.dimensions;\n const isSemi = variant === 'semi';\n const cx = w / 2;\n const cy = isSemi ? h * 0.85 : h / 2;\n const padding = 8;\n const outer = isSemi ? Math.min(cx, cy) - padding : Math.min(w, h) / 2 - padding;\n const defaultInner = variant === 'pie' ? 0 : Math.round(outer * 0.55);\n const inner = config.innerRadius !== undefined ? config.innerRadius : defaultInner;\n const outerR = Math.max(inner + 1, outer);\n\n const slices = data;\n const { end, start } = semiAngles(variant);\n\n currentArcs = computeArcs(\n slices,\n cx,\n cy,\n outerR,\n inner,\n start,\n end,\n padPixels,\n cornerRadius,\n (i) => seriesColor(i),\n false,\n );\n\n setAttributes(bgCircle, { cx, cy, r: inner > 0 ? inner : 0 });\n bgCircle.setAttribute('style', 'fill:var(--prism-bg,#fff)');\n\n while (pieGroup.children.length > currentArcs.length) pieGroup.removeChild(pieGroup.lastChild!);\n\n labelGroup.replaceChildren();\n\n const motion = resolveMotion(config.transition, 0);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n let path = pieGroup.children[i] as SVGPathElement | undefined;\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-pie-slice' });\n pieGroup.appendChild(path);\n }\n\n path.setAttribute('fill', arc.color);\n path.setAttribute('stroke', 'none');\n path.style.cursor = config.onClick || config.onHover ? 'pointer' : '';\n }\n\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n if (dur > 0) {\n let rafStart: number | null = null;\n\n const frame = (ts: number) => {\n if (rafStart === null) rafStart = ts;\n\n const t = easing(Math.min(1, (ts - rafStart) / dur));\n const revealAngle = tweenNumber(start, end, t);\n\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (!el) continue;\n\n if (revealAngle <= a.startAngle) {\n setAttributes(el, { d: '' });\n } else {\n const visibleEnd = Math.min(a.endAngle, revealAngle);\n\n setAttributes(el, { d: arcPath({ ...a, endAngle: visibleEnd }) });\n }\n }\n\n if (t < 1) {\n activeRaf = requestAnimationFrame(frame);\n } else {\n activeRaf = null;\n renderLabels(slices);\n }\n };\n\n activeRaf = requestAnimationFrame(frame);\n } else {\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (el) setAttributes(el, { d: arcPath(a) });\n }\n\n renderLabels(slices);\n }\n\n legend?.update(currentArcs.map((arc) => ({ color: arc.color, name: arc.slice.label ?? '' })));\n tooltip?.hide();\n\n const onMouseMove = (e: MouseEvent): void => {\n const svgRect = svg.getBoundingClientRect();\n const mx = e.clientX - svgRect.left;\n const my = e.clientY - svgRect.top;\n const hit = hitTestArc(currentArcs, mx, my, variant);\n\n if (hit >= 0) {\n const arc = currentArcs[hit];\n\n config.onHover?.(arc.slice, hit);\n\n const { x, y } = arcCentroid(arc);\n const contR = container.getBoundingClientRect();\n\n tooltip?.show(\n x + (svgRect.left - contR.left),\n y + (svgRect.top - contR.top),\n { key: hit, value: arc.slice.value },\n { color: arc.color, data: [], name: arc.slice.label ?? '' },\n );\n } else {\n config.onHover?.(null, null);\n tooltip?.hide();\n }\n };\n\n const onMouseLeave = (): void => {\n config.onHover?.(null, null);\n tooltip?.hide();\n };\n\n const onClick = (e: MouseEvent): void => {\n if (!config.onClick) return;\n\n const svgRect = svg.getBoundingClientRect();\n const mx = e.clientX - svgRect.left;\n const my = e.clientY - svgRect.top;\n const hit = hitTestArc(currentArcs, mx, my, variant);\n\n if (hit >= 0) config.onClick(currentArcs[hit].slice, hit);\n };\n\n return { onClick, onMouseLeave, onMouseMove };\n },\n (next) => {\n data = next;\n },\n );\n\n return {\n get disposalSignal(): AbortSignal {\n return handle!.disposalSignal;\n },\n\n dispose() {\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n handle!.dispose();\n },\n\n get disposed(): boolean {\n return handle!.disposed;\n },\n\n el: handle!.el,\n\n update(next) {\n handle!.update(next);\n },\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n } catch (error) {\n handle?.dispose();\n throw error;\n }\n}\n\nfunction hitTestArc(arcs: Arc[], mx: number, my: number, variant: PieChartConfig['variant']): number {\n for (let i = 0; i < arcs.length; i++) {\n const arc = arcs[i];\n const dx = mx - arc.centerX;\n const dy = my - arc.centerY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n if (dist < arc.outerRadius && dist >= arc.innerRadius) {\n const rawAngle = Math.atan2(dx, -dy);\n\n if (variant === 'semi') {\n if (rawAngle >= arc.startAngle - 1e-9 && rawAngle <= arc.endAngle + 1e-9) return i;\n } else {\n const angle = rawAngle < 0 ? rawAngle + TWO_PI : rawAngle;\n\n if (angle >= arc.startAngle - 1e-9 && angle <= arc.endAngle + 1e-9) return i;\n }\n }\n }\n\n return -1;\n}\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import type { ChartHandle, PieChartConfig } from '../../types';
2
- export declare function createPieChart(container: HTMLElement, config: PieChartConfig): ChartHandle;
1
+ import type { ChartHandle, PieChartConfig, PieSliceConfig } from '../../types';
2
+ export declare function createPieChart(container: HTMLElement, config: PieChartConfig): ChartHandle<PieSliceConfig[]>;
3
3
  //# sourceMappingURL=pie-chart.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pie-chart.d.ts","sourceRoot":"","sources":["../../../src/charts/pie/pie-chart.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAkB,MAAM,aAAa,CAAC;AAY/E,wBAAgB,cAAc,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,cAAc,GAAG,WAAW,CAiP1F"}
1
+ {"version":3,"file":"pie-chart.d.ts","sourceRoot":"","sources":["../../../src/charts/pie/pie-chart.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAY/E,wBAAgB,cAAc,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,cAAc,GAAG,WAAW,CAAC,cAAc,EAAE,CAAC,CA2P5G"}
@@ -1,40 +1,39 @@
1
- import { resolveEasing as e } from "../../animation/easing.js";
2
- import { resolveMotion as t } from "../../animation/motion.js";
3
- import { tweenNumber as n } from "../../animation/tween.js";
4
- import { createSvgElement as r, setAttributes as i } from "../../svg/element.js";
5
- import { createRadialScaffold as a } from "../../core/chart-scaffold.js";
6
- import { seriesColor as o } from "../../theme/index.js";
1
+ import { createSvgElement as e, setAttributes as t } from "../../svg/element.js";
2
+ import { createRadialScaffold as n } from "../../core/chart-scaffold.js";
3
+ import { seriesColor as r } from "../../theme/index.js";
4
+ import { resolveEasing as i } from "../../animation/easing.js";
5
+ import { resolveMotion as a } from "../../animation/motion.js";
6
+ import { tweenNumber as o } from "../../animation/tween.js";
7
7
  import { arcCentroid as s, arcPath as c, computeArcs as l } from "./pie-renderer.js";
8
- import { isReactive as u } from "@vielzeug/ripple";
9
8
  //#region src/charts/pie/pie-chart.ts
10
- var d = 2 * Math.PI, f = -Math.PI / 2, p = Math.PI / 2;
11
- function m(e) {
9
+ var u = 2 * Math.PI, d = -Math.PI / 2, f = Math.PI / 2;
10
+ function p(e) {
12
11
  return e === "semi" ? {
13
- end: p,
14
- start: f
12
+ end: f,
13
+ start: d
15
14
  } : {
16
- end: d,
15
+ end: u,
17
16
  start: 0
18
17
  };
19
18
  }
20
- function h(d, f) {
21
- let p = f.variant ?? "pie", h = f.padPixels ?? (p === "pie" ? 0 : 8), _ = f.cornerRadius ?? (p === "pie" ? 0 : 8), v = r("circle", {
19
+ function m(u, d) {
20
+ let f = d.variant ?? "pie", m = d.padPixels ?? (f === "pie" ? 0 : 8), g = d.cornerRadius ?? (f === "pie" ? 0 : 8), _ = d.data, v = e("circle", {
22
21
  class: "prism-pie-bg",
23
22
  "pointer-events": "none"
24
- }), y = r("g", {
23
+ }), y = e("g", {
25
24
  class: "prism-pie-slices",
26
25
  "shape-rendering": "geometricPrecision"
27
- }), b = r("g", {
26
+ }), b = e("g", {
28
27
  class: "prism-pie-labels",
29
28
  "pointer-events": "none"
30
29
  }), x = [], S = null;
31
- function C(e) {
32
- for (; b.children.length > x.length;) b.removeChild(b.lastChild);
33
- for (let t = 0; t < x.length; t++) {
34
- let n = x[t], a = e[t];
30
+ function C(n) {
31
+ b.replaceChildren();
32
+ for (let r = 0; r < x.length; r++) {
33
+ let i = x[r], a = n[r];
35
34
  if (!a?.label) continue;
36
- let { x: o, y: c } = s(n), l = b.children[t];
37
- l || (l = r("text", { class: "prism-pie-label" }), b.appendChild(l)), i(l, {
35
+ let { x: o, y: c } = s(i), l = e("text", { class: "prism-pie-label" });
36
+ t(l, {
38
37
  "dominant-baseline": "middle",
39
38
  fill: "var(--prism-pie-label-color, #fff)",
40
39
  "font-family": "var(--prism-font-family, system-ui)",
@@ -42,101 +41,111 @@ function h(d, f) {
42
41
  "text-anchor": "middle",
43
42
  x: o,
44
43
  y: c
45
- }), l.textContent = a.label;
44
+ }), l.textContent = a.label, b.appendChild(l);
46
45
  }
47
46
  }
48
- let w = a(d, {
49
- a11y: f.a11y,
50
- legend: f.legend,
51
- plugins: f.plugins,
52
- tooltip: f.tooltip
53
- }, (a) => {
54
- let { legend: w, svg: T, tooltip: E } = a;
55
- T.contains(v) || (T.appendChild(v), T.appendChild(y), T.appendChild(b));
56
- let { height: D, width: O } = a.dimensions.value, k = p === "semi", A = O / 2, j = k ? D * .85 : D / 2, M = k ? Math.min(A, j) - 8 : Math.min(O, D) / 2 - 8, N = p === "pie" ? 0 : Math.round(M * .55), P = f.innerRadius === void 0 ? N : f.innerRadius, F = Math.max(P + 1, M), I = u(f.data) ? f.data.value : f.data, { end: L, start: R } = m(p);
57
- for (x = l(I, A, j, F, P, R, L, h, _, (e) => o(e), !1), i(v, {
58
- cx: A,
59
- cy: j,
60
- r: P > 0 ? P : 0
61
- }), v.setAttribute("style", "fill:var(--prism-bg,#fff)"); y.children.length > x.length;) y.removeChild(y.lastChild);
62
- for (; b.children.length > x.length;) b.removeChild(b.lastChild);
63
- let z = t(f.transition, 0), B = z.duration, V = e(z.easing);
64
- for (let e = 0; e < x.length; e++) {
65
- let t = x[e], n = y.children[e];
66
- n || (n = r("path", { class: "prism-pie-slice" }), y.appendChild(n)), n.setAttribute("fill", t.color), n.setAttribute("stroke", "none"), n.style.cursor = f.onClick || f.onHover ? "pointer" : "";
67
- }
68
- if (S !== null && (cancelAnimationFrame(S), S = null), B > 0) {
69
- let e = null, t = (r) => {
70
- e === null && (e = r);
71
- let a = V(Math.min(1, (r - e) / B)), o = n(R, L, a);
72
- for (let e = 0; e < x.length; e++) {
73
- let t = x[e], n = y.children[e];
74
- if (n) if (o <= t.startAngle) i(n, { d: "" });
75
- else {
76
- let e = Math.min(t.endAngle, o);
77
- i(n, { d: c({
78
- ...t,
79
- endAngle: e
80
- }) });
47
+ let w;
48
+ try {
49
+ return w = n(u, {
50
+ a11y: d.a11y,
51
+ legend: d.legend,
52
+ tooltip: d.tooltip
53
+ }, (n) => {
54
+ let { legend: w, svg: T, tooltip: E } = n;
55
+ T.contains(v) || (T.appendChild(v), T.appendChild(y), T.appendChild(b));
56
+ let { height: D, width: O } = n.dimensions, k = f === "semi", A = O / 2, j = k ? D * .85 : D / 2, M = k ? Math.min(A, j) - 8 : Math.min(O, D) / 2 - 8, N = f === "pie" ? 0 : Math.round(M * .55), P = d.innerRadius === void 0 ? N : d.innerRadius, F = Math.max(P + 1, M), I = _, { end: L, start: R } = p(f);
57
+ for (x = l(I, A, j, F, P, R, L, m, g, (e) => r(e), !1), t(v, {
58
+ cx: A,
59
+ cy: j,
60
+ r: P > 0 ? P : 0
61
+ }), v.setAttribute("style", "fill:var(--prism-bg,#fff)"); y.children.length > x.length;) y.removeChild(y.lastChild);
62
+ b.replaceChildren();
63
+ let z = a(d.transition, 0), B = z.duration, V = i(z.easing);
64
+ for (let t = 0; t < x.length; t++) {
65
+ let n = x[t], r = y.children[t];
66
+ r || (r = e("path", { class: "prism-pie-slice" }), y.appendChild(r)), r.setAttribute("fill", n.color), r.setAttribute("stroke", "none"), r.style.cursor = d.onClick || d.onHover ? "pointer" : "";
67
+ }
68
+ if (S !== null && (cancelAnimationFrame(S), S = null), B > 0) {
69
+ let e = null, n = (r) => {
70
+ e === null && (e = r);
71
+ let i = V(Math.min(1, (r - e) / B)), a = o(R, L, i);
72
+ for (let e = 0; e < x.length; e++) {
73
+ let n = x[e], r = y.children[e];
74
+ if (r) {
75
+ if (a <= n.startAngle) t(r, { d: "" });
76
+ else {
77
+ let e = Math.min(n.endAngle, a);
78
+ t(r, { d: c({
79
+ ...n,
80
+ endAngle: e
81
+ }) });
82
+ }
83
+ }
81
84
  }
85
+ i < 1 ? S = requestAnimationFrame(n) : (S = null, C(I));
86
+ };
87
+ S = requestAnimationFrame(n);
88
+ } else {
89
+ for (let e = 0; e < x.length; e++) {
90
+ let n = x[e], r = y.children[e];
91
+ r && t(r, { d: c(n) });
82
92
  }
83
- a < 1 ? S = requestAnimationFrame(t) : (S = null, C(I));
84
- };
85
- S = requestAnimationFrame(t);
86
- } else {
87
- for (let e = 0; e < x.length; e++) {
88
- let t = x[e], n = y.children[e];
89
- n && i(n, { d: c(t) });
93
+ C(I);
90
94
  }
91
- C(I);
92
- }
93
- return w?.update(x.map((e) => ({
94
- color: e.color,
95
- name: e.slice.label ?? ""
96
- }))), E?.hide(), {
97
- onClick: (e) => {
98
- if (!f.onClick) return;
99
- let t = T.getBoundingClientRect(), n = e.clientX - t.left, r = e.clientY - t.top, i = g(x, n, r, p);
100
- i >= 0 && f.onClick(x[i].slice, i);
95
+ return w?.update(x.map((e) => ({
96
+ color: e.color,
97
+ name: e.slice.label ?? ""
98
+ }))), E?.hide(), {
99
+ onClick: (e) => {
100
+ if (!d.onClick) return;
101
+ let t = T.getBoundingClientRect(), n = e.clientX - t.left, r = e.clientY - t.top, i = h(x, n, r, f);
102
+ i >= 0 && d.onClick(x[i].slice, i);
103
+ },
104
+ onMouseLeave: () => {
105
+ d.onHover?.(null, null), E?.hide();
106
+ },
107
+ onMouseMove: (e) => {
108
+ let t = T.getBoundingClientRect(), n = e.clientX - t.left, r = e.clientY - t.top, i = h(x, n, r, f);
109
+ if (i >= 0) {
110
+ let e = x[i];
111
+ d.onHover?.(e.slice, i);
112
+ let { x: n, y: r } = s(e), a = u.getBoundingClientRect();
113
+ E?.show(n + (t.left - a.left), r + (t.top - a.top), {
114
+ key: i,
115
+ value: e.slice.value
116
+ }, {
117
+ color: e.color,
118
+ data: [],
119
+ name: e.slice.label ?? ""
120
+ });
121
+ } else d.onHover?.(null, null), E?.hide();
122
+ }
123
+ };
124
+ }, (e) => {
125
+ _ = e;
126
+ }), {
127
+ get disposalSignal() {
128
+ return w.disposalSignal;
129
+ },
130
+ dispose() {
131
+ S !== null && (cancelAnimationFrame(S), S = null), w.dispose();
132
+ },
133
+ get disposed() {
134
+ return w.disposed;
101
135
  },
102
- onMouseLeave: () => {
103
- f.onHover?.(null, null), E?.hide();
136
+ el: w.el,
137
+ update(e) {
138
+ w.update(e);
104
139
  },
105
- onMouseMove: (e) => {
106
- let t = T.getBoundingClientRect(), n = e.clientX - t.left, r = e.clientY - t.top, i = g(x, n, r, p);
107
- if (i >= 0) {
108
- let e = x[i];
109
- f.onHover?.(e.slice, i);
110
- let { x: n, y: r } = s(e), a = d.getBoundingClientRect();
111
- E?.show(n + (t.left - a.left), r + (t.top - a.top), {
112
- key: i,
113
- value: e.slice.value
114
- }, {
115
- color: e.color,
116
- data: [],
117
- name: e.slice.label ?? ""
118
- });
119
- } else f.onHover?.(null, null), E?.hide();
140
+ [Symbol.dispose]() {
141
+ this.dispose();
120
142
  }
121
143
  };
122
- });
123
- return {
124
- get disposalSignal() {
125
- return w.disposalSignal;
126
- },
127
- dispose() {
128
- S !== null && (cancelAnimationFrame(S), S = null), w.dispose();
129
- },
130
- get disposed() {
131
- return w.disposed;
132
- },
133
- el: w.el,
134
- [Symbol.dispose]() {
135
- this.dispose();
136
- }
137
- };
144
+ } catch (e) {
145
+ throw w?.dispose(), e;
146
+ }
138
147
  }
139
- function g(e, t, n, r) {
148
+ function h(e, t, n, r) {
140
149
  for (let i = 0; i < e.length; i++) {
141
150
  let a = e[i], o = t - a.centerX, s = n - a.centerY, c = Math.sqrt(o * o + s * s);
142
151
  if (c < a.outerRadius && c >= a.innerRadius) {
@@ -144,7 +153,7 @@ function g(e, t, n, r) {
144
153
  if (r === "semi") {
145
154
  if (e >= a.startAngle - 1e-9 && e <= a.endAngle + 1e-9) return i;
146
155
  } else {
147
- let t = e < 0 ? e + d : e;
156
+ let t = e < 0 ? e + u : e;
148
157
  if (t >= a.startAngle - 1e-9 && t <= a.endAngle + 1e-9) return i;
149
158
  }
150
159
  }
@@ -152,6 +161,6 @@ function g(e, t, n, r) {
152
161
  return -1;
153
162
  }
154
163
  //#endregion
155
- export { h as createPieChart };
164
+ export { m as createPieChart };
156
165
 
157
166
  //# sourceMappingURL=pie-chart.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pie-chart.js","names":[],"sources":["../../../src/charts/pie/pie-chart.ts"],"sourcesContent":["import { isReactive } from '@vielzeug/ripple';\nimport { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { tweenNumber } from '../../animation/tween';\nimport type { ChartEventHandlers } from '../../core/chart-scaffold';\nimport { createRadialScaffold } from '../../core/chart-scaffold';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport { seriesColor } from '../../theme';\nimport type { ChartHandle, PieChartConfig, PieSliceConfig } from '../../types';\nimport { type Arc, arcCentroid, arcPath, computeArcs } from './pie-renderer';\n\nconst TWO_PI = 2 * Math.PI;\n\nconst SEMI_START = -Math.PI / 2; // -90° = 9-o'clock (left)\nconst SEMI_END = Math.PI / 2; // +90° = 3-o'clock (right) → true 180° half-circle\n\nfunction semiAngles(variant: PieChartConfig['variant']): { end: number; start: number } {\n return variant === 'semi' ? { end: SEMI_END, start: SEMI_START } : { end: TWO_PI, start: 0 };\n}\n\nexport function createPieChart(container: HTMLElement, config: PieChartConfig): ChartHandle {\n const variant = config.variant ?? 'pie';\n const padPixels = config.padPixels ?? (variant === 'pie' ? 0 : 8);\n const cornerRadius = config.cornerRadius ?? (variant === 'pie' ? 0 : 8);\n\n // Pie SVG elements live directly on the SVG (not inside chartArea groups).\n // We create them once and reuse across renders.\n const bgCircle = createSvgElement('circle', { class: 'prism-pie-bg', 'pointer-events': 'none' });\n const pieGroup = createSvgElement('g', {\n class: 'prism-pie-slices',\n 'shape-rendering': 'geometricPrecision',\n });\n const labelGroup = createSvgElement('g', { class: 'prism-pie-labels', 'pointer-events': 'none' });\n\n // Current arcs shared between renderFn and event handlers via closure.\n let currentArcs: Arc[] = [];\n let activeRaf: number | null = null;\n\n function renderLabels(slices: PieSliceConfig[]): void {\n while (labelGroup.children.length > currentArcs.length) labelGroup.removeChild(labelGroup.lastChild!);\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n const slice = slices[i];\n\n if (!slice?.label) continue;\n\n const { x, y } = arcCentroid(arc);\n let text = labelGroup.children[i] as SVGTextElement | undefined;\n\n if (!text) {\n text = createSvgElement('text', { class: 'prism-pie-label' });\n labelGroup.appendChild(text);\n }\n\n setAttributes(text, {\n 'dominant-baseline': 'middle',\n fill: 'var(--prism-pie-label-color, #fff)',\n 'font-family': 'var(--prism-font-family, system-ui)',\n 'font-size': 'var(--prism-pie-label-size, 12px)',\n 'text-anchor': 'middle',\n x,\n y,\n });\n\n text.textContent = slice.label;\n }\n }\n\n const handle = createRadialScaffold(\n container,\n {\n a11y: config.a11y,\n legend: config.legend,\n plugins: config.plugins,\n tooltip: config.tooltip,\n },\n (ctx): ChartEventHandlers => {\n const { legend, svg, tooltip } = ctx;\n\n // Append pie groups to SVG on first render (idempotent).\n if (!svg.contains(bgCircle)) {\n svg.appendChild(bgCircle);\n svg.appendChild(pieGroup);\n svg.appendChild(labelGroup);\n }\n\n const { height: h, width: w } = ctx.dimensions.value;\n const isSemi = variant === 'semi';\n const cx = w / 2;\n const cy = isSemi ? h * 0.85 : h / 2;\n const padding = 8;\n const outer = isSemi ? Math.min(cx, cy) - padding : Math.min(w, h) / 2 - padding;\n const defaultInner = variant === 'pie' ? 0 : Math.round(outer * 0.55);\n const inner = config.innerRadius !== undefined ? config.innerRadius : defaultInner;\n const outerR = Math.max(inner + 1, outer);\n\n const slices = isReactive(config.data) ? config.data.value : config.data;\n const { end, start } = semiAngles(variant);\n\n currentArcs = computeArcs(\n slices,\n cx,\n cy,\n outerR,\n inner,\n start,\n end,\n padPixels,\n cornerRadius,\n (i) => seriesColor(i),\n false,\n );\n\n setAttributes(bgCircle, { cx, cy, r: inner > 0 ? inner : 0 });\n bgCircle.setAttribute('style', 'fill:var(--prism-bg,#fff)');\n\n while (pieGroup.children.length > currentArcs.length) pieGroup.removeChild(pieGroup.lastChild!);\n\n while (labelGroup.children.length > currentArcs.length) labelGroup.removeChild(labelGroup.lastChild!);\n\n const motion = resolveMotion(config.transition, 0);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n let path = pieGroup.children[i] as SVGPathElement | undefined;\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-pie-slice' });\n pieGroup.appendChild(path);\n }\n\n path.setAttribute('fill', arc.color);\n path.setAttribute('stroke', 'none');\n path.style.cursor = config.onClick || config.onHover ? 'pointer' : '';\n }\n\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n if (dur > 0) {\n let rafStart: number | null = null;\n\n const frame = (ts: number) => {\n if (rafStart === null) rafStart = ts;\n\n const t = easing(Math.min(1, (ts - rafStart) / dur));\n const revealAngle = tweenNumber(start, end, t);\n\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (!el) continue;\n\n if (revealAngle <= a.startAngle) {\n setAttributes(el, { d: '' });\n } else {\n const visibleEnd = Math.min(a.endAngle, revealAngle);\n\n setAttributes(el, { d: arcPath({ ...a, endAngle: visibleEnd }) });\n }\n }\n\n if (t < 1) {\n activeRaf = requestAnimationFrame(frame);\n } else {\n activeRaf = null;\n renderLabels(slices);\n }\n };\n\n activeRaf = requestAnimationFrame(frame);\n } else {\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (el) setAttributes(el, { d: arcPath(a) });\n }\n\n renderLabels(slices);\n }\n\n legend?.update(currentArcs.map((arc) => ({ color: arc.color, name: arc.slice.label ?? '' })));\n tooltip?.hide();\n\n const onMouseMove = (e: MouseEvent): void => {\n const svgRect = svg.getBoundingClientRect();\n const mx = e.clientX - svgRect.left;\n const my = e.clientY - svgRect.top;\n const hit = hitTestArc(currentArcs, mx, my, variant);\n\n if (hit >= 0) {\n const arc = currentArcs[hit];\n\n config.onHover?.(arc.slice, hit);\n\n const { x, y } = arcCentroid(arc);\n const contR = container.getBoundingClientRect();\n\n tooltip?.show(\n x + (svgRect.left - contR.left),\n y + (svgRect.top - contR.top),\n { key: hit, value: arc.slice.value },\n { color: arc.color, data: [], name: arc.slice.label ?? '' },\n );\n } else {\n config.onHover?.(null, null);\n tooltip?.hide();\n }\n };\n\n const onMouseLeave = (): void => {\n config.onHover?.(null, null);\n tooltip?.hide();\n };\n\n const onClick = (e: MouseEvent): void => {\n if (!config.onClick) return;\n\n const svgRect = svg.getBoundingClientRect();\n const mx = e.clientX - svgRect.left;\n const my = e.clientY - svgRect.top;\n const hit = hitTestArc(currentArcs, mx, my, variant);\n\n if (hit >= 0) config.onClick(currentArcs[hit].slice, hit);\n };\n\n return { onClick, onMouseLeave, onMouseMove };\n },\n );\n\n return {\n get disposalSignal(): AbortSignal {\n return handle.disposalSignal;\n },\n\n dispose() {\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n handle.dispose();\n },\n\n get disposed(): boolean {\n return handle.disposed;\n },\n\n el: handle.el,\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n}\n\nfunction hitTestArc(arcs: Arc[], mx: number, my: number, variant: PieChartConfig['variant']): number {\n for (let i = 0; i < arcs.length; i++) {\n const arc = arcs[i];\n const dx = mx - arc.centerX;\n const dy = my - arc.centerY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n if (dist < arc.outerRadius && dist >= arc.innerRadius) {\n const rawAngle = Math.atan2(dx, -dy);\n\n if (variant === 'semi') {\n if (rawAngle >= arc.startAngle - 1e-9 && rawAngle <= arc.endAngle + 1e-9) return i;\n } else {\n const angle = rawAngle < 0 ? rawAngle + TWO_PI : rawAngle;\n\n if (angle >= arc.startAngle - 1e-9 && angle <= arc.endAngle + 1e-9) return i;\n }\n }\n }\n\n return -1;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pie-chart.js","names":[],"sources":["../../../src/charts/pie/pie-chart.ts"],"sourcesContent":["import { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { tweenNumber } from '../../animation/tween';\nimport type { ChartEventHandlers } from '../../core/chart-scaffold';\nimport { createRadialScaffold } from '../../core/chart-scaffold';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport { seriesColor } from '../../theme';\nimport type { ChartHandle, PieChartConfig, PieSliceConfig } from '../../types';\nimport { type Arc, arcCentroid, arcPath, computeArcs } from './pie-renderer';\n\nconst TWO_PI = 2 * Math.PI;\n\nconst SEMI_START = -Math.PI / 2; // -90° = 9-o'clock (left)\nconst SEMI_END = Math.PI / 2; // +90° = 3-o'clock (right) → true 180° half-circle\n\nfunction semiAngles(variant: PieChartConfig['variant']): { end: number; start: number } {\n return variant === 'semi' ? { end: SEMI_END, start: SEMI_START } : { end: TWO_PI, start: 0 };\n}\n\nexport function createPieChart(container: HTMLElement, config: PieChartConfig): ChartHandle<PieSliceConfig[]> {\n const variant = config.variant ?? 'pie';\n const padPixels = config.padPixels ?? (variant === 'pie' ? 0 : 8);\n const cornerRadius = config.cornerRadius ?? (variant === 'pie' ? 0 : 8);\n let data = config.data;\n\n // Pie SVG elements live directly on the SVG (not inside chartArea groups).\n // We create them once and reuse across renders.\n const bgCircle = createSvgElement('circle', { class: 'prism-pie-bg', 'pointer-events': 'none' });\n const pieGroup = createSvgElement('g', {\n class: 'prism-pie-slices',\n 'shape-rendering': 'geometricPrecision',\n });\n const labelGroup = createSvgElement('g', { class: 'prism-pie-labels', 'pointer-events': 'none' });\n\n // Current arcs shared between renderFn and event handlers via closure.\n let currentArcs: Arc[] = [];\n let activeRaf: number | null = null;\n\n function renderLabels(slices: PieSliceConfig[]): void {\n labelGroup.replaceChildren();\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n const slice = slices[i];\n\n if (!slice?.label) continue;\n\n const { x, y } = arcCentroid(arc);\n const text = createSvgElement('text', { class: 'prism-pie-label' });\n\n setAttributes(text, {\n 'dominant-baseline': 'middle',\n fill: 'var(--prism-pie-label-color, #fff)',\n 'font-family': 'var(--prism-font-family, system-ui)',\n 'font-size': 'var(--prism-pie-label-size, 12px)',\n 'text-anchor': 'middle',\n x,\n y,\n });\n\n text.textContent = slice.label;\n labelGroup.appendChild(text);\n }\n }\n\n let handle: ChartHandle<PieSliceConfig[]> | undefined;\n\n try {\n handle = createRadialScaffold(\n container,\n {\n a11y: config.a11y,\n legend: config.legend,\n tooltip: config.tooltip,\n },\n (ctx): ChartEventHandlers => {\n const { legend, svg, tooltip } = ctx;\n\n // Append pie groups to SVG on first render (idempotent).\n if (!svg.contains(bgCircle)) {\n svg.appendChild(bgCircle);\n svg.appendChild(pieGroup);\n svg.appendChild(labelGroup);\n }\n\n const { height: h, width: w } = ctx.dimensions;\n const isSemi = variant === 'semi';\n const cx = w / 2;\n const cy = isSemi ? h * 0.85 : h / 2;\n const padding = 8;\n const outer = isSemi ? Math.min(cx, cy) - padding : Math.min(w, h) / 2 - padding;\n const defaultInner = variant === 'pie' ? 0 : Math.round(outer * 0.55);\n const inner = config.innerRadius !== undefined ? config.innerRadius : defaultInner;\n const outerR = Math.max(inner + 1, outer);\n\n const slices = data;\n const { end, start } = semiAngles(variant);\n\n currentArcs = computeArcs(\n slices,\n cx,\n cy,\n outerR,\n inner,\n start,\n end,\n padPixels,\n cornerRadius,\n (i) => seriesColor(i),\n false,\n );\n\n setAttributes(bgCircle, { cx, cy, r: inner > 0 ? inner : 0 });\n bgCircle.setAttribute('style', 'fill:var(--prism-bg,#fff)');\n\n while (pieGroup.children.length > currentArcs.length) pieGroup.removeChild(pieGroup.lastChild!);\n\n labelGroup.replaceChildren();\n\n const motion = resolveMotion(config.transition, 0);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n let path = pieGroup.children[i] as SVGPathElement | undefined;\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-pie-slice' });\n pieGroup.appendChild(path);\n }\n\n path.setAttribute('fill', arc.color);\n path.setAttribute('stroke', 'none');\n path.style.cursor = config.onClick || config.onHover ? 'pointer' : '';\n }\n\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n if (dur > 0) {\n let rafStart: number | null = null;\n\n const frame = (ts: number) => {\n if (rafStart === null) rafStart = ts;\n\n const t = easing(Math.min(1, (ts - rafStart) / dur));\n const revealAngle = tweenNumber(start, end, t);\n\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (!el) continue;\n\n if (revealAngle <= a.startAngle) {\n setAttributes(el, { d: '' });\n } else {\n const visibleEnd = Math.min(a.endAngle, revealAngle);\n\n setAttributes(el, { d: arcPath({ ...a, endAngle: visibleEnd }) });\n }\n }\n\n if (t < 1) {\n activeRaf = requestAnimationFrame(frame);\n } else {\n activeRaf = null;\n renderLabels(slices);\n }\n };\n\n activeRaf = requestAnimationFrame(frame);\n } else {\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (el) setAttributes(el, { d: arcPath(a) });\n }\n\n renderLabels(slices);\n }\n\n legend?.update(currentArcs.map((arc) => ({ color: arc.color, name: arc.slice.label ?? '' })));\n tooltip?.hide();\n\n const onMouseMove = (e: MouseEvent): void => {\n const svgRect = svg.getBoundingClientRect();\n const mx = e.clientX - svgRect.left;\n const my = e.clientY - svgRect.top;\n const hit = hitTestArc(currentArcs, mx, my, variant);\n\n if (hit >= 0) {\n const arc = currentArcs[hit];\n\n config.onHover?.(arc.slice, hit);\n\n const { x, y } = arcCentroid(arc);\n const contR = container.getBoundingClientRect();\n\n tooltip?.show(\n x + (svgRect.left - contR.left),\n y + (svgRect.top - contR.top),\n { key: hit, value: arc.slice.value },\n { color: arc.color, data: [], name: arc.slice.label ?? '' },\n );\n } else {\n config.onHover?.(null, null);\n tooltip?.hide();\n }\n };\n\n const onMouseLeave = (): void => {\n config.onHover?.(null, null);\n tooltip?.hide();\n };\n\n const onClick = (e: MouseEvent): void => {\n if (!config.onClick) return;\n\n const svgRect = svg.getBoundingClientRect();\n const mx = e.clientX - svgRect.left;\n const my = e.clientY - svgRect.top;\n const hit = hitTestArc(currentArcs, mx, my, variant);\n\n if (hit >= 0) config.onClick(currentArcs[hit].slice, hit);\n };\n\n return { onClick, onMouseLeave, onMouseMove };\n },\n (next) => {\n data = next;\n },\n );\n\n return {\n get disposalSignal(): AbortSignal {\n return handle!.disposalSignal;\n },\n\n dispose() {\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n handle!.dispose();\n },\n\n get disposed(): boolean {\n return handle!.disposed;\n },\n\n el: handle!.el,\n\n update(next) {\n handle!.update(next);\n },\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n } catch (error) {\n handle?.dispose();\n throw error;\n }\n}\n\nfunction hitTestArc(arcs: Arc[], mx: number, my: number, variant: PieChartConfig['variant']): number {\n for (let i = 0; i < arcs.length; i++) {\n const arc = arcs[i];\n const dx = mx - arc.centerX;\n const dy = my - arc.centerY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n if (dist < arc.outerRadius && dist >= arc.innerRadius) {\n const rawAngle = Math.atan2(dx, -dy);\n\n if (variant === 'semi') {\n if (rawAngle >= arc.startAngle - 1e-9 && rawAngle <= arc.endAngle + 1e-9) return i;\n } else {\n const angle = rawAngle < 0 ? rawAngle + TWO_PI : rawAngle;\n\n if (angle >= arc.startAngle - 1e-9 && angle <= arc.endAngle + 1e-9) return i;\n }\n }\n }\n\n return -1;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require("../../animation/easing.cjs"),t=require("../../animation/motion.cjs"),n=require("../../animation/tween.cjs"),r=require("../../svg/element.cjs"),i=require("../../core/chart-base.cjs"),a=require("../../svg/path.cjs");let o=require("@vielzeug/ripple");function s(e,t,n){if(e.length===0)return[];let r=t/Math.max(1,e.length-1),i=Math.min(...e),a=Math.max(...e)-i||1;return e.map((e,t)=>({x:t*r,y:n-(e-i)/a*n}))}function c(e,t,n,r=`linear`){if(e.length===0)return``;let i=s(e,t,n),o=i.map(e=>({x:e.x,y:n}));return a.areaPath(i,o,r??`linear`)}function l(e,t,n,r){if(e.length===0)return``;let i=s(e,t,n);return r===`monotone`?a.monotonePath(i):r===`step`?a.stepPath(i):a.linePath(i)}function u(i,a,o,s,c,l,u){let d=a.length,f=Math.max(1,o/d-1),p=o/d,m=Math.min(0,...a),h=Math.max(...a)-m||1,g=t.resolveMotion(l,0),_=g.duration,v=e.resolveEasing(g.easing);for(;i.children.length>d;){let e=i.lastElementChild;e&&i.removeChild(e)}for(let e=0;e<d;e++){let t=Math.max(1,(a[e]-m)/h*s),o=s-t,l=i.children[e];if(l||(l=r.createSvgElement(`rect`,{class:`prism-spark-bar`}),i.appendChild(l)),r.setAttributes(l,{fill:c,width:f,x:e*p}),_>0&&!l.hasAttribute(`data-init`)){l.setAttribute(`data-init`,`1`),r.setAttributes(l,{height:0,y:s});let e=null,i={h:0,y:s},a={h:t,y:o},c=t=>{if(u?.aborted)return;e===null&&(e=t);let o=v(Math.min(1,(t-e)/_));r.setAttributes(l,{height:n.tweenNumber(i.h,a.h,o),y:n.tweenNumber(i.y,a.y,o)}),o<1&&requestAnimationFrame(c)};requestAnimationFrame(c)}else l.setAttribute(`data-init`,`1`),r.setAttributes(l,{height:t,y:o})}}function d(e){return e.length>0&&e[0]!==null&&typeof e[0]==`object`}function f(e,t,n,r,i,a,o){let s=Math.min(i,n/2,r/2),c=a?s:0,l=a?s:0,u=o?s:0,d=o?s:0;return[`M${e+c},${t}`,`H${e+n-u}`,u?`Q${e+n},${t} ${e+n},${t+u}`:``,`V${t+r-d}`,d?`Q${e+n},${t+r} ${e+n-d},${t+r}`:``,`H${e+l}`,l?`Q${e},${t+r} ${e},${t+r-l}`:``,`V${t+c}`,c?`Q${e},${t} ${e+c},${t}`:``,`Z`].filter(Boolean).join(``)}function p(e){return`var(--prism-color-${e%8+1})`}function m(e,t){let n=t.variant??`line`,a=t.color??`var(--prism-color-1)`,s=t.curve??`linear`,m=t.strokeWidth??1.5,h=t.fillOpacity??.2,g=i.createChartBase(e,{...t.a11y?{a11y:t.a11y}:{ariaHidden:!0},margin:{bottom:0,left:0,right:0,top:0}}),{svg:_}=g;_.classList.add(`prism-sparkline`);let v=r.createSvgElement(`g`,{class:`prism-spark-inner`});_.appendChild(v);let y;function b(){let{height:e,width:i}=g.dimensions.value,_=(0,o.isReactive)(t.data)?t.data.value:t.data;for(;v.firstChild;)v.removeChild(v.firstChild);if(_.length!==0){if(n===`stack`&&d(_)){let n=r.createSvgElement(`g`,{class:`prism-spark-stack`});v.appendChild(n);let a=t.cornerRadius??4,o=_,s=o.reduce((e,t)=>e+Math.max(0,t.value),0);if(s>0){let c=(t.padPixels??0)/2,l=0;o.forEach((t,u)=>{let d=Math.round(l);l+=Math.max(0,t.value)/s*i;let m=u===o.length-1?i:Math.round(l),h=u===0,g=u===o.length-1,_=f(d+(h?0:c),0,Math.max(0,m-d-(h?0:c)-(g?0:c)),e,a,h,g),v=r.createSvgElement(`path`,{class:`prism-spark-stack-segment`});r.setAttributes(v,{d:_,fill:t.color??p(u)}),n.appendChild(v)})}}else if(n===`bar`){let n=r.createSvgElement(`g`,{class:`prism-spark-bars`});v.appendChild(n),u(n,_,i,e,a,t.transition,S.signal)}else{if(n===`area`){let t=r.createSvgElement(`path`,{class:`prism-spark-fill`}),n=c(_,i,e,s);r.setAttributes(t,{d:n,fill:a,"fill-opacity":h,stroke:`none`}),v.appendChild(t)}let t=r.createSvgElement(`path`,{class:`prism-spark-line`}),o=l(_,i,e,s);r.setAttributes(t,{d:o,fill:`none`,stroke:a,"stroke-width":m}),v.appendChild(t)}d(_)||x(_)}}function x(e){if(y?.(),y=void 0,!t.onHover&&!t.onClick||e.length<=1)return;let{width:n}=g.dimensions.value;_.style.cursor=`crosshair`;let r=n/(e.length-1),i=n=>{let i=_.getBoundingClientRect(),a=n.clientX-i.left,o=Math.max(0,Math.min(e.length-1,Math.round(a/r)));t.onHover?.(o,e[o])},a=()=>t.onHover?.(null,null),o=n=>{if(!t.onClick)return;let i=_.getBoundingClientRect(),a=n.clientX-i.left,o=Math.max(0,Math.min(e.length-1,Math.round(a/r)));t.onClick(o,e[o])};_.addEventListener(`mousemove`,i),_.addEventListener(`mouseleave`,a),_.addEventListener(`click`,o),y=()=>{_.removeEventListener(`mousemove`,i),_.removeEventListener(`mouseleave`,a),_.removeEventListener(`click`,o)}}let S=new AbortController,C=(0,o.createScope)();C.run(()=>{(0,o.effect)(()=>{b()},{scheduler:`microtask`})});let w=!1;return{get disposalSignal(){return S.signal},dispose(){w||(w=!0,S.abort(),y?.(),C.dispose(),g.dispose())},get disposed(){return w},el:_,[Symbol.dispose](){this.dispose()}}}exports.createSparkline=m;
1
+ const e=require("../../svg/element.cjs"),t=require("../../errors.cjs"),n=require("../../core/chart-base.cjs"),r=require("../../animation/easing.cjs"),i=require("../../animation/motion.cjs"),a=require("../../animation/tween.cjs"),o=require("../../svg/path.cjs");function s(e,t,n){if(e.length===0)return[];let r=t/Math.max(1,e.length-1),i=Math.min(...e),a=Math.max(...e)-i||1;return e.map((e,t)=>({x:t*r,y:n-(e-i)/a*n}))}function c(e,t,n,r=`linear`){if(e.length===0)return``;let i=s(e,t,n),a=i.map(e=>({x:e.x,y:n}));return o.areaPath(i,a,r??`linear`)}function l(e,t,n,r){if(e.length===0)return``;let i=s(e,t,n);return r===`monotone`?o.monotonePath(i):r===`step`?o.stepPath(i):o.linePath(i)}function u(t,n,o,s,c,l,u){let d=n.length,f=Math.max(1,o/d-1),p=o/d,m=Math.min(0,...n),h=Math.max(...n)-m||1,g=i.resolveMotion(l,0),_=g.duration,v=r.resolveEasing(g.easing);for(;t.children.length>d;){let e=t.lastElementChild;e&&t.removeChild(e)}for(let r=0;r<d;r++){let i=Math.max(1,(n[r]-m)/h*s),o=s-i,l=t.children[r];if(l||(l=e.createSvgElement(`rect`,{class:`prism-spark-bar`}),t.appendChild(l)),e.setAttributes(l,{fill:c,width:f,x:r*p}),_>0&&!l.hasAttribute(`data-init`)){l.setAttribute(`data-init`,`1`),e.setAttributes(l,{height:0,y:s});let t=null,n={h:0,y:s},r={h:i,y:o},c=i=>{if(u?.aborted)return;t===null&&(t=i);let o=v(Math.min(1,(i-t)/_));e.setAttributes(l,{height:a.tweenNumber(n.h,r.h,o),y:a.tweenNumber(n.y,r.y,o)}),o<1&&requestAnimationFrame(c)};requestAnimationFrame(c)}else l.setAttribute(`data-init`,`1`),e.setAttributes(l,{height:i,y:o})}}function d(e){return e.length>0&&e[0]!==null&&typeof e[0]==`object`}function f(e,t,n,r,i,a,o){let s=Math.min(i,n/2,r/2),c=a?s:0,l=a?s:0,u=o?s:0,d=o?s:0;return[`M${e+c},${t}`,`H${e+n-u}`,u?`Q${e+n},${t} ${e+n},${t+u}`:``,`V${t+r-d}`,d?`Q${e+n},${t+r} ${e+n-d},${t+r}`:``,`H${e+l}`,l?`Q${e},${t+r} ${e},${t+r-l}`:``,`V${t+c}`,c?`Q${e},${t} ${e+c},${t}`:``,`Z`].filter(Boolean).join(``)}function p(e){return`var(--prism-color-${e%8+1})`}function m(r,i){let a=i.variant??`line`,o=i.color??`var(--prism-color-1)`,s=i.curve??`linear`,m=i.strokeWidth??1.5,h=i.fillOpacity??.2,g=i.data,_=n.createChartBase(r,{a11y:i.a11y,margin:{bottom:0,left:0,right:0,top:0}},x),{svg:v}=_;v.classList.add(`prism-sparkline`);let y=e.createSvgElement(`g`,{class:`prism-spark-inner`});v.appendChild(y);let b;function x(){let{height:t,width:n}=_.dimensions;for(;y.firstChild;)y.removeChild(y.firstChild);if(g.length!==0){if(a===`stack`&&d(g)){let r=e.createSvgElement(`g`,{class:`prism-spark-stack`});y.appendChild(r);let a=i.cornerRadius??4,o=g,s=o.reduce((e,t)=>e+Math.max(0,t.value),0);if(s>0){let c=(i.padPixels??0)/2,l=0;o.forEach((i,u)=>{let d=Math.round(l);l+=Math.max(0,i.value)/s*n;let m=u===o.length-1?n:Math.round(l),h=u===0,g=u===o.length-1,_=f(d+(h?0:c),0,Math.max(0,m-d-(h?0:c)-(g?0:c)),t,a,h,g),v=e.createSvgElement(`path`,{class:`prism-spark-stack-segment`});e.setAttributes(v,{d:_,fill:i.color??p(u)}),r.appendChild(v)})}}else if(a===`bar`){let r=e.createSvgElement(`g`,{class:`prism-spark-bars`});y.appendChild(r),u(r,g,n,t,o,i.transition,C.signal)}else{if(a===`area`){let r=e.createSvgElement(`path`,{class:`prism-spark-fill`}),i=c(g,n,t,s);e.setAttributes(r,{d:i,fill:o,"fill-opacity":h,stroke:`none`}),y.appendChild(r)}let r=e.createSvgElement(`path`,{class:`prism-spark-line`}),i=l(g,n,t,s);e.setAttributes(r,{d:i,fill:`none`,stroke:o,"stroke-width":m}),y.appendChild(r)}d(g)||S(g)}}function S(e){if(b?.(),b=void 0,!i.onHover&&!i.onClick||e.length<=1)return;let{width:t}=_.dimensions;v.style.cursor=`crosshair`;let n=t/(e.length-1),r=t=>{let r=v.getBoundingClientRect(),a=t.clientX-r.left,o=Math.max(0,Math.min(e.length-1,Math.round(a/n)));i.onHover?.(o,e[o])},a=()=>i.onHover?.(null,null),o=t=>{if(!i.onClick)return;let r=v.getBoundingClientRect(),a=t.clientX-r.left,o=Math.max(0,Math.min(e.length-1,Math.round(a/n)));i.onClick(o,e[o])};v.addEventListener(`mousemove`,r),v.addEventListener(`mouseleave`,a),v.addEventListener(`click`,o),b=()=>{v.removeEventListener(`mousemove`,r),v.removeEventListener(`mouseleave`,a),v.removeEventListener(`click`,o)}}let C=new AbortController,w=!1;try{return x(),{get disposalSignal(){return C.signal},dispose(){w||(w=!0,C.abort(),b?.(),_.dispose())},get disposed(){return w},el:v,update(e){if(w)throw new t.PrismRenderError(`Cannot update a disposed chart.`);g=e,x()},[Symbol.dispose](){this.dispose()}}}catch(e){throw C.abort(),b?.(),_.dispose(),e instanceof t.PrismRenderError?e:new t.PrismRenderError(`Failed to render chart.`,{cause:e})}}exports.createSparkline=m;
2
2
  //# sourceMappingURL=sparkline.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"sparkline.cjs","names":[],"sources":["../../../src/charts/sparkline/sparkline.ts"],"sourcesContent":["import { createScope, effect, isReactive } from '@vielzeug/ripple';\nimport { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { tweenNumber } from '../../animation/tween';\nimport { createChartBase } from '../../core/chart-base';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport type { Point } from '../../svg/path';\nimport { areaPath, linePath, monotonePath, stepPath } from '../../svg/path';\nimport type { ChartHandle, SparklineConfig, StackSegment } from '../../types';\n\nfunction buildTopPoints(data: number[], width: number, height: number): Point[] {\n if (data.length === 0) return [];\n\n const xStep = width / Math.max(1, data.length - 1);\n const min = Math.min(...data);\n const max = Math.max(...data);\n const yRange = max - min || 1;\n\n return data.map((v, i) => ({\n x: i * xStep,\n y: height - ((v - min) / yRange) * height,\n }));\n}\n\nfunction buildAreaPath(\n data: number[],\n width: number,\n height: number,\n curve: SparklineConfig['curve'] = 'linear',\n): string {\n if (data.length === 0) return '';\n\n const top = buildTopPoints(data, width, height);\n const bottom = top.map((p) => ({ x: p.x, y: height }));\n\n return areaPath(top, bottom, curve ?? 'linear');\n}\n\nfunction buildPath(data: number[], width: number, height: number, curve: SparklineConfig['curve']): string {\n if (data.length === 0) return '';\n\n const points = buildTopPoints(data, width, height);\n\n return curve === 'monotone' ? monotonePath(points) : curve === 'step' ? stepPath(points) : linePath(points);\n}\n\nfunction renderSparkBars(\n parent: SVGGElement,\n data: number[],\n width: number,\n height: number,\n color: string,\n transition?: SparklineConfig['transition'],\n disposalSignal?: AbortSignal,\n): void {\n const count = data.length;\n const barW = Math.max(1, width / count - 1);\n const gap = width / count;\n const min = Math.min(0, ...data);\n const max = Math.max(...data);\n const yRange = max - min || 1;\n const motion = resolveMotion(transition, 0);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n while (parent.children.length > count) {\n const last = parent.lastElementChild;\n\n if (last) parent.removeChild(last);\n }\n\n for (let i = 0; i < count; i++) {\n const finalH = Math.max(1, ((data[i] - min) / yRange) * height);\n const finalY = height - finalH;\n\n let rect = parent.children[i] as SVGRectElement | undefined;\n\n if (!rect) {\n rect = createSvgElement('rect', { class: 'prism-spark-bar' });\n parent.appendChild(rect);\n }\n\n setAttributes(rect, { fill: color, width: barW, x: i * gap });\n\n if (dur > 0 && !rect.hasAttribute('data-init')) {\n rect.setAttribute('data-init', '1');\n setAttributes(rect, { height: 0, y: height });\n\n let start: number | null = null;\n const from = { h: 0, y: height };\n const to = { h: finalH, y: finalY };\n\n const frame = (ts: number) => {\n if (disposalSignal?.aborted) return;\n\n if (start === null) start = ts;\n\n const t = easing(Math.min(1, (ts - start) / dur));\n\n setAttributes(rect!, {\n height: tweenNumber(from.h, to.h, t),\n y: tweenNumber(from.y, to.y, t),\n });\n\n if (t < 1) requestAnimationFrame(frame);\n };\n\n requestAnimationFrame(frame);\n } else {\n rect.setAttribute('data-init', '1');\n setAttributes(rect, { height: finalH, y: finalY });\n }\n }\n}\n\nfunction isStackData(data: number[] | StackSegment[]): data is StackSegment[] {\n return data.length > 0 && data[0] !== null && typeof data[0] === 'object';\n}\n\nfunction buildRoundedStackRect(\n x: number,\n y: number,\n w: number,\n h: number,\n r: number,\n roundLeft: boolean,\n roundRight: boolean,\n): string {\n const maxR = Math.min(r, w / 2, h / 2);\n const tl = roundLeft ? maxR : 0;\n const bl = roundLeft ? maxR : 0;\n const tr = roundRight ? maxR : 0;\n const br = roundRight ? maxR : 0;\n\n return [\n `M${x + tl},${y}`,\n `H${x + w - tr}`,\n tr ? `Q${x + w},${y} ${x + w},${y + tr}` : '',\n `V${y + h - br}`,\n br ? `Q${x + w},${y + h} ${x + w - br},${y + h}` : '',\n `H${x + bl}`,\n bl ? `Q${x},${y + h} ${x},${y + h - bl}` : '',\n `V${y + tl}`,\n tl ? `Q${x},${y} ${x + tl},${y}` : '',\n 'Z',\n ]\n .filter(Boolean)\n .join('');\n}\n\nfunction defaultStackColor(i: number): string {\n return `var(--prism-color-${(i % 8) + 1})`;\n}\n\nexport function createSparkline(container: HTMLElement, config: SparklineConfig): ChartHandle {\n const variant = config.variant ?? 'line';\n const color = config.color ?? 'var(--prism-color-1)';\n const curve = config.curve ?? 'linear';\n const strokeWidth = config.strokeWidth ?? 1.5;\n const fillOpacity = config.fillOpacity ?? 0.2;\n\n const base = createChartBase(container, {\n ...(config.a11y ? { a11y: config.a11y } : { ariaHidden: true }),\n margin: { bottom: 0, left: 0, right: 0, top: 0 },\n });\n\n const { svg } = base;\n\n svg.classList.add('prism-sparkline');\n\n const innerGroup = createSvgElement('g', { class: 'prism-spark-inner' });\n\n svg.appendChild(innerGroup);\n\n let cleanupInteraction: (() => void) | undefined;\n\n function renderAll(): void {\n const { height: h, width: w } = base.dimensions.value;\n const data = isReactive(config.data) ? config.data.value : config.data;\n\n while (innerGroup.firstChild) innerGroup.removeChild(innerGroup.firstChild);\n\n if (data.length === 0) return;\n\n if (variant === 'stack' && isStackData(data)) {\n const stackGroup = createSvgElement('g', { class: 'prism-spark-stack' });\n\n innerGroup.appendChild(stackGroup);\n\n const cornerRadius = config.cornerRadius ?? 4;\n const segs = data as StackSegment[];\n const total = segs.reduce((s, d) => s + Math.max(0, d.value), 0);\n\n if (total > 0) {\n const half = (config.padPixels ?? 0) / 2;\n let xAcc = 0;\n\n segs.forEach((seg, i) => {\n const xStart = Math.round(xAcc);\n\n xAcc += (Math.max(0, seg.value) / total) * w;\n\n const xEnd = i === segs.length - 1 ? w : Math.round(xAcc);\n const isFirst = i === 0;\n const isLast = i === segs.length - 1;\n const drawX = xStart + (isFirst ? 0 : half);\n const drawW = Math.max(0, xEnd - xStart - (isFirst ? 0 : half) - (isLast ? 0 : half));\n const d = buildRoundedStackRect(drawX, 0, drawW, h, cornerRadius, isFirst, isLast);\n const path = createSvgElement('path', { class: 'prism-spark-stack-segment' });\n\n setAttributes(path, { d, fill: seg.color ?? defaultStackColor(i) });\n stackGroup.appendChild(path);\n });\n }\n } else if (variant === 'bar') {\n const barsGroup = createSvgElement('g', { class: 'prism-spark-bars' });\n\n innerGroup.appendChild(barsGroup);\n renderSparkBars(barsGroup, data as number[], w, h, color, config.transition, ac.signal);\n } else {\n if (variant === 'area') {\n const fill = createSvgElement('path', { class: 'prism-spark-fill' });\n const fillD = buildAreaPath(data as number[], w, h, curve);\n\n setAttributes(fill, { d: fillD, fill: color, 'fill-opacity': fillOpacity, stroke: 'none' });\n innerGroup.appendChild(fill);\n }\n\n const path = createSvgElement('path', { class: 'prism-spark-line' });\n const pathD = buildPath(data as number[], w, h, curve);\n\n setAttributes(path, { d: pathD, fill: 'none', stroke: color, 'stroke-width': strokeWidth });\n innerGroup.appendChild(path);\n }\n\n if (!isStackData(data)) attachInteraction(data as number[]);\n }\n\n function attachInteraction(data: number[]): void {\n cleanupInteraction?.();\n cleanupInteraction = undefined;\n\n if (!config.onHover && !config.onClick) return;\n\n if (data.length <= 1) return;\n\n const { width: w } = base.dimensions.value;\n\n svg.style.cursor = 'crosshair';\n\n const xStep = w / (data.length - 1);\n\n const handleMove = (e: MouseEvent) => {\n const rect = svg.getBoundingClientRect();\n const relX = e.clientX - rect.left;\n const idx = Math.max(0, Math.min(data.length - 1, Math.round(relX / xStep)));\n\n config.onHover?.(idx, data[idx]);\n };\n\n const handleLeave = () => config.onHover?.(null, null);\n\n const handleClick = (e: MouseEvent) => {\n if (!config.onClick) return;\n\n const rect = svg.getBoundingClientRect();\n const relX = e.clientX - rect.left;\n const idx = Math.max(0, Math.min(data.length - 1, Math.round(relX / xStep)));\n\n config.onClick(idx, data[idx]);\n };\n\n svg.addEventListener('mousemove', handleMove);\n svg.addEventListener('mouseleave', handleLeave);\n svg.addEventListener('click', handleClick);\n\n cleanupInteraction = () => {\n svg.removeEventListener('mousemove', handleMove);\n svg.removeEventListener('mouseleave', handleLeave);\n svg.removeEventListener('click', handleClick);\n };\n }\n\n const ac = new AbortController();\n\n const scope = createScope();\n\n scope.run(() => {\n effect(\n () => {\n renderAll();\n },\n { scheduler: 'microtask' },\n );\n });\n\n let isDisposed = false;\n\n return {\n get disposalSignal(): AbortSignal {\n return ac.signal;\n },\n\n dispose() {\n if (isDisposed) return;\n\n isDisposed = true;\n ac.abort();\n cleanupInteraction?.();\n scope.dispose();\n base.dispose();\n },\n\n get disposed(): boolean {\n return isDisposed;\n },\n\n el: svg,\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sparkline.cjs","names":[],"sources":["../../../src/charts/sparkline/sparkline.ts"],"sourcesContent":["import { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { tweenNumber } from '../../animation/tween';\nimport { createChartBase } from '../../core/chart-base';\nimport { PrismRenderError } from '../../errors';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport type { Point } from '../../svg/path';\nimport { areaPath, linePath, monotonePath, stepPath } from '../../svg/path';\nimport type { ChartHandle, SparklineConfig, StackSegment } from '../../types';\n\nfunction buildTopPoints(data: number[], width: number, height: number): Point[] {\n if (data.length === 0) return [];\n\n const xStep = width / Math.max(1, data.length - 1);\n const min = Math.min(...data);\n const max = Math.max(...data);\n const yRange = max - min || 1;\n\n return data.map((v, i) => ({\n x: i * xStep,\n y: height - ((v - min) / yRange) * height,\n }));\n}\n\nfunction buildAreaPath(\n data: number[],\n width: number,\n height: number,\n curve: SparklineConfig['curve'] = 'linear',\n): string {\n if (data.length === 0) return '';\n\n const top = buildTopPoints(data, width, height);\n const bottom = top.map((p) => ({ x: p.x, y: height }));\n\n return areaPath(top, bottom, curve ?? 'linear');\n}\n\nfunction buildPath(data: number[], width: number, height: number, curve: SparklineConfig['curve']): string {\n if (data.length === 0) return '';\n\n const points = buildTopPoints(data, width, height);\n\n return curve === 'monotone' ? monotonePath(points) : curve === 'step' ? stepPath(points) : linePath(points);\n}\n\nfunction renderSparkBars(\n parent: SVGGElement,\n data: number[],\n width: number,\n height: number,\n color: string,\n transition?: SparklineConfig['transition'],\n disposalSignal?: AbortSignal,\n): void {\n const count = data.length;\n const barW = Math.max(1, width / count - 1);\n const gap = width / count;\n const min = Math.min(0, ...data);\n const max = Math.max(...data);\n const yRange = max - min || 1;\n const motion = resolveMotion(transition, 0);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n while (parent.children.length > count) {\n const last = parent.lastElementChild;\n\n if (last) parent.removeChild(last);\n }\n\n for (let i = 0; i < count; i++) {\n const finalH = Math.max(1, ((data[i] - min) / yRange) * height);\n const finalY = height - finalH;\n\n let rect = parent.children[i] as SVGRectElement | undefined;\n\n if (!rect) {\n rect = createSvgElement('rect', { class: 'prism-spark-bar' });\n parent.appendChild(rect);\n }\n\n setAttributes(rect, { fill: color, width: barW, x: i * gap });\n\n if (dur > 0 && !rect.hasAttribute('data-init')) {\n rect.setAttribute('data-init', '1');\n setAttributes(rect, { height: 0, y: height });\n\n let start: number | null = null;\n const from = { h: 0, y: height };\n const to = { h: finalH, y: finalY };\n\n const frame = (ts: number) => {\n if (disposalSignal?.aborted) return;\n\n if (start === null) start = ts;\n\n const t = easing(Math.min(1, (ts - start) / dur));\n\n setAttributes(rect!, {\n height: tweenNumber(from.h, to.h, t),\n y: tweenNumber(from.y, to.y, t),\n });\n\n if (t < 1) requestAnimationFrame(frame);\n };\n\n requestAnimationFrame(frame);\n } else {\n rect.setAttribute('data-init', '1');\n setAttributes(rect, { height: finalH, y: finalY });\n }\n }\n}\n\nfunction isStackData(data: number[] | StackSegment[]): data is StackSegment[] {\n return data.length > 0 && data[0] !== null && typeof data[0] === 'object';\n}\n\nfunction buildRoundedStackRect(\n x: number,\n y: number,\n w: number,\n h: number,\n r: number,\n roundLeft: boolean,\n roundRight: boolean,\n): string {\n const maxR = Math.min(r, w / 2, h / 2);\n const tl = roundLeft ? maxR : 0;\n const bl = roundLeft ? maxR : 0;\n const tr = roundRight ? maxR : 0;\n const br = roundRight ? maxR : 0;\n\n return [\n `M${x + tl},${y}`,\n `H${x + w - tr}`,\n tr ? `Q${x + w},${y} ${x + w},${y + tr}` : '',\n `V${y + h - br}`,\n br ? `Q${x + w},${y + h} ${x + w - br},${y + h}` : '',\n `H${x + bl}`,\n bl ? `Q${x},${y + h} ${x},${y + h - bl}` : '',\n `V${y + tl}`,\n tl ? `Q${x},${y} ${x + tl},${y}` : '',\n 'Z',\n ]\n .filter(Boolean)\n .join('');\n}\n\nfunction defaultStackColor(i: number): string {\n return `var(--prism-color-${(i % 8) + 1})`;\n}\n\nexport function createSparkline(\n container: HTMLElement,\n config: SparklineConfig,\n): ChartHandle<number[] | StackSegment[]> {\n const variant = config.variant ?? 'line';\n const color = config.color ?? 'var(--prism-color-1)';\n const curve = config.curve ?? 'linear';\n const strokeWidth = config.strokeWidth ?? 1.5;\n const fillOpacity = config.fillOpacity ?? 0.2;\n let data = config.data;\n\n const base = createChartBase(\n container,\n {\n a11y: config.a11y,\n margin: { bottom: 0, left: 0, right: 0, top: 0 },\n },\n renderAll,\n );\n\n const { svg } = base;\n\n svg.classList.add('prism-sparkline');\n\n const innerGroup = createSvgElement('g', { class: 'prism-spark-inner' });\n\n svg.appendChild(innerGroup);\n\n let cleanupInteraction: (() => void) | undefined;\n\n function renderAll(): void {\n const { height: h, width: w } = base.dimensions;\n\n while (innerGroup.firstChild) innerGroup.removeChild(innerGroup.firstChild);\n\n if (data.length === 0) return;\n\n if (variant === 'stack' && isStackData(data)) {\n const stackGroup = createSvgElement('g', { class: 'prism-spark-stack' });\n\n innerGroup.appendChild(stackGroup);\n\n const cornerRadius = config.cornerRadius ?? 4;\n const segs = data as StackSegment[];\n const total = segs.reduce((s, d) => s + Math.max(0, d.value), 0);\n\n if (total > 0) {\n const half = (config.padPixels ?? 0) / 2;\n let xAcc = 0;\n\n segs.forEach((seg, i) => {\n const xStart = Math.round(xAcc);\n\n xAcc += (Math.max(0, seg.value) / total) * w;\n\n const xEnd = i === segs.length - 1 ? w : Math.round(xAcc);\n const isFirst = i === 0;\n const isLast = i === segs.length - 1;\n const drawX = xStart + (isFirst ? 0 : half);\n const drawW = Math.max(0, xEnd - xStart - (isFirst ? 0 : half) - (isLast ? 0 : half));\n const d = buildRoundedStackRect(drawX, 0, drawW, h, cornerRadius, isFirst, isLast);\n const path = createSvgElement('path', { class: 'prism-spark-stack-segment' });\n\n setAttributes(path, { d, fill: seg.color ?? defaultStackColor(i) });\n stackGroup.appendChild(path);\n });\n }\n } else if (variant === 'bar') {\n const barsGroup = createSvgElement('g', { class: 'prism-spark-bars' });\n\n innerGroup.appendChild(barsGroup);\n renderSparkBars(barsGroup, data as number[], w, h, color, config.transition, ac.signal);\n } else {\n if (variant === 'area') {\n const fill = createSvgElement('path', { class: 'prism-spark-fill' });\n const fillD = buildAreaPath(data as number[], w, h, curve);\n\n setAttributes(fill, { d: fillD, fill: color, 'fill-opacity': fillOpacity, stroke: 'none' });\n innerGroup.appendChild(fill);\n }\n\n const path = createSvgElement('path', { class: 'prism-spark-line' });\n const pathD = buildPath(data as number[], w, h, curve);\n\n setAttributes(path, { d: pathD, fill: 'none', stroke: color, 'stroke-width': strokeWidth });\n innerGroup.appendChild(path);\n }\n\n if (!isStackData(data)) attachInteraction(data as number[]);\n }\n\n function attachInteraction(data: number[]): void {\n cleanupInteraction?.();\n cleanupInteraction = undefined;\n\n if (!config.onHover && !config.onClick) return;\n\n if (data.length <= 1) return;\n\n const { width: w } = base.dimensions;\n\n svg.style.cursor = 'crosshair';\n\n const xStep = w / (data.length - 1);\n\n const handleMove = (e: MouseEvent) => {\n const rect = svg.getBoundingClientRect();\n const relX = e.clientX - rect.left;\n const idx = Math.max(0, Math.min(data.length - 1, Math.round(relX / xStep)));\n\n config.onHover?.(idx, data[idx]);\n };\n\n const handleLeave = () => config.onHover?.(null, null);\n\n const handleClick = (e: MouseEvent) => {\n if (!config.onClick) return;\n\n const rect = svg.getBoundingClientRect();\n const relX = e.clientX - rect.left;\n const idx = Math.max(0, Math.min(data.length - 1, Math.round(relX / xStep)));\n\n config.onClick(idx, data[idx]);\n };\n\n svg.addEventListener('mousemove', handleMove);\n svg.addEventListener('mouseleave', handleLeave);\n svg.addEventListener('click', handleClick);\n\n cleanupInteraction = () => {\n svg.removeEventListener('mousemove', handleMove);\n svg.removeEventListener('mouseleave', handleLeave);\n svg.removeEventListener('click', handleClick);\n };\n }\n\n const ac = new AbortController();\n let isDisposed = false;\n\n try {\n renderAll();\n\n return {\n get disposalSignal(): AbortSignal {\n return ac.signal;\n },\n\n dispose() {\n if (isDisposed) return;\n\n isDisposed = true;\n ac.abort();\n cleanupInteraction?.();\n base.dispose();\n },\n\n get disposed(): boolean {\n return isDisposed;\n },\n\n el: svg,\n\n update(next) {\n if (isDisposed) throw new PrismRenderError('Cannot update a disposed chart.');\n data = next;\n renderAll();\n },\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n } catch (error) {\n ac.abort();\n cleanupInteraction?.();\n base.dispose();\n throw error instanceof PrismRenderError ? error : new PrismRenderError('Failed to render chart.', { cause: error });\n }\n}\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import type { ChartHandle, SparklineConfig } from '../../types';
2
- export declare function createSparkline(container: HTMLElement, config: SparklineConfig): ChartHandle;
1
+ import type { ChartHandle, SparklineConfig, StackSegment } from '../../types';
2
+ export declare function createSparkline(container: HTMLElement, config: SparklineConfig): ChartHandle<number[] | StackSegment[]>;
3
3
  //# sourceMappingURL=sparkline.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sparkline.d.ts","sourceRoot":"","sources":["../../../src/charts/sparkline/sparkline.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAgB,MAAM,aAAa,CAAC;AAkJ9E,wBAAgB,eAAe,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,eAAe,GAAG,WAAW,CAyK5F"}
1
+ {"version":3,"file":"sparkline.d.ts","sourceRoot":"","sources":["../../../src/charts/sparkline/sparkline.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAkJ9E,wBAAgB,eAAe,CAC7B,SAAS,EAAE,WAAW,EACtB,MAAM,EAAE,eAAe,GACtB,WAAW,CAAC,MAAM,EAAE,GAAG,YAAY,EAAE,CAAC,CA+KxC"}