@vielzeug/prism 26.10.2 → 26.10.3

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 (89) hide show
  1. package/dist/_dev.cjs.map +1 -1
  2. package/dist/_dev.js.map +1 -1
  3. package/dist/_tappers.cjs +2 -0
  4. package/dist/_tappers.cjs.map +1 -0
  5. package/dist/_tappers.d.ts +10 -0
  6. package/dist/_tappers.d.ts.map +1 -0
  7. package/dist/_tappers.js +2 -0
  8. package/dist/_tappers.js.map +1 -0
  9. package/dist/animation/transition.cjs +1 -1
  10. package/dist/animation/transition.cjs.map +1 -1
  11. package/dist/animation/transition.d.ts +32 -3
  12. package/dist/animation/transition.d.ts.map +1 -1
  13. package/dist/animation/transition.js +1 -1
  14. package/dist/animation/transition.js.map +1 -1
  15. package/dist/charts/area/area-chart.cjs +1 -1
  16. package/dist/charts/area/area-chart.cjs.map +1 -1
  17. package/dist/charts/area/area-chart.d.ts.map +1 -1
  18. package/dist/charts/area/area-chart.js +1 -1
  19. package/dist/charts/area/area-chart.js.map +1 -1
  20. package/dist/charts/area/area-renderer.cjs +1 -1
  21. package/dist/charts/area/area-renderer.cjs.map +1 -1
  22. package/dist/charts/area/area-renderer.d.ts.map +1 -1
  23. package/dist/charts/area/area-renderer.js +1 -1
  24. package/dist/charts/area/area-renderer.js.map +1 -1
  25. package/dist/charts/line/line-chart.cjs +1 -1
  26. package/dist/charts/line/line-chart.cjs.map +1 -1
  27. package/dist/charts/line/line-chart.d.ts.map +1 -1
  28. package/dist/charts/line/line-chart.js +1 -1
  29. package/dist/charts/line/line-chart.js.map +1 -1
  30. package/dist/charts/line/line-renderer.cjs +1 -1
  31. package/dist/charts/line/line-renderer.cjs.map +1 -1
  32. package/dist/charts/line/line-renderer.d.ts.map +1 -1
  33. package/dist/charts/line/line-renderer.js +1 -1
  34. package/dist/charts/line/line-renderer.js.map +1 -1
  35. package/dist/charts/pie/pie-chart.cjs +1 -1
  36. package/dist/charts/pie/pie-chart.cjs.map +1 -1
  37. package/dist/charts/pie/pie-chart.d.ts.map +1 -1
  38. package/dist/charts/pie/pie-chart.js +1 -1
  39. package/dist/charts/pie/pie-chart.js.map +1 -1
  40. package/dist/charts/radar/radar-chart.cjs +1 -1
  41. package/dist/charts/radar/radar-chart.cjs.map +1 -1
  42. package/dist/charts/radar/radar-chart.d.ts.map +1 -1
  43. package/dist/charts/radar/radar-chart.js +1 -1
  44. package/dist/charts/radar/radar-chart.js.map +1 -1
  45. package/dist/charts/sparkline/sparkline.cjs +1 -1
  46. package/dist/charts/sparkline/sparkline.cjs.map +1 -1
  47. package/dist/charts/sparkline/sparkline.d.ts.map +1 -1
  48. package/dist/charts/sparkline/sparkline.js +1 -1
  49. package/dist/charts/sparkline/sparkline.js.map +1 -1
  50. package/dist/core/chart-scaffold.cjs +1 -1
  51. package/dist/core/chart-scaffold.cjs.map +1 -1
  52. package/dist/core/chart-scaffold.d.ts.map +1 -1
  53. package/dist/core/chart-scaffold.js +1 -1
  54. package/dist/core/chart-scaffold.js.map +1 -1
  55. package/dist/index.d.ts +1 -1
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/interaction/series-interaction.cjs +1 -1
  58. package/dist/interaction/series-interaction.cjs.map +1 -1
  59. package/dist/interaction/series-interaction.d.ts +3 -1
  60. package/dist/interaction/series-interaction.d.ts.map +1 -1
  61. package/dist/interaction/series-interaction.js +1 -1
  62. package/dist/interaction/series-interaction.js.map +1 -1
  63. package/dist/prism.cjs +1 -1
  64. package/dist/prism.cjs.map +1 -1
  65. package/dist/prism.iife.js +1 -1
  66. package/dist/prism.iife.js.map +1 -1
  67. package/dist/prism.js +1 -1
  68. package/dist/prism.js.map +1 -1
  69. package/dist/types.d.ts +37 -4
  70. package/dist/types.d.ts.map +1 -1
  71. package/package.json +2 -14
  72. package/dist/animation/index.d.ts +0 -6
  73. package/dist/animation/index.d.ts.map +0 -1
  74. package/dist/axes/index.d.ts +0 -3
  75. package/dist/axes/index.d.ts.map +0 -1
  76. package/dist/core/index.d.ts +0 -7
  77. package/dist/core/index.d.ts.map +0 -1
  78. package/dist/devtools/index.d.ts +0 -52
  79. package/dist/devtools/index.d.ts.map +0 -1
  80. package/dist/devtools.cjs +0 -2
  81. package/dist/devtools.cjs.map +0 -1
  82. package/dist/devtools.js +0 -2
  83. package/dist/devtools.js.map +0 -1
  84. package/dist/interaction/index.d.ts +0 -8
  85. package/dist/interaction/index.d.ts.map +0 -1
  86. package/dist/scales/index.d.ts +0 -4
  87. package/dist/scales/index.d.ts.map +0 -1
  88. package/dist/svg/index.d.ts +0 -5
  89. package/dist/svg/index.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"sparkline.js","names":[],"sources":["../../../src/charts/sparkline/sparkline.ts"],"sourcesContent":["import { warn } from '../../_dev';\nimport { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { tweenNumber } from '../../animation/tween';\nimport { createChartBase } from '../../core/chart-base';\nimport { uniqueId } from '../../core/ids';\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\n/** Fits the 3.5px hover marker plus its ring inside the SVG. */\nconst PLOT_INSET = 5;\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;\n const showEndPoint = config.showEndPoint ?? true;\n const gradientId = uniqueId('prism-spark-fill');\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 /** Line and area plots are inset so dots on the first and last values are not clipped. */\n function plotArea(): { h: number; inset: number; w: number } {\n const { height, width } = base.dimensions;\n const inset = variant === 'line' || variant === 'area' ? PLOT_INSET : 0;\n\n return { h: Math.max(1, height - inset * 2), inset, w: Math.max(1, width - inset * 2) };\n }\n\n function renderAll(): void {\n const { height: h, width: w } = base.dimensions;\n const plot = plotArea();\n\n while (innerGroup.firstChild) innerGroup.removeChild(innerGroup.firstChild);\n\n innerGroup.setAttribute('transform', `translate(${plot.inset},${plot.inset})`);\n\n if (data.length === 0) return;\n\n if (!isStackData(data) && data.some((v) => !Number.isFinite(v))) {\n warn('createSparkline: data contains non-finite values; they are drawn as the minimum.');\n }\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 defs = createSvgElement('defs');\n const gradient = createSvgElement('linearGradient', { id: gradientId, x1: 0, x2: 0, y1: 0, y2: 1 });\n\n for (const [offset, className] of [\n [0, 'prism-spark-stop-top'],\n [1, 'prism-spark-stop-bottom'],\n ] as const) {\n const stop = createSvgElement('stop', { class: className, offset, 'stop-color': color });\n\n stop.style.stopColor = color;\n gradient.appendChild(stop);\n }\n\n defs.appendChild(gradient);\n innerGroup.appendChild(defs);\n\n const fill = createSvgElement('path', { class: 'prism-spark-fill' });\n const fillD = buildAreaPath(data as number[], plot.w, plot.h, curve);\n\n setAttributes(fill, { d: fillD, fill: `url(#${gradientId})`, stroke: 'none' });\n fill.style.fillOpacity = fillOpacity === undefined ? '' : String(fillOpacity);\n innerGroup.appendChild(fill);\n }\n\n const path = createSvgElement('path', { class: 'prism-spark-line' });\n const pathD = buildPath(data as number[], plot.w, plot.h, curve);\n\n setAttributes(path, { d: pathD, fill: 'none', stroke: color, 'stroke-width': strokeWidth });\n innerGroup.appendChild(path);\n\n const end = buildTopPoints(data as number[], plot.w, plot.h).at(-1);\n\n if (showEndPoint && end) {\n innerGroup.appendChild(\n createSvgElement('circle', { class: 'prism-spark-end', cx: end.x, cy: end.y, fill: color, r: 2.5 }),\n );\n }\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 { h, inset, w } = plotArea();\n\n svg.style.cursor = 'crosshair';\n\n const xStep = w / (data.length - 1);\n const points = variant === 'bar' ? [] : buildTopPoints(data, w, h);\n const marker = createSvgElement('circle', { class: 'prism-spark-marker', fill: color, r: 3.5 });\n const indexAt = (clientX: number): number =>\n Math.max(0, Math.min(data.length - 1, Math.round((clientX - svg.getBoundingClientRect().left - inset) / xStep)));\n\n marker.style.display = 'none';\n innerGroup.appendChild(marker);\n\n const handleMove = (e: MouseEvent) => {\n const idx = indexAt(e.clientX);\n const point = points[idx];\n\n if (point) {\n setAttributes(marker, { cx: point.x, cy: point.y });\n marker.style.display = '';\n }\n\n config.onHover?.(idx, data[idx]);\n };\n\n const handleLeave = () => {\n marker.style.display = 'none';\n config.onHover?.(null, null);\n };\n\n const handleClick = (e: MouseEvent) => {\n if (!config.onClick) return;\n\n const idx = indexAt(e.clientX);\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
+ {"version":3,"file":"sparkline.js","names":[],"sources":["../../../src/charts/sparkline/sparkline.ts"],"sourcesContent":["import { warn } from '../../_dev';\nimport { createTappers } from '../../_tappers';\nimport { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { startTween } from '../../animation/transition';\nimport { tweenNumber } from '../../animation/tween';\nimport { createChartBase } from '../../core/chart-base';\nimport { uniqueId } from '../../core/ids';\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, PrismEvent, SparklineConfig, StackSegment } from '../../types';\n\n/** Fits the 3.5px hover marker plus its ring inside the SVG. */\nconst PLOT_INSET = 5;\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\n startTween({\n count: 1,\n duration: dur,\n easing,\n onFrame: (progress) => {\n const t = progress(0);\n\n setAttributes(rect!, {\n height: tweenNumber(0, finalH, t),\n y: tweenNumber(height, finalY, t),\n });\n },\n signal: disposalSignal,\n });\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;\n const showEndPoint = config.showEndPoint ?? true;\n const gradientId = uniqueId('prism-spark-fill');\n const tappers = createTappers<PrismEvent>();\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 () => {\n tappers.emit({ height: base.dimensions.height, type: 'resize', width: base.dimensions.width });\n renderAll();\n },\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 /** Line and area plots are inset so dots on the first and last values are not clipped. */\n function plotArea(): { h: number; inset: number; w: number } {\n const { height, width } = base.dimensions;\n const inset = variant === 'line' || variant === 'area' ? PLOT_INSET : 0;\n\n return { h: Math.max(1, height - inset * 2), inset, w: Math.max(1, width - inset * 2) };\n }\n\n function renderAll(): void {\n const { height: h, width: w } = base.dimensions;\n const plot = plotArea();\n\n while (innerGroup.firstChild) innerGroup.removeChild(innerGroup.firstChild);\n\n innerGroup.setAttribute('transform', `translate(${plot.inset},${plot.inset})`);\n\n if (data.length === 0) return;\n\n if (!isStackData(data) && data.some((v) => !Number.isFinite(v))) {\n warn('createSparkline: data contains non-finite values; they are drawn as the minimum.');\n }\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 defs = createSvgElement('defs');\n const gradient = createSvgElement('linearGradient', { id: gradientId, x1: 0, x2: 0, y1: 0, y2: 1 });\n\n for (const [offset, className] of [\n [0, 'prism-spark-stop-top'],\n [1, 'prism-spark-stop-bottom'],\n ] as const) {\n const stop = createSvgElement('stop', { class: className, offset, 'stop-color': color });\n\n stop.style.stopColor = color;\n gradient.appendChild(stop);\n }\n\n defs.appendChild(gradient);\n innerGroup.appendChild(defs);\n\n const fill = createSvgElement('path', { class: 'prism-spark-fill' });\n const fillD = buildAreaPath(data as number[], plot.w, plot.h, curve);\n\n setAttributes(fill, { d: fillD, fill: `url(#${gradientId})`, stroke: 'none' });\n fill.style.fillOpacity = fillOpacity === undefined ? '' : String(fillOpacity);\n innerGroup.appendChild(fill);\n }\n\n const path = createSvgElement('path', { class: 'prism-spark-line' });\n const pathD = buildPath(data as number[], plot.w, plot.h, curve);\n\n setAttributes(path, { d: pathD, fill: 'none', stroke: color, 'stroke-width': strokeWidth });\n innerGroup.appendChild(path);\n\n const end = buildTopPoints(data as number[], plot.w, plot.h).at(-1);\n\n if (showEndPoint && end) {\n innerGroup.appendChild(\n createSvgElement('circle', { class: 'prism-spark-end', cx: end.x, cy: end.y, fill: color, r: 2.5 }),\n );\n }\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 { h, inset, w } = plotArea();\n\n svg.style.cursor = 'crosshair';\n\n const xStep = w / (data.length - 1);\n const points = variant === 'bar' ? [] : buildTopPoints(data, w, h);\n const marker = createSvgElement('circle', { class: 'prism-spark-marker', fill: color, r: 3.5 });\n const indexAt = (clientX: number): number =>\n Math.max(0, Math.min(data.length - 1, Math.round((clientX - svg.getBoundingClientRect().left - inset) / xStep)));\n\n marker.style.display = 'none';\n innerGroup.appendChild(marker);\n\n const handleMove = (e: MouseEvent) => {\n const idx = indexAt(e.clientX);\n const point = points[idx];\n\n if (point) {\n setAttributes(marker, { cx: point.x, cy: point.y });\n marker.style.display = '';\n }\n\n config.onHover?.({ index: idx, originalEvent: e, value: data[idx] });\n };\n\n const handleLeave = () => {\n marker.style.display = 'none';\n config.onHover?.(null);\n };\n\n const handleClick = (e: MouseEvent) => {\n if (!config.onClick) return;\n\n const idx = indexAt(e.clientX);\n\n config.onClick({ index: idx, originalEvent: e, value: 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 tappers.emit({ type: 'dispose' });\n tappers.stop();\n ac.abort();\n cleanupInteraction?.();\n base.dispose();\n },\n\n get disposed(): boolean {\n return isDisposed;\n },\n\n el: svg,\n\n tap: tappers.tap,\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,2 +1,2 @@
1
- const e=require("../svg/element.cjs"),t=require("../errors.cjs"),n=require("../interaction/announcer.cjs"),r=require("../interaction/legend.cjs"),i=require("../interaction/tooltip.cjs"),a=require("./chart-base.cjs");function clearCartesianDom(t,n,r,i){e.removeChildren(t.series),e.removeChildren(t.grid),e.removeChildren(t.xAxis),e.removeChildren(t.yAxis),n?.update([]),r?.hide(),i?.hide()}function runScaffold(e,o,s,c,l){let render=()=>{},u=null,d=a.createChartBase(e,{a11y:o.a11y,chrome:()=>u?.el??null,margin:o.margin},()=>render()),f=o.tooltip?i.createTooltip(e,o.tooltip):null;u=o.legend?r.createLegend(e,o.legend):null;let p=new AbortController,m=s(d,f,u,p.signal,n.createAnnouncer(d.svg,`prism-live`)),h=!1,g=makeEventManager(d.svg);render=()=>{h||g.attach(c(m))};try{render()}catch(e){throw h=!0,p.abort(),g.detach(),f?.dispose(),u?.dispose(),d.dispose(),e instanceof t.PrismRenderError?e:new t.PrismRenderError(`Failed to render chart.`,{cause:e})}return{get disposalSignal(){return p.signal},dispose(){h||(h=!0,p.abort(),g.detach(),f?.dispose(),u?.dispose(),d.dispose())},get disposed(){return h},el:d.svg,update(e){if(h)throw new t.PrismRenderError(`Cannot update a disposed chart.`);l(e),render()},[Symbol.dispose](){this.dispose()}}}function makeEventManager(e){let t=null;return{attach(n){t&&=(t.onMouseMove&&e.removeEventListener(`mousemove`,t.onMouseMove),t.onMouseLeave&&e.removeEventListener(`mouseleave`,t.onMouseLeave),t.onClick&&e.removeEventListener(`click`,t.onClick),t.onKeyDown&&e.removeEventListener(`keydown`,t.onKeyDown),null),n&&(t=n,n.onMouseMove&&e.addEventListener(`mousemove`,n.onMouseMove),n.onMouseLeave&&e.addEventListener(`mouseleave`,n.onMouseLeave),n.onClick&&e.addEventListener(`click`,n.onClick),n.onKeyDown&&e.addEventListener(`keydown`,n.onKeyDown))},detach(){this.attach(void 0)}}}function createChartScaffold(t,n,r,i){return runScaffold(t,n,(n,r,i,a,o)=>{let s={grid:e.createSvgElement(`g`,{"aria-hidden":`true`,class:`prism-grid`}),series:e.createSvgElement(`g`,{class:`prism-series`}),xAxis:e.createSvgElement(`g`,{class:`prism-x-axis`}),yAxis:e.createSvgElement(`g`,{class:`prism-y-axis`})};return n.chartArea.appendChild(s.grid),n.chartArea.appendChild(s.xAxis),n.chartArea.appendChild(s.yAxis),n.chartArea.appendChild(s.series),{announcer:o,chartArea:n.chartArea,container:t,dimensions:n.dimensions,disposalSignal:a,groups:s,legend:i,svg:n.svg,tooltip:r}},r,i)}function createRadialScaffold(e,t,n,r){return runScaffold(e,t,(t,n,r,i,a)=>({announcer:a,container:e,dimensions:t.dimensions,disposalSignal:i,legend:r,svg:t.svg,tooltip:n}),n,r)}exports.clearCartesianDom=clearCartesianDom,exports.createChartScaffold=createChartScaffold,exports.createRadialScaffold=createRadialScaffold;
1
+ const e=require("../svg/element.cjs"),t=require("../_tappers.cjs"),n=require("../errors.cjs"),r=require("../interaction/announcer.cjs"),i=require("../interaction/legend.cjs"),a=require("../interaction/tooltip.cjs"),o=require("./chart-base.cjs");function clearCartesianDom(t,n,r,i){e.removeChildren(t.series),e.removeChildren(t.grid),e.removeChildren(t.xAxis),e.removeChildren(t.yAxis),n?.update([]),r?.hide(),i?.hide()}function runScaffold(e,s,c,l,u){let render=()=>{},d=t.createTappers(),f=null,p=o.createChartBase(e,{a11y:s.a11y,chrome:()=>f?.el??null,margin:s.margin},()=>{d.emit({height:p.dimensions.height,type:`resize`,width:p.dimensions.width}),render()}),m=s.tooltip?a.createTooltip(e,s.tooltip):null;f=s.legend?i.createLegend(e,s.legend):null;let h=new AbortController,g=c(p,m,f,h.signal,r.createAnnouncer(p.svg,`prism-live`)),_=!1,v=makeEventManager(p.svg);render=()=>{_||v.attach(l(g))};try{render()}catch(e){throw _=!0,h.abort(),v.detach(),m?.dispose(),f?.dispose(),p.dispose(),e instanceof n.PrismRenderError?e:new n.PrismRenderError(`Failed to render chart.`,{cause:e})}return{get disposalSignal(){return h.signal},dispose(){_||(_=!0,d.emit({type:`dispose`}),d.stop(),h.abort(),v.detach(),m?.dispose(),f?.dispose(),p.dispose())},get disposed(){return _},el:p.svg,tap:d.tap,update(e){if(_)throw new n.PrismRenderError(`Cannot update a disposed chart.`);u(e),render()},[Symbol.dispose](){this.dispose()}}}function makeEventManager(e){let t=null;return{attach(n){t&&=(t.onMouseMove&&e.removeEventListener(`mousemove`,t.onMouseMove),t.onMouseLeave&&e.removeEventListener(`mouseleave`,t.onMouseLeave),t.onClick&&e.removeEventListener(`click`,t.onClick),t.onKeyDown&&e.removeEventListener(`keydown`,t.onKeyDown),null),n&&(t=n,n.onMouseMove&&e.addEventListener(`mousemove`,n.onMouseMove),n.onMouseLeave&&e.addEventListener(`mouseleave`,n.onMouseLeave),n.onClick&&e.addEventListener(`click`,n.onClick),n.onKeyDown&&e.addEventListener(`keydown`,n.onKeyDown))},detach(){this.attach(void 0)}}}function createChartScaffold(t,n,r,i){return runScaffold(t,n,(n,r,i,a,o)=>{let s={grid:e.createSvgElement(`g`,{"aria-hidden":`true`,class:`prism-grid`}),series:e.createSvgElement(`g`,{class:`prism-series`}),xAxis:e.createSvgElement(`g`,{class:`prism-x-axis`}),yAxis:e.createSvgElement(`g`,{class:`prism-y-axis`})};return n.chartArea.appendChild(s.grid),n.chartArea.appendChild(s.xAxis),n.chartArea.appendChild(s.yAxis),n.chartArea.appendChild(s.series),{announcer:o,chartArea:n.chartArea,container:t,dimensions:n.dimensions,disposalSignal:a,groups:s,legend:i,svg:n.svg,tooltip:r}},r,i)}function createRadialScaffold(e,t,n,r){return runScaffold(e,t,(t,n,r,i,a)=>({announcer:a,container:e,dimensions:t.dimensions,disposalSignal:i,legend:r,svg:t.svg,tooltip:n}),n,r)}exports.clearCartesianDom=clearCartesianDom,exports.createChartScaffold=createChartScaffold,exports.createRadialScaffold=createRadialScaffold;
2
2
  //# sourceMappingURL=chart-scaffold.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"chart-scaffold.cjs","names":[],"sources":["../../src/core/chart-scaffold.ts"],"sourcesContent":["import { PrismRenderError } from '../errors';\nimport { type Announcer, createAnnouncer } from '../interaction/announcer';\nimport type { CrosshairState } from '../interaction/crosshair';\nimport type { LegendState } from '../interaction/legend';\nimport { createLegend } from '../interaction/legend';\nimport type { TooltipState } from '../interaction/tooltip';\nimport { createTooltip } from '../interaction/tooltip';\nimport { createSvgElement, removeChildren } from '../svg/element';\nimport type { BaseChartConfig, ChartDimensions, ChartHandle } from '../types';\nimport { createChartBase } from './chart-base';\n\nexport interface ScaffoldGroups {\n grid: SVGGElement;\n series: SVGGElement;\n xAxis: SVGGElement;\n yAxis: SVGGElement;\n}\n\n/**\n * Clears a cartesian chart's series/grid/axis groups and hides its legend/tooltip/crosshair :\n * shared by every cartesian chart factory's \"no data\" early-return so an update\n * to empty data leaves a fully blank chart, not a half-cleared one.\n */\nexport function clearCartesianDom(\n groups: ScaffoldGroups,\n legend: LegendState | null,\n tooltip: TooltipState | null,\n crosshair?: CrosshairState | null,\n): void {\n removeChildren(groups.series);\n removeChildren(groups.grid);\n removeChildren(groups.xAxis);\n removeChildren(groups.yAxis);\n legend?.update([]);\n tooltip?.hide();\n crosshair?.hide();\n}\n\nexport interface ScaffoldContext {\n /** Speaks hover/keyboard values when no tooltip is shown (the tooltip is its own live region). */\n announcer: Announcer;\n chartArea: SVGGElement;\n container: HTMLElement;\n dimensions: ChartDimensions;\n /** Aborted when the chart is disposed: renderers use this to stop rescheduling in-flight `requestAnimationFrame` transitions. */\n disposalSignal: AbortSignal;\n groups: ScaffoldGroups;\n legend: LegendState | null;\n svg: SVGSVGElement;\n tooltip: TooltipState | null;\n}\n\nexport interface RadialScaffoldContext {\n announcer: Announcer;\n container: HTMLElement;\n dimensions: ChartDimensions;\n /** Aborted when the chart is disposed: renderers use this to stop rescheduling in-flight `requestAnimationFrame` transitions. */\n disposalSignal: AbortSignal;\n legend: LegendState | null;\n svg: SVGSVGElement;\n tooltip: TooltipState | null;\n}\n\nexport interface ChartEventHandlers {\n onClick?: (event: MouseEvent) => void;\n onKeyDown?: (event: KeyboardEvent) => void;\n onMouseLeave?: (event: MouseEvent) => void;\n onMouseMove?: (event: MouseEvent) => void;\n}\n\nfunction runScaffold<TCtx, TData>(\n container: HTMLElement,\n config: BaseChartConfig,\n buildCtx: (\n base: {\n chartArea: SVGGElement;\n dimensions: ChartDimensions;\n svg: SVGSVGElement;\n },\n tooltip: TooltipState | null,\n legend: LegendState | null,\n disposalSignal: AbortSignal,\n announcer: Announcer,\n ) => TCtx,\n renderFn: (ctx: TCtx) => ChartEventHandlers | undefined,\n updateData: (data: TData) => void,\n): ChartHandle<TData> {\n let render = () => {};\n // The legend is created after the base (bottom legends append after the svg), but the\n // chrome accessor runs only from the resize observer's async callback — by which time\n // the legend exists — so the deferred reference is safe.\n let legend: LegendState | null = null;\n const base = createChartBase(\n container,\n { a11y: config.a11y, chrome: () => legend?.el ?? null, margin: config.margin },\n () => render(),\n );\n const tooltip = config.tooltip ? createTooltip(container, config.tooltip) : null;\n legend = config.legend ? createLegend(container, config.legend) : null;\n const ac = new AbortController();\n const ctx = buildCtx(base, tooltip, legend, ac.signal, createAnnouncer(base.svg, 'prism-live'));\n\n let disposed = false;\n const events = makeEventManager(base.svg);\n\n render = () => {\n if (disposed) return;\n events.attach(renderFn(ctx));\n };\n\n try {\n render();\n } catch (error) {\n disposed = true;\n ac.abort();\n events.detach();\n tooltip?.dispose();\n legend?.dispose();\n base.dispose();\n throw error instanceof PrismRenderError ? error : new PrismRenderError('Failed to render chart.', { cause: error });\n }\n\n return {\n get disposalSignal(): AbortSignal {\n return ac.signal;\n },\n\n dispose() {\n if (disposed) return;\n\n disposed = true;\n ac.abort();\n events.detach();\n tooltip?.dispose();\n legend?.dispose();\n base.dispose();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n el: base.svg,\n\n update(data) {\n if (disposed) throw new PrismRenderError('Cannot update a disposed chart.');\n updateData(data);\n render();\n },\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n}\n\nfunction makeEventManager(svg: SVGSVGElement): {\n attach(handlers: ChartEventHandlers | undefined): void;\n detach(): void;\n} {\n let active: ChartEventHandlers | null = null;\n\n return {\n attach(handlers) {\n if (active) {\n if (active.onMouseMove) svg.removeEventListener('mousemove', active.onMouseMove);\n\n if (active.onMouseLeave) svg.removeEventListener('mouseleave', active.onMouseLeave);\n\n if (active.onClick) svg.removeEventListener('click', active.onClick);\n\n if (active.onKeyDown) svg.removeEventListener('keydown', active.onKeyDown);\n\n active = null;\n }\n\n if (!handlers) return;\n\n active = handlers;\n\n if (handlers.onMouseMove) svg.addEventListener('mousemove', handlers.onMouseMove);\n\n if (handlers.onMouseLeave) svg.addEventListener('mouseleave', handlers.onMouseLeave);\n\n if (handlers.onClick) svg.addEventListener('click', handlers.onClick);\n\n if (handlers.onKeyDown) svg.addEventListener('keydown', handlers.onKeyDown);\n },\n detach() {\n this.attach(undefined);\n },\n };\n}\n\n/**\n * Cartesian scaffold: provides grid/axis/series SVG groups and a render loop.\n * `renderFn` returns optional `ChartEventHandlers` that are attached/replaced\n * after every data update or resize.\n */\nexport function createChartScaffold<TData>(\n container: HTMLElement,\n config: BaseChartConfig,\n renderFn: (ctx: ScaffoldContext) => ChartEventHandlers | undefined,\n updateData: (data: TData) => void,\n): ChartHandle<TData> {\n return runScaffold(\n container,\n config,\n (base, tooltip, legend, disposalSignal, announcer) => {\n const groups: ScaffoldGroups = {\n // Grid lines are purely decorative relative to the root svg's own role=\"img\"/aria-label.\n // Axis groups are NOT hidden wholesale: they can contain a meaningful `.prism-axis-title`;\n // `renderAxis` marks its own decorative tick lines/labels individually instead.\n grid: createSvgElement('g', { 'aria-hidden': 'true', class: 'prism-grid' }),\n series: createSvgElement('g', { class: 'prism-series' }),\n xAxis: createSvgElement('g', { class: 'prism-x-axis' }),\n yAxis: createSvgElement('g', { class: 'prism-y-axis' }),\n };\n\n base.chartArea.appendChild(groups.grid);\n base.chartArea.appendChild(groups.xAxis);\n base.chartArea.appendChild(groups.yAxis);\n base.chartArea.appendChild(groups.series);\n\n return {\n announcer,\n chartArea: base.chartArea,\n container,\n dimensions: base.dimensions,\n disposalSignal,\n groups,\n legend,\n svg: base.svg,\n tooltip,\n } satisfies ScaffoldContext;\n },\n renderFn,\n updateData,\n );\n}\n\n/**\n * Radial scaffold: for charts that do not use cartesian axis groups\n * (pie, donut, semi). Provides only tooltip, legend, and the SVG root.\n */\nexport function createRadialScaffold<TData>(\n container: HTMLElement,\n config: BaseChartConfig,\n renderFn: (ctx: RadialScaffoldContext) => ChartEventHandlers | undefined,\n updateData: (data: TData) => void,\n): ChartHandle<TData> {\n return runScaffold(\n container,\n config,\n (base, tooltip, legend, disposalSignal, announcer) =>\n ({\n announcer,\n container,\n dimensions: base.dimensions,\n disposalSignal,\n legend,\n svg: base.svg,\n tooltip,\n }) satisfies RadialScaffoldContext,\n renderFn,\n updateData,\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"chart-scaffold.cjs","names":[],"sources":["../../src/core/chart-scaffold.ts"],"sourcesContent":["import { createTappers } from '../_tappers';\nimport { PrismRenderError } from '../errors';\nimport { type Announcer, createAnnouncer } from '../interaction/announcer';\nimport type { CrosshairState } from '../interaction/crosshair';\nimport type { LegendState } from '../interaction/legend';\nimport { createLegend } from '../interaction/legend';\nimport type { TooltipState } from '../interaction/tooltip';\nimport { createTooltip } from '../interaction/tooltip';\nimport { createSvgElement, removeChildren } from '../svg/element';\nimport type { BaseChartConfig, ChartDimensions, ChartHandle, PrismEvent } from '../types';\nimport { createChartBase } from './chart-base';\n\nexport interface ScaffoldGroups {\n grid: SVGGElement;\n series: SVGGElement;\n xAxis: SVGGElement;\n yAxis: SVGGElement;\n}\n\n/**\n * Clears a cartesian chart's series/grid/axis groups and hides its legend/tooltip/crosshair :\n * shared by every cartesian chart factory's \"no data\" early-return so an update\n * to empty data leaves a fully blank chart, not a half-cleared one.\n */\nexport function clearCartesianDom(\n groups: ScaffoldGroups,\n legend: LegendState | null,\n tooltip: TooltipState | null,\n crosshair?: CrosshairState | null,\n): void {\n removeChildren(groups.series);\n removeChildren(groups.grid);\n removeChildren(groups.xAxis);\n removeChildren(groups.yAxis);\n legend?.update([]);\n tooltip?.hide();\n crosshair?.hide();\n}\n\nexport interface ScaffoldContext {\n /** Speaks hover/keyboard values when no tooltip is shown (the tooltip is its own live region). */\n announcer: Announcer;\n chartArea: SVGGElement;\n container: HTMLElement;\n dimensions: ChartDimensions;\n /** Aborted when the chart is disposed: renderers use this to stop rescheduling in-flight `requestAnimationFrame` transitions. */\n disposalSignal: AbortSignal;\n groups: ScaffoldGroups;\n legend: LegendState | null;\n svg: SVGSVGElement;\n tooltip: TooltipState | null;\n}\n\nexport interface RadialScaffoldContext {\n announcer: Announcer;\n container: HTMLElement;\n dimensions: ChartDimensions;\n /** Aborted when the chart is disposed: renderers use this to stop rescheduling in-flight `requestAnimationFrame` transitions. */\n disposalSignal: AbortSignal;\n legend: LegendState | null;\n svg: SVGSVGElement;\n tooltip: TooltipState | null;\n}\n\nexport interface ChartEventHandlers {\n onClick?: (event: MouseEvent) => void;\n onKeyDown?: (event: KeyboardEvent) => void;\n onMouseLeave?: (event: MouseEvent) => void;\n onMouseMove?: (event: MouseEvent) => void;\n}\n\nfunction runScaffold<TCtx, TData>(\n container: HTMLElement,\n config: BaseChartConfig,\n buildCtx: (\n base: {\n chartArea: SVGGElement;\n dimensions: ChartDimensions;\n svg: SVGSVGElement;\n },\n tooltip: TooltipState | null,\n legend: LegendState | null,\n disposalSignal: AbortSignal,\n announcer: Announcer,\n ) => TCtx,\n renderFn: (ctx: TCtx) => ChartEventHandlers | undefined,\n updateData: (data: TData) => void,\n): ChartHandle<TData> {\n let render = () => {};\n const tappers = createTappers<PrismEvent>();\n // The legend is created after the base (bottom legends append after the svg), but the\n // chrome accessor runs only from the resize observer's async callback — by which time\n // the legend exists — so the deferred reference is safe.\n let legend: LegendState | null = null;\n const base = createChartBase(\n container,\n { a11y: config.a11y, chrome: () => legend?.el ?? null, margin: config.margin },\n () => {\n tappers.emit({ height: base.dimensions.height, type: 'resize', width: base.dimensions.width });\n render();\n },\n );\n const tooltip = config.tooltip ? createTooltip(container, config.tooltip) : null;\n legend = config.legend ? createLegend(container, config.legend) : null;\n const ac = new AbortController();\n const ctx = buildCtx(base, tooltip, legend, ac.signal, createAnnouncer(base.svg, 'prism-live'));\n\n let disposed = false;\n const events = makeEventManager(base.svg);\n\n render = () => {\n if (disposed) return;\n events.attach(renderFn(ctx));\n };\n\n try {\n render();\n } catch (error) {\n disposed = true;\n ac.abort();\n events.detach();\n tooltip?.dispose();\n legend?.dispose();\n base.dispose();\n throw error instanceof PrismRenderError ? error : new PrismRenderError('Failed to render chart.', { cause: error });\n }\n\n return {\n get disposalSignal(): AbortSignal {\n return ac.signal;\n },\n\n dispose() {\n if (disposed) return;\n\n disposed = true;\n tappers.emit({ type: 'dispose' });\n tappers.stop();\n ac.abort();\n events.detach();\n tooltip?.dispose();\n legend?.dispose();\n base.dispose();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n el: base.svg,\n\n tap: tappers.tap,\n\n update(data) {\n if (disposed) throw new PrismRenderError('Cannot update a disposed chart.');\n updateData(data);\n render();\n },\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n}\n\nfunction makeEventManager(svg: SVGSVGElement): {\n attach(handlers: ChartEventHandlers | undefined): void;\n detach(): void;\n} {\n let active: ChartEventHandlers | null = null;\n\n return {\n attach(handlers) {\n if (active) {\n if (active.onMouseMove) svg.removeEventListener('mousemove', active.onMouseMove);\n\n if (active.onMouseLeave) svg.removeEventListener('mouseleave', active.onMouseLeave);\n\n if (active.onClick) svg.removeEventListener('click', active.onClick);\n\n if (active.onKeyDown) svg.removeEventListener('keydown', active.onKeyDown);\n\n active = null;\n }\n\n if (!handlers) return;\n\n active = handlers;\n\n if (handlers.onMouseMove) svg.addEventListener('mousemove', handlers.onMouseMove);\n\n if (handlers.onMouseLeave) svg.addEventListener('mouseleave', handlers.onMouseLeave);\n\n if (handlers.onClick) svg.addEventListener('click', handlers.onClick);\n\n if (handlers.onKeyDown) svg.addEventListener('keydown', handlers.onKeyDown);\n },\n detach() {\n this.attach(undefined);\n },\n };\n}\n\n/**\n * Cartesian scaffold: provides grid/axis/series SVG groups and a render loop.\n * `renderFn` returns optional `ChartEventHandlers` that are attached/replaced\n * after every data update or resize.\n */\nexport function createChartScaffold<TData>(\n container: HTMLElement,\n config: BaseChartConfig,\n renderFn: (ctx: ScaffoldContext) => ChartEventHandlers | undefined,\n updateData: (data: TData) => void,\n): ChartHandle<TData> {\n return runScaffold(\n container,\n config,\n (base, tooltip, legend, disposalSignal, announcer) => {\n const groups: ScaffoldGroups = {\n // Grid lines are purely decorative relative to the root svg's own role=\"img\"/aria-label.\n // Axis groups are NOT hidden wholesale: they can contain a meaningful `.prism-axis-title`;\n // `renderAxis` marks its own decorative tick lines/labels individually instead.\n grid: createSvgElement('g', { 'aria-hidden': 'true', class: 'prism-grid' }),\n series: createSvgElement('g', { class: 'prism-series' }),\n xAxis: createSvgElement('g', { class: 'prism-x-axis' }),\n yAxis: createSvgElement('g', { class: 'prism-y-axis' }),\n };\n\n base.chartArea.appendChild(groups.grid);\n base.chartArea.appendChild(groups.xAxis);\n base.chartArea.appendChild(groups.yAxis);\n base.chartArea.appendChild(groups.series);\n\n return {\n announcer,\n chartArea: base.chartArea,\n container,\n dimensions: base.dimensions,\n disposalSignal,\n groups,\n legend,\n svg: base.svg,\n tooltip,\n } satisfies ScaffoldContext;\n },\n renderFn,\n updateData,\n );\n}\n\n/**\n * Radial scaffold: for charts that do not use cartesian axis groups\n * (pie, donut, semi). Provides only tooltip, legend, and the SVG root.\n */\nexport function createRadialScaffold<TData>(\n container: HTMLElement,\n config: BaseChartConfig,\n renderFn: (ctx: RadialScaffoldContext) => ChartEventHandlers | undefined,\n updateData: (data: TData) => void,\n): ChartHandle<TData> {\n return runScaffold(\n container,\n config,\n (base, tooltip, legend, disposalSignal, announcer) =>\n ({\n announcer,\n container,\n dimensions: base.dimensions,\n disposalSignal,\n legend,\n svg: base.svg,\n tooltip,\n }) satisfies RadialScaffoldContext,\n renderFn,\n updateData,\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"chart-scaffold.d.ts","sourceRoot":"","sources":["../../src/core/chart-scaffold.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,0BAA0B,CAAC;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAG3D,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG9E,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,WAAW,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,WAAW,GAAG,IAAI,EAC1B,OAAO,EAAE,YAAY,GAAG,IAAI,EAC5B,SAAS,CAAC,EAAE,cAAc,GAAG,IAAI,GAChC,IAAI,CAQN;AAED,MAAM,WAAW,eAAe;IAC9B,kGAAkG;IAClG,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,WAAW,CAAC;IACvB,SAAS,EAAE,WAAW,CAAC;IACvB,UAAU,EAAE,eAAe,CAAC;IAC5B,iIAAiI;IACjI,cAAc,EAAE,WAAW,CAAC;IAC5B,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,GAAG,EAAE,aAAa,CAAC;IACnB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,WAAW,CAAC;IACvB,UAAU,EAAE,eAAe,CAAC;IAC5B,iIAAiI;IACjI,cAAc,EAAE,WAAW,CAAC;IAC5B,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,GAAG,EAAE,aAAa,CAAC;IACnB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC3C,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAC3C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CAC3C;AA8HD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EACvC,SAAS,EAAE,WAAW,EACtB,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,kBAAkB,GAAG,SAAS,EAClE,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,GAChC,WAAW,CAAC,KAAK,CAAC,CAmCpB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EACxC,SAAS,EAAE,WAAW,EACtB,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,kBAAkB,GAAG,SAAS,EACxE,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,GAChC,WAAW,CAAC,KAAK,CAAC,CAiBpB"}
1
+ {"version":3,"file":"chart-scaffold.d.ts","sourceRoot":"","sources":["../../src/core/chart-scaffold.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,0BAA0B,CAAC;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAG3D,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAc,MAAM,UAAU,CAAC;AAG1F,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,WAAW,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,WAAW,GAAG,IAAI,EAC1B,OAAO,EAAE,YAAY,GAAG,IAAI,EAC5B,SAAS,CAAC,EAAE,cAAc,GAAG,IAAI,GAChC,IAAI,CAQN;AAED,MAAM,WAAW,eAAe;IAC9B,kGAAkG;IAClG,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,WAAW,CAAC;IACvB,SAAS,EAAE,WAAW,CAAC;IACvB,UAAU,EAAE,eAAe,CAAC;IAC5B,iIAAiI;IACjI,cAAc,EAAE,WAAW,CAAC;IAC5B,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,GAAG,EAAE,aAAa,CAAC;IACnB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,WAAW,CAAC;IACvB,UAAU,EAAE,eAAe,CAAC;IAC5B,iIAAiI;IACjI,cAAc,EAAE,WAAW,CAAC;IAC5B,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,GAAG,EAAE,aAAa,CAAC;IACnB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC3C,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAC3C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CAC3C;AAsID;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EACvC,SAAS,EAAE,WAAW,EACtB,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,kBAAkB,GAAG,SAAS,EAClE,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,GAChC,WAAW,CAAC,KAAK,CAAC,CAmCpB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EACxC,SAAS,EAAE,WAAW,EACtB,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,kBAAkB,GAAG,SAAS,EACxE,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,GAChC,WAAW,CAAC,KAAK,CAAC,CAiBpB"}
@@ -1,2 +1,2 @@
1
- import{createSvgElement as e,removeChildren as t}from"../svg/element.js";import{PrismRenderError as n}from"../errors.js";import{createAnnouncer as r}from"../interaction/announcer.js";import{createLegend as i}from"../interaction/legend.js";import{createTooltip as a}from"../interaction/tooltip.js";import{createChartBase as o}from"./chart-base.js";function clearCartesianDom(e,n,r,i){t(e.series),t(e.grid),t(e.xAxis),t(e.yAxis),n?.update([]),r?.hide(),i?.hide()}function runScaffold(e,t,s,c,l){let render=()=>{},u=null,d=o(e,{a11y:t.a11y,chrome:()=>u?.el??null,margin:t.margin},()=>render()),f=t.tooltip?a(e,t.tooltip):null;u=t.legend?i(e,t.legend):null;let p=new AbortController,m=s(d,f,u,p.signal,r(d.svg,`prism-live`)),h=!1,g=makeEventManager(d.svg);render=()=>{h||g.attach(c(m))};try{render()}catch(e){throw h=!0,p.abort(),g.detach(),f?.dispose(),u?.dispose(),d.dispose(),e instanceof n?e:new n(`Failed to render chart.`,{cause:e})}return{get disposalSignal(){return p.signal},dispose(){h||(h=!0,p.abort(),g.detach(),f?.dispose(),u?.dispose(),d.dispose())},get disposed(){return h},el:d.svg,update(e){if(h)throw new n(`Cannot update a disposed chart.`);l(e),render()},[Symbol.dispose](){this.dispose()}}}function makeEventManager(e){let t=null;return{attach(n){t&&=(t.onMouseMove&&e.removeEventListener(`mousemove`,t.onMouseMove),t.onMouseLeave&&e.removeEventListener(`mouseleave`,t.onMouseLeave),t.onClick&&e.removeEventListener(`click`,t.onClick),t.onKeyDown&&e.removeEventListener(`keydown`,t.onKeyDown),null),n&&(t=n,n.onMouseMove&&e.addEventListener(`mousemove`,n.onMouseMove),n.onMouseLeave&&e.addEventListener(`mouseleave`,n.onMouseLeave),n.onClick&&e.addEventListener(`click`,n.onClick),n.onKeyDown&&e.addEventListener(`keydown`,n.onKeyDown))},detach(){this.attach(void 0)}}}function createChartScaffold(t,n,r,i){return runScaffold(t,n,(n,r,i,a,o)=>{let s={grid:e(`g`,{"aria-hidden":`true`,class:`prism-grid`}),series:e(`g`,{class:`prism-series`}),xAxis:e(`g`,{class:`prism-x-axis`}),yAxis:e(`g`,{class:`prism-y-axis`})};return n.chartArea.appendChild(s.grid),n.chartArea.appendChild(s.xAxis),n.chartArea.appendChild(s.yAxis),n.chartArea.appendChild(s.series),{announcer:o,chartArea:n.chartArea,container:t,dimensions:n.dimensions,disposalSignal:a,groups:s,legend:i,svg:n.svg,tooltip:r}},r,i)}function createRadialScaffold(e,t,n,r){return runScaffold(e,t,(t,n,r,i,a)=>({announcer:a,container:e,dimensions:t.dimensions,disposalSignal:i,legend:r,svg:t.svg,tooltip:n}),n,r)}export{clearCartesianDom,createChartScaffold,createRadialScaffold};
1
+ import{createSvgElement as e,removeChildren as t}from"../svg/element.js";import{createTappers as n}from"../_tappers.js";import{PrismRenderError as r}from"../errors.js";import{createAnnouncer as i}from"../interaction/announcer.js";import{createLegend as a}from"../interaction/legend.js";import{createTooltip as o}from"../interaction/tooltip.js";import{createChartBase as s}from"./chart-base.js";function clearCartesianDom(e,n,r,i){t(e.series),t(e.grid),t(e.xAxis),t(e.yAxis),n?.update([]),r?.hide(),i?.hide()}function runScaffold(e,t,c,l,u){let render=()=>{},d=n(),f=null,p=s(e,{a11y:t.a11y,chrome:()=>f?.el??null,margin:t.margin},()=>{d.emit({height:p.dimensions.height,type:`resize`,width:p.dimensions.width}),render()}),m=t.tooltip?o(e,t.tooltip):null;f=t.legend?a(e,t.legend):null;let h=new AbortController,g=c(p,m,f,h.signal,i(p.svg,`prism-live`)),_=!1,v=makeEventManager(p.svg);render=()=>{_||v.attach(l(g))};try{render()}catch(e){throw _=!0,h.abort(),v.detach(),m?.dispose(),f?.dispose(),p.dispose(),e instanceof r?e:new r(`Failed to render chart.`,{cause:e})}return{get disposalSignal(){return h.signal},dispose(){_||(_=!0,d.emit({type:`dispose`}),d.stop(),h.abort(),v.detach(),m?.dispose(),f?.dispose(),p.dispose())},get disposed(){return _},el:p.svg,tap:d.tap,update(e){if(_)throw new r(`Cannot update a disposed chart.`);u(e),render()},[Symbol.dispose](){this.dispose()}}}function makeEventManager(e){let t=null;return{attach(n){t&&=(t.onMouseMove&&e.removeEventListener(`mousemove`,t.onMouseMove),t.onMouseLeave&&e.removeEventListener(`mouseleave`,t.onMouseLeave),t.onClick&&e.removeEventListener(`click`,t.onClick),t.onKeyDown&&e.removeEventListener(`keydown`,t.onKeyDown),null),n&&(t=n,n.onMouseMove&&e.addEventListener(`mousemove`,n.onMouseMove),n.onMouseLeave&&e.addEventListener(`mouseleave`,n.onMouseLeave),n.onClick&&e.addEventListener(`click`,n.onClick),n.onKeyDown&&e.addEventListener(`keydown`,n.onKeyDown))},detach(){this.attach(void 0)}}}function createChartScaffold(t,n,r,i){return runScaffold(t,n,(n,r,i,a,o)=>{let s={grid:e(`g`,{"aria-hidden":`true`,class:`prism-grid`}),series:e(`g`,{class:`prism-series`}),xAxis:e(`g`,{class:`prism-x-axis`}),yAxis:e(`g`,{class:`prism-y-axis`})};return n.chartArea.appendChild(s.grid),n.chartArea.appendChild(s.xAxis),n.chartArea.appendChild(s.yAxis),n.chartArea.appendChild(s.series),{announcer:o,chartArea:n.chartArea,container:t,dimensions:n.dimensions,disposalSignal:a,groups:s,legend:i,svg:n.svg,tooltip:r}},r,i)}function createRadialScaffold(e,t,n,r){return runScaffold(e,t,(t,n,r,i,a)=>({announcer:a,container:e,dimensions:t.dimensions,disposalSignal:i,legend:r,svg:t.svg,tooltip:n}),n,r)}export{clearCartesianDom,createChartScaffold,createRadialScaffold};
2
2
  //# sourceMappingURL=chart-scaffold.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chart-scaffold.js","names":[],"sources":["../../src/core/chart-scaffold.ts"],"sourcesContent":["import { PrismRenderError } from '../errors';\nimport { type Announcer, createAnnouncer } from '../interaction/announcer';\nimport type { CrosshairState } from '../interaction/crosshair';\nimport type { LegendState } from '../interaction/legend';\nimport { createLegend } from '../interaction/legend';\nimport type { TooltipState } from '../interaction/tooltip';\nimport { createTooltip } from '../interaction/tooltip';\nimport { createSvgElement, removeChildren } from '../svg/element';\nimport type { BaseChartConfig, ChartDimensions, ChartHandle } from '../types';\nimport { createChartBase } from './chart-base';\n\nexport interface ScaffoldGroups {\n grid: SVGGElement;\n series: SVGGElement;\n xAxis: SVGGElement;\n yAxis: SVGGElement;\n}\n\n/**\n * Clears a cartesian chart's series/grid/axis groups and hides its legend/tooltip/crosshair :\n * shared by every cartesian chart factory's \"no data\" early-return so an update\n * to empty data leaves a fully blank chart, not a half-cleared one.\n */\nexport function clearCartesianDom(\n groups: ScaffoldGroups,\n legend: LegendState | null,\n tooltip: TooltipState | null,\n crosshair?: CrosshairState | null,\n): void {\n removeChildren(groups.series);\n removeChildren(groups.grid);\n removeChildren(groups.xAxis);\n removeChildren(groups.yAxis);\n legend?.update([]);\n tooltip?.hide();\n crosshair?.hide();\n}\n\nexport interface ScaffoldContext {\n /** Speaks hover/keyboard values when no tooltip is shown (the tooltip is its own live region). */\n announcer: Announcer;\n chartArea: SVGGElement;\n container: HTMLElement;\n dimensions: ChartDimensions;\n /** Aborted when the chart is disposed: renderers use this to stop rescheduling in-flight `requestAnimationFrame` transitions. */\n disposalSignal: AbortSignal;\n groups: ScaffoldGroups;\n legend: LegendState | null;\n svg: SVGSVGElement;\n tooltip: TooltipState | null;\n}\n\nexport interface RadialScaffoldContext {\n announcer: Announcer;\n container: HTMLElement;\n dimensions: ChartDimensions;\n /** Aborted when the chart is disposed: renderers use this to stop rescheduling in-flight `requestAnimationFrame` transitions. */\n disposalSignal: AbortSignal;\n legend: LegendState | null;\n svg: SVGSVGElement;\n tooltip: TooltipState | null;\n}\n\nexport interface ChartEventHandlers {\n onClick?: (event: MouseEvent) => void;\n onKeyDown?: (event: KeyboardEvent) => void;\n onMouseLeave?: (event: MouseEvent) => void;\n onMouseMove?: (event: MouseEvent) => void;\n}\n\nfunction runScaffold<TCtx, TData>(\n container: HTMLElement,\n config: BaseChartConfig,\n buildCtx: (\n base: {\n chartArea: SVGGElement;\n dimensions: ChartDimensions;\n svg: SVGSVGElement;\n },\n tooltip: TooltipState | null,\n legend: LegendState | null,\n disposalSignal: AbortSignal,\n announcer: Announcer,\n ) => TCtx,\n renderFn: (ctx: TCtx) => ChartEventHandlers | undefined,\n updateData: (data: TData) => void,\n): ChartHandle<TData> {\n let render = () => {};\n // The legend is created after the base (bottom legends append after the svg), but the\n // chrome accessor runs only from the resize observer's async callback — by which time\n // the legend exists — so the deferred reference is safe.\n let legend: LegendState | null = null;\n const base = createChartBase(\n container,\n { a11y: config.a11y, chrome: () => legend?.el ?? null, margin: config.margin },\n () => render(),\n );\n const tooltip = config.tooltip ? createTooltip(container, config.tooltip) : null;\n legend = config.legend ? createLegend(container, config.legend) : null;\n const ac = new AbortController();\n const ctx = buildCtx(base, tooltip, legend, ac.signal, createAnnouncer(base.svg, 'prism-live'));\n\n let disposed = false;\n const events = makeEventManager(base.svg);\n\n render = () => {\n if (disposed) return;\n events.attach(renderFn(ctx));\n };\n\n try {\n render();\n } catch (error) {\n disposed = true;\n ac.abort();\n events.detach();\n tooltip?.dispose();\n legend?.dispose();\n base.dispose();\n throw error instanceof PrismRenderError ? error : new PrismRenderError('Failed to render chart.', { cause: error });\n }\n\n return {\n get disposalSignal(): AbortSignal {\n return ac.signal;\n },\n\n dispose() {\n if (disposed) return;\n\n disposed = true;\n ac.abort();\n events.detach();\n tooltip?.dispose();\n legend?.dispose();\n base.dispose();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n el: base.svg,\n\n update(data) {\n if (disposed) throw new PrismRenderError('Cannot update a disposed chart.');\n updateData(data);\n render();\n },\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n}\n\nfunction makeEventManager(svg: SVGSVGElement): {\n attach(handlers: ChartEventHandlers | undefined): void;\n detach(): void;\n} {\n let active: ChartEventHandlers | null = null;\n\n return {\n attach(handlers) {\n if (active) {\n if (active.onMouseMove) svg.removeEventListener('mousemove', active.onMouseMove);\n\n if (active.onMouseLeave) svg.removeEventListener('mouseleave', active.onMouseLeave);\n\n if (active.onClick) svg.removeEventListener('click', active.onClick);\n\n if (active.onKeyDown) svg.removeEventListener('keydown', active.onKeyDown);\n\n active = null;\n }\n\n if (!handlers) return;\n\n active = handlers;\n\n if (handlers.onMouseMove) svg.addEventListener('mousemove', handlers.onMouseMove);\n\n if (handlers.onMouseLeave) svg.addEventListener('mouseleave', handlers.onMouseLeave);\n\n if (handlers.onClick) svg.addEventListener('click', handlers.onClick);\n\n if (handlers.onKeyDown) svg.addEventListener('keydown', handlers.onKeyDown);\n },\n detach() {\n this.attach(undefined);\n },\n };\n}\n\n/**\n * Cartesian scaffold: provides grid/axis/series SVG groups and a render loop.\n * `renderFn` returns optional `ChartEventHandlers` that are attached/replaced\n * after every data update or resize.\n */\nexport function createChartScaffold<TData>(\n container: HTMLElement,\n config: BaseChartConfig,\n renderFn: (ctx: ScaffoldContext) => ChartEventHandlers | undefined,\n updateData: (data: TData) => void,\n): ChartHandle<TData> {\n return runScaffold(\n container,\n config,\n (base, tooltip, legend, disposalSignal, announcer) => {\n const groups: ScaffoldGroups = {\n // Grid lines are purely decorative relative to the root svg's own role=\"img\"/aria-label.\n // Axis groups are NOT hidden wholesale: they can contain a meaningful `.prism-axis-title`;\n // `renderAxis` marks its own decorative tick lines/labels individually instead.\n grid: createSvgElement('g', { 'aria-hidden': 'true', class: 'prism-grid' }),\n series: createSvgElement('g', { class: 'prism-series' }),\n xAxis: createSvgElement('g', { class: 'prism-x-axis' }),\n yAxis: createSvgElement('g', { class: 'prism-y-axis' }),\n };\n\n base.chartArea.appendChild(groups.grid);\n base.chartArea.appendChild(groups.xAxis);\n base.chartArea.appendChild(groups.yAxis);\n base.chartArea.appendChild(groups.series);\n\n return {\n announcer,\n chartArea: base.chartArea,\n container,\n dimensions: base.dimensions,\n disposalSignal,\n groups,\n legend,\n svg: base.svg,\n tooltip,\n } satisfies ScaffoldContext;\n },\n renderFn,\n updateData,\n );\n}\n\n/**\n * Radial scaffold: for charts that do not use cartesian axis groups\n * (pie, donut, semi). Provides only tooltip, legend, and the SVG root.\n */\nexport function createRadialScaffold<TData>(\n container: HTMLElement,\n config: BaseChartConfig,\n renderFn: (ctx: RadialScaffoldContext) => ChartEventHandlers | undefined,\n updateData: (data: TData) => void,\n): ChartHandle<TData> {\n return runScaffold(\n container,\n config,\n (base, tooltip, legend, disposalSignal, announcer) =>\n ({\n announcer,\n container,\n dimensions: base.dimensions,\n disposalSignal,\n legend,\n svg: base.svg,\n tooltip,\n }) satisfies RadialScaffoldContext,\n renderFn,\n updateData,\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"chart-scaffold.js","names":[],"sources":["../../src/core/chart-scaffold.ts"],"sourcesContent":["import { createTappers } from '../_tappers';\nimport { PrismRenderError } from '../errors';\nimport { type Announcer, createAnnouncer } from '../interaction/announcer';\nimport type { CrosshairState } from '../interaction/crosshair';\nimport type { LegendState } from '../interaction/legend';\nimport { createLegend } from '../interaction/legend';\nimport type { TooltipState } from '../interaction/tooltip';\nimport { createTooltip } from '../interaction/tooltip';\nimport { createSvgElement, removeChildren } from '../svg/element';\nimport type { BaseChartConfig, ChartDimensions, ChartHandle, PrismEvent } from '../types';\nimport { createChartBase } from './chart-base';\n\nexport interface ScaffoldGroups {\n grid: SVGGElement;\n series: SVGGElement;\n xAxis: SVGGElement;\n yAxis: SVGGElement;\n}\n\n/**\n * Clears a cartesian chart's series/grid/axis groups and hides its legend/tooltip/crosshair :\n * shared by every cartesian chart factory's \"no data\" early-return so an update\n * to empty data leaves a fully blank chart, not a half-cleared one.\n */\nexport function clearCartesianDom(\n groups: ScaffoldGroups,\n legend: LegendState | null,\n tooltip: TooltipState | null,\n crosshair?: CrosshairState | null,\n): void {\n removeChildren(groups.series);\n removeChildren(groups.grid);\n removeChildren(groups.xAxis);\n removeChildren(groups.yAxis);\n legend?.update([]);\n tooltip?.hide();\n crosshair?.hide();\n}\n\nexport interface ScaffoldContext {\n /** Speaks hover/keyboard values when no tooltip is shown (the tooltip is its own live region). */\n announcer: Announcer;\n chartArea: SVGGElement;\n container: HTMLElement;\n dimensions: ChartDimensions;\n /** Aborted when the chart is disposed: renderers use this to stop rescheduling in-flight `requestAnimationFrame` transitions. */\n disposalSignal: AbortSignal;\n groups: ScaffoldGroups;\n legend: LegendState | null;\n svg: SVGSVGElement;\n tooltip: TooltipState | null;\n}\n\nexport interface RadialScaffoldContext {\n announcer: Announcer;\n container: HTMLElement;\n dimensions: ChartDimensions;\n /** Aborted when the chart is disposed: renderers use this to stop rescheduling in-flight `requestAnimationFrame` transitions. */\n disposalSignal: AbortSignal;\n legend: LegendState | null;\n svg: SVGSVGElement;\n tooltip: TooltipState | null;\n}\n\nexport interface ChartEventHandlers {\n onClick?: (event: MouseEvent) => void;\n onKeyDown?: (event: KeyboardEvent) => void;\n onMouseLeave?: (event: MouseEvent) => void;\n onMouseMove?: (event: MouseEvent) => void;\n}\n\nfunction runScaffold<TCtx, TData>(\n container: HTMLElement,\n config: BaseChartConfig,\n buildCtx: (\n base: {\n chartArea: SVGGElement;\n dimensions: ChartDimensions;\n svg: SVGSVGElement;\n },\n tooltip: TooltipState | null,\n legend: LegendState | null,\n disposalSignal: AbortSignal,\n announcer: Announcer,\n ) => TCtx,\n renderFn: (ctx: TCtx) => ChartEventHandlers | undefined,\n updateData: (data: TData) => void,\n): ChartHandle<TData> {\n let render = () => {};\n const tappers = createTappers<PrismEvent>();\n // The legend is created after the base (bottom legends append after the svg), but the\n // chrome accessor runs only from the resize observer's async callback — by which time\n // the legend exists — so the deferred reference is safe.\n let legend: LegendState | null = null;\n const base = createChartBase(\n container,\n { a11y: config.a11y, chrome: () => legend?.el ?? null, margin: config.margin },\n () => {\n tappers.emit({ height: base.dimensions.height, type: 'resize', width: base.dimensions.width });\n render();\n },\n );\n const tooltip = config.tooltip ? createTooltip(container, config.tooltip) : null;\n legend = config.legend ? createLegend(container, config.legend) : null;\n const ac = new AbortController();\n const ctx = buildCtx(base, tooltip, legend, ac.signal, createAnnouncer(base.svg, 'prism-live'));\n\n let disposed = false;\n const events = makeEventManager(base.svg);\n\n render = () => {\n if (disposed) return;\n events.attach(renderFn(ctx));\n };\n\n try {\n render();\n } catch (error) {\n disposed = true;\n ac.abort();\n events.detach();\n tooltip?.dispose();\n legend?.dispose();\n base.dispose();\n throw error instanceof PrismRenderError ? error : new PrismRenderError('Failed to render chart.', { cause: error });\n }\n\n return {\n get disposalSignal(): AbortSignal {\n return ac.signal;\n },\n\n dispose() {\n if (disposed) return;\n\n disposed = true;\n tappers.emit({ type: 'dispose' });\n tappers.stop();\n ac.abort();\n events.detach();\n tooltip?.dispose();\n legend?.dispose();\n base.dispose();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n el: base.svg,\n\n tap: tappers.tap,\n\n update(data) {\n if (disposed) throw new PrismRenderError('Cannot update a disposed chart.');\n updateData(data);\n render();\n },\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n}\n\nfunction makeEventManager(svg: SVGSVGElement): {\n attach(handlers: ChartEventHandlers | undefined): void;\n detach(): void;\n} {\n let active: ChartEventHandlers | null = null;\n\n return {\n attach(handlers) {\n if (active) {\n if (active.onMouseMove) svg.removeEventListener('mousemove', active.onMouseMove);\n\n if (active.onMouseLeave) svg.removeEventListener('mouseleave', active.onMouseLeave);\n\n if (active.onClick) svg.removeEventListener('click', active.onClick);\n\n if (active.onKeyDown) svg.removeEventListener('keydown', active.onKeyDown);\n\n active = null;\n }\n\n if (!handlers) return;\n\n active = handlers;\n\n if (handlers.onMouseMove) svg.addEventListener('mousemove', handlers.onMouseMove);\n\n if (handlers.onMouseLeave) svg.addEventListener('mouseleave', handlers.onMouseLeave);\n\n if (handlers.onClick) svg.addEventListener('click', handlers.onClick);\n\n if (handlers.onKeyDown) svg.addEventListener('keydown', handlers.onKeyDown);\n },\n detach() {\n this.attach(undefined);\n },\n };\n}\n\n/**\n * Cartesian scaffold: provides grid/axis/series SVG groups and a render loop.\n * `renderFn` returns optional `ChartEventHandlers` that are attached/replaced\n * after every data update or resize.\n */\nexport function createChartScaffold<TData>(\n container: HTMLElement,\n config: BaseChartConfig,\n renderFn: (ctx: ScaffoldContext) => ChartEventHandlers | undefined,\n updateData: (data: TData) => void,\n): ChartHandle<TData> {\n return runScaffold(\n container,\n config,\n (base, tooltip, legend, disposalSignal, announcer) => {\n const groups: ScaffoldGroups = {\n // Grid lines are purely decorative relative to the root svg's own role=\"img\"/aria-label.\n // Axis groups are NOT hidden wholesale: they can contain a meaningful `.prism-axis-title`;\n // `renderAxis` marks its own decorative tick lines/labels individually instead.\n grid: createSvgElement('g', { 'aria-hidden': 'true', class: 'prism-grid' }),\n series: createSvgElement('g', { class: 'prism-series' }),\n xAxis: createSvgElement('g', { class: 'prism-x-axis' }),\n yAxis: createSvgElement('g', { class: 'prism-y-axis' }),\n };\n\n base.chartArea.appendChild(groups.grid);\n base.chartArea.appendChild(groups.xAxis);\n base.chartArea.appendChild(groups.yAxis);\n base.chartArea.appendChild(groups.series);\n\n return {\n announcer,\n chartArea: base.chartArea,\n container,\n dimensions: base.dimensions,\n disposalSignal,\n groups,\n legend,\n svg: base.svg,\n tooltip,\n } satisfies ScaffoldContext;\n },\n renderFn,\n updateData,\n );\n}\n\n/**\n * Radial scaffold: for charts that do not use cartesian axis groups\n * (pie, donut, semi). Provides only tooltip, legend, and the SVG root.\n */\nexport function createRadialScaffold<TData>(\n container: HTMLElement,\n config: BaseChartConfig,\n renderFn: (ctx: RadialScaffoldContext) => ChartEventHandlers | undefined,\n updateData: (data: TData) => void,\n): ChartHandle<TData> {\n return runScaffold(\n container,\n config,\n (base, tooltip, legend, disposalSignal, announcer) =>\n ({\n announcer,\n container,\n dimensions: base.dimensions,\n disposalSignal,\n legend,\n svg: base.svg,\n tooltip,\n }) satisfies RadialScaffoldContext,\n renderFn,\n updateData,\n );\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -11,5 +11,5 @@ export { linearScale } from './scales/linear';
11
11
  export { timeScale } from './scales/time';
12
12
  export type { BandScaleConfig, LinearScaleConfig, TimeScaleConfig } from './scales/types';
13
13
  export { resetTheme, seriesColor, setTheme } from './theme';
14
- export type { AreaChartConfig, AreaSeriesConfig, AxisConfig, AxisPosition, BandScale, BarChartConfig, BarSeriesConfig, BarVariant, BaseChartConfig, ChartA11y, ChartDimensions, ChartEvent, ChartHandle, ChartMargin, ContinuousDatum, CrosshairConfig, Datum, GridConfig, HorizontalAxisPosition, LegendConfig, LegendPosition, LineChartConfig, LineSeriesConfig, PieChartConfig, PieSliceConfig, PieVariant, PrismTheme, RadarAxisConfig, RadarAxisValue, RadarChartConfig, RadarEvent, RadarGridConfig, RadarSeriesConfig, Scale, Series, SeriesValue, SparklineConfig, SparklineVariant, StackSegment, TooltipConfig, TransitionConfig, VerticalAxisPosition, XAxisConfig, YAxisConfig, } from './types';
14
+ export type { AreaChartConfig, AreaSeriesConfig, AxisConfig, AxisPosition, BandScale, BarChartConfig, BarSeriesConfig, BarVariant, BaseChartConfig, ChartA11y, ChartDimensions, ChartEvent, ChartHandle, ChartMargin, ContinuousDatum, CrosshairConfig, Datum, GridConfig, HorizontalAxisPosition, LegendConfig, LegendPosition, LineChartConfig, LineSeriesConfig, PieChartConfig, PieEvent, PieSliceConfig, PieVariant, PrismEvent, PrismTheme, RadarAxisConfig, RadarAxisValue, RadarChartConfig, RadarEvent, RadarGridConfig, RadarSeriesConfig, Scale, Series, SeriesValue, SparklineConfig, SparklineEvent, SparklineVariant, StackSegment, TooltipConfig, TransitionConfig, VerticalAxisPosition, XAxisConfig, YAxisConfig, } from './types';
15
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAExD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAE1F,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5D,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,SAAS,EACT,cAAc,EACd,eAAe,EACf,UAAU,EACV,eAAe,EACf,SAAS,EACT,eAAe,EACf,UAAU,EACV,WAAW,EACX,WAAW,EACX,eAAe,EACf,eAAe,EACf,KAAK,EACL,UAAU,EACV,sBAAsB,EACtB,YAAY,EACZ,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,UAAU,EACV,UAAU,EACV,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,KAAK,EACL,MAAM,EACN,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,WAAW,EACX,WAAW,GACZ,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAExD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAE1F,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5D,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,SAAS,EACT,cAAc,EACd,eAAe,EACf,UAAU,EACV,eAAe,EACf,SAAS,EACT,eAAe,EACf,UAAU,EACV,WAAW,EACX,WAAW,EACX,eAAe,EACf,eAAe,EACf,KAAK,EACL,UAAU,EACV,sBAAsB,EACtB,YAAY,EACZ,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,QAAQ,EACR,cAAc,EACd,UAAU,EACV,UAAU,EACV,UAAU,EACV,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,KAAK,EACL,MAAM,EACN,WAAW,EACX,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,WAAW,EACX,WAAW,GACZ,MAAM,SAAS,CAAC"}
@@ -1,2 +1,2 @@
1
- const e=require("../svg/element.cjs"),t=require("./announcer.cjs"),n=require("./tooltip.cjs"),r=require("../core/layout.cjs"),i=require("../core/cartesian-model.cjs"),a=require("./events.cjs");var keyOrder=e=>e instanceof Date?e.getTime():Number(e);function keyLabel(e){return e instanceof Date?e.toLocaleDateString():String(e)}function findNearestKey(e,t,n){let r=null,i=1/0;for(let a=0;a<t.length;a++)for(let o=0;o<(t[a]?.length??0);o++){let s=e[a]?.[o],c=t[a]?.[o];if(!s||!c)continue;let l=Math.abs(c.x-n);l<i&&(i=l,r=s.key)}return r}function createSeriesInteraction(o){let s=-1,c=!1,renderedHit=e=>{let t=e.target;if(!(t instanceof SVGElement)||t.tagName.toLowerCase()!==`circle`||!o.seriesGroup.contains(t)||!t.parentElement)return null;let n=t.parentElement;for(;n&&n.parentNode!==o.seriesGroup;)n=n.parentElement;if(!n)return null;let r=[...o.seriesGroup.children].indexOf(n),i=[...t.parentElement.children].indexOf(t),a=o.getData()[r]?.[i],s=o.getPoints()[r]?.[i];return a&&s?{datum:a,point:s,seriesIndex:r}:null},entriesAt=e=>{let t=i.keyId(e),n=o.getPoints();return o.getData().map((e,r)=>{let a=e.findIndex(e=>i.keyId(e.key)===t);return a===-1?{datum:void 0,point:void 0}:{datum:e[a],point:n[r]?.[a]}})},nearestIndex=(e,t)=>{let n=-1,r=1/0;return e.forEach(({point:e},i)=>{if(!e)return;let a=Number.isFinite(t)?Math.abs(e.y-t):0;a<r&&(r=a,n=i)}),n},highlight=(t,n)=>{let r=o.colors();o.markers.replaceChildren(),t.forEach(({point:t},n)=>{t&&o.markers.appendChild(e.createSvgElement(`circle`,{class:`prism-active-point`,cx:t.x,cy:t.y,fill:r[n],r:4}))});let i=[...o.seriesGroup.children];o.seriesGroup.classList.toggle(`prism-series-focused`,n>=0&&i.length>1);for(let[e,t]of i.entries())t.classList.toggle(`prism-series-active`,e===n)},clear=()=>{o.crosshair?.hide(),o.tooltip?.hide(),o.announcer.clear(),highlight([],-1),c=!1,o.onHover?.(null)},eventFor=(e,t,n)=>{let r=entriesAt(e),i=renderedHit(n),a=i?.seriesIndex??nearestIndex(r,t);i&&(r[a]={datum:i.datum,point:i.point});let s=o.getSeriesList(),c=r[a]?.datum;if(a<0||!c)return null;let l=r.map((e,t)=>({datum:e.datum,series:s[t]}));return{entries:r,event:{datum:c,originalEvent:n,series:s[a],values:l},index:a}},focus=(e,i,a)=>{let s=eventFor(e,i?.y??NaN,a);if(!s)return;let{entries:l,event:u,index:d}=s,f=l[d].point,p=o.dims(),m=r.chartArea(p.width,p.height,p.margin),h=o.crosshair?.snap===!1&&i,g=keyLabel(e),_=u.values??[],v=o.colors();o.crosshair?.show(h?i.x:f.x,h?i.y:f.y,m.width,m.height),highlight(l,d);let y=t.describeValues(g,_);if(o.tooltip){let e=_.flatMap(({datum:e,series:t},n)=>e?[{color:v[n],name:t.name,value:String(e.value)}]:[]);o.tooltip.show(f.x+p.margin.left,f.y+p.margin.top,u.datum,u.series,n.comparisonContent(o.svg.ownerDocument,g,e,y))}else o.announcer.announce(y);c=!0,o.onHover?.(u)},pointerKey=e=>{let t=renderedHit(e);if(t)return{key:t.datum.key,pos:t.point};let n=o.getPoints();if(n.every(e=>e.length===0))return null;let i=o.dims(),s=a.getMousePosition(o.svg,e,i.margin.left,i.margin.top),c=r.chartArea(i.width,i.height,i.margin);if(s.x<0||s.x>c.width||s.y<0||s.y>c.height)return null;let l=findNearestKey(o.getData(),n,s.x);return l===null?null:{key:l,pos:s}},sortedKeys=()=>[...new Map(o.getData().flat().map(e=>[i.keyId(e.key),e.key])).values()].sort((e,t)=>keyOrder(e)-keyOrder(t)),onMouseMove=e=>{let t=pointerKey(e);t?focus(t.key,t.pos,e):c&&clear()},onClick=e=>{if(!o.onClick)return;let t=pointerKey(e),n=t&&eventFor(t.key,t.pos.y,e);n&&o.onClick(n.event)},onKeyDown=e=>{let t=sortedKeys();if(t.length===0)return;let n=t.length-1,r={ArrowLeft:s<0?n:Math.max(0,s-1),ArrowRight:s<0?0:Math.min(n,s+1),End:n,Home:0};if(e.key in r)e.preventDefault(),s=r[e.key],focus(t[s],null,e);else if((e.key===`Enter`||e.key===` `)&&s>=0&&o.onClick){e.preventDefault();let n=eventFor(t[s],NaN,e);n&&o.onClick(n.event)}else e.key===`Escape`&&(s=-1,clear())};return{onClick,onKeyDown,onMouseLeave:clear,onMouseMove}}function ensureMarkerGroup(t,n){if(n&&t.contains(n))return n;let r=e.createSvgElement(`g`,{"aria-hidden":`true`,class:`prism-active-points`,"pointer-events":`none`});return t.appendChild(r),r}exports.createSeriesInteraction=createSeriesInteraction,exports.ensureMarkerGroup=ensureMarkerGroup,exports.keyLabel=keyLabel;
1
+ const e=require("../svg/element.cjs"),t=require("./announcer.cjs"),n=require("./tooltip.cjs"),r=require("../core/layout.cjs"),i=require("../core/cartesian-model.cjs"),a=require("./events.cjs");var keyOrder=e=>e instanceof Date?e.getTime():Number(e);function keyLabel(e){return e instanceof Date?e.toLocaleDateString():String(e)}function findNearestKey(e,t,n){let r=null,i=1/0;for(let a=0;a<t.length;a++)for(let o=0;o<(t[a]?.length??0);o++){let s=e[a]?.[o],c=t[a]?.[o];if(!s||!c)continue;let l=Math.abs(c.x-n);l<i&&(i=l,r=s.key)}return r}function createSeriesInteraction(o){let s=-1,c=!1,renderedHit=e=>{let t=e.target;if(!(t instanceof SVGElement)||t.tagName.toLowerCase()!==`circle`||!o.seriesGroup.contains(t)||!t.parentElement)return null;let n=t.parentElement;for(;n&&n.parentNode!==o.seriesGroup;)n=n.parentElement;if(!n)return null;let r=[...o.seriesGroup.children].indexOf(n),i=[...t.parentElement.children].indexOf(t),a=o.getData()[r]?.[i],s=o.getPoints()[r]?.[i];return a&&s?{datum:a,point:s,seriesIndex:r}:null},entriesAt=e=>{let t=i.keyId(e),n=o.getPoints();return o.getData().map((e,r)=>{let a=e.findIndex(e=>i.keyId(e.key)===t);return a===-1?{datum:void 0,point:void 0}:{datum:e[a],point:n[r]?.[a]}})},nearestIndex=(e,t)=>{let n=-1,r=1/0;return e.forEach(({point:e},i)=>{if(!e)return;let a=Number.isFinite(t)?Math.abs(e.y-t):0;a<r&&(r=a,n=i)}),n},highlight=(t,n)=>{let r=o.colors();o.markers.replaceChildren(),t.forEach(({point:t},n)=>{t&&o.markers.appendChild(e.createSvgElement(`circle`,{class:`prism-active-point`,cx:t.x,cy:t.y,fill:r[n],r:4}))});let i=[...o.seriesGroup.children];o.seriesGroup.classList.toggle(`prism-series-focused`,n>=0&&i.length>1);for(let[e,t]of i.entries())t.classList.toggle(`prism-series-active`,e===n)},clear=()=>{o.crosshair?.hide(),o.tooltip?.hide(),o.announcer.clear(),highlight([],-1),c=!1,o.onHover?.(null)},eventFor=(e,t,n)=>{let r=entriesAt(e),i=renderedHit(n),a=i?.seriesIndex??nearestIndex(r,t);i&&(r[a]={datum:i.datum,point:i.point});let s=o.getSeriesList(),c=r[a]?.datum;if(a<0||!c)return null;let l=r.map((e,t)=>({datum:e.datum,series:s[t]}));return{entries:r,event:{datum:c,originalEvent:n,series:s[a],values:l},index:a}},focus=(e,i,a)=>{let s=eventFor(e,i?.y??NaN,a);if(!s)return;let{entries:l,event:u,index:d}=s,f=l[d].point,p=o.dims(),m=r.chartArea(p.width,p.height,o.margin),h=o.crosshair?.snap===!1&&i,g=keyLabel(e),_=u.values??[],v=o.colors();o.crosshair?.show(h?i.x:f.x,h?i.y:f.y,m.width,m.height),highlight(l,d);let y=t.describeValues(g,_);if(o.tooltip){let e=_.flatMap(({datum:e,series:t},n)=>e?[{color:v[n],name:t.name,value:String(e.value)}]:[]);o.tooltip.show(f.x+o.margin.left,f.y+o.margin.top,u.datum,u.series,n.comparisonContent(o.svg.ownerDocument,g,e,y))}else o.announcer.announce(y);c=!0,o.onHover?.(u)},pointerKey=e=>{let t=renderedHit(e);if(t)return{key:t.datum.key,pos:t.point};let n=o.getPoints();if(n.every(e=>e.length===0))return null;let i=o.dims(),s=a.getMousePosition(o.svg,e,o.margin.left,o.margin.top),c=r.chartArea(i.width,i.height,o.margin);if(s.x<0||s.x>c.width||s.y<0||s.y>c.height)return null;let l=findNearestKey(o.getData(),n,s.x);return l===null?null:{key:l,pos:s}},sortedKeys=()=>[...new Map(o.getData().flat().map(e=>[i.keyId(e.key),e.key])).values()].sort((e,t)=>keyOrder(e)-keyOrder(t)),onMouseMove=e=>{let t=pointerKey(e);t?focus(t.key,t.pos,e):c&&clear()},onClick=e=>{if(!o.onClick)return;let t=pointerKey(e),n=t&&eventFor(t.key,t.pos.y,e);n&&o.onClick(n.event)},onKeyDown=e=>{let t=sortedKeys();if(t.length===0)return;let n=t.length-1,r={ArrowLeft:s<0?n:Math.max(0,s-1),ArrowRight:s<0?0:Math.min(n,s+1),End:n,Home:0};if(e.key in r)e.preventDefault(),s=r[e.key],focus(t[s],null,e);else if((e.key===`Enter`||e.key===` `)&&s>=0&&o.onClick){e.preventDefault();let n=eventFor(t[s],NaN,e);n&&o.onClick(n.event)}else e.key===`Escape`&&(s=-1,clear())};return{onClick,onKeyDown,onMouseLeave:clear,onMouseMove}}function ensureMarkerGroup(t,n){if(n&&t.contains(n))return n;let r=e.createSvgElement(`g`,{"aria-hidden":`true`,class:`prism-active-points`,"pointer-events":`none`});return t.appendChild(r),r}exports.createSeriesInteraction=createSeriesInteraction,exports.ensureMarkerGroup=ensureMarkerGroup,exports.keyLabel=keyLabel;
2
2
  //# sourceMappingURL=series-interaction.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"series-interaction.cjs","names":[],"sources":["../../src/interaction/series-interaction.ts"],"sourcesContent":["import { keyId } from '../core/cartesian-model';\nimport type { ChartEventHandlers } from '../core/chart-scaffold';\nimport { chartArea } from '../core/layout';\nimport { createSvgElement } from '../svg/element';\nimport type { Point } from '../svg/path';\nimport type { ChartDimensions, ChartEvent, Datum, Series, SeriesValue } from '../types';\nimport { type Announcer, describeValues } from './announcer';\nimport type { CrosshairState } from './crosshair';\nimport { getMousePosition } from './events';\nimport { comparisonContent, type TooltipState } from './tooltip';\n\nexport interface SeriesInteractionOptions {\n announcer: Announcer;\n colors: () => string[];\n crosshair?: CrosshairState | null;\n dims: () => ChartDimensions;\n getData: () => Datum[][];\n getPoints: () => Point[][];\n getSeriesList: () => Series[];\n /** Receives one marker per series at the active key. */\n markers: SVGGElement;\n onClick?: ((event: ChartEvent) => void) | undefined;\n onHover?: ((event: ChartEvent | null) => void) | undefined;\n /** Parent of the per-series groups; the nearest series is emphasised and the rest dim. */\n seriesGroup: SVGGElement;\n svg: SVGSVGElement;\n tooltip?: TooltipState | null;\n}\n\ninterface KeyEntry {\n datum: Datum | undefined;\n point: Point | undefined;\n}\n\nconst keyOrder = (key: Datum['key']): number => (key instanceof Date ? key.getTime() : Number(key));\n\nexport function keyLabel(key: Datum['key']): string {\n return key instanceof Date ? key.toLocaleDateString() : String(key);\n}\n\nfunction findNearestKey(allData: Datum[][], allPoints: Point[][], posX: number): Datum['key'] | null {\n let nearest: Datum['key'] | null = null;\n let minXDistance = Infinity;\n\n for (let seriesIndex = 0; seriesIndex < allPoints.length; seriesIndex++) {\n for (let datumIndex = 0; datumIndex < (allPoints[seriesIndex]?.length ?? 0); datumIndex++) {\n const datum = allData[seriesIndex]?.[datumIndex];\n const point = allPoints[seriesIndex]?.[datumIndex];\n\n if (!datum || !point) continue;\n\n const distance = Math.abs(point.x - posX);\n\n if (distance < minXDistance) {\n minXDistance = distance;\n nearest = datum.key;\n }\n }\n }\n\n return nearest;\n}\n\nexport function createSeriesInteraction(opts: SeriesInteractionOptions): ChartEventHandlers {\n let keyboardIndex = -1;\n let active = false;\n\n const renderedHit = (event: Event): { datum: Datum; point: Point; seriesIndex: number } | null => {\n const target = event.target;\n if (\n !(target instanceof SVGElement) ||\n target.tagName.toLowerCase() !== 'circle' ||\n !opts.seriesGroup.contains(target) ||\n !target.parentElement\n )\n return null;\n let group: Element | null = target.parentElement;\n while (group && group.parentNode !== opts.seriesGroup) group = group.parentElement;\n if (!group) return null;\n const seriesIndex = [...opts.seriesGroup.children].indexOf(group);\n const datumIndex = [...target.parentElement.children].indexOf(target);\n const datum = opts.getData()[seriesIndex]?.[datumIndex];\n const point = opts.getPoints()[seriesIndex]?.[datumIndex];\n return datum && point ? { datum, point, seriesIndex } : null;\n };\n\n const entriesAt = (key: Datum['key']): KeyEntry[] => {\n const id = keyId(key);\n const allPoints = opts.getPoints();\n\n return opts.getData().map((data, seriesIndex) => {\n const datumIndex = data.findIndex((datum) => keyId(datum.key) === id);\n\n return datumIndex === -1\n ? { datum: undefined, point: undefined }\n : { datum: data[datumIndex], point: allPoints[seriesIndex]?.[datumIndex] };\n });\n };\n\n const nearestIndex = (entries: KeyEntry[], posY: number): number => {\n let best = -1;\n let minDistance = Infinity;\n\n entries.forEach(({ point }, index) => {\n if (!point) return;\n\n const distance = Number.isFinite(posY) ? Math.abs(point.y - posY) : 0;\n\n if (distance < minDistance) {\n minDistance = distance;\n best = index;\n }\n });\n\n return best;\n };\n\n const highlight = (entries: KeyEntry[], emphasised: number): void => {\n const colors = opts.colors();\n\n opts.markers.replaceChildren();\n entries.forEach(({ point }, index) => {\n if (!point) return;\n\n opts.markers.appendChild(\n createSvgElement('circle', {\n class: 'prism-active-point',\n cx: point.x,\n cy: point.y,\n fill: colors[index],\n r: 4,\n }),\n );\n });\n\n const groups = [...opts.seriesGroup.children];\n\n opts.seriesGroup.classList.toggle('prism-series-focused', emphasised >= 0 && groups.length > 1);\n for (const [index, group] of groups.entries()) group.classList.toggle('prism-series-active', index === emphasised);\n };\n\n const clear = (): void => {\n opts.crosshair?.hide();\n opts.tooltip?.hide();\n opts.announcer.clear();\n highlight([], -1);\n active = false;\n opts.onHover?.(null);\n };\n\n const eventFor = (\n key: Datum['key'],\n posY: number,\n originalEvent: Event,\n ): { entries: KeyEntry[]; event: ChartEvent; index: number } | null => {\n const entries = entriesAt(key);\n const hit = renderedHit(originalEvent);\n const index = hit?.seriesIndex ?? nearestIndex(entries, posY);\n if (hit) entries[index] = { datum: hit.datum, point: hit.point };\n const seriesList = opts.getSeriesList();\n const datum = entries[index]?.datum;\n\n if (index < 0 || !datum) return null;\n\n const values: SeriesValue[] = entries.map((entry, i) => ({ datum: entry.datum, series: seriesList[i] }));\n\n return { entries, event: { datum, originalEvent, series: seriesList[index], values }, index };\n };\n\n const focus = (key: Datum['key'], pos: Point | null, originalEvent: Event): void => {\n const found = eventFor(key, pos?.y ?? Number.NaN, originalEvent);\n\n if (!found) return;\n\n const { entries, event, index } = found;\n const point = entries[index].point!;\n const dims = opts.dims();\n const area = chartArea(dims.width, dims.height, dims.margin);\n const raw = opts.crosshair?.snap === false && pos;\n const label = keyLabel(key);\n const values = event.values ?? [];\n const colors = opts.colors();\n\n opts.crosshair?.show(raw ? pos.x : point.x, raw ? pos.y : point.y, area.width, area.height);\n highlight(entries, index);\n\n const spoken = describeValues(label, values);\n\n if (opts.tooltip) {\n const rows = values.flatMap(({ datum, series }, i) =>\n datum ? [{ color: colors[i], name: series.name, value: String(datum.value) }] : [],\n );\n\n opts.tooltip.show(\n point.x + dims.margin.left,\n point.y + dims.margin.top,\n event.datum,\n event.series,\n comparisonContent(opts.svg.ownerDocument, label, rows, spoken),\n );\n } else {\n opts.announcer.announce(spoken);\n }\n\n active = true;\n opts.onHover?.(event);\n };\n\n const pointerKey = (event: MouseEvent): { key: Datum['key']; pos: Point } | null => {\n const rendered = renderedHit(event);\n if (rendered) return { key: rendered.datum.key, pos: rendered.point };\n const allPoints = opts.getPoints();\n\n if (allPoints.every((points) => points.length === 0)) return null;\n\n const dims = opts.dims();\n const pos = getMousePosition(opts.svg, event, dims.margin.left, dims.margin.top);\n const area = chartArea(dims.width, dims.height, dims.margin);\n\n if (pos.x < 0 || pos.x > area.width || pos.y < 0 || pos.y > area.height) return null;\n\n const key = findNearestKey(opts.getData(), allPoints, pos.x);\n\n return key === null ? null : { key, pos };\n };\n\n const sortedKeys = (): Datum['key'][] =>\n [\n ...new Map(\n opts\n .getData()\n .flat()\n .map((datum) => [keyId(datum.key), datum.key]),\n ).values(),\n ].sort((a, b) => keyOrder(a) - keyOrder(b));\n\n const onMouseMove = (event: MouseEvent): void => {\n const hit = pointerKey(event);\n\n if (hit) focus(hit.key, hit.pos, event);\n else if (active) clear();\n };\n\n const onClick = (event: MouseEvent): void => {\n if (!opts.onClick) return;\n\n const hit = pointerKey(event);\n const found = hit && eventFor(hit.key, hit.pos.y, event);\n\n if (found) opts.onClick(found.event);\n };\n\n const onKeyDown = (event: KeyboardEvent): void => {\n const keys = sortedKeys();\n\n if (keys.length === 0) return;\n\n const last = keys.length - 1;\n const target: Record<string, number> = {\n ArrowLeft: keyboardIndex < 0 ? last : Math.max(0, keyboardIndex - 1),\n ArrowRight: keyboardIndex < 0 ? 0 : Math.min(last, keyboardIndex + 1),\n End: last,\n Home: 0,\n };\n\n if (event.key in target) {\n event.preventDefault();\n keyboardIndex = target[event.key];\n focus(keys[keyboardIndex], null, event);\n } else if ((event.key === 'Enter' || event.key === ' ') && keyboardIndex >= 0 && opts.onClick) {\n event.preventDefault();\n\n const found = eventFor(keys[keyboardIndex], Number.NaN, event);\n\n if (found) opts.onClick(found.event);\n } else if (event.key === 'Escape') {\n keyboardIndex = -1;\n clear();\n }\n };\n\n return { onClick, onKeyDown, onMouseLeave: clear, onMouseMove };\n}\n\n/** Group for the per-series active markers, reused across renders. */\nexport function ensureMarkerGroup(parent: SVGGElement, current: SVGGElement | null): SVGGElement {\n if (current && parent.contains(current)) return current;\n\n const group = createSvgElement('g', {\n 'aria-hidden': 'true',\n class: 'prism-active-points',\n 'pointer-events': 'none',\n });\n\n parent.appendChild(group);\n\n return group;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"series-interaction.cjs","names":[],"sources":["../../src/interaction/series-interaction.ts"],"sourcesContent":["import { keyId } from '../core/cartesian-model';\nimport type { ChartEventHandlers } from '../core/chart-scaffold';\nimport { chartArea } from '../core/layout';\nimport { createSvgElement } from '../svg/element';\nimport type { Point } from '../svg/path';\nimport type { ChartDimensions, ChartEvent, ChartMargin, Datum, Series, SeriesValue } from '../types';\nimport { type Announcer, describeValues } from './announcer';\nimport type { CrosshairState } from './crosshair';\nimport { getMousePosition } from './events';\nimport { comparisonContent, type TooltipState } from './tooltip';\n\nexport interface SeriesInteractionOptions {\n announcer: Announcer;\n colors: () => string[];\n crosshair?: CrosshairState | null;\n dims: () => ChartDimensions;\n getData: () => Datum[][];\n getPoints: () => Point[][];\n getSeriesList: () => Series[];\n /** Effective chart margin (including any dual-axis widening): hit bounds and tooltip offsets use this, never the shared dimensions. */\n margin: ChartMargin;\n /** Receives one marker per series at the active key. */\n markers: SVGGElement;\n onClick?: ((event: ChartEvent) => void) | undefined;\n onHover?: ((event: ChartEvent | null) => void) | undefined;\n /** Parent of the per-series groups; the nearest series is emphasised and the rest dim. */\n seriesGroup: SVGGElement;\n svg: SVGSVGElement;\n tooltip?: TooltipState | null;\n}\n\ninterface KeyEntry {\n datum: Datum | undefined;\n point: Point | undefined;\n}\n\nconst keyOrder = (key: Datum['key']): number => (key instanceof Date ? key.getTime() : Number(key));\n\nexport function keyLabel(key: Datum['key']): string {\n return key instanceof Date ? key.toLocaleDateString() : String(key);\n}\n\nfunction findNearestKey(allData: Datum[][], allPoints: Point[][], posX: number): Datum['key'] | null {\n let nearest: Datum['key'] | null = null;\n let minXDistance = Infinity;\n\n for (let seriesIndex = 0; seriesIndex < allPoints.length; seriesIndex++) {\n for (let datumIndex = 0; datumIndex < (allPoints[seriesIndex]?.length ?? 0); datumIndex++) {\n const datum = allData[seriesIndex]?.[datumIndex];\n const point = allPoints[seriesIndex]?.[datumIndex];\n\n if (!datum || !point) continue;\n\n const distance = Math.abs(point.x - posX);\n\n if (distance < minXDistance) {\n minXDistance = distance;\n nearest = datum.key;\n }\n }\n }\n\n return nearest;\n}\n\nexport function createSeriesInteraction(opts: SeriesInteractionOptions): ChartEventHandlers {\n let keyboardIndex = -1;\n let active = false;\n\n const renderedHit = (event: Event): { datum: Datum; point: Point; seriesIndex: number } | null => {\n const target = event.target;\n if (\n !(target instanceof SVGElement) ||\n target.tagName.toLowerCase() !== 'circle' ||\n !opts.seriesGroup.contains(target) ||\n !target.parentElement\n )\n return null;\n let group: Element | null = target.parentElement;\n while (group && group.parentNode !== opts.seriesGroup) group = group.parentElement;\n if (!group) return null;\n const seriesIndex = [...opts.seriesGroup.children].indexOf(group);\n const datumIndex = [...target.parentElement.children].indexOf(target);\n const datum = opts.getData()[seriesIndex]?.[datumIndex];\n const point = opts.getPoints()[seriesIndex]?.[datumIndex];\n return datum && point ? { datum, point, seriesIndex } : null;\n };\n\n const entriesAt = (key: Datum['key']): KeyEntry[] => {\n const id = keyId(key);\n const allPoints = opts.getPoints();\n\n return opts.getData().map((data, seriesIndex) => {\n const datumIndex = data.findIndex((datum) => keyId(datum.key) === id);\n\n return datumIndex === -1\n ? { datum: undefined, point: undefined }\n : { datum: data[datumIndex], point: allPoints[seriesIndex]?.[datumIndex] };\n });\n };\n\n const nearestIndex = (entries: KeyEntry[], posY: number): number => {\n let best = -1;\n let minDistance = Infinity;\n\n entries.forEach(({ point }, index) => {\n if (!point) return;\n\n const distance = Number.isFinite(posY) ? Math.abs(point.y - posY) : 0;\n\n if (distance < minDistance) {\n minDistance = distance;\n best = index;\n }\n });\n\n return best;\n };\n\n const highlight = (entries: KeyEntry[], emphasised: number): void => {\n const colors = opts.colors();\n\n opts.markers.replaceChildren();\n entries.forEach(({ point }, index) => {\n if (!point) return;\n\n opts.markers.appendChild(\n createSvgElement('circle', {\n class: 'prism-active-point',\n cx: point.x,\n cy: point.y,\n fill: colors[index],\n r: 4,\n }),\n );\n });\n\n const groups = [...opts.seriesGroup.children];\n\n opts.seriesGroup.classList.toggle('prism-series-focused', emphasised >= 0 && groups.length > 1);\n for (const [index, group] of groups.entries()) group.classList.toggle('prism-series-active', index === emphasised);\n };\n\n const clear = (): void => {\n opts.crosshair?.hide();\n opts.tooltip?.hide();\n opts.announcer.clear();\n highlight([], -1);\n active = false;\n opts.onHover?.(null);\n };\n\n const eventFor = (\n key: Datum['key'],\n posY: number,\n originalEvent: Event,\n ): { entries: KeyEntry[]; event: ChartEvent; index: number } | null => {\n const entries = entriesAt(key);\n const hit = renderedHit(originalEvent);\n const index = hit?.seriesIndex ?? nearestIndex(entries, posY);\n if (hit) entries[index] = { datum: hit.datum, point: hit.point };\n const seriesList = opts.getSeriesList();\n const datum = entries[index]?.datum;\n\n if (index < 0 || !datum) return null;\n\n const values: SeriesValue[] = entries.map((entry, i) => ({ datum: entry.datum, series: seriesList[i] }));\n\n return { entries, event: { datum, originalEvent, series: seriesList[index], values }, index };\n };\n\n const focus = (key: Datum['key'], pos: Point | null, originalEvent: Event): void => {\n const found = eventFor(key, pos?.y ?? Number.NaN, originalEvent);\n\n if (!found) return;\n\n const { entries, event, index } = found;\n const point = entries[index].point!;\n const dims = opts.dims();\n const area = chartArea(dims.width, dims.height, opts.margin);\n const raw = opts.crosshair?.snap === false && pos;\n const label = keyLabel(key);\n const values = event.values ?? [];\n const colors = opts.colors();\n\n opts.crosshair?.show(raw ? pos.x : point.x, raw ? pos.y : point.y, area.width, area.height);\n highlight(entries, index);\n\n const spoken = describeValues(label, values);\n\n if (opts.tooltip) {\n const rows = values.flatMap(({ datum, series }, i) =>\n datum ? [{ color: colors[i], name: series.name, value: String(datum.value) }] : [],\n );\n\n opts.tooltip.show(\n point.x + opts.margin.left,\n point.y + opts.margin.top,\n event.datum,\n event.series,\n comparisonContent(opts.svg.ownerDocument, label, rows, spoken),\n );\n } else {\n opts.announcer.announce(spoken);\n }\n\n active = true;\n opts.onHover?.(event);\n };\n\n const pointerKey = (event: MouseEvent): { key: Datum['key']; pos: Point } | null => {\n const rendered = renderedHit(event);\n if (rendered) return { key: rendered.datum.key, pos: rendered.point };\n const allPoints = opts.getPoints();\n\n if (allPoints.every((points) => points.length === 0)) return null;\n\n const dims = opts.dims();\n const pos = getMousePosition(opts.svg, event, opts.margin.left, opts.margin.top);\n const area = chartArea(dims.width, dims.height, opts.margin);\n\n if (pos.x < 0 || pos.x > area.width || pos.y < 0 || pos.y > area.height) return null;\n\n const key = findNearestKey(opts.getData(), allPoints, pos.x);\n\n return key === null ? null : { key, pos };\n };\n\n const sortedKeys = (): Datum['key'][] =>\n [\n ...new Map(\n opts\n .getData()\n .flat()\n .map((datum) => [keyId(datum.key), datum.key]),\n ).values(),\n ].sort((a, b) => keyOrder(a) - keyOrder(b));\n\n const onMouseMove = (event: MouseEvent): void => {\n const hit = pointerKey(event);\n\n if (hit) focus(hit.key, hit.pos, event);\n else if (active) clear();\n };\n\n const onClick = (event: MouseEvent): void => {\n if (!opts.onClick) return;\n\n const hit = pointerKey(event);\n const found = hit && eventFor(hit.key, hit.pos.y, event);\n\n if (found) opts.onClick(found.event);\n };\n\n const onKeyDown = (event: KeyboardEvent): void => {\n const keys = sortedKeys();\n\n if (keys.length === 0) return;\n\n const last = keys.length - 1;\n const target: Record<string, number> = {\n ArrowLeft: keyboardIndex < 0 ? last : Math.max(0, keyboardIndex - 1),\n ArrowRight: keyboardIndex < 0 ? 0 : Math.min(last, keyboardIndex + 1),\n End: last,\n Home: 0,\n };\n\n if (event.key in target) {\n event.preventDefault();\n keyboardIndex = target[event.key];\n focus(keys[keyboardIndex], null, event);\n } else if ((event.key === 'Enter' || event.key === ' ') && keyboardIndex >= 0 && opts.onClick) {\n event.preventDefault();\n\n const found = eventFor(keys[keyboardIndex], Number.NaN, event);\n\n if (found) opts.onClick(found.event);\n } else if (event.key === 'Escape') {\n keyboardIndex = -1;\n clear();\n }\n };\n\n return { onClick, onKeyDown, onMouseLeave: clear, onMouseMove };\n}\n\n/** Group for the per-series active markers, reused across renders. */\nexport function ensureMarkerGroup(parent: SVGGElement, current: SVGGElement | null): SVGGElement {\n if (current && parent.contains(current)) return current;\n\n const group = createSvgElement('g', {\n 'aria-hidden': 'true',\n class: 'prism-active-points',\n 'pointer-events': 'none',\n });\n\n parent.appendChild(group);\n\n return group;\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import type { ChartEventHandlers } from '../core/chart-scaffold';
2
2
  import type { Point } from '../svg/path';
3
- import type { ChartDimensions, ChartEvent, Datum, Series } from '../types';
3
+ import type { ChartDimensions, ChartEvent, ChartMargin, Datum, Series } from '../types';
4
4
  import { type Announcer } from './announcer';
5
5
  import type { CrosshairState } from './crosshair';
6
6
  import { type TooltipState } from './tooltip';
@@ -12,6 +12,8 @@ export interface SeriesInteractionOptions {
12
12
  getData: () => Datum[][];
13
13
  getPoints: () => Point[][];
14
14
  getSeriesList: () => Series[];
15
+ /** Effective chart margin (including any dual-axis widening): hit bounds and tooltip offsets use this, never the shared dimensions. */
16
+ margin: ChartMargin;
15
17
  /** Receives one marker per series at the active key. */
16
18
  markers: SVGGElement;
17
19
  onClick?: ((event: ChartEvent) => void) | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"series-interaction.d.ts","sourceRoot":"","sources":["../../src/interaction/series-interaction.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAGjE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAe,MAAM,UAAU,CAAC;AACxF,OAAO,EAAE,KAAK,SAAS,EAAkB,MAAM,aAAa,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAEjE,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,SAAS,CAAC;IACrB,MAAM,EAAE,MAAM,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAClC,IAAI,EAAE,MAAM,eAAe,CAAC;IAC5B,OAAO,EAAE,MAAM,KAAK,EAAE,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,KAAK,EAAE,EAAE,CAAC;IAC3B,aAAa,EAAE,MAAM,MAAM,EAAE,CAAC;IAC9B,wDAAwD;IACxD,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC3D,0FAA0F;IAC1F,WAAW,EAAE,WAAW,CAAC;IACzB,GAAG,EAAE,aAAa,CAAC;IACnB,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CAC/B;AASD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,MAAM,CAElD;AAyBD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,wBAAwB,GAAG,kBAAkB,CA2N1F;AAED,sEAAsE;AACtE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI,GAAG,WAAW,CAY/F"}
1
+ {"version":3,"file":"series-interaction.d.ts","sourceRoot":"","sources":["../../src/interaction/series-interaction.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAGjE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAe,MAAM,UAAU,CAAC;AACrG,OAAO,EAAE,KAAK,SAAS,EAAkB,MAAM,aAAa,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAEjE,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,SAAS,CAAC;IACrB,MAAM,EAAE,MAAM,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAClC,IAAI,EAAE,MAAM,eAAe,CAAC;IAC5B,OAAO,EAAE,MAAM,KAAK,EAAE,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,KAAK,EAAE,EAAE,CAAC;IAC3B,aAAa,EAAE,MAAM,MAAM,EAAE,CAAC;IAC9B,uIAAuI;IACvI,MAAM,EAAE,WAAW,CAAC;IACpB,wDAAwD;IACxD,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC3D,0FAA0F;IAC1F,WAAW,EAAE,WAAW,CAAC;IACzB,GAAG,EAAE,aAAa,CAAC;IACnB,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CAC/B;AASD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,MAAM,CAElD;AAyBD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,wBAAwB,GAAG,kBAAkB,CA2N1F;AAED,sEAAsE;AACtE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI,GAAG,WAAW,CAY/F"}
@@ -1,2 +1,2 @@
1
- import{createSvgElement as e}from"../svg/element.js";import{describeValues as t}from"./announcer.js";import{comparisonContent as n}from"./tooltip.js";import{chartArea as r}from"../core/layout.js";import{keyId as i}from"../core/cartesian-model.js";import{getMousePosition as a}from"./events.js";var keyOrder=e=>e instanceof Date?e.getTime():Number(e);function keyLabel(e){return e instanceof Date?e.toLocaleDateString():String(e)}function findNearestKey(e,t,n){let r=null,i=1/0;for(let a=0;a<t.length;a++)for(let o=0;o<(t[a]?.length??0);o++){let s=e[a]?.[o],c=t[a]?.[o];if(!s||!c)continue;let l=Math.abs(c.x-n);l<i&&(i=l,r=s.key)}return r}function createSeriesInteraction(o){let s=-1,c=!1,renderedHit=e=>{let t=e.target;if(!(t instanceof SVGElement)||t.tagName.toLowerCase()!==`circle`||!o.seriesGroup.contains(t)||!t.parentElement)return null;let n=t.parentElement;for(;n&&n.parentNode!==o.seriesGroup;)n=n.parentElement;if(!n)return null;let r=[...o.seriesGroup.children].indexOf(n),i=[...t.parentElement.children].indexOf(t),a=o.getData()[r]?.[i],s=o.getPoints()[r]?.[i];return a&&s?{datum:a,point:s,seriesIndex:r}:null},entriesAt=e=>{let t=i(e),n=o.getPoints();return o.getData().map((e,r)=>{let a=e.findIndex(e=>i(e.key)===t);return a===-1?{datum:void 0,point:void 0}:{datum:e[a],point:n[r]?.[a]}})},nearestIndex=(e,t)=>{let n=-1,r=1/0;return e.forEach(({point:e},i)=>{if(!e)return;let a=Number.isFinite(t)?Math.abs(e.y-t):0;a<r&&(r=a,n=i)}),n},highlight=(t,n)=>{let r=o.colors();o.markers.replaceChildren(),t.forEach(({point:t},n)=>{t&&o.markers.appendChild(e(`circle`,{class:`prism-active-point`,cx:t.x,cy:t.y,fill:r[n],r:4}))});let i=[...o.seriesGroup.children];o.seriesGroup.classList.toggle(`prism-series-focused`,n>=0&&i.length>1);for(let[e,t]of i.entries())t.classList.toggle(`prism-series-active`,e===n)},clear=()=>{o.crosshair?.hide(),o.tooltip?.hide(),o.announcer.clear(),highlight([],-1),c=!1,o.onHover?.(null)},eventFor=(e,t,n)=>{let r=entriesAt(e),i=renderedHit(n),a=i?.seriesIndex??nearestIndex(r,t);i&&(r[a]={datum:i.datum,point:i.point});let s=o.getSeriesList(),c=r[a]?.datum;if(a<0||!c)return null;let l=r.map((e,t)=>({datum:e.datum,series:s[t]}));return{entries:r,event:{datum:c,originalEvent:n,series:s[a],values:l},index:a}},focus=(e,i,a)=>{let s=eventFor(e,i?.y??NaN,a);if(!s)return;let{entries:l,event:u,index:d}=s,f=l[d].point,p=o.dims(),m=r(p.width,p.height,p.margin),h=o.crosshair?.snap===!1&&i,g=keyLabel(e),_=u.values??[],v=o.colors();o.crosshair?.show(h?i.x:f.x,h?i.y:f.y,m.width,m.height),highlight(l,d);let y=t(g,_);if(o.tooltip){let e=_.flatMap(({datum:e,series:t},n)=>e?[{color:v[n],name:t.name,value:String(e.value)}]:[]);o.tooltip.show(f.x+p.margin.left,f.y+p.margin.top,u.datum,u.series,n(o.svg.ownerDocument,g,e,y))}else o.announcer.announce(y);c=!0,o.onHover?.(u)},pointerKey=e=>{let t=renderedHit(e);if(t)return{key:t.datum.key,pos:t.point};let n=o.getPoints();if(n.every(e=>e.length===0))return null;let i=o.dims(),s=a(o.svg,e,i.margin.left,i.margin.top),c=r(i.width,i.height,i.margin);if(s.x<0||s.x>c.width||s.y<0||s.y>c.height)return null;let l=findNearestKey(o.getData(),n,s.x);return l===null?null:{key:l,pos:s}},sortedKeys=()=>[...new Map(o.getData().flat().map(e=>[i(e.key),e.key])).values()].sort((e,t)=>keyOrder(e)-keyOrder(t)),onMouseMove=e=>{let t=pointerKey(e);t?focus(t.key,t.pos,e):c&&clear()},onClick=e=>{if(!o.onClick)return;let t=pointerKey(e),n=t&&eventFor(t.key,t.pos.y,e);n&&o.onClick(n.event)},onKeyDown=e=>{let t=sortedKeys();if(t.length===0)return;let n=t.length-1,r={ArrowLeft:s<0?n:Math.max(0,s-1),ArrowRight:s<0?0:Math.min(n,s+1),End:n,Home:0};if(e.key in r)e.preventDefault(),s=r[e.key],focus(t[s],null,e);else if((e.key===`Enter`||e.key===` `)&&s>=0&&o.onClick){e.preventDefault();let n=eventFor(t[s],NaN,e);n&&o.onClick(n.event)}else e.key===`Escape`&&(s=-1,clear())};return{onClick,onKeyDown,onMouseLeave:clear,onMouseMove}}function ensureMarkerGroup(t,n){if(n&&t.contains(n))return n;let r=e(`g`,{"aria-hidden":`true`,class:`prism-active-points`,"pointer-events":`none`});return t.appendChild(r),r}export{createSeriesInteraction,ensureMarkerGroup,keyLabel};
1
+ import{createSvgElement as e}from"../svg/element.js";import{describeValues as t}from"./announcer.js";import{comparisonContent as n}from"./tooltip.js";import{chartArea as r}from"../core/layout.js";import{keyId as i}from"../core/cartesian-model.js";import{getMousePosition as a}from"./events.js";var keyOrder=e=>e instanceof Date?e.getTime():Number(e);function keyLabel(e){return e instanceof Date?e.toLocaleDateString():String(e)}function findNearestKey(e,t,n){let r=null,i=1/0;for(let a=0;a<t.length;a++)for(let o=0;o<(t[a]?.length??0);o++){let s=e[a]?.[o],c=t[a]?.[o];if(!s||!c)continue;let l=Math.abs(c.x-n);l<i&&(i=l,r=s.key)}return r}function createSeriesInteraction(o){let s=-1,c=!1,renderedHit=e=>{let t=e.target;if(!(t instanceof SVGElement)||t.tagName.toLowerCase()!==`circle`||!o.seriesGroup.contains(t)||!t.parentElement)return null;let n=t.parentElement;for(;n&&n.parentNode!==o.seriesGroup;)n=n.parentElement;if(!n)return null;let r=[...o.seriesGroup.children].indexOf(n),i=[...t.parentElement.children].indexOf(t),a=o.getData()[r]?.[i],s=o.getPoints()[r]?.[i];return a&&s?{datum:a,point:s,seriesIndex:r}:null},entriesAt=e=>{let t=i(e),n=o.getPoints();return o.getData().map((e,r)=>{let a=e.findIndex(e=>i(e.key)===t);return a===-1?{datum:void 0,point:void 0}:{datum:e[a],point:n[r]?.[a]}})},nearestIndex=(e,t)=>{let n=-1,r=1/0;return e.forEach(({point:e},i)=>{if(!e)return;let a=Number.isFinite(t)?Math.abs(e.y-t):0;a<r&&(r=a,n=i)}),n},highlight=(t,n)=>{let r=o.colors();o.markers.replaceChildren(),t.forEach(({point:t},n)=>{t&&o.markers.appendChild(e(`circle`,{class:`prism-active-point`,cx:t.x,cy:t.y,fill:r[n],r:4}))});let i=[...o.seriesGroup.children];o.seriesGroup.classList.toggle(`prism-series-focused`,n>=0&&i.length>1);for(let[e,t]of i.entries())t.classList.toggle(`prism-series-active`,e===n)},clear=()=>{o.crosshair?.hide(),o.tooltip?.hide(),o.announcer.clear(),highlight([],-1),c=!1,o.onHover?.(null)},eventFor=(e,t,n)=>{let r=entriesAt(e),i=renderedHit(n),a=i?.seriesIndex??nearestIndex(r,t);i&&(r[a]={datum:i.datum,point:i.point});let s=o.getSeriesList(),c=r[a]?.datum;if(a<0||!c)return null;let l=r.map((e,t)=>({datum:e.datum,series:s[t]}));return{entries:r,event:{datum:c,originalEvent:n,series:s[a],values:l},index:a}},focus=(e,i,a)=>{let s=eventFor(e,i?.y??NaN,a);if(!s)return;let{entries:l,event:u,index:d}=s,f=l[d].point,p=o.dims(),m=r(p.width,p.height,o.margin),h=o.crosshair?.snap===!1&&i,g=keyLabel(e),_=u.values??[],v=o.colors();o.crosshair?.show(h?i.x:f.x,h?i.y:f.y,m.width,m.height),highlight(l,d);let y=t(g,_);if(o.tooltip){let e=_.flatMap(({datum:e,series:t},n)=>e?[{color:v[n],name:t.name,value:String(e.value)}]:[]);o.tooltip.show(f.x+o.margin.left,f.y+o.margin.top,u.datum,u.series,n(o.svg.ownerDocument,g,e,y))}else o.announcer.announce(y);c=!0,o.onHover?.(u)},pointerKey=e=>{let t=renderedHit(e);if(t)return{key:t.datum.key,pos:t.point};let n=o.getPoints();if(n.every(e=>e.length===0))return null;let i=o.dims(),s=a(o.svg,e,o.margin.left,o.margin.top),c=r(i.width,i.height,o.margin);if(s.x<0||s.x>c.width||s.y<0||s.y>c.height)return null;let l=findNearestKey(o.getData(),n,s.x);return l===null?null:{key:l,pos:s}},sortedKeys=()=>[...new Map(o.getData().flat().map(e=>[i(e.key),e.key])).values()].sort((e,t)=>keyOrder(e)-keyOrder(t)),onMouseMove=e=>{let t=pointerKey(e);t?focus(t.key,t.pos,e):c&&clear()},onClick=e=>{if(!o.onClick)return;let t=pointerKey(e),n=t&&eventFor(t.key,t.pos.y,e);n&&o.onClick(n.event)},onKeyDown=e=>{let t=sortedKeys();if(t.length===0)return;let n=t.length-1,r={ArrowLeft:s<0?n:Math.max(0,s-1),ArrowRight:s<0?0:Math.min(n,s+1),End:n,Home:0};if(e.key in r)e.preventDefault(),s=r[e.key],focus(t[s],null,e);else if((e.key===`Enter`||e.key===` `)&&s>=0&&o.onClick){e.preventDefault();let n=eventFor(t[s],NaN,e);n&&o.onClick(n.event)}else e.key===`Escape`&&(s=-1,clear())};return{onClick,onKeyDown,onMouseLeave:clear,onMouseMove}}function ensureMarkerGroup(t,n){if(n&&t.contains(n))return n;let r=e(`g`,{"aria-hidden":`true`,class:`prism-active-points`,"pointer-events":`none`});return t.appendChild(r),r}export{createSeriesInteraction,ensureMarkerGroup,keyLabel};
2
2
  //# sourceMappingURL=series-interaction.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"series-interaction.js","names":[],"sources":["../../src/interaction/series-interaction.ts"],"sourcesContent":["import { keyId } from '../core/cartesian-model';\nimport type { ChartEventHandlers } from '../core/chart-scaffold';\nimport { chartArea } from '../core/layout';\nimport { createSvgElement } from '../svg/element';\nimport type { Point } from '../svg/path';\nimport type { ChartDimensions, ChartEvent, Datum, Series, SeriesValue } from '../types';\nimport { type Announcer, describeValues } from './announcer';\nimport type { CrosshairState } from './crosshair';\nimport { getMousePosition } from './events';\nimport { comparisonContent, type TooltipState } from './tooltip';\n\nexport interface SeriesInteractionOptions {\n announcer: Announcer;\n colors: () => string[];\n crosshair?: CrosshairState | null;\n dims: () => ChartDimensions;\n getData: () => Datum[][];\n getPoints: () => Point[][];\n getSeriesList: () => Series[];\n /** Receives one marker per series at the active key. */\n markers: SVGGElement;\n onClick?: ((event: ChartEvent) => void) | undefined;\n onHover?: ((event: ChartEvent | null) => void) | undefined;\n /** Parent of the per-series groups; the nearest series is emphasised and the rest dim. */\n seriesGroup: SVGGElement;\n svg: SVGSVGElement;\n tooltip?: TooltipState | null;\n}\n\ninterface KeyEntry {\n datum: Datum | undefined;\n point: Point | undefined;\n}\n\nconst keyOrder = (key: Datum['key']): number => (key instanceof Date ? key.getTime() : Number(key));\n\nexport function keyLabel(key: Datum['key']): string {\n return key instanceof Date ? key.toLocaleDateString() : String(key);\n}\n\nfunction findNearestKey(allData: Datum[][], allPoints: Point[][], posX: number): Datum['key'] | null {\n let nearest: Datum['key'] | null = null;\n let minXDistance = Infinity;\n\n for (let seriesIndex = 0; seriesIndex < allPoints.length; seriesIndex++) {\n for (let datumIndex = 0; datumIndex < (allPoints[seriesIndex]?.length ?? 0); datumIndex++) {\n const datum = allData[seriesIndex]?.[datumIndex];\n const point = allPoints[seriesIndex]?.[datumIndex];\n\n if (!datum || !point) continue;\n\n const distance = Math.abs(point.x - posX);\n\n if (distance < minXDistance) {\n minXDistance = distance;\n nearest = datum.key;\n }\n }\n }\n\n return nearest;\n}\n\nexport function createSeriesInteraction(opts: SeriesInteractionOptions): ChartEventHandlers {\n let keyboardIndex = -1;\n let active = false;\n\n const renderedHit = (event: Event): { datum: Datum; point: Point; seriesIndex: number } | null => {\n const target = event.target;\n if (\n !(target instanceof SVGElement) ||\n target.tagName.toLowerCase() !== 'circle' ||\n !opts.seriesGroup.contains(target) ||\n !target.parentElement\n )\n return null;\n let group: Element | null = target.parentElement;\n while (group && group.parentNode !== opts.seriesGroup) group = group.parentElement;\n if (!group) return null;\n const seriesIndex = [...opts.seriesGroup.children].indexOf(group);\n const datumIndex = [...target.parentElement.children].indexOf(target);\n const datum = opts.getData()[seriesIndex]?.[datumIndex];\n const point = opts.getPoints()[seriesIndex]?.[datumIndex];\n return datum && point ? { datum, point, seriesIndex } : null;\n };\n\n const entriesAt = (key: Datum['key']): KeyEntry[] => {\n const id = keyId(key);\n const allPoints = opts.getPoints();\n\n return opts.getData().map((data, seriesIndex) => {\n const datumIndex = data.findIndex((datum) => keyId(datum.key) === id);\n\n return datumIndex === -1\n ? { datum: undefined, point: undefined }\n : { datum: data[datumIndex], point: allPoints[seriesIndex]?.[datumIndex] };\n });\n };\n\n const nearestIndex = (entries: KeyEntry[], posY: number): number => {\n let best = -1;\n let minDistance = Infinity;\n\n entries.forEach(({ point }, index) => {\n if (!point) return;\n\n const distance = Number.isFinite(posY) ? Math.abs(point.y - posY) : 0;\n\n if (distance < minDistance) {\n minDistance = distance;\n best = index;\n }\n });\n\n return best;\n };\n\n const highlight = (entries: KeyEntry[], emphasised: number): void => {\n const colors = opts.colors();\n\n opts.markers.replaceChildren();\n entries.forEach(({ point }, index) => {\n if (!point) return;\n\n opts.markers.appendChild(\n createSvgElement('circle', {\n class: 'prism-active-point',\n cx: point.x,\n cy: point.y,\n fill: colors[index],\n r: 4,\n }),\n );\n });\n\n const groups = [...opts.seriesGroup.children];\n\n opts.seriesGroup.classList.toggle('prism-series-focused', emphasised >= 0 && groups.length > 1);\n for (const [index, group] of groups.entries()) group.classList.toggle('prism-series-active', index === emphasised);\n };\n\n const clear = (): void => {\n opts.crosshair?.hide();\n opts.tooltip?.hide();\n opts.announcer.clear();\n highlight([], -1);\n active = false;\n opts.onHover?.(null);\n };\n\n const eventFor = (\n key: Datum['key'],\n posY: number,\n originalEvent: Event,\n ): { entries: KeyEntry[]; event: ChartEvent; index: number } | null => {\n const entries = entriesAt(key);\n const hit = renderedHit(originalEvent);\n const index = hit?.seriesIndex ?? nearestIndex(entries, posY);\n if (hit) entries[index] = { datum: hit.datum, point: hit.point };\n const seriesList = opts.getSeriesList();\n const datum = entries[index]?.datum;\n\n if (index < 0 || !datum) return null;\n\n const values: SeriesValue[] = entries.map((entry, i) => ({ datum: entry.datum, series: seriesList[i] }));\n\n return { entries, event: { datum, originalEvent, series: seriesList[index], values }, index };\n };\n\n const focus = (key: Datum['key'], pos: Point | null, originalEvent: Event): void => {\n const found = eventFor(key, pos?.y ?? Number.NaN, originalEvent);\n\n if (!found) return;\n\n const { entries, event, index } = found;\n const point = entries[index].point!;\n const dims = opts.dims();\n const area = chartArea(dims.width, dims.height, dims.margin);\n const raw = opts.crosshair?.snap === false && pos;\n const label = keyLabel(key);\n const values = event.values ?? [];\n const colors = opts.colors();\n\n opts.crosshair?.show(raw ? pos.x : point.x, raw ? pos.y : point.y, area.width, area.height);\n highlight(entries, index);\n\n const spoken = describeValues(label, values);\n\n if (opts.tooltip) {\n const rows = values.flatMap(({ datum, series }, i) =>\n datum ? [{ color: colors[i], name: series.name, value: String(datum.value) }] : [],\n );\n\n opts.tooltip.show(\n point.x + dims.margin.left,\n point.y + dims.margin.top,\n event.datum,\n event.series,\n comparisonContent(opts.svg.ownerDocument, label, rows, spoken),\n );\n } else {\n opts.announcer.announce(spoken);\n }\n\n active = true;\n opts.onHover?.(event);\n };\n\n const pointerKey = (event: MouseEvent): { key: Datum['key']; pos: Point } | null => {\n const rendered = renderedHit(event);\n if (rendered) return { key: rendered.datum.key, pos: rendered.point };\n const allPoints = opts.getPoints();\n\n if (allPoints.every((points) => points.length === 0)) return null;\n\n const dims = opts.dims();\n const pos = getMousePosition(opts.svg, event, dims.margin.left, dims.margin.top);\n const area = chartArea(dims.width, dims.height, dims.margin);\n\n if (pos.x < 0 || pos.x > area.width || pos.y < 0 || pos.y > area.height) return null;\n\n const key = findNearestKey(opts.getData(), allPoints, pos.x);\n\n return key === null ? null : { key, pos };\n };\n\n const sortedKeys = (): Datum['key'][] =>\n [\n ...new Map(\n opts\n .getData()\n .flat()\n .map((datum) => [keyId(datum.key), datum.key]),\n ).values(),\n ].sort((a, b) => keyOrder(a) - keyOrder(b));\n\n const onMouseMove = (event: MouseEvent): void => {\n const hit = pointerKey(event);\n\n if (hit) focus(hit.key, hit.pos, event);\n else if (active) clear();\n };\n\n const onClick = (event: MouseEvent): void => {\n if (!opts.onClick) return;\n\n const hit = pointerKey(event);\n const found = hit && eventFor(hit.key, hit.pos.y, event);\n\n if (found) opts.onClick(found.event);\n };\n\n const onKeyDown = (event: KeyboardEvent): void => {\n const keys = sortedKeys();\n\n if (keys.length === 0) return;\n\n const last = keys.length - 1;\n const target: Record<string, number> = {\n ArrowLeft: keyboardIndex < 0 ? last : Math.max(0, keyboardIndex - 1),\n ArrowRight: keyboardIndex < 0 ? 0 : Math.min(last, keyboardIndex + 1),\n End: last,\n Home: 0,\n };\n\n if (event.key in target) {\n event.preventDefault();\n keyboardIndex = target[event.key];\n focus(keys[keyboardIndex], null, event);\n } else if ((event.key === 'Enter' || event.key === ' ') && keyboardIndex >= 0 && opts.onClick) {\n event.preventDefault();\n\n const found = eventFor(keys[keyboardIndex], Number.NaN, event);\n\n if (found) opts.onClick(found.event);\n } else if (event.key === 'Escape') {\n keyboardIndex = -1;\n clear();\n }\n };\n\n return { onClick, onKeyDown, onMouseLeave: clear, onMouseMove };\n}\n\n/** Group for the per-series active markers, reused across renders. */\nexport function ensureMarkerGroup(parent: SVGGElement, current: SVGGElement | null): SVGGElement {\n if (current && parent.contains(current)) return current;\n\n const group = createSvgElement('g', {\n 'aria-hidden': 'true',\n class: 'prism-active-points',\n 'pointer-events': 'none',\n });\n\n parent.appendChild(group);\n\n return group;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"series-interaction.js","names":[],"sources":["../../src/interaction/series-interaction.ts"],"sourcesContent":["import { keyId } from '../core/cartesian-model';\nimport type { ChartEventHandlers } from '../core/chart-scaffold';\nimport { chartArea } from '../core/layout';\nimport { createSvgElement } from '../svg/element';\nimport type { Point } from '../svg/path';\nimport type { ChartDimensions, ChartEvent, ChartMargin, Datum, Series, SeriesValue } from '../types';\nimport { type Announcer, describeValues } from './announcer';\nimport type { CrosshairState } from './crosshair';\nimport { getMousePosition } from './events';\nimport { comparisonContent, type TooltipState } from './tooltip';\n\nexport interface SeriesInteractionOptions {\n announcer: Announcer;\n colors: () => string[];\n crosshair?: CrosshairState | null;\n dims: () => ChartDimensions;\n getData: () => Datum[][];\n getPoints: () => Point[][];\n getSeriesList: () => Series[];\n /** Effective chart margin (including any dual-axis widening): hit bounds and tooltip offsets use this, never the shared dimensions. */\n margin: ChartMargin;\n /** Receives one marker per series at the active key. */\n markers: SVGGElement;\n onClick?: ((event: ChartEvent) => void) | undefined;\n onHover?: ((event: ChartEvent | null) => void) | undefined;\n /** Parent of the per-series groups; the nearest series is emphasised and the rest dim. */\n seriesGroup: SVGGElement;\n svg: SVGSVGElement;\n tooltip?: TooltipState | null;\n}\n\ninterface KeyEntry {\n datum: Datum | undefined;\n point: Point | undefined;\n}\n\nconst keyOrder = (key: Datum['key']): number => (key instanceof Date ? key.getTime() : Number(key));\n\nexport function keyLabel(key: Datum['key']): string {\n return key instanceof Date ? key.toLocaleDateString() : String(key);\n}\n\nfunction findNearestKey(allData: Datum[][], allPoints: Point[][], posX: number): Datum['key'] | null {\n let nearest: Datum['key'] | null = null;\n let minXDistance = Infinity;\n\n for (let seriesIndex = 0; seriesIndex < allPoints.length; seriesIndex++) {\n for (let datumIndex = 0; datumIndex < (allPoints[seriesIndex]?.length ?? 0); datumIndex++) {\n const datum = allData[seriesIndex]?.[datumIndex];\n const point = allPoints[seriesIndex]?.[datumIndex];\n\n if (!datum || !point) continue;\n\n const distance = Math.abs(point.x - posX);\n\n if (distance < minXDistance) {\n minXDistance = distance;\n nearest = datum.key;\n }\n }\n }\n\n return nearest;\n}\n\nexport function createSeriesInteraction(opts: SeriesInteractionOptions): ChartEventHandlers {\n let keyboardIndex = -1;\n let active = false;\n\n const renderedHit = (event: Event): { datum: Datum; point: Point; seriesIndex: number } | null => {\n const target = event.target;\n if (\n !(target instanceof SVGElement) ||\n target.tagName.toLowerCase() !== 'circle' ||\n !opts.seriesGroup.contains(target) ||\n !target.parentElement\n )\n return null;\n let group: Element | null = target.parentElement;\n while (group && group.parentNode !== opts.seriesGroup) group = group.parentElement;\n if (!group) return null;\n const seriesIndex = [...opts.seriesGroup.children].indexOf(group);\n const datumIndex = [...target.parentElement.children].indexOf(target);\n const datum = opts.getData()[seriesIndex]?.[datumIndex];\n const point = opts.getPoints()[seriesIndex]?.[datumIndex];\n return datum && point ? { datum, point, seriesIndex } : null;\n };\n\n const entriesAt = (key: Datum['key']): KeyEntry[] => {\n const id = keyId(key);\n const allPoints = opts.getPoints();\n\n return opts.getData().map((data, seriesIndex) => {\n const datumIndex = data.findIndex((datum) => keyId(datum.key) === id);\n\n return datumIndex === -1\n ? { datum: undefined, point: undefined }\n : { datum: data[datumIndex], point: allPoints[seriesIndex]?.[datumIndex] };\n });\n };\n\n const nearestIndex = (entries: KeyEntry[], posY: number): number => {\n let best = -1;\n let minDistance = Infinity;\n\n entries.forEach(({ point }, index) => {\n if (!point) return;\n\n const distance = Number.isFinite(posY) ? Math.abs(point.y - posY) : 0;\n\n if (distance < minDistance) {\n minDistance = distance;\n best = index;\n }\n });\n\n return best;\n };\n\n const highlight = (entries: KeyEntry[], emphasised: number): void => {\n const colors = opts.colors();\n\n opts.markers.replaceChildren();\n entries.forEach(({ point }, index) => {\n if (!point) return;\n\n opts.markers.appendChild(\n createSvgElement('circle', {\n class: 'prism-active-point',\n cx: point.x,\n cy: point.y,\n fill: colors[index],\n r: 4,\n }),\n );\n });\n\n const groups = [...opts.seriesGroup.children];\n\n opts.seriesGroup.classList.toggle('prism-series-focused', emphasised >= 0 && groups.length > 1);\n for (const [index, group] of groups.entries()) group.classList.toggle('prism-series-active', index === emphasised);\n };\n\n const clear = (): void => {\n opts.crosshair?.hide();\n opts.tooltip?.hide();\n opts.announcer.clear();\n highlight([], -1);\n active = false;\n opts.onHover?.(null);\n };\n\n const eventFor = (\n key: Datum['key'],\n posY: number,\n originalEvent: Event,\n ): { entries: KeyEntry[]; event: ChartEvent; index: number } | null => {\n const entries = entriesAt(key);\n const hit = renderedHit(originalEvent);\n const index = hit?.seriesIndex ?? nearestIndex(entries, posY);\n if (hit) entries[index] = { datum: hit.datum, point: hit.point };\n const seriesList = opts.getSeriesList();\n const datum = entries[index]?.datum;\n\n if (index < 0 || !datum) return null;\n\n const values: SeriesValue[] = entries.map((entry, i) => ({ datum: entry.datum, series: seriesList[i] }));\n\n return { entries, event: { datum, originalEvent, series: seriesList[index], values }, index };\n };\n\n const focus = (key: Datum['key'], pos: Point | null, originalEvent: Event): void => {\n const found = eventFor(key, pos?.y ?? Number.NaN, originalEvent);\n\n if (!found) return;\n\n const { entries, event, index } = found;\n const point = entries[index].point!;\n const dims = opts.dims();\n const area = chartArea(dims.width, dims.height, opts.margin);\n const raw = opts.crosshair?.snap === false && pos;\n const label = keyLabel(key);\n const values = event.values ?? [];\n const colors = opts.colors();\n\n opts.crosshair?.show(raw ? pos.x : point.x, raw ? pos.y : point.y, area.width, area.height);\n highlight(entries, index);\n\n const spoken = describeValues(label, values);\n\n if (opts.tooltip) {\n const rows = values.flatMap(({ datum, series }, i) =>\n datum ? [{ color: colors[i], name: series.name, value: String(datum.value) }] : [],\n );\n\n opts.tooltip.show(\n point.x + opts.margin.left,\n point.y + opts.margin.top,\n event.datum,\n event.series,\n comparisonContent(opts.svg.ownerDocument, label, rows, spoken),\n );\n } else {\n opts.announcer.announce(spoken);\n }\n\n active = true;\n opts.onHover?.(event);\n };\n\n const pointerKey = (event: MouseEvent): { key: Datum['key']; pos: Point } | null => {\n const rendered = renderedHit(event);\n if (rendered) return { key: rendered.datum.key, pos: rendered.point };\n const allPoints = opts.getPoints();\n\n if (allPoints.every((points) => points.length === 0)) return null;\n\n const dims = opts.dims();\n const pos = getMousePosition(opts.svg, event, opts.margin.left, opts.margin.top);\n const area = chartArea(dims.width, dims.height, opts.margin);\n\n if (pos.x < 0 || pos.x > area.width || pos.y < 0 || pos.y > area.height) return null;\n\n const key = findNearestKey(opts.getData(), allPoints, pos.x);\n\n return key === null ? null : { key, pos };\n };\n\n const sortedKeys = (): Datum['key'][] =>\n [\n ...new Map(\n opts\n .getData()\n .flat()\n .map((datum) => [keyId(datum.key), datum.key]),\n ).values(),\n ].sort((a, b) => keyOrder(a) - keyOrder(b));\n\n const onMouseMove = (event: MouseEvent): void => {\n const hit = pointerKey(event);\n\n if (hit) focus(hit.key, hit.pos, event);\n else if (active) clear();\n };\n\n const onClick = (event: MouseEvent): void => {\n if (!opts.onClick) return;\n\n const hit = pointerKey(event);\n const found = hit && eventFor(hit.key, hit.pos.y, event);\n\n if (found) opts.onClick(found.event);\n };\n\n const onKeyDown = (event: KeyboardEvent): void => {\n const keys = sortedKeys();\n\n if (keys.length === 0) return;\n\n const last = keys.length - 1;\n const target: Record<string, number> = {\n ArrowLeft: keyboardIndex < 0 ? last : Math.max(0, keyboardIndex - 1),\n ArrowRight: keyboardIndex < 0 ? 0 : Math.min(last, keyboardIndex + 1),\n End: last,\n Home: 0,\n };\n\n if (event.key in target) {\n event.preventDefault();\n keyboardIndex = target[event.key];\n focus(keys[keyboardIndex], null, event);\n } else if ((event.key === 'Enter' || event.key === ' ') && keyboardIndex >= 0 && opts.onClick) {\n event.preventDefault();\n\n const found = eventFor(keys[keyboardIndex], Number.NaN, event);\n\n if (found) opts.onClick(found.event);\n } else if (event.key === 'Escape') {\n keyboardIndex = -1;\n clear();\n }\n };\n\n return { onClick, onKeyDown, onMouseLeave: clear, onMouseMove };\n}\n\n/** Group for the per-series active markers, reused across renders. */\nexport function ensureMarkerGroup(parent: SVGGElement, current: SVGGElement | null): SVGGElement {\n if (current && parent.contains(current)) return current;\n\n const group = createSvgElement('g', {\n 'aria-hidden': 'true',\n class: 'prism-active-points',\n 'pointer-events': 'none',\n });\n\n parent.appendChild(group);\n\n return group;\n}\n"],"mappings":"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"}