@vielzeug/prism 3.0.0 → 26.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/dist/_dev.cjs +1 -1
  2. package/dist/_dev.cjs.map +1 -1
  3. package/dist/_dev.js +1 -5
  4. package/dist/_dev.js.map +1 -1
  5. package/dist/animation/easing.cjs +1 -1
  6. package/dist/animation/easing.cjs.map +1 -1
  7. package/dist/animation/easing.js +1 -13
  8. package/dist/animation/easing.js.map +1 -1
  9. package/dist/animation/motion.cjs +1 -1
  10. package/dist/animation/motion.cjs.map +1 -1
  11. package/dist/animation/motion.js +1 -12
  12. package/dist/animation/motion.js.map +1 -1
  13. package/dist/animation/transition.cjs +1 -1
  14. package/dist/animation/transition.cjs.map +1 -1
  15. package/dist/animation/transition.js +1 -28
  16. package/dist/animation/transition.js.map +1 -1
  17. package/dist/animation/tween.cjs +1 -1
  18. package/dist/animation/tween.cjs.map +1 -1
  19. package/dist/animation/tween.js +1 -7
  20. package/dist/animation/tween.js.map +1 -1
  21. package/dist/axes/axis.cjs +1 -1
  22. package/dist/axes/axis.cjs.map +1 -1
  23. package/dist/axes/axis.js +1 -63
  24. package/dist/axes/axis.js.map +1 -1
  25. package/dist/axes/grid.cjs +1 -1
  26. package/dist/axes/grid.cjs.map +1 -1
  27. package/dist/axes/grid.js +1 -29
  28. package/dist/axes/grid.js.map +1 -1
  29. package/dist/axes/scale-utils.cjs +1 -1
  30. package/dist/axes/scale-utils.cjs.map +1 -1
  31. package/dist/axes/scale-utils.js +1 -10
  32. package/dist/axes/scale-utils.js.map +1 -1
  33. package/dist/charts/area/area-chart.cjs +1 -1
  34. package/dist/charts/area/area-chart.cjs.map +1 -1
  35. package/dist/charts/area/area-chart.js +1 -57
  36. package/dist/charts/area/area-chart.js.map +1 -1
  37. package/dist/charts/area/area-renderer.cjs +1 -1
  38. package/dist/charts/area/area-renderer.cjs.map +1 -1
  39. package/dist/charts/area/area-renderer.js +1 -73
  40. package/dist/charts/area/area-renderer.js.map +1 -1
  41. package/dist/charts/bar/bar-chart.cjs +1 -1
  42. package/dist/charts/bar/bar-chart.cjs.map +1 -1
  43. package/dist/charts/bar/bar-chart.js +1 -169
  44. package/dist/charts/bar/bar-chart.js.map +1 -1
  45. package/dist/charts/bar/bar-hit-test.cjs +1 -1
  46. package/dist/charts/bar/bar-hit-test.cjs.map +1 -1
  47. package/dist/charts/bar/bar-hit-test.js +1 -29
  48. package/dist/charts/bar/bar-hit-test.js.map +1 -1
  49. package/dist/charts/bar/bar-renderer.cjs +1 -1
  50. package/dist/charts/bar/bar-renderer.cjs.map +1 -1
  51. package/dist/charts/bar/bar-renderer.js +1 -106
  52. package/dist/charts/bar/bar-renderer.js.map +1 -1
  53. package/dist/charts/line/line-chart.cjs +1 -1
  54. package/dist/charts/line/line-chart.cjs.map +1 -1
  55. package/dist/charts/line/line-chart.js +1 -58
  56. package/dist/charts/line/line-chart.js.map +1 -1
  57. package/dist/charts/line/line-renderer.cjs +1 -1
  58. package/dist/charts/line/line-renderer.cjs.map +1 -1
  59. package/dist/charts/line/line-renderer.js +1 -100
  60. package/dist/charts/line/line-renderer.js.map +1 -1
  61. package/dist/charts/pie/pie-chart.cjs +1 -1
  62. package/dist/charts/pie/pie-chart.cjs.map +1 -1
  63. package/dist/charts/pie/pie-chart.js +1 -165
  64. package/dist/charts/pie/pie-chart.js.map +1 -1
  65. package/dist/charts/pie/pie-renderer.cjs +1 -1
  66. package/dist/charts/pie/pie-renderer.cjs.map +1 -1
  67. package/dist/charts/pie/pie-renderer.js +1 -76
  68. package/dist/charts/pie/pie-renderer.js.map +1 -1
  69. package/dist/charts/sparkline/sparkline.cjs +1 -1
  70. package/dist/charts/sparkline/sparkline.cjs.map +1 -1
  71. package/dist/charts/sparkline/sparkline.js +1 -191
  72. package/dist/charts/sparkline/sparkline.js.map +1 -1
  73. package/dist/core/cartesian-model.cjs +1 -1
  74. package/dist/core/cartesian-model.cjs.map +1 -1
  75. package/dist/core/cartesian-model.js +1 -30
  76. package/dist/core/cartesian-model.js.map +1 -1
  77. package/dist/core/cartesian-scales.cjs +1 -1
  78. package/dist/core/cartesian-scales.cjs.map +1 -1
  79. package/dist/core/cartesian-scales.js +1 -37
  80. package/dist/core/cartesian-scales.js.map +1 -1
  81. package/dist/core/chart-base.cjs +1 -1
  82. package/dist/core/chart-base.cjs.map +1 -1
  83. package/dist/core/chart-base.js +1 -53
  84. package/dist/core/chart-base.js.map +1 -1
  85. package/dist/core/chart-scaffold.cjs +1 -1
  86. package/dist/core/chart-scaffold.cjs.map +1 -1
  87. package/dist/core/chart-scaffold.js +1 -89
  88. package/dist/core/chart-scaffold.js.map +1 -1
  89. package/dist/core/layout.cjs +1 -1
  90. package/dist/core/layout.cjs.map +1 -1
  91. package/dist/core/layout.js +1 -22
  92. package/dist/core/layout.js.map +1 -1
  93. package/dist/core/responsive.cjs +1 -1
  94. package/dist/core/responsive.cjs.map +1 -1
  95. package/dist/core/responsive.js +1 -19
  96. package/dist/core/responsive.js.map +1 -1
  97. package/dist/devtools.cjs +1 -1
  98. package/dist/devtools.cjs.map +1 -1
  99. package/dist/devtools.js +1 -18
  100. package/dist/devtools.js.map +1 -1
  101. package/dist/errors.cjs +1 -1
  102. package/dist/errors.cjs.map +1 -1
  103. package/dist/errors.js +1 -9
  104. package/dist/errors.js.map +1 -1
  105. package/dist/index.js +1 -11
  106. package/dist/interaction/crosshair.cjs +1 -1
  107. package/dist/interaction/crosshair.cjs.map +1 -1
  108. package/dist/interaction/crosshair.js +1 -45
  109. package/dist/interaction/crosshair.js.map +1 -1
  110. package/dist/interaction/events.cjs +1 -1
  111. package/dist/interaction/events.cjs.map +1 -1
  112. package/dist/interaction/events.js +1 -11
  113. package/dist/interaction/events.js.map +1 -1
  114. package/dist/interaction/legend.cjs +1 -1
  115. package/dist/interaction/legend.cjs.map +1 -1
  116. package/dist/interaction/legend.js +1 -30
  117. package/dist/interaction/legend.js.map +1 -1
  118. package/dist/interaction/series-interaction.cjs +1 -1
  119. package/dist/interaction/series-interaction.cjs.map +1 -1
  120. package/dist/interaction/series-interaction.js +1 -97
  121. package/dist/interaction/series-interaction.js.map +1 -1
  122. package/dist/interaction/tooltip.cjs +1 -1
  123. package/dist/interaction/tooltip.cjs.map +1 -1
  124. package/dist/interaction/tooltip.js +1 -63
  125. package/dist/interaction/tooltip.js.map +1 -1
  126. package/dist/prism.cjs +1 -1
  127. package/dist/prism.cjs.map +1 -1
  128. package/dist/prism.iife.js +1 -1
  129. package/dist/prism.iife.js.map +1 -1
  130. package/dist/prism.js +1 -1
  131. package/dist/prism.js.map +1 -1
  132. package/dist/scales/band.cjs +1 -1
  133. package/dist/scales/band.cjs.map +1 -1
  134. package/dist/scales/band.js +1 -39
  135. package/dist/scales/band.js.map +1 -1
  136. package/dist/scales/linear.cjs +1 -1
  137. package/dist/scales/linear.cjs.map +1 -1
  138. package/dist/scales/linear.js +1 -43
  139. package/dist/scales/linear.js.map +1 -1
  140. package/dist/scales/time.cjs +1 -1
  141. package/dist/scales/time.cjs.map +1 -1
  142. package/dist/scales/time.js +1 -61
  143. package/dist/scales/time.js.map +1 -1
  144. package/dist/svg/element.cjs +1 -1
  145. package/dist/svg/element.cjs.map +1 -1
  146. package/dist/svg/element.js +1 -22
  147. package/dist/svg/element.js.map +1 -1
  148. package/dist/svg/path.cjs +1 -1
  149. package/dist/svg/path.cjs.map +1 -1
  150. package/dist/svg/path.js +1 -48
  151. package/dist/svg/path.js.map +1 -1
  152. package/dist/svg/text.cjs +1 -1
  153. package/dist/svg/text.cjs.map +1 -1
  154. package/dist/svg/text.js +1 -9
  155. package/dist/svg/text.js.map +1 -1
  156. package/dist/theme/index.cjs +1 -1
  157. package/dist/theme/index.cjs.map +1 -1
  158. package/dist/theme/index.js +1 -19
  159. package/dist/theme/index.js.map +1 -1
  160. package/package.json +5 -5
@@ -1,101 +1,2 @@
1
- import "../../_dev.js";
2
- import { createSvgElement as e, setAttributes as t } from "../../svg/element.js";
3
- import { resolveEasing as n } from "../../animation/easing.js";
4
- import { resolveMotion as r } from "../../animation/motion.js";
5
- import { tweenNumber as i } from "../../animation/tween.js";
6
- import { linePath as a, monotonePath as o, stepPath as s } from "../../svg/path.js";
7
- //#region src/charts/line/line-renderer.ts
8
- var c = /* @__PURE__ */ new WeakMap();
9
- function l(e, t) {
10
- return t === "monotone" ? o(e) : t === "step" ? s(e) : a(e);
11
- }
12
- function u(a, o, s) {
13
- let u = r(s.transition, 0), d = u.duration, f = n(u.easing), p = a.querySelector(".prism-line-path");
14
- p || (p = e("path", {
15
- class: "prism-line-path",
16
- fill: "none"
17
- }), a.appendChild(p)), t(p, {
18
- stroke: s.color,
19
- "stroke-width": s.strokeWidth
20
- });
21
- let m = a.querySelector(".prism-line-dots");
22
- if (s.showPoints ? m || (m = e("g", { class: "prism-line-dots" }), a.appendChild(m)) : m &&= (m.remove(), null), d === 0) {
23
- if (t(p, { d: l(o, s.curve) }), m) {
24
- for (; m.children.length > o.length;) m.removeChild(m.lastChild);
25
- for (let n = 0; n < o.length; n++) {
26
- let r = m.children[n];
27
- r || (r = e("circle", { class: "prism-line-dot" }), m.appendChild(r)), t(r, {
28
- cx: o[n].x,
29
- cy: o[n].y,
30
- fill: s.color,
31
- r: s.pointRadius
32
- });
33
- }
34
- }
35
- return;
36
- }
37
- c.get(a)?.();
38
- let h = !!p.getAttribute("d"), g = [], _ = null;
39
- if (m) {
40
- let n = m.children.length;
41
- for (let e = 0; e < n; e++) {
42
- let t = m.children[e], n = {
43
- x: Number(t.getAttribute("cx")),
44
- y: Number(t.getAttribute("cy"))
45
- };
46
- g.push(n), _ = n;
47
- }
48
- for (; m.children.length > o.length;) m.removeChild(m.lastChild);
49
- for (let n = m.children.length; n < o.length; n++) {
50
- let r = e("circle", { class: "prism-line-dot" });
51
- t(r, {
52
- cx: o[n].x,
53
- cy: o[n].y,
54
- fill: s.color,
55
- r: s.pointRadius
56
- }), m.appendChild(r);
57
- }
58
- }
59
- for (let e = g.length; e < o.length; e++) g.push(_ ?? o[e]);
60
- let v = null;
61
- function y(e) {
62
- if (s.disposalSignal?.aborted) {
63
- c.delete(a);
64
- return;
65
- }
66
- v === null && (v = e);
67
- let n = Math.min(1, (e - v) / d), r = f(n), u = o.map((e, t) => {
68
- let n = g[t] ?? e;
69
- return {
70
- x: i(n.x, e.x, r),
71
- y: i(n.y, e.y, r)
72
- };
73
- });
74
- if (t(p, { d: l(u, s.curve) }), m) for (let e = 0; e < o.length; e++) {
75
- let n = m.children[e];
76
- n && t(n, {
77
- cx: u[e].x,
78
- cy: u[e].y
79
- });
80
- }
81
- if (n < 1) {
82
- let e = requestAnimationFrame(y);
83
- c.set(a, () => cancelAnimationFrame(e));
84
- } else c.delete(a);
85
- }
86
- if (!h) t(p, { d: l(o, s.curve) });
87
- else {
88
- let e = requestAnimationFrame(y);
89
- c.set(a, () => cancelAnimationFrame(e));
90
- }
91
- }
92
- function d(e, t, n) {
93
- return e.some((e) => e.key == null) || e.some((e) => typeof e.key == "string"), e.map((e) => ({
94
- x: t.map(e.key),
95
- y: n.map(e.value)
96
- }));
97
- }
98
- //#endregion
99
- export { d as computePoints, u as renderLine };
100
-
1
+ import"../../_dev.js";import{createSvgElement as e,setAttributes as t}from"../../svg/element.js";import{resolveEasing as n}from"../../animation/easing.js";import{resolveMotion as r}from"../../animation/motion.js";import{tweenNumber as i}from"../../animation/tween.js";import{linePath as a,monotonePath as o,stepPath as s}from"../../svg/path.js";var c=new WeakMap;function buildPath(e,t){return t===`monotone`?o(e):t===`step`?s(e):a(e)}function renderLine(a,o,s){let l=r(s.transition,0),u=l.duration,d=n(l.easing),f=a.querySelector(`.prism-line-path`);f||(f=e(`path`,{class:`prism-line-path`,fill:`none`}),a.appendChild(f)),t(f,{stroke:s.color,"stroke-width":s.strokeWidth});let p=a.querySelector(`.prism-line-dots`);if(s.showPoints?p||(p=e(`g`,{class:`prism-line-dots`}),a.appendChild(p)):p&&=(p.remove(),null),u===0){if(t(f,{d:buildPath(o,s.curve)}),p){for(;p.children.length>o.length;)p.removeChild(p.lastChild);for(let n=0;n<o.length;n++){let r=p.children[n];r||(r=e(`circle`,{class:`prism-line-dot`}),p.appendChild(r)),t(r,{cx:o[n].x,cy:o[n].y,fill:s.color,r:s.pointRadius})}}return}c.get(a)?.();let m=!!f.getAttribute(`d`),h=[],g=null;if(p){let n=p.children.length;for(let e=0;e<n;e++){let t=p.children[e],n={x:Number(t.getAttribute(`cx`)),y:Number(t.getAttribute(`cy`))};h.push(n),g=n}for(;p.children.length>o.length;)p.removeChild(p.lastChild);for(let n=p.children.length;n<o.length;n++){let r=e(`circle`,{class:`prism-line-dot`});t(r,{cx:o[n].x,cy:o[n].y,fill:s.color,r:s.pointRadius}),p.appendChild(r)}}for(let e=h.length;e<o.length;e++)h.push(g??o[e]);let _=null;function frame(e){if(s.disposalSignal?.aborted){c.delete(a);return}_===null&&(_=e);let n=Math.min(1,(e-_)/u),r=d(n),l=o.map((e,t)=>{let n=h[t]??e;return{x:i(n.x,e.x,r),y:i(n.y,e.y,r)}});if(t(f,{d:buildPath(l,s.curve)}),p)for(let e=0;e<o.length;e++){let n=p.children[e];n&&t(n,{cx:l[e].x,cy:l[e].y})}if(n<1){let e=requestAnimationFrame(frame);c.set(a,()=>cancelAnimationFrame(e))}else c.delete(a)}if(!m)t(f,{d:buildPath(o,s.curve)});else{let e=requestAnimationFrame(frame);c.set(a,()=>cancelAnimationFrame(e))}}function computePoints(e,t,n){return e.some(e=>e.key==null)||e.some(e=>typeof e.key==`string`),e.map(e=>({x:t.map(e.key),y:n.map(e.value)}))}export{computePoints,renderLine};
101
2
  //# sourceMappingURL=line-renderer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"line-renderer.js","names":[],"sources":["../../../src/charts/line/line-renderer.ts"],"sourcesContent":["import { warn } from '../../_dev';\nimport { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { tweenNumber } from '../../animation/tween';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport type { Point } from '../../svg/path';\nimport { linePath, monotonePath, stepPath } from '../../svg/path';\nimport type { ContinuousDatum, Scale, TransitionConfig } from '../../types';\n\nexport interface LineRenderOptions {\n color: string;\n curve: 'linear' | 'monotone' | 'step';\n /** Aborted when the owning chart is disposed — stops the transition's `requestAnimationFrame` loop from rescheduling. */\n disposalSignal?: AbortSignal;\n pointRadius: number;\n showPoints: boolean;\n strokeWidth: number;\n transition?: TransitionConfig;\n}\n\nconst activeAnimations = new WeakMap<SVGGElement, () => void>();\n\nfunction buildPath(pts: Point[], curve: LineRenderOptions['curve']): string {\n return curve === 'monotone' ? monotonePath(pts) : curve === 'step' ? stepPath(pts) : linePath(pts);\n}\n\nexport function renderLine(parent: SVGGElement, points: Point[], options: LineRenderOptions): void {\n const motion = resolveMotion(options.transition, 0);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n let path = parent.querySelector<SVGPathElement>('.prism-line-path');\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-line-path', fill: 'none' });\n parent.appendChild(path);\n }\n\n setAttributes(path, { stroke: options.color, 'stroke-width': options.strokeWidth });\n\n let dotsGroup = parent.querySelector<SVGGElement>('.prism-line-dots');\n\n if (options.showPoints) {\n if (!dotsGroup) {\n dotsGroup = createSvgElement('g', { class: 'prism-line-dots' });\n parent.appendChild(dotsGroup);\n }\n } else if (dotsGroup) {\n dotsGroup.remove();\n dotsGroup = null;\n }\n\n if (dur === 0) {\n setAttributes(path, { d: buildPath(points, options.curve) });\n\n if (dotsGroup) {\n while (dotsGroup.children.length > points.length) dotsGroup.removeChild(dotsGroup.lastChild!);\n\n for (let i = 0; i < points.length; i++) {\n let c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (!c) {\n c = createSvgElement('circle', { class: 'prism-line-dot' });\n dotsGroup.appendChild(c);\n }\n\n setAttributes(c, { cx: points[i].x, cy: points[i].y, fill: options.color, r: options.pointRadius });\n }\n }\n\n return;\n }\n\n activeAnimations.get(parent)?.();\n\n const hasExisting = !!path.getAttribute('d');\n\n const fromPts: Point[] = [];\n let lastKnown: Point | null = null;\n\n if (dotsGroup) {\n const existingCount = dotsGroup.children.length;\n\n for (let i = 0; i < existingCount; i++) {\n const c = dotsGroup.children[i] as SVGCircleElement;\n const pt = { x: Number(c.getAttribute('cx')), y: Number(c.getAttribute('cy')) };\n\n fromPts.push(pt);\n lastKnown = pt;\n }\n\n while (dotsGroup.children.length > points.length) dotsGroup.removeChild(dotsGroup.lastChild!);\n\n for (let i = dotsGroup.children.length; i < points.length; i++) {\n const c = createSvgElement('circle', { class: 'prism-line-dot' });\n\n setAttributes(c, { cx: points[i].x, cy: points[i].y, fill: options.color, r: options.pointRadius });\n dotsGroup.appendChild(c);\n }\n }\n\n for (let i = fromPts.length; i < points.length; i++) {\n fromPts.push(lastKnown ?? points[i]);\n }\n\n let startTime: number | null = null;\n\n function frame(ts: number) {\n if (options.disposalSignal?.aborted) {\n activeAnimations.delete(parent);\n\n return;\n }\n\n if (startTime === null) startTime = ts;\n\n const t = Math.min(1, (ts - startTime) / dur);\n const e = easing(t);\n const interpolated: Point[] = points.map((to, i) => {\n const from = fromPts[i] ?? to;\n\n return { x: tweenNumber(from.x, to.x, e), y: tweenNumber(from.y, to.y, e) };\n });\n\n setAttributes(path!, { d: buildPath(interpolated, options.curve) });\n\n if (dotsGroup) {\n for (let i = 0; i < points.length; i++) {\n const c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (c) setAttributes(c, { cx: interpolated[i].x, cy: interpolated[i].y });\n }\n }\n\n if (t < 1) {\n const id = requestAnimationFrame(frame);\n\n activeAnimations.set(parent, () => cancelAnimationFrame(id));\n } else {\n activeAnimations.delete(parent);\n }\n }\n\n if (!hasExisting) {\n setAttributes(path, { d: buildPath(points, options.curve) });\n } else {\n const id = requestAnimationFrame(frame);\n\n activeAnimations.set(parent, () => cancelAnimationFrame(id));\n }\n}\n\nexport function computePoints(data: ContinuousDatum[], xScale: Scale<Date | number>, yScale: Scale<number>): Point[] {\n if (data.some((d) => d.key == null)) {\n warn(\n 'computePoints: datum.key is null or undefined — data must use the Datum shape { key, value }. Did you pass { x, y } instead?',\n );\n } else if (data.some((d) => typeof d.key === 'string')) {\n warn('computePoints: string keys are not supported for line/area charts — use numeric or Date keys.');\n }\n\n return data.map((d) => ({\n x: xScale.map(d.key as Date | number),\n y: yScale.map(d.value),\n }));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"line-renderer.js","names":[],"sources":["../../../src/charts/line/line-renderer.ts"],"sourcesContent":["import { warn } from '../../_dev';\nimport { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { tweenNumber } from '../../animation/tween';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport type { Point } from '../../svg/path';\nimport { linePath, monotonePath, stepPath } from '../../svg/path';\nimport type { ContinuousDatum, Scale, TransitionConfig } from '../../types';\n\nexport interface LineRenderOptions {\n color: string;\n curve: 'linear' | 'monotone' | 'step';\n /** Aborted when the owning chart is disposed — stops the transition's `requestAnimationFrame` loop from rescheduling. */\n disposalSignal?: AbortSignal;\n pointRadius: number;\n showPoints: boolean;\n strokeWidth: number;\n transition?: TransitionConfig;\n}\n\nconst activeAnimations = new WeakMap<SVGGElement, () => void>();\n\nfunction buildPath(pts: Point[], curve: LineRenderOptions['curve']): string {\n return curve === 'monotone' ? monotonePath(pts) : curve === 'step' ? stepPath(pts) : linePath(pts);\n}\n\nexport function renderLine(parent: SVGGElement, points: Point[], options: LineRenderOptions): void {\n const motion = resolveMotion(options.transition, 0);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n let path = parent.querySelector<SVGPathElement>('.prism-line-path');\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-line-path', fill: 'none' });\n parent.appendChild(path);\n }\n\n setAttributes(path, { stroke: options.color, 'stroke-width': options.strokeWidth });\n\n let dotsGroup = parent.querySelector<SVGGElement>('.prism-line-dots');\n\n if (options.showPoints) {\n if (!dotsGroup) {\n dotsGroup = createSvgElement('g', { class: 'prism-line-dots' });\n parent.appendChild(dotsGroup);\n }\n } else if (dotsGroup) {\n dotsGroup.remove();\n dotsGroup = null;\n }\n\n if (dur === 0) {\n setAttributes(path, { d: buildPath(points, options.curve) });\n\n if (dotsGroup) {\n while (dotsGroup.children.length > points.length) dotsGroup.removeChild(dotsGroup.lastChild!);\n\n for (let i = 0; i < points.length; i++) {\n let c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (!c) {\n c = createSvgElement('circle', { class: 'prism-line-dot' });\n dotsGroup.appendChild(c);\n }\n\n setAttributes(c, { cx: points[i].x, cy: points[i].y, fill: options.color, r: options.pointRadius });\n }\n }\n\n return;\n }\n\n activeAnimations.get(parent)?.();\n\n const hasExisting = !!path.getAttribute('d');\n\n const fromPts: Point[] = [];\n let lastKnown: Point | null = null;\n\n if (dotsGroup) {\n const existingCount = dotsGroup.children.length;\n\n for (let i = 0; i < existingCount; i++) {\n const c = dotsGroup.children[i] as SVGCircleElement;\n const pt = { x: Number(c.getAttribute('cx')), y: Number(c.getAttribute('cy')) };\n\n fromPts.push(pt);\n lastKnown = pt;\n }\n\n while (dotsGroup.children.length > points.length) dotsGroup.removeChild(dotsGroup.lastChild!);\n\n for (let i = dotsGroup.children.length; i < points.length; i++) {\n const c = createSvgElement('circle', { class: 'prism-line-dot' });\n\n setAttributes(c, { cx: points[i].x, cy: points[i].y, fill: options.color, r: options.pointRadius });\n dotsGroup.appendChild(c);\n }\n }\n\n for (let i = fromPts.length; i < points.length; i++) {\n fromPts.push(lastKnown ?? points[i]);\n }\n\n let startTime: number | null = null;\n\n function frame(ts: number) {\n if (options.disposalSignal?.aborted) {\n activeAnimations.delete(parent);\n\n return;\n }\n\n if (startTime === null) startTime = ts;\n\n const t = Math.min(1, (ts - startTime) / dur);\n const e = easing(t);\n const interpolated: Point[] = points.map((to, i) => {\n const from = fromPts[i] ?? to;\n\n return { x: tweenNumber(from.x, to.x, e), y: tweenNumber(from.y, to.y, e) };\n });\n\n setAttributes(path!, { d: buildPath(interpolated, options.curve) });\n\n if (dotsGroup) {\n for (let i = 0; i < points.length; i++) {\n const c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (c) setAttributes(c, { cx: interpolated[i].x, cy: interpolated[i].y });\n }\n }\n\n if (t < 1) {\n const id = requestAnimationFrame(frame);\n\n activeAnimations.set(parent, () => cancelAnimationFrame(id));\n } else {\n activeAnimations.delete(parent);\n }\n }\n\n if (!hasExisting) {\n setAttributes(path, { d: buildPath(points, options.curve) });\n } else {\n const id = requestAnimationFrame(frame);\n\n activeAnimations.set(parent, () => cancelAnimationFrame(id));\n }\n}\n\nexport function computePoints(data: ContinuousDatum[], xScale: Scale<Date | number>, yScale: Scale<number>): Point[] {\n if (data.some((d) => d.key == null)) {\n warn(\n 'computePoints: datum.key is null or undefined — data must use the Datum shape { key, value }. Did you pass { x, y } instead?',\n );\n } else if (data.some((d) => typeof d.key === 'string')) {\n warn('computePoints: string keys are not supported for line/area charts — use numeric or Date keys.');\n }\n\n return data.map((d) => ({\n x: xScale.map(d.key as Date | number),\n y: yScale.map(d.value),\n }));\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require("../../svg/element.cjs"),t=require("../../core/chart-scaffold.cjs"),n=require("../../theme/index.cjs"),r=require("../../animation/easing.cjs"),i=require("../../animation/motion.cjs"),a=require("../../animation/tween.cjs"),o=require("./pie-renderer.cjs");var s=2*Math.PI,c=-Math.PI/2,l=Math.PI/2;function u(e){return e===`semi`?{end:l,start:c}:{end:s,start:0}}function d(s,c){let l=c.variant??`pie`,d=c.padPixels??(l===`pie`?0:8),p=c.cornerRadius??(l===`pie`?0:8),m=c.data,h=e.createSvgElement(`circle`,{class:`prism-pie-bg`,"pointer-events":`none`}),g=e.createSvgElement(`g`,{class:`prism-pie-slices`,"shape-rendering":`geometricPrecision`}),_=e.createSvgElement(`g`,{class:`prism-pie-labels`,"pointer-events":`none`}),v=[],y=null;function b(t){_.replaceChildren();for(let n=0;n<v.length;n++){let r=v[n],i=t[n];if(!i?.label)continue;let{x:a,y:s}=o.arcCentroid(r),c=e.createSvgElement(`text`,{class:`prism-pie-label`});e.setAttributes(c,{"dominant-baseline":`middle`,fill:`var(--prism-pie-label-color, #fff)`,"font-family":`var(--prism-font-family, system-ui)`,"font-size":`var(--prism-pie-label-size, 12px)`,"text-anchor":`middle`,x:a,y:s}),c.textContent=i.label,_.appendChild(c)}}let x;try{return x=t.createRadialScaffold(s,{a11y:c.a11y,legend:c.legend,tooltip:c.tooltip},t=>{let{legend:x,svg:S,tooltip:C}=t;S.contains(h)||(S.appendChild(h),S.appendChild(g),S.appendChild(_));let{height:w,width:T}=t.dimensions,E=l===`semi`,D=T/2,O=E?w*.85:w/2,k=E?Math.min(D,O)-8:Math.min(T,w)/2-8,A=l===`pie`?0:Math.round(k*.55),j=c.innerRadius===void 0?A:c.innerRadius,M=Math.max(j+1,k),N=m,{end:P,start:F}=u(l);for(v=o.computeArcs(N,D,O,M,j,F,P,d,p,e=>n.seriesColor(e),!1),e.setAttributes(h,{cx:D,cy:O,r:j>0?j:0}),h.setAttribute(`style`,`fill:var(--prism-bg,#fff)`);g.children.length>v.length;)g.removeChild(g.lastChild);_.replaceChildren();let I=i.resolveMotion(c.transition,0),L=I.duration,R=r.resolveEasing(I.easing);for(let t=0;t<v.length;t++){let n=v[t],r=g.children[t];r||(r=e.createSvgElement(`path`,{class:`prism-pie-slice`}),g.appendChild(r)),r.setAttribute(`fill`,n.color),r.setAttribute(`stroke`,`none`),r.style.cursor=c.onClick||c.onHover?`pointer`:``}if(y!==null&&(cancelAnimationFrame(y),y=null),L>0){let t=null,n=r=>{t===null&&(t=r);let i=R(Math.min(1,(r-t)/L)),s=a.tweenNumber(F,P,i);for(let t=0;t<v.length;t++){let n=v[t],r=g.children[t];if(r){if(s<=n.startAngle)e.setAttributes(r,{d:``});else{let t=Math.min(n.endAngle,s);e.setAttributes(r,{d:o.arcPath({...n,endAngle:t})})}}}i<1?y=requestAnimationFrame(n):(y=null,b(N))};y=requestAnimationFrame(n)}else{for(let t=0;t<v.length;t++){let n=v[t],r=g.children[t];r&&e.setAttributes(r,{d:o.arcPath(n)})}b(N)}return x?.update(v.map(e=>({color:e.color,name:e.slice.label??``}))),C?.hide(),{onClick:e=>{if(!c.onClick)return;let t=S.getBoundingClientRect(),n=e.clientX-t.left,r=e.clientY-t.top,i=f(v,n,r,l);i>=0&&c.onClick(v[i].slice,i)},onMouseLeave:()=>{c.onHover?.(null,null),C?.hide()},onMouseMove:e=>{let t=S.getBoundingClientRect(),n=e.clientX-t.left,r=e.clientY-t.top,i=f(v,n,r,l);if(i>=0){let e=v[i];c.onHover?.(e.slice,i);let{x:n,y:r}=o.arcCentroid(e),a=s.getBoundingClientRect();C?.show(n+(t.left-a.left),r+(t.top-a.top),{key:i,value:e.slice.value},{color:e.color,data:[],name:e.slice.label??``})}else c.onHover?.(null,null),C?.hide()}}},e=>{m=e}),{get disposalSignal(){return x.disposalSignal},dispose(){y!==null&&(cancelAnimationFrame(y),y=null),x.dispose()},get disposed(){return x.disposed},el:x.el,update(e){x.update(e)},[Symbol.dispose](){this.dispose()}}}catch(e){throw x?.dispose(),e}}function f(e,t,n,r){for(let i=0;i<e.length;i++){let a=e[i],o=t-a.centerX,c=n-a.centerY,l=Math.sqrt(o*o+c*c);if(l<a.outerRadius&&l>=a.innerRadius){let e=Math.atan2(o,-c);if(r===`semi`){if(e>=a.startAngle-1e-9&&e<=a.endAngle+1e-9)return i}else{let t=e<0?e+s:e;if(t>=a.startAngle-1e-9&&t<=a.endAngle+1e-9)return i}}}return-1}exports.createPieChart=d;
1
+ const e=require("../../svg/element.cjs"),t=require("../../core/chart-scaffold.cjs"),n=require("../../theme/index.cjs"),r=require("../../animation/easing.cjs"),i=require("../../animation/motion.cjs"),a=require("../../animation/tween.cjs"),o=require("./pie-renderer.cjs");var s=2*Math.PI,c=-Math.PI/2,l=Math.PI/2;function semiAngles(e){return e===`semi`?{end:l,start:c}:{end:s,start:0}}function createPieChart(s,c){let l=c.variant??`pie`,u=c.padPixels??(l===`pie`?0:8),d=c.cornerRadius??(l===`pie`?0:8),f=c.data,p=e.createSvgElement(`circle`,{class:`prism-pie-bg`,"pointer-events":`none`}),m=e.createSvgElement(`g`,{class:`prism-pie-slices`,"shape-rendering":`geometricPrecision`}),h=e.createSvgElement(`g`,{class:`prism-pie-labels`,"pointer-events":`none`}),g=[],_=null;function renderLabels(t){h.replaceChildren();for(let n=0;n<g.length;n++){let r=g[n],i=t[n];if(!i?.label)continue;let{x:a,y:s}=o.arcCentroid(r),c=e.createSvgElement(`text`,{class:`prism-pie-label`});e.setAttributes(c,{"dominant-baseline":`middle`,fill:`var(--prism-pie-label-color, #fff)`,"font-family":`var(--prism-font-family, system-ui)`,"font-size":`var(--prism-pie-label-size, 12px)`,"text-anchor":`middle`,x:a,y:s}),c.textContent=i.label,h.appendChild(c)}}let v;try{return v=t.createRadialScaffold(s,{a11y:c.a11y,legend:c.legend,tooltip:c.tooltip},t=>{let{legend:v,svg:y,tooltip:b}=t;y.contains(p)||(y.appendChild(p),y.appendChild(m),y.appendChild(h));let{height:x,width:S}=t.dimensions,C=l===`semi`,w=S/2,T=C?x*.85:x/2,E=C?Math.min(w,T)-8:Math.min(S,x)/2-8,D=l===`pie`?0:Math.round(E*.55),O=c.innerRadius===void 0?D:c.innerRadius,k=Math.max(O+1,E),A=f,{end:j,start:M}=semiAngles(l);for(g=o.computeArcs(A,w,T,k,O,M,j,u,d,e=>n.seriesColor(e),!1),e.setAttributes(p,{cx:w,cy:T,r:O>0?O:0}),p.setAttribute(`style`,`fill:var(--prism-bg,#fff)`);m.children.length>g.length;)m.removeChild(m.lastChild);h.replaceChildren();let N=i.resolveMotion(c.transition,0),P=N.duration,F=r.resolveEasing(N.easing);for(let t=0;t<g.length;t++){let n=g[t],r=m.children[t];r||(r=e.createSvgElement(`path`,{class:`prism-pie-slice`}),m.appendChild(r)),r.setAttribute(`fill`,n.color),r.setAttribute(`stroke`,`none`),r.style.cursor=c.onClick||c.onHover?`pointer`:``}if(_!==null&&(cancelAnimationFrame(_),_=null),P>0){let t=null,frame=n=>{t===null&&(t=n);let r=F(Math.min(1,(n-t)/P)),i=a.tweenNumber(M,j,r);for(let t=0;t<g.length;t++){let n=g[t],r=m.children[t];if(r){if(i<=n.startAngle)e.setAttributes(r,{d:``});else{let t=Math.min(n.endAngle,i);e.setAttributes(r,{d:o.arcPath({...n,endAngle:t})})}}}r<1?_=requestAnimationFrame(frame):(_=null,renderLabels(A))};_=requestAnimationFrame(frame)}else{for(let t=0;t<g.length;t++){let n=g[t],r=m.children[t];r&&e.setAttributes(r,{d:o.arcPath(n)})}renderLabels(A)}v?.update(g.map(e=>({color:e.color,name:e.slice.label??``}))),b?.hide();let onMouseMove=e=>{let t=y.getBoundingClientRect(),n=e.clientX-t.left,r=e.clientY-t.top,i=hitTestArc(g,n,r,l);if(i>=0){let e=g[i];c.onHover?.(e.slice,i);let{x:n,y:r}=o.arcCentroid(e),a=s.getBoundingClientRect();b?.show(n+(t.left-a.left),r+(t.top-a.top),{key:i,value:e.slice.value},{color:e.color,data:[],name:e.slice.label??``})}else c.onHover?.(null,null),b?.hide()},onMouseLeave=()=>{c.onHover?.(null,null),b?.hide()},onClick=e=>{if(!c.onClick)return;let t=y.getBoundingClientRect(),n=e.clientX-t.left,r=e.clientY-t.top,i=hitTestArc(g,n,r,l);i>=0&&c.onClick(g[i].slice,i)};return{onClick,onMouseLeave,onMouseMove}},e=>{f=e}),{get disposalSignal(){return v.disposalSignal},dispose(){_!==null&&(cancelAnimationFrame(_),_=null),v.dispose()},get disposed(){return v.disposed},el:v.el,update(e){v.update(e)},[Symbol.dispose](){this.dispose()}}}catch(e){throw v?.dispose(),e}}function hitTestArc(e,t,n,r){for(let i=0;i<e.length;i++){let a=e[i],o=t-a.centerX,c=n-a.centerY,l=Math.sqrt(o*o+c*c);if(l<a.outerRadius&&l>=a.innerRadius){let e=Math.atan2(o,-c);if(r===`semi`){if(e>=a.startAngle-1e-9&&e<=a.endAngle+1e-9)return i}else{let t=e<0?e+s:e;if(t>=a.startAngle-1e-9&&t<=a.endAngle+1e-9)return i}}}return-1}exports.createPieChart=createPieChart;
2
2
  //# sourceMappingURL=pie-chart.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"pie-chart.cjs","names":[],"sources":["../../../src/charts/pie/pie-chart.ts"],"sourcesContent":["import { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { tweenNumber } from '../../animation/tween';\nimport type { ChartEventHandlers } from '../../core/chart-scaffold';\nimport { createRadialScaffold } from '../../core/chart-scaffold';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport { seriesColor } from '../../theme';\nimport type { ChartHandle, PieChartConfig, PieSliceConfig } from '../../types';\nimport { type Arc, arcCentroid, arcPath, computeArcs } from './pie-renderer';\n\nconst TWO_PI = 2 * Math.PI;\n\nconst SEMI_START = -Math.PI / 2; // -90° = 9-o'clock (left)\nconst SEMI_END = Math.PI / 2; // +90° = 3-o'clock (right) → true 180° half-circle\n\nfunction semiAngles(variant: PieChartConfig['variant']): { end: number; start: number } {\n return variant === 'semi' ? { end: SEMI_END, start: SEMI_START } : { end: TWO_PI, start: 0 };\n}\n\nexport function createPieChart(container: HTMLElement, config: PieChartConfig): ChartHandle<PieSliceConfig[]> {\n const variant = config.variant ?? 'pie';\n const padPixels = config.padPixels ?? (variant === 'pie' ? 0 : 8);\n const cornerRadius = config.cornerRadius ?? (variant === 'pie' ? 0 : 8);\n let data = config.data;\n\n // Pie SVG elements live directly on the SVG (not inside chartArea groups).\n // We create them once and reuse across renders.\n const bgCircle = createSvgElement('circle', { class: 'prism-pie-bg', 'pointer-events': 'none' });\n const pieGroup = createSvgElement('g', {\n class: 'prism-pie-slices',\n 'shape-rendering': 'geometricPrecision',\n });\n const labelGroup = createSvgElement('g', { class: 'prism-pie-labels', 'pointer-events': 'none' });\n\n // Current arcs shared between renderFn and event handlers via closure.\n let currentArcs: Arc[] = [];\n let activeRaf: number | null = null;\n\n function renderLabels(slices: PieSliceConfig[]): void {\n labelGroup.replaceChildren();\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n const slice = slices[i];\n\n if (!slice?.label) continue;\n\n const { x, y } = arcCentroid(arc);\n const text = createSvgElement('text', { class: 'prism-pie-label' });\n\n setAttributes(text, {\n 'dominant-baseline': 'middle',\n fill: 'var(--prism-pie-label-color, #fff)',\n 'font-family': 'var(--prism-font-family, system-ui)',\n 'font-size': 'var(--prism-pie-label-size, 12px)',\n 'text-anchor': 'middle',\n x,\n y,\n });\n\n text.textContent = slice.label;\n labelGroup.appendChild(text);\n }\n }\n\n let handle: ChartHandle<PieSliceConfig[]> | undefined;\n\n try {\n handle = createRadialScaffold(\n container,\n {\n a11y: config.a11y,\n legend: config.legend,\n tooltip: config.tooltip,\n },\n (ctx): ChartEventHandlers => {\n const { legend, svg, tooltip } = ctx;\n\n // Append pie groups to SVG on first render (idempotent).\n if (!svg.contains(bgCircle)) {\n svg.appendChild(bgCircle);\n svg.appendChild(pieGroup);\n svg.appendChild(labelGroup);\n }\n\n const { height: h, width: w } = ctx.dimensions;\n const isSemi = variant === 'semi';\n const cx = w / 2;\n const cy = isSemi ? h * 0.85 : h / 2;\n const padding = 8;\n const outer = isSemi ? Math.min(cx, cy) - padding : Math.min(w, h) / 2 - padding;\n const defaultInner = variant === 'pie' ? 0 : Math.round(outer * 0.55);\n const inner = config.innerRadius !== undefined ? config.innerRadius : defaultInner;\n const outerR = Math.max(inner + 1, outer);\n\n const slices = data;\n const { end, start } = semiAngles(variant);\n\n currentArcs = computeArcs(\n slices,\n cx,\n cy,\n outerR,\n inner,\n start,\n end,\n padPixels,\n cornerRadius,\n (i) => seriesColor(i),\n false,\n );\n\n setAttributes(bgCircle, { cx, cy, r: inner > 0 ? inner : 0 });\n bgCircle.setAttribute('style', 'fill:var(--prism-bg,#fff)');\n\n while (pieGroup.children.length > currentArcs.length) pieGroup.removeChild(pieGroup.lastChild!);\n\n labelGroup.replaceChildren();\n\n const motion = resolveMotion(config.transition, 0);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n let path = pieGroup.children[i] as SVGPathElement | undefined;\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-pie-slice' });\n pieGroup.appendChild(path);\n }\n\n path.setAttribute('fill', arc.color);\n path.setAttribute('stroke', 'none');\n path.style.cursor = config.onClick || config.onHover ? 'pointer' : '';\n }\n\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n if (dur > 0) {\n let rafStart: number | null = null;\n\n const frame = (ts: number) => {\n if (rafStart === null) rafStart = ts;\n\n const t = easing(Math.min(1, (ts - rafStart) / dur));\n const revealAngle = tweenNumber(start, end, t);\n\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (!el) continue;\n\n if (revealAngle <= a.startAngle) {\n setAttributes(el, { d: '' });\n } else {\n const visibleEnd = Math.min(a.endAngle, revealAngle);\n\n setAttributes(el, { d: arcPath({ ...a, endAngle: visibleEnd }) });\n }\n }\n\n if (t < 1) {\n activeRaf = requestAnimationFrame(frame);\n } else {\n activeRaf = null;\n renderLabels(slices);\n }\n };\n\n activeRaf = requestAnimationFrame(frame);\n } else {\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (el) setAttributes(el, { d: arcPath(a) });\n }\n\n renderLabels(slices);\n }\n\n legend?.update(currentArcs.map((arc) => ({ color: arc.color, name: arc.slice.label ?? '' })));\n tooltip?.hide();\n\n const onMouseMove = (e: MouseEvent): void => {\n const svgRect = svg.getBoundingClientRect();\n const mx = e.clientX - svgRect.left;\n const my = e.clientY - svgRect.top;\n const hit = hitTestArc(currentArcs, mx, my, variant);\n\n if (hit >= 0) {\n const arc = currentArcs[hit];\n\n config.onHover?.(arc.slice, hit);\n\n const { x, y } = arcCentroid(arc);\n const contR = container.getBoundingClientRect();\n\n tooltip?.show(\n x + (svgRect.left - contR.left),\n y + (svgRect.top - contR.top),\n { key: hit, value: arc.slice.value },\n { color: arc.color, data: [], name: arc.slice.label ?? '' },\n );\n } else {\n config.onHover?.(null, null);\n tooltip?.hide();\n }\n };\n\n const onMouseLeave = (): void => {\n config.onHover?.(null, null);\n tooltip?.hide();\n };\n\n const onClick = (e: MouseEvent): void => {\n if (!config.onClick) return;\n\n const svgRect = svg.getBoundingClientRect();\n const mx = e.clientX - svgRect.left;\n const my = e.clientY - svgRect.top;\n const hit = hitTestArc(currentArcs, mx, my, variant);\n\n if (hit >= 0) config.onClick(currentArcs[hit].slice, hit);\n };\n\n return { onClick, onMouseLeave, onMouseMove };\n },\n (next) => {\n data = next;\n },\n );\n\n return {\n get disposalSignal(): AbortSignal {\n return handle!.disposalSignal;\n },\n\n dispose() {\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n handle!.dispose();\n },\n\n get disposed(): boolean {\n return handle!.disposed;\n },\n\n el: handle!.el,\n\n update(next) {\n handle!.update(next);\n },\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n } catch (error) {\n handle?.dispose();\n throw error;\n }\n}\n\nfunction hitTestArc(arcs: Arc[], mx: number, my: number, variant: PieChartConfig['variant']): number {\n for (let i = 0; i < arcs.length; i++) {\n const arc = arcs[i];\n const dx = mx - arc.centerX;\n const dy = my - arc.centerY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n if (dist < arc.outerRadius && dist >= arc.innerRadius) {\n const rawAngle = Math.atan2(dx, -dy);\n\n if (variant === 'semi') {\n if (rawAngle >= arc.startAngle - 1e-9 && rawAngle <= arc.endAngle + 1e-9) return i;\n } else {\n const angle = rawAngle < 0 ? rawAngle + TWO_PI : rawAngle;\n\n if (angle >= arc.startAngle - 1e-9 && angle <= arc.endAngle + 1e-9) return i;\n }\n }\n }\n\n return -1;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pie-chart.cjs","names":[],"sources":["../../../src/charts/pie/pie-chart.ts"],"sourcesContent":["import { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { tweenNumber } from '../../animation/tween';\nimport type { ChartEventHandlers } from '../../core/chart-scaffold';\nimport { createRadialScaffold } from '../../core/chart-scaffold';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport { seriesColor } from '../../theme';\nimport type { ChartHandle, PieChartConfig, PieSliceConfig } from '../../types';\nimport { type Arc, arcCentroid, arcPath, computeArcs } from './pie-renderer';\n\nconst TWO_PI = 2 * Math.PI;\n\nconst SEMI_START = -Math.PI / 2; // -90° = 9-o'clock (left)\nconst SEMI_END = Math.PI / 2; // +90° = 3-o'clock (right) → true 180° half-circle\n\nfunction semiAngles(variant: PieChartConfig['variant']): { end: number; start: number } {\n return variant === 'semi' ? { end: SEMI_END, start: SEMI_START } : { end: TWO_PI, start: 0 };\n}\n\nexport function createPieChart(container: HTMLElement, config: PieChartConfig): ChartHandle<PieSliceConfig[]> {\n const variant = config.variant ?? 'pie';\n const padPixels = config.padPixels ?? (variant === 'pie' ? 0 : 8);\n const cornerRadius = config.cornerRadius ?? (variant === 'pie' ? 0 : 8);\n let data = config.data;\n\n // Pie SVG elements live directly on the SVG (not inside chartArea groups).\n // We create them once and reuse across renders.\n const bgCircle = createSvgElement('circle', { class: 'prism-pie-bg', 'pointer-events': 'none' });\n const pieGroup = createSvgElement('g', {\n class: 'prism-pie-slices',\n 'shape-rendering': 'geometricPrecision',\n });\n const labelGroup = createSvgElement('g', { class: 'prism-pie-labels', 'pointer-events': 'none' });\n\n // Current arcs shared between renderFn and event handlers via closure.\n let currentArcs: Arc[] = [];\n let activeRaf: number | null = null;\n\n function renderLabels(slices: PieSliceConfig[]): void {\n labelGroup.replaceChildren();\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n const slice = slices[i];\n\n if (!slice?.label) continue;\n\n const { x, y } = arcCentroid(arc);\n const text = createSvgElement('text', { class: 'prism-pie-label' });\n\n setAttributes(text, {\n 'dominant-baseline': 'middle',\n fill: 'var(--prism-pie-label-color, #fff)',\n 'font-family': 'var(--prism-font-family, system-ui)',\n 'font-size': 'var(--prism-pie-label-size, 12px)',\n 'text-anchor': 'middle',\n x,\n y,\n });\n\n text.textContent = slice.label;\n labelGroup.appendChild(text);\n }\n }\n\n let handle: ChartHandle<PieSliceConfig[]> | undefined;\n\n try {\n handle = createRadialScaffold(\n container,\n {\n a11y: config.a11y,\n legend: config.legend,\n tooltip: config.tooltip,\n },\n (ctx): ChartEventHandlers => {\n const { legend, svg, tooltip } = ctx;\n\n // Append pie groups to SVG on first render (idempotent).\n if (!svg.contains(bgCircle)) {\n svg.appendChild(bgCircle);\n svg.appendChild(pieGroup);\n svg.appendChild(labelGroup);\n }\n\n const { height: h, width: w } = ctx.dimensions;\n const isSemi = variant === 'semi';\n const cx = w / 2;\n const cy = isSemi ? h * 0.85 : h / 2;\n const padding = 8;\n const outer = isSemi ? Math.min(cx, cy) - padding : Math.min(w, h) / 2 - padding;\n const defaultInner = variant === 'pie' ? 0 : Math.round(outer * 0.55);\n const inner = config.innerRadius !== undefined ? config.innerRadius : defaultInner;\n const outerR = Math.max(inner + 1, outer);\n\n const slices = data;\n const { end, start } = semiAngles(variant);\n\n currentArcs = computeArcs(\n slices,\n cx,\n cy,\n outerR,\n inner,\n start,\n end,\n padPixels,\n cornerRadius,\n (i) => seriesColor(i),\n false,\n );\n\n setAttributes(bgCircle, { cx, cy, r: inner > 0 ? inner : 0 });\n bgCircle.setAttribute('style', 'fill:var(--prism-bg,#fff)');\n\n while (pieGroup.children.length > currentArcs.length) pieGroup.removeChild(pieGroup.lastChild!);\n\n labelGroup.replaceChildren();\n\n const motion = resolveMotion(config.transition, 0);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n let path = pieGroup.children[i] as SVGPathElement | undefined;\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-pie-slice' });\n pieGroup.appendChild(path);\n }\n\n path.setAttribute('fill', arc.color);\n path.setAttribute('stroke', 'none');\n path.style.cursor = config.onClick || config.onHover ? 'pointer' : '';\n }\n\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n if (dur > 0) {\n let rafStart: number | null = null;\n\n const frame = (ts: number) => {\n if (rafStart === null) rafStart = ts;\n\n const t = easing(Math.min(1, (ts - rafStart) / dur));\n const revealAngle = tweenNumber(start, end, t);\n\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (!el) continue;\n\n if (revealAngle <= a.startAngle) {\n setAttributes(el, { d: '' });\n } else {\n const visibleEnd = Math.min(a.endAngle, revealAngle);\n\n setAttributes(el, { d: arcPath({ ...a, endAngle: visibleEnd }) });\n }\n }\n\n if (t < 1) {\n activeRaf = requestAnimationFrame(frame);\n } else {\n activeRaf = null;\n renderLabels(slices);\n }\n };\n\n activeRaf = requestAnimationFrame(frame);\n } else {\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (el) setAttributes(el, { d: arcPath(a) });\n }\n\n renderLabels(slices);\n }\n\n legend?.update(currentArcs.map((arc) => ({ color: arc.color, name: arc.slice.label ?? '' })));\n tooltip?.hide();\n\n const onMouseMove = (e: MouseEvent): void => {\n const svgRect = svg.getBoundingClientRect();\n const mx = e.clientX - svgRect.left;\n const my = e.clientY - svgRect.top;\n const hit = hitTestArc(currentArcs, mx, my, variant);\n\n if (hit >= 0) {\n const arc = currentArcs[hit];\n\n config.onHover?.(arc.slice, hit);\n\n const { x, y } = arcCentroid(arc);\n const contR = container.getBoundingClientRect();\n\n tooltip?.show(\n x + (svgRect.left - contR.left),\n y + (svgRect.top - contR.top),\n { key: hit, value: arc.slice.value },\n { color: arc.color, data: [], name: arc.slice.label ?? '' },\n );\n } else {\n config.onHover?.(null, null);\n tooltip?.hide();\n }\n };\n\n const onMouseLeave = (): void => {\n config.onHover?.(null, null);\n tooltip?.hide();\n };\n\n const onClick = (e: MouseEvent): void => {\n if (!config.onClick) return;\n\n const svgRect = svg.getBoundingClientRect();\n const mx = e.clientX - svgRect.left;\n const my = e.clientY - svgRect.top;\n const hit = hitTestArc(currentArcs, mx, my, variant);\n\n if (hit >= 0) config.onClick(currentArcs[hit].slice, hit);\n };\n\n return { onClick, onMouseLeave, onMouseMove };\n },\n (next) => {\n data = next;\n },\n );\n\n return {\n get disposalSignal(): AbortSignal {\n return handle!.disposalSignal;\n },\n\n dispose() {\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n handle!.dispose();\n },\n\n get disposed(): boolean {\n return handle!.disposed;\n },\n\n el: handle!.el,\n\n update(next) {\n handle!.update(next);\n },\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n } catch (error) {\n handle?.dispose();\n throw error;\n }\n}\n\nfunction hitTestArc(arcs: Arc[], mx: number, my: number, variant: PieChartConfig['variant']): number {\n for (let i = 0; i < arcs.length; i++) {\n const arc = arcs[i];\n const dx = mx - arc.centerX;\n const dy = my - arc.centerY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n if (dist < arc.outerRadius && dist >= arc.innerRadius) {\n const rawAngle = Math.atan2(dx, -dy);\n\n if (variant === 'semi') {\n if (rawAngle >= arc.startAngle - 1e-9 && rawAngle <= arc.endAngle + 1e-9) return i;\n } else {\n const angle = rawAngle < 0 ? rawAngle + TWO_PI : rawAngle;\n\n if (angle >= arc.startAngle - 1e-9 && angle <= arc.endAngle + 1e-9) return i;\n }\n }\n }\n\n return -1;\n}\n"],"mappings":"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"}
@@ -1,166 +1,2 @@
1
- import { createSvgElement as e, setAttributes as t } from "../../svg/element.js";
2
- import { createRadialScaffold as n } from "../../core/chart-scaffold.js";
3
- import { seriesColor as r } from "../../theme/index.js";
4
- import { resolveEasing as i } from "../../animation/easing.js";
5
- import { resolveMotion as a } from "../../animation/motion.js";
6
- import { tweenNumber as o } from "../../animation/tween.js";
7
- import { arcCentroid as s, arcPath as c, computeArcs as l } from "./pie-renderer.js";
8
- //#region src/charts/pie/pie-chart.ts
9
- var u = 2 * Math.PI, d = -Math.PI / 2, f = Math.PI / 2;
10
- function p(e) {
11
- return e === "semi" ? {
12
- end: f,
13
- start: d
14
- } : {
15
- end: u,
16
- start: 0
17
- };
18
- }
19
- function m(u, d) {
20
- let f = d.variant ?? "pie", m = d.padPixels ?? (f === "pie" ? 0 : 8), g = d.cornerRadius ?? (f === "pie" ? 0 : 8), _ = d.data, v = e("circle", {
21
- class: "prism-pie-bg",
22
- "pointer-events": "none"
23
- }), y = e("g", {
24
- class: "prism-pie-slices",
25
- "shape-rendering": "geometricPrecision"
26
- }), b = e("g", {
27
- class: "prism-pie-labels",
28
- "pointer-events": "none"
29
- }), x = [], S = null;
30
- function C(n) {
31
- b.replaceChildren();
32
- for (let r = 0; r < x.length; r++) {
33
- let i = x[r], a = n[r];
34
- if (!a?.label) continue;
35
- let { x: o, y: c } = s(i), l = e("text", { class: "prism-pie-label" });
36
- t(l, {
37
- "dominant-baseline": "middle",
38
- fill: "var(--prism-pie-label-color, #fff)",
39
- "font-family": "var(--prism-font-family, system-ui)",
40
- "font-size": "var(--prism-pie-label-size, 12px)",
41
- "text-anchor": "middle",
42
- x: o,
43
- y: c
44
- }), l.textContent = a.label, b.appendChild(l);
45
- }
46
- }
47
- let w;
48
- try {
49
- return w = n(u, {
50
- a11y: d.a11y,
51
- legend: d.legend,
52
- tooltip: d.tooltip
53
- }, (n) => {
54
- let { legend: w, svg: T, tooltip: E } = n;
55
- T.contains(v) || (T.appendChild(v), T.appendChild(y), T.appendChild(b));
56
- let { height: D, width: O } = n.dimensions, k = f === "semi", A = O / 2, j = k ? D * .85 : D / 2, M = k ? Math.min(A, j) - 8 : Math.min(O, D) / 2 - 8, N = f === "pie" ? 0 : Math.round(M * .55), P = d.innerRadius === void 0 ? N : d.innerRadius, F = Math.max(P + 1, M), I = _, { end: L, start: R } = p(f);
57
- for (x = l(I, A, j, F, P, R, L, m, g, (e) => r(e), !1), t(v, {
58
- cx: A,
59
- cy: j,
60
- r: P > 0 ? P : 0
61
- }), v.setAttribute("style", "fill:var(--prism-bg,#fff)"); y.children.length > x.length;) y.removeChild(y.lastChild);
62
- b.replaceChildren();
63
- let z = a(d.transition, 0), B = z.duration, V = i(z.easing);
64
- for (let t = 0; t < x.length; t++) {
65
- let n = x[t], r = y.children[t];
66
- r || (r = e("path", { class: "prism-pie-slice" }), y.appendChild(r)), r.setAttribute("fill", n.color), r.setAttribute("stroke", "none"), r.style.cursor = d.onClick || d.onHover ? "pointer" : "";
67
- }
68
- if (S !== null && (cancelAnimationFrame(S), S = null), B > 0) {
69
- let e = null, n = (r) => {
70
- e === null && (e = r);
71
- let i = V(Math.min(1, (r - e) / B)), a = o(R, L, i);
72
- for (let e = 0; e < x.length; e++) {
73
- let n = x[e], r = y.children[e];
74
- if (r) {
75
- if (a <= n.startAngle) t(r, { d: "" });
76
- else {
77
- let e = Math.min(n.endAngle, a);
78
- t(r, { d: c({
79
- ...n,
80
- endAngle: e
81
- }) });
82
- }
83
- }
84
- }
85
- i < 1 ? S = requestAnimationFrame(n) : (S = null, C(I));
86
- };
87
- S = requestAnimationFrame(n);
88
- } else {
89
- for (let e = 0; e < x.length; e++) {
90
- let n = x[e], r = y.children[e];
91
- r && t(r, { d: c(n) });
92
- }
93
- C(I);
94
- }
95
- return w?.update(x.map((e) => ({
96
- color: e.color,
97
- name: e.slice.label ?? ""
98
- }))), E?.hide(), {
99
- onClick: (e) => {
100
- if (!d.onClick) return;
101
- let t = T.getBoundingClientRect(), n = e.clientX - t.left, r = e.clientY - t.top, i = h(x, n, r, f);
102
- i >= 0 && d.onClick(x[i].slice, i);
103
- },
104
- onMouseLeave: () => {
105
- d.onHover?.(null, null), E?.hide();
106
- },
107
- onMouseMove: (e) => {
108
- let t = T.getBoundingClientRect(), n = e.clientX - t.left, r = e.clientY - t.top, i = h(x, n, r, f);
109
- if (i >= 0) {
110
- let e = x[i];
111
- d.onHover?.(e.slice, i);
112
- let { x: n, y: r } = s(e), a = u.getBoundingClientRect();
113
- E?.show(n + (t.left - a.left), r + (t.top - a.top), {
114
- key: i,
115
- value: e.slice.value
116
- }, {
117
- color: e.color,
118
- data: [],
119
- name: e.slice.label ?? ""
120
- });
121
- } else d.onHover?.(null, null), E?.hide();
122
- }
123
- };
124
- }, (e) => {
125
- _ = e;
126
- }), {
127
- get disposalSignal() {
128
- return w.disposalSignal;
129
- },
130
- dispose() {
131
- S !== null && (cancelAnimationFrame(S), S = null), w.dispose();
132
- },
133
- get disposed() {
134
- return w.disposed;
135
- },
136
- el: w.el,
137
- update(e) {
138
- w.update(e);
139
- },
140
- [Symbol.dispose]() {
141
- this.dispose();
142
- }
143
- };
144
- } catch (e) {
145
- throw w?.dispose(), e;
146
- }
147
- }
148
- function h(e, t, n, r) {
149
- for (let i = 0; i < e.length; i++) {
150
- let a = e[i], o = t - a.centerX, s = n - a.centerY, c = Math.sqrt(o * o + s * s);
151
- if (c < a.outerRadius && c >= a.innerRadius) {
152
- let e = Math.atan2(o, -s);
153
- if (r === "semi") {
154
- if (e >= a.startAngle - 1e-9 && e <= a.endAngle + 1e-9) return i;
155
- } else {
156
- let t = e < 0 ? e + u : e;
157
- if (t >= a.startAngle - 1e-9 && t <= a.endAngle + 1e-9) return i;
158
- }
159
- }
160
- }
161
- return -1;
162
- }
163
- //#endregion
164
- export { m as createPieChart };
165
-
1
+ import{createSvgElement as e,setAttributes as t}from"../../svg/element.js";import{createRadialScaffold as n}from"../../core/chart-scaffold.js";import{seriesColor as r}from"../../theme/index.js";import{resolveEasing as i}from"../../animation/easing.js";import{resolveMotion as a}from"../../animation/motion.js";import{tweenNumber as o}from"../../animation/tween.js";import{arcCentroid as s,arcPath as c,computeArcs as l}from"./pie-renderer.js";var u=2*Math.PI,d=-Math.PI/2,f=Math.PI/2;function semiAngles(e){return e===`semi`?{end:f,start:d}:{end:u,start:0}}function createPieChart(u,d){let f=d.variant??`pie`,p=d.padPixels??(f===`pie`?0:8),m=d.cornerRadius??(f===`pie`?0:8),h=d.data,g=e(`circle`,{class:`prism-pie-bg`,"pointer-events":`none`}),_=e(`g`,{class:`prism-pie-slices`,"shape-rendering":`geometricPrecision`}),v=e(`g`,{class:`prism-pie-labels`,"pointer-events":`none`}),y=[],b=null;function renderLabels(n){v.replaceChildren();for(let r=0;r<y.length;r++){let i=y[r],a=n[r];if(!a?.label)continue;let{x:o,y:c}=s(i),l=e(`text`,{class:`prism-pie-label`});t(l,{"dominant-baseline":`middle`,fill:`var(--prism-pie-label-color, #fff)`,"font-family":`var(--prism-font-family, system-ui)`,"font-size":`var(--prism-pie-label-size, 12px)`,"text-anchor":`middle`,x:o,y:c}),l.textContent=a.label,v.appendChild(l)}}let x;try{return x=n(u,{a11y:d.a11y,legend:d.legend,tooltip:d.tooltip},n=>{let{legend:x,svg:S,tooltip:C}=n;S.contains(g)||(S.appendChild(g),S.appendChild(_),S.appendChild(v));let{height:w,width:T}=n.dimensions,E=f===`semi`,D=T/2,O=E?w*.85:w/2,k=E?Math.min(D,O)-8:Math.min(T,w)/2-8,A=f===`pie`?0:Math.round(k*.55),j=d.innerRadius===void 0?A:d.innerRadius,M=Math.max(j+1,k),N=h,{end:P,start:F}=semiAngles(f);for(y=l(N,D,O,M,j,F,P,p,m,e=>r(e),!1),t(g,{cx:D,cy:O,r:j>0?j:0}),g.setAttribute(`style`,`fill:var(--prism-bg,#fff)`);_.children.length>y.length;)_.removeChild(_.lastChild);v.replaceChildren();let I=a(d.transition,0),L=I.duration,R=i(I.easing);for(let t=0;t<y.length;t++){let n=y[t],r=_.children[t];r||(r=e(`path`,{class:`prism-pie-slice`}),_.appendChild(r)),r.setAttribute(`fill`,n.color),r.setAttribute(`stroke`,`none`),r.style.cursor=d.onClick||d.onHover?`pointer`:``}if(b!==null&&(cancelAnimationFrame(b),b=null),L>0){let e=null,frame=n=>{e===null&&(e=n);let r=R(Math.min(1,(n-e)/L)),i=o(F,P,r);for(let e=0;e<y.length;e++){let n=y[e],r=_.children[e];if(r){if(i<=n.startAngle)t(r,{d:``});else{let e=Math.min(n.endAngle,i);t(r,{d:c({...n,endAngle:e})})}}}r<1?b=requestAnimationFrame(frame):(b=null,renderLabels(N))};b=requestAnimationFrame(frame)}else{for(let e=0;e<y.length;e++){let n=y[e],r=_.children[e];r&&t(r,{d:c(n)})}renderLabels(N)}x?.update(y.map(e=>({color:e.color,name:e.slice.label??``}))),C?.hide();let onMouseMove=e=>{let t=S.getBoundingClientRect(),n=e.clientX-t.left,r=e.clientY-t.top,i=hitTestArc(y,n,r,f);if(i>=0){let e=y[i];d.onHover?.(e.slice,i);let{x:n,y:r}=s(e),a=u.getBoundingClientRect();C?.show(n+(t.left-a.left),r+(t.top-a.top),{key:i,value:e.slice.value},{color:e.color,data:[],name:e.slice.label??``})}else d.onHover?.(null,null),C?.hide()},onMouseLeave=()=>{d.onHover?.(null,null),C?.hide()},onClick=e=>{if(!d.onClick)return;let t=S.getBoundingClientRect(),n=e.clientX-t.left,r=e.clientY-t.top,i=hitTestArc(y,n,r,f);i>=0&&d.onClick(y[i].slice,i)};return{onClick,onMouseLeave,onMouseMove}},e=>{h=e}),{get disposalSignal(){return x.disposalSignal},dispose(){b!==null&&(cancelAnimationFrame(b),b=null),x.dispose()},get disposed(){return x.disposed},el:x.el,update(e){x.update(e)},[Symbol.dispose](){this.dispose()}}}catch(e){throw x?.dispose(),e}}function hitTestArc(e,t,n,r){for(let i=0;i<e.length;i++){let a=e[i],o=t-a.centerX,s=n-a.centerY,c=Math.sqrt(o*o+s*s);if(c<a.outerRadius&&c>=a.innerRadius){let e=Math.atan2(o,-s);if(r===`semi`){if(e>=a.startAngle-1e-9&&e<=a.endAngle+1e-9)return i}else{let t=e<0?e+u:e;if(t>=a.startAngle-1e-9&&t<=a.endAngle+1e-9)return i}}}return-1}export{createPieChart};
166
2
  //# sourceMappingURL=pie-chart.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pie-chart.js","names":[],"sources":["../../../src/charts/pie/pie-chart.ts"],"sourcesContent":["import { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { tweenNumber } from '../../animation/tween';\nimport type { ChartEventHandlers } from '../../core/chart-scaffold';\nimport { createRadialScaffold } from '../../core/chart-scaffold';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport { seriesColor } from '../../theme';\nimport type { ChartHandle, PieChartConfig, PieSliceConfig } from '../../types';\nimport { type Arc, arcCentroid, arcPath, computeArcs } from './pie-renderer';\n\nconst TWO_PI = 2 * Math.PI;\n\nconst SEMI_START = -Math.PI / 2; // -90° = 9-o'clock (left)\nconst SEMI_END = Math.PI / 2; // +90° = 3-o'clock (right) → true 180° half-circle\n\nfunction semiAngles(variant: PieChartConfig['variant']): { end: number; start: number } {\n return variant === 'semi' ? { end: SEMI_END, start: SEMI_START } : { end: TWO_PI, start: 0 };\n}\n\nexport function createPieChart(container: HTMLElement, config: PieChartConfig): ChartHandle<PieSliceConfig[]> {\n const variant = config.variant ?? 'pie';\n const padPixels = config.padPixels ?? (variant === 'pie' ? 0 : 8);\n const cornerRadius = config.cornerRadius ?? (variant === 'pie' ? 0 : 8);\n let data = config.data;\n\n // Pie SVG elements live directly on the SVG (not inside chartArea groups).\n // We create them once and reuse across renders.\n const bgCircle = createSvgElement('circle', { class: 'prism-pie-bg', 'pointer-events': 'none' });\n const pieGroup = createSvgElement('g', {\n class: 'prism-pie-slices',\n 'shape-rendering': 'geometricPrecision',\n });\n const labelGroup = createSvgElement('g', { class: 'prism-pie-labels', 'pointer-events': 'none' });\n\n // Current arcs shared between renderFn and event handlers via closure.\n let currentArcs: Arc[] = [];\n let activeRaf: number | null = null;\n\n function renderLabels(slices: PieSliceConfig[]): void {\n labelGroup.replaceChildren();\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n const slice = slices[i];\n\n if (!slice?.label) continue;\n\n const { x, y } = arcCentroid(arc);\n const text = createSvgElement('text', { class: 'prism-pie-label' });\n\n setAttributes(text, {\n 'dominant-baseline': 'middle',\n fill: 'var(--prism-pie-label-color, #fff)',\n 'font-family': 'var(--prism-font-family, system-ui)',\n 'font-size': 'var(--prism-pie-label-size, 12px)',\n 'text-anchor': 'middle',\n x,\n y,\n });\n\n text.textContent = slice.label;\n labelGroup.appendChild(text);\n }\n }\n\n let handle: ChartHandle<PieSliceConfig[]> | undefined;\n\n try {\n handle = createRadialScaffold(\n container,\n {\n a11y: config.a11y,\n legend: config.legend,\n tooltip: config.tooltip,\n },\n (ctx): ChartEventHandlers => {\n const { legend, svg, tooltip } = ctx;\n\n // Append pie groups to SVG on first render (idempotent).\n if (!svg.contains(bgCircle)) {\n svg.appendChild(bgCircle);\n svg.appendChild(pieGroup);\n svg.appendChild(labelGroup);\n }\n\n const { height: h, width: w } = ctx.dimensions;\n const isSemi = variant === 'semi';\n const cx = w / 2;\n const cy = isSemi ? h * 0.85 : h / 2;\n const padding = 8;\n const outer = isSemi ? Math.min(cx, cy) - padding : Math.min(w, h) / 2 - padding;\n const defaultInner = variant === 'pie' ? 0 : Math.round(outer * 0.55);\n const inner = config.innerRadius !== undefined ? config.innerRadius : defaultInner;\n const outerR = Math.max(inner + 1, outer);\n\n const slices = data;\n const { end, start } = semiAngles(variant);\n\n currentArcs = computeArcs(\n slices,\n cx,\n cy,\n outerR,\n inner,\n start,\n end,\n padPixels,\n cornerRadius,\n (i) => seriesColor(i),\n false,\n );\n\n setAttributes(bgCircle, { cx, cy, r: inner > 0 ? inner : 0 });\n bgCircle.setAttribute('style', 'fill:var(--prism-bg,#fff)');\n\n while (pieGroup.children.length > currentArcs.length) pieGroup.removeChild(pieGroup.lastChild!);\n\n labelGroup.replaceChildren();\n\n const motion = resolveMotion(config.transition, 0);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n let path = pieGroup.children[i] as SVGPathElement | undefined;\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-pie-slice' });\n pieGroup.appendChild(path);\n }\n\n path.setAttribute('fill', arc.color);\n path.setAttribute('stroke', 'none');\n path.style.cursor = config.onClick || config.onHover ? 'pointer' : '';\n }\n\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n if (dur > 0) {\n let rafStart: number | null = null;\n\n const frame = (ts: number) => {\n if (rafStart === null) rafStart = ts;\n\n const t = easing(Math.min(1, (ts - rafStart) / dur));\n const revealAngle = tweenNumber(start, end, t);\n\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (!el) continue;\n\n if (revealAngle <= a.startAngle) {\n setAttributes(el, { d: '' });\n } else {\n const visibleEnd = Math.min(a.endAngle, revealAngle);\n\n setAttributes(el, { d: arcPath({ ...a, endAngle: visibleEnd }) });\n }\n }\n\n if (t < 1) {\n activeRaf = requestAnimationFrame(frame);\n } else {\n activeRaf = null;\n renderLabels(slices);\n }\n };\n\n activeRaf = requestAnimationFrame(frame);\n } else {\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (el) setAttributes(el, { d: arcPath(a) });\n }\n\n renderLabels(slices);\n }\n\n legend?.update(currentArcs.map((arc) => ({ color: arc.color, name: arc.slice.label ?? '' })));\n tooltip?.hide();\n\n const onMouseMove = (e: MouseEvent): void => {\n const svgRect = svg.getBoundingClientRect();\n const mx = e.clientX - svgRect.left;\n const my = e.clientY - svgRect.top;\n const hit = hitTestArc(currentArcs, mx, my, variant);\n\n if (hit >= 0) {\n const arc = currentArcs[hit];\n\n config.onHover?.(arc.slice, hit);\n\n const { x, y } = arcCentroid(arc);\n const contR = container.getBoundingClientRect();\n\n tooltip?.show(\n x + (svgRect.left - contR.left),\n y + (svgRect.top - contR.top),\n { key: hit, value: arc.slice.value },\n { color: arc.color, data: [], name: arc.slice.label ?? '' },\n );\n } else {\n config.onHover?.(null, null);\n tooltip?.hide();\n }\n };\n\n const onMouseLeave = (): void => {\n config.onHover?.(null, null);\n tooltip?.hide();\n };\n\n const onClick = (e: MouseEvent): void => {\n if (!config.onClick) return;\n\n const svgRect = svg.getBoundingClientRect();\n const mx = e.clientX - svgRect.left;\n const my = e.clientY - svgRect.top;\n const hit = hitTestArc(currentArcs, mx, my, variant);\n\n if (hit >= 0) config.onClick(currentArcs[hit].slice, hit);\n };\n\n return { onClick, onMouseLeave, onMouseMove };\n },\n (next) => {\n data = next;\n },\n );\n\n return {\n get disposalSignal(): AbortSignal {\n return handle!.disposalSignal;\n },\n\n dispose() {\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n handle!.dispose();\n },\n\n get disposed(): boolean {\n return handle!.disposed;\n },\n\n el: handle!.el,\n\n update(next) {\n handle!.update(next);\n },\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n } catch (error) {\n handle?.dispose();\n throw error;\n }\n}\n\nfunction hitTestArc(arcs: Arc[], mx: number, my: number, variant: PieChartConfig['variant']): number {\n for (let i = 0; i < arcs.length; i++) {\n const arc = arcs[i];\n const dx = mx - arc.centerX;\n const dy = my - arc.centerY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n if (dist < arc.outerRadius && dist >= arc.innerRadius) {\n const rawAngle = Math.atan2(dx, -dy);\n\n if (variant === 'semi') {\n if (rawAngle >= arc.startAngle - 1e-9 && rawAngle <= arc.endAngle + 1e-9) return i;\n } else {\n const angle = rawAngle < 0 ? rawAngle + TWO_PI : rawAngle;\n\n if (angle >= arc.startAngle - 1e-9 && angle <= arc.endAngle + 1e-9) return i;\n }\n }\n }\n\n return -1;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pie-chart.js","names":[],"sources":["../../../src/charts/pie/pie-chart.ts"],"sourcesContent":["import { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { tweenNumber } from '../../animation/tween';\nimport type { ChartEventHandlers } from '../../core/chart-scaffold';\nimport { createRadialScaffold } from '../../core/chart-scaffold';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport { seriesColor } from '../../theme';\nimport type { ChartHandle, PieChartConfig, PieSliceConfig } from '../../types';\nimport { type Arc, arcCentroid, arcPath, computeArcs } from './pie-renderer';\n\nconst TWO_PI = 2 * Math.PI;\n\nconst SEMI_START = -Math.PI / 2; // -90° = 9-o'clock (left)\nconst SEMI_END = Math.PI / 2; // +90° = 3-o'clock (right) → true 180° half-circle\n\nfunction semiAngles(variant: PieChartConfig['variant']): { end: number; start: number } {\n return variant === 'semi' ? { end: SEMI_END, start: SEMI_START } : { end: TWO_PI, start: 0 };\n}\n\nexport function createPieChart(container: HTMLElement, config: PieChartConfig): ChartHandle<PieSliceConfig[]> {\n const variant = config.variant ?? 'pie';\n const padPixels = config.padPixels ?? (variant === 'pie' ? 0 : 8);\n const cornerRadius = config.cornerRadius ?? (variant === 'pie' ? 0 : 8);\n let data = config.data;\n\n // Pie SVG elements live directly on the SVG (not inside chartArea groups).\n // We create them once and reuse across renders.\n const bgCircle = createSvgElement('circle', { class: 'prism-pie-bg', 'pointer-events': 'none' });\n const pieGroup = createSvgElement('g', {\n class: 'prism-pie-slices',\n 'shape-rendering': 'geometricPrecision',\n });\n const labelGroup = createSvgElement('g', { class: 'prism-pie-labels', 'pointer-events': 'none' });\n\n // Current arcs shared between renderFn and event handlers via closure.\n let currentArcs: Arc[] = [];\n let activeRaf: number | null = null;\n\n function renderLabels(slices: PieSliceConfig[]): void {\n labelGroup.replaceChildren();\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n const slice = slices[i];\n\n if (!slice?.label) continue;\n\n const { x, y } = arcCentroid(arc);\n const text = createSvgElement('text', { class: 'prism-pie-label' });\n\n setAttributes(text, {\n 'dominant-baseline': 'middle',\n fill: 'var(--prism-pie-label-color, #fff)',\n 'font-family': 'var(--prism-font-family, system-ui)',\n 'font-size': 'var(--prism-pie-label-size, 12px)',\n 'text-anchor': 'middle',\n x,\n y,\n });\n\n text.textContent = slice.label;\n labelGroup.appendChild(text);\n }\n }\n\n let handle: ChartHandle<PieSliceConfig[]> | undefined;\n\n try {\n handle = createRadialScaffold(\n container,\n {\n a11y: config.a11y,\n legend: config.legend,\n tooltip: config.tooltip,\n },\n (ctx): ChartEventHandlers => {\n const { legend, svg, tooltip } = ctx;\n\n // Append pie groups to SVG on first render (idempotent).\n if (!svg.contains(bgCircle)) {\n svg.appendChild(bgCircle);\n svg.appendChild(pieGroup);\n svg.appendChild(labelGroup);\n }\n\n const { height: h, width: w } = ctx.dimensions;\n const isSemi = variant === 'semi';\n const cx = w / 2;\n const cy = isSemi ? h * 0.85 : h / 2;\n const padding = 8;\n const outer = isSemi ? Math.min(cx, cy) - padding : Math.min(w, h) / 2 - padding;\n const defaultInner = variant === 'pie' ? 0 : Math.round(outer * 0.55);\n const inner = config.innerRadius !== undefined ? config.innerRadius : defaultInner;\n const outerR = Math.max(inner + 1, outer);\n\n const slices = data;\n const { end, start } = semiAngles(variant);\n\n currentArcs = computeArcs(\n slices,\n cx,\n cy,\n outerR,\n inner,\n start,\n end,\n padPixels,\n cornerRadius,\n (i) => seriesColor(i),\n false,\n );\n\n setAttributes(bgCircle, { cx, cy, r: inner > 0 ? inner : 0 });\n bgCircle.setAttribute('style', 'fill:var(--prism-bg,#fff)');\n\n while (pieGroup.children.length > currentArcs.length) pieGroup.removeChild(pieGroup.lastChild!);\n\n labelGroup.replaceChildren();\n\n const motion = resolveMotion(config.transition, 0);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n let path = pieGroup.children[i] as SVGPathElement | undefined;\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-pie-slice' });\n pieGroup.appendChild(path);\n }\n\n path.setAttribute('fill', arc.color);\n path.setAttribute('stroke', 'none');\n path.style.cursor = config.onClick || config.onHover ? 'pointer' : '';\n }\n\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n if (dur > 0) {\n let rafStart: number | null = null;\n\n const frame = (ts: number) => {\n if (rafStart === null) rafStart = ts;\n\n const t = easing(Math.min(1, (ts - rafStart) / dur));\n const revealAngle = tweenNumber(start, end, t);\n\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (!el) continue;\n\n if (revealAngle <= a.startAngle) {\n setAttributes(el, { d: '' });\n } else {\n const visibleEnd = Math.min(a.endAngle, revealAngle);\n\n setAttributes(el, { d: arcPath({ ...a, endAngle: visibleEnd }) });\n }\n }\n\n if (t < 1) {\n activeRaf = requestAnimationFrame(frame);\n } else {\n activeRaf = null;\n renderLabels(slices);\n }\n };\n\n activeRaf = requestAnimationFrame(frame);\n } else {\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (el) setAttributes(el, { d: arcPath(a) });\n }\n\n renderLabels(slices);\n }\n\n legend?.update(currentArcs.map((arc) => ({ color: arc.color, name: arc.slice.label ?? '' })));\n tooltip?.hide();\n\n const onMouseMove = (e: MouseEvent): void => {\n const svgRect = svg.getBoundingClientRect();\n const mx = e.clientX - svgRect.left;\n const my = e.clientY - svgRect.top;\n const hit = hitTestArc(currentArcs, mx, my, variant);\n\n if (hit >= 0) {\n const arc = currentArcs[hit];\n\n config.onHover?.(arc.slice, hit);\n\n const { x, y } = arcCentroid(arc);\n const contR = container.getBoundingClientRect();\n\n tooltip?.show(\n x + (svgRect.left - contR.left),\n y + (svgRect.top - contR.top),\n { key: hit, value: arc.slice.value },\n { color: arc.color, data: [], name: arc.slice.label ?? '' },\n );\n } else {\n config.onHover?.(null, null);\n tooltip?.hide();\n }\n };\n\n const onMouseLeave = (): void => {\n config.onHover?.(null, null);\n tooltip?.hide();\n };\n\n const onClick = (e: MouseEvent): void => {\n if (!config.onClick) return;\n\n const svgRect = svg.getBoundingClientRect();\n const mx = e.clientX - svgRect.left;\n const my = e.clientY - svgRect.top;\n const hit = hitTestArc(currentArcs, mx, my, variant);\n\n if (hit >= 0) config.onClick(currentArcs[hit].slice, hit);\n };\n\n return { onClick, onMouseLeave, onMouseMove };\n },\n (next) => {\n data = next;\n },\n );\n\n return {\n get disposalSignal(): AbortSignal {\n return handle!.disposalSignal;\n },\n\n dispose() {\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n handle!.dispose();\n },\n\n get disposed(): boolean {\n return handle!.disposed;\n },\n\n el: handle!.el,\n\n update(next) {\n handle!.update(next);\n },\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n } catch (error) {\n handle?.dispose();\n throw error;\n }\n}\n\nfunction hitTestArc(arcs: Arc[], mx: number, my: number, variant: PieChartConfig['variant']): number {\n for (let i = 0; i < arcs.length; i++) {\n const arc = arcs[i];\n const dx = mx - arc.centerX;\n const dy = my - arc.centerY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n if (dist < arc.outerRadius && dist >= arc.innerRadius) {\n const rawAngle = Math.atan2(dx, -dy);\n\n if (variant === 'semi') {\n if (rawAngle >= arc.startAngle - 1e-9 && rawAngle <= arc.endAngle + 1e-9) return i;\n } else {\n const angle = rawAngle < 0 ? rawAngle + TWO_PI : rawAngle;\n\n if (angle >= arc.startAngle - 1e-9 && angle <= arc.endAngle + 1e-9) return i;\n }\n }\n }\n\n return -1;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- function e(e,t,n,r,i,a,o,s,c,l,u=!1){let d=e.reduce((e,t)=>e+Math.max(0,t.value),0);if(d===0)return[];let f=o-a,p=r>0?Math.asin(Math.min(1,s/2/r)):0,m=a,h=e.length;return e.map((e,a)=>{let o=Math.max(0,e.value)/d*f,s=m,g=m+o;m+=o;let _=Math.min(p,o/2);return{capEnd:u&&a===h-1,capStart:u&&a===0,centerX:t,centerY:n,color:e.color??l(a),cornerRadius:c,endAngle:g,index:a,innerRadius:i,outerRadius:r,padAngle:_,slice:e,startAngle:s}})}function t(e,t,n,r){return`${e+n*Math.sin(r)},${t-n*Math.cos(r)}`}function n(e,t,n){return e+t*Math.sin(n)}function r(e,t,n){return e-t*Math.cos(n)}function i(e){let{capEnd:i,capStart:a,centerX:o,centerY:s,cornerRadius:c,endAngle:l,innerRadius:u,outerRadius:d,padAngle:f,startAngle:p}=e,m=l-p;if(m<=0)return``;if(m>=2*Math.PI-1e-6){let e=p+Math.PI;return u<=0?`M${t(o,s,d,p)}A${d},${d},0,1,1,${t(o,s,d,e)}A${d},${d},0,1,1,${t(o,s,d,p)}Z`:[`M${t(o,s,d,p)}`,`A${d},${d},0,1,1,${t(o,s,d,e)}`,`A${d},${d},0,1,1,${t(o,s,d,p)}`,`M${t(o,s,u,p)}`,`A${u},${u},0,1,0,${t(o,s,u,e)}`,`A${u},${u},0,1,0,${t(o,s,u,p)}`,`Z`].join(``)}let h=a?p:p+f,g=i?l:l-f;if(g<=h)return``;let _=g-h;if(c<=0){let e=+(_>Math.PI);return u<=0?`M${o},${s}L${t(o,s,d,h)}A${d},${d},0,${e},1,${t(o,s,d,g)}Z`:[`M${t(o,s,d,h)}`,`A${d},${d},0,${e},1,${t(o,s,d,g)}`,`L${t(o,s,u,g)}`,`A${u},${u},0,${e},0,${t(o,s,u,h)}`,`Z`].join(``)}let v=Math.min(c/d,_/2),y=Math.min(c/u,_/2),b=Math.min(c,(d-u)/2),x=(d-u)/2,S=h+(a?0:v),C=g-(i?0:v),w=h+(a?0:y),T=g-(i?0:y),E=+(C-S>Math.PI),D=+(T-w>Math.PI),O=n(o,d,h),k=r(s,d,h),A=n(o,d,g),j=r(s,d,g),M=n(o,u,h),N=r(s,u,h),P=n(o,u,g),F=r(s,u,g),I=b/(d-u),L=`${O+(M-O)*I},${k+(N-k)*I}`,R=`${A+(P-A)*I},${j+(F-j)*I}`,z=`${M+(O-M)*I},${N+(k-N)*I}`,B=`${P+(A-P)*I},${F+(j-F)*I}`,V=[];return a?V.push(`M${t(o,s,d,h)}`):(V.push(`M${L}`),V.push(`Q${O},${k},${t(o,s,d,S)}`)),V.push(`A${d},${d},0,${E},1,${t(o,s,d,C)}`),i?V.push(`A${x},${x},0,0,1,${t(o,s,u,g)}`):(V.push(`Q${A},${j},${R}`),V.push(`L${B}`),V.push(`Q${P},${F},${t(o,s,u,T)}`)),V.push(`A${u},${u},0,${D},0,${t(o,s,u,w)}`),a?V.push(`A${x},${x},0,0,0,${t(o,s,d,h)}`):V.push(`Q${M},${N},${z}`),V.push(`Z`),V.join(``)}function a(e){let t=(e.startAngle+e.endAngle)/2,n=(e.outerRadius+e.innerRadius)/2;return{x:e.centerX+n*Math.sin(t),y:e.centerY-n*Math.cos(t)}}exports.arcCentroid=a,exports.arcPath=i,exports.computeArcs=e;
1
+ function computeArcs(e,t,n,r,i,a,o,s,c,l,u=!1){let d=e.reduce((e,t)=>e+Math.max(0,t.value),0);if(d===0)return[];let f=o-a,m=r>0?Math.asin(Math.min(1,s/2/r)):0,h=a,g=e.length;return e.map((e,a)=>{let o=Math.max(0,e.value)/d*f,s=h,_=h+o;h+=o;let v=Math.min(m,o/2);return{capEnd:u&&a===g-1,capStart:u&&a===0,centerX:t,centerY:n,color:e.color??l(a),cornerRadius:c,endAngle:_,index:a,innerRadius:i,outerRadius:r,padAngle:v,slice:e,startAngle:s}})}function p(e,t,n,r){return`${e+n*Math.sin(r)},${t-n*Math.cos(r)}`}function px(e,t,n){return e+t*Math.sin(n)}function py(e,t,n){return e-t*Math.cos(n)}function arcPath(e){let{capEnd:t,capStart:n,centerX:r,centerY:i,cornerRadius:a,endAngle:o,innerRadius:s,outerRadius:c,padAngle:l,startAngle:u}=e,d=o-u;if(d<=0)return``;if(d>=2*Math.PI-1e-6){let e=u+Math.PI;return s<=0?`M${p(r,i,c,u)}A${c},${c},0,1,1,${p(r,i,c,e)}A${c},${c},0,1,1,${p(r,i,c,u)}Z`:[`M${p(r,i,c,u)}`,`A${c},${c},0,1,1,${p(r,i,c,e)}`,`A${c},${c},0,1,1,${p(r,i,c,u)}`,`M${p(r,i,s,u)}`,`A${s},${s},0,1,0,${p(r,i,s,e)}`,`A${s},${s},0,1,0,${p(r,i,s,u)}`,`Z`].join(``)}let f=n?u:u+l,m=t?o:o-l;if(m<=f)return``;let h=m-f;if(a<=0){let e=+(h>Math.PI);return s<=0?`M${r},${i}L${p(r,i,c,f)}A${c},${c},0,${e},1,${p(r,i,c,m)}Z`:[`M${p(r,i,c,f)}`,`A${c},${c},0,${e},1,${p(r,i,c,m)}`,`L${p(r,i,s,m)}`,`A${s},${s},0,${e},0,${p(r,i,s,f)}`,`Z`].join(``)}let g=Math.min(a/c,h/2),_=Math.min(a/s,h/2),v=Math.min(a,(c-s)/2),y=(c-s)/2,b=f+(n?0:g),x=m-(t?0:g),S=f+(n?0:_),C=m-(t?0:_),w=+(x-b>Math.PI),T=+(C-S>Math.PI),E=px(r,c,f),D=py(i,c,f),O=px(r,c,m),k=py(i,c,m),A=px(r,s,f),j=py(i,s,f),M=px(r,s,m),N=py(i,s,m),P=v/(c-s),F=`${E+(A-E)*P},${D+(j-D)*P}`,I=`${O+(M-O)*P},${k+(N-k)*P}`,L=`${A+(E-A)*P},${j+(D-j)*P}`,R=`${M+(O-M)*P},${N+(k-N)*P}`,z=[];return n?z.push(`M${p(r,i,c,f)}`):(z.push(`M${F}`),z.push(`Q${E},${D},${p(r,i,c,b)}`)),z.push(`A${c},${c},0,${w},1,${p(r,i,c,x)}`),t?z.push(`A${y},${y},0,0,1,${p(r,i,s,m)}`):(z.push(`Q${O},${k},${I}`),z.push(`L${R}`),z.push(`Q${M},${N},${p(r,i,s,C)}`)),z.push(`A${s},${s},0,${T},0,${p(r,i,s,S)}`),n?z.push(`A${y},${y},0,0,0,${p(r,i,c,f)}`):z.push(`Q${A},${j},${L}`),z.push(`Z`),z.join(``)}function arcCentroid(e){let t=(e.startAngle+e.endAngle)/2,n=(e.outerRadius+e.innerRadius)/2;return{x:e.centerX+n*Math.sin(t),y:e.centerY-n*Math.cos(t)}}exports.arcCentroid=arcCentroid,exports.arcPath=arcPath,exports.computeArcs=computeArcs;
2
2
  //# sourceMappingURL=pie-renderer.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"pie-renderer.cjs","names":[],"sources":["../../../src/charts/pie/pie-renderer.ts"],"sourcesContent":["import type { PieSliceConfig } from '../../types';\n\nexport interface Arc {\n capEnd: boolean;\n capStart: boolean;\n centerX: number;\n centerY: number;\n color: string;\n cornerRadius: number;\n endAngle: number;\n index: number;\n innerRadius: number;\n outerRadius: number;\n padAngle: number;\n slice: PieSliceConfig;\n startAngle: number;\n}\n\nexport function computeArcs(\n slices: PieSliceConfig[],\n cx: number,\n cy: number,\n outerRadius: number,\n innerRadius: number,\n startAngle: number,\n endAngle: number,\n padPixels: number,\n cornerRadius: number,\n defaultColors: (i: number) => string,\n capEnds = false,\n): Arc[] {\n const total = slices.reduce((s, d) => s + Math.max(0, d.value), 0);\n\n if (total === 0) return [];\n\n const range = endAngle - startAngle;\n const halfGapAngle = outerRadius > 0 ? Math.asin(Math.min(1, padPixels / 2 / outerRadius)) : 0;\n\n let currentAngle = startAngle;\n const n = slices.length;\n\n return slices.map((slice, i) => {\n const fraction = Math.max(0, slice.value) / total;\n const sliceRange = fraction * range;\n const rawStart = currentAngle;\n const rawEnd = currentAngle + sliceRange;\n\n currentAngle += sliceRange;\n\n const padAngle = Math.min(halfGapAngle, sliceRange / 2);\n\n return {\n capEnd: capEnds && i === n - 1,\n capStart: capEnds && i === 0,\n centerX: cx,\n centerY: cy,\n color: slice.color ?? defaultColors(i),\n cornerRadius,\n endAngle: rawEnd,\n index: i,\n innerRadius,\n outerRadius,\n padAngle,\n slice,\n startAngle: rawStart,\n };\n });\n}\n\n// Polar to cartesian, returns x,y string for SVG path\nfunction p(cx: number, cy: number, r: number, a: number): string {\n return `${cx + r * Math.sin(a)},${cy - r * Math.cos(a)}`;\n}\n\n// Cartesian x component\nfunction px(cx: number, r: number, a: number): number {\n return cx + r * Math.sin(a);\n}\n\n// Cartesian y component\nfunction py(cy: number, r: number, a: number): number {\n return cy - r * Math.cos(a);\n}\n\nexport function arcPath(arc: Arc): string {\n const {\n capEnd,\n capStart,\n centerX: cx,\n centerY: cy,\n cornerRadius: cr,\n endAngle,\n innerRadius,\n outerRadius,\n padAngle,\n startAngle,\n } = arc;\n\n const sweep = endAngle - startAngle;\n\n if (sweep <= 0) return '';\n\n // ── Full circle ─────────────────────────────────────────────────────────────\n if (sweep >= 2 * Math.PI - 1e-6) {\n const mid = startAngle + Math.PI;\n\n if (innerRadius <= 0) {\n return `M${p(cx, cy, outerRadius, startAngle)}A${outerRadius},${outerRadius},0,1,1,${p(cx, cy, outerRadius, mid)}A${outerRadius},${outerRadius},0,1,1,${p(cx, cy, outerRadius, startAngle)}Z`;\n }\n\n return [\n `M${p(cx, cy, outerRadius, startAngle)}`,\n `A${outerRadius},${outerRadius},0,1,1,${p(cx, cy, outerRadius, mid)}`,\n `A${outerRadius},${outerRadius},0,1,1,${p(cx, cy, outerRadius, startAngle)}`,\n `M${p(cx, cy, innerRadius, startAngle)}`,\n `A${innerRadius},${innerRadius},0,1,0,${p(cx, cy, innerRadius, mid)}`,\n `A${innerRadius},${innerRadius},0,1,0,${p(cx, cy, innerRadius, startAngle)}`,\n 'Z',\n ].join('');\n }\n\n // Cap ends don't get a padAngle inset (no adjacent slice on that side)\n const sa = capStart ? startAngle : startAngle + padAngle;\n const ea = capEnd ? endAngle : endAngle - padAngle;\n\n if (ea <= sa) return '';\n\n const paddedSweep = ea - sa;\n\n // ── No rounding ─────────────────────────────────────────────────────────────\n if (cr <= 0) {\n const large = paddedSweep > Math.PI ? 1 : 0;\n\n if (innerRadius <= 0) {\n return `M${cx},${cy}L${p(cx, cy, outerRadius, sa)}A${outerRadius},${outerRadius},0,${large},1,${p(cx, cy, outerRadius, ea)}Z`;\n }\n\n return [\n `M${p(cx, cy, outerRadius, sa)}`,\n `A${outerRadius},${outerRadius},0,${large},1,${p(cx, cy, outerRadius, ea)}`,\n `L${p(cx, cy, innerRadius, ea)}`,\n `A${innerRadius},${innerRadius},0,${large},0,${p(cx, cy, innerRadius, sa)}`,\n 'Z',\n ].join('');\n }\n\n // ── Rounded corners (or semicircle caps at open ends) ────────────────────────\n // Corner bezier pull amounts\n const outerPull = Math.min(cr / outerRadius, paddedSweep / 2);\n const innerPull = Math.min(cr / innerRadius, paddedSweep / 2);\n const radialPull = Math.min(cr, (outerRadius - innerRadius) / 2);\n const capR = (outerRadius - innerRadius) / 2; // semicircle cap radius\n\n // Shortened arc angles (for corners)\n const oS = sa + (capStart ? 0 : outerPull);\n const oE = ea - (capEnd ? 0 : outerPull);\n const iS = sa + (capStart ? 0 : innerPull);\n const iE = ea - (capEnd ? 0 : innerPull);\n\n const largeO = oE - oS > Math.PI ? 1 : 0;\n const largeI = iE - iS > Math.PI ? 1 : 0;\n\n // Unrounded corner cartesian positions (at full sa/ea, not shortened)\n const cxOs = px(cx, outerRadius, sa);\n const cyOs = py(cy, outerRadius, sa);\n const cxOe = px(cx, outerRadius, ea);\n const cyOe = py(cy, outerRadius, ea);\n const cxIs = px(cx, innerRadius, sa);\n const cyIs = py(cy, innerRadius, sa);\n const cxIe = px(cx, innerRadius, ea);\n const cyIe = py(cy, innerRadius, ea);\n\n const frac = radialPull / (outerRadius - innerRadius);\n const pOsRad = `${cxOs + (cxIs - cxOs) * frac},${cyOs + (cyIs - cyOs) * frac}`;\n const pOeRad = `${cxOe + (cxIe - cxOe) * frac},${cyOe + (cyIe - cyOe) * frac}`;\n const pIsRad = `${cxIs + (cxOs - cxIs) * frac},${cyIs + (cyOs - cyIs) * frac}`;\n const pIeRad = `${cxIe + (cxOe - cxIe) * frac},${cyIe + (cyOe - cyIe) * frac}`;\n\n const segs: string[] = [];\n\n // Start edge\n if (capStart) {\n segs.push(`M${p(cx, cy, outerRadius, sa)}`);\n } else {\n segs.push(`M${pOsRad}`);\n segs.push(`Q${cxOs},${cyOs},${p(cx, cy, outerRadius, oS)}`);\n }\n\n // Outer arc\n segs.push(`A${outerRadius},${outerRadius},0,${largeO},1,${p(cx, cy, outerRadius, oE)}`);\n\n // End edge\n if (capEnd) {\n // Semicircle cap from outer-end → inner-end, bulging away from center (CW)\n segs.push(`A${capR},${capR},0,0,1,${p(cx, cy, innerRadius, ea)}`);\n } else {\n segs.push(`Q${cxOe},${cyOe},${pOeRad}`);\n segs.push(`L${pIeRad}`);\n segs.push(`Q${cxIe},${cyIe},${p(cx, cy, innerRadius, iE)}`);\n }\n\n // Inner arc (reversed, CCW)\n segs.push(`A${innerRadius},${innerRadius},0,${largeI},0,${p(cx, cy, innerRadius, iS)}`);\n\n // Start edge close\n if (capStart) {\n // Semicircle cap from inner-start → outer-start, bulging away from center (CCW)\n segs.push(`A${capR},${capR},0,0,0,${p(cx, cy, outerRadius, sa)}`);\n } else {\n segs.push(`Q${cxIs},${cyIs},${pIsRad}`);\n }\n\n segs.push('Z');\n\n return segs.join('');\n}\n\nexport function arcCentroid(arc: Arc): { x: number; y: number } {\n const mid = (arc.startAngle + arc.endAngle) / 2;\n const r = (arc.outerRadius + arc.innerRadius) / 2;\n\n return {\n x: arc.centerX + r * Math.sin(mid),\n y: arc.centerY - r * Math.cos(mid),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pie-renderer.cjs","names":[],"sources":["../../../src/charts/pie/pie-renderer.ts"],"sourcesContent":["import type { PieSliceConfig } from '../../types';\n\nexport interface Arc {\n capEnd: boolean;\n capStart: boolean;\n centerX: number;\n centerY: number;\n color: string;\n cornerRadius: number;\n endAngle: number;\n index: number;\n innerRadius: number;\n outerRadius: number;\n padAngle: number;\n slice: PieSliceConfig;\n startAngle: number;\n}\n\nexport function computeArcs(\n slices: PieSliceConfig[],\n cx: number,\n cy: number,\n outerRadius: number,\n innerRadius: number,\n startAngle: number,\n endAngle: number,\n padPixels: number,\n cornerRadius: number,\n defaultColors: (i: number) => string,\n capEnds = false,\n): Arc[] {\n const total = slices.reduce((s, d) => s + Math.max(0, d.value), 0);\n\n if (total === 0) return [];\n\n const range = endAngle - startAngle;\n const halfGapAngle = outerRadius > 0 ? Math.asin(Math.min(1, padPixels / 2 / outerRadius)) : 0;\n\n let currentAngle = startAngle;\n const n = slices.length;\n\n return slices.map((slice, i) => {\n const fraction = Math.max(0, slice.value) / total;\n const sliceRange = fraction * range;\n const rawStart = currentAngle;\n const rawEnd = currentAngle + sliceRange;\n\n currentAngle += sliceRange;\n\n const padAngle = Math.min(halfGapAngle, sliceRange / 2);\n\n return {\n capEnd: capEnds && i === n - 1,\n capStart: capEnds && i === 0,\n centerX: cx,\n centerY: cy,\n color: slice.color ?? defaultColors(i),\n cornerRadius,\n endAngle: rawEnd,\n index: i,\n innerRadius,\n outerRadius,\n padAngle,\n slice,\n startAngle: rawStart,\n };\n });\n}\n\n// Polar to cartesian, returns x,y string for SVG path\nfunction p(cx: number, cy: number, r: number, a: number): string {\n return `${cx + r * Math.sin(a)},${cy - r * Math.cos(a)}`;\n}\n\n// Cartesian x component\nfunction px(cx: number, r: number, a: number): number {\n return cx + r * Math.sin(a);\n}\n\n// Cartesian y component\nfunction py(cy: number, r: number, a: number): number {\n return cy - r * Math.cos(a);\n}\n\nexport function arcPath(arc: Arc): string {\n const {\n capEnd,\n capStart,\n centerX: cx,\n centerY: cy,\n cornerRadius: cr,\n endAngle,\n innerRadius,\n outerRadius,\n padAngle,\n startAngle,\n } = arc;\n\n const sweep = endAngle - startAngle;\n\n if (sweep <= 0) return '';\n\n // ── Full circle ─────────────────────────────────────────────────────────────\n if (sweep >= 2 * Math.PI - 1e-6) {\n const mid = startAngle + Math.PI;\n\n if (innerRadius <= 0) {\n return `M${p(cx, cy, outerRadius, startAngle)}A${outerRadius},${outerRadius},0,1,1,${p(cx, cy, outerRadius, mid)}A${outerRadius},${outerRadius},0,1,1,${p(cx, cy, outerRadius, startAngle)}Z`;\n }\n\n return [\n `M${p(cx, cy, outerRadius, startAngle)}`,\n `A${outerRadius},${outerRadius},0,1,1,${p(cx, cy, outerRadius, mid)}`,\n `A${outerRadius},${outerRadius},0,1,1,${p(cx, cy, outerRadius, startAngle)}`,\n `M${p(cx, cy, innerRadius, startAngle)}`,\n `A${innerRadius},${innerRadius},0,1,0,${p(cx, cy, innerRadius, mid)}`,\n `A${innerRadius},${innerRadius},0,1,0,${p(cx, cy, innerRadius, startAngle)}`,\n 'Z',\n ].join('');\n }\n\n // Cap ends don't get a padAngle inset (no adjacent slice on that side)\n const sa = capStart ? startAngle : startAngle + padAngle;\n const ea = capEnd ? endAngle : endAngle - padAngle;\n\n if (ea <= sa) return '';\n\n const paddedSweep = ea - sa;\n\n // ── No rounding ─────────────────────────────────────────────────────────────\n if (cr <= 0) {\n const large = paddedSweep > Math.PI ? 1 : 0;\n\n if (innerRadius <= 0) {\n return `M${cx},${cy}L${p(cx, cy, outerRadius, sa)}A${outerRadius},${outerRadius},0,${large},1,${p(cx, cy, outerRadius, ea)}Z`;\n }\n\n return [\n `M${p(cx, cy, outerRadius, sa)}`,\n `A${outerRadius},${outerRadius},0,${large},1,${p(cx, cy, outerRadius, ea)}`,\n `L${p(cx, cy, innerRadius, ea)}`,\n `A${innerRadius},${innerRadius},0,${large},0,${p(cx, cy, innerRadius, sa)}`,\n 'Z',\n ].join('');\n }\n\n // ── Rounded corners (or semicircle caps at open ends) ────────────────────────\n // Corner bezier pull amounts\n const outerPull = Math.min(cr / outerRadius, paddedSweep / 2);\n const innerPull = Math.min(cr / innerRadius, paddedSweep / 2);\n const radialPull = Math.min(cr, (outerRadius - innerRadius) / 2);\n const capR = (outerRadius - innerRadius) / 2; // semicircle cap radius\n\n // Shortened arc angles (for corners)\n const oS = sa + (capStart ? 0 : outerPull);\n const oE = ea - (capEnd ? 0 : outerPull);\n const iS = sa + (capStart ? 0 : innerPull);\n const iE = ea - (capEnd ? 0 : innerPull);\n\n const largeO = oE - oS > Math.PI ? 1 : 0;\n const largeI = iE - iS > Math.PI ? 1 : 0;\n\n // Unrounded corner cartesian positions (at full sa/ea, not shortened)\n const cxOs = px(cx, outerRadius, sa);\n const cyOs = py(cy, outerRadius, sa);\n const cxOe = px(cx, outerRadius, ea);\n const cyOe = py(cy, outerRadius, ea);\n const cxIs = px(cx, innerRadius, sa);\n const cyIs = py(cy, innerRadius, sa);\n const cxIe = px(cx, innerRadius, ea);\n const cyIe = py(cy, innerRadius, ea);\n\n const frac = radialPull / (outerRadius - innerRadius);\n const pOsRad = `${cxOs + (cxIs - cxOs) * frac},${cyOs + (cyIs - cyOs) * frac}`;\n const pOeRad = `${cxOe + (cxIe - cxOe) * frac},${cyOe + (cyIe - cyOe) * frac}`;\n const pIsRad = `${cxIs + (cxOs - cxIs) * frac},${cyIs + (cyOs - cyIs) * frac}`;\n const pIeRad = `${cxIe + (cxOe - cxIe) * frac},${cyIe + (cyOe - cyIe) * frac}`;\n\n const segs: string[] = [];\n\n // Start edge\n if (capStart) {\n segs.push(`M${p(cx, cy, outerRadius, sa)}`);\n } else {\n segs.push(`M${pOsRad}`);\n segs.push(`Q${cxOs},${cyOs},${p(cx, cy, outerRadius, oS)}`);\n }\n\n // Outer arc\n segs.push(`A${outerRadius},${outerRadius},0,${largeO},1,${p(cx, cy, outerRadius, oE)}`);\n\n // End edge\n if (capEnd) {\n // Semicircle cap from outer-end → inner-end, bulging away from center (CW)\n segs.push(`A${capR},${capR},0,0,1,${p(cx, cy, innerRadius, ea)}`);\n } else {\n segs.push(`Q${cxOe},${cyOe},${pOeRad}`);\n segs.push(`L${pIeRad}`);\n segs.push(`Q${cxIe},${cyIe},${p(cx, cy, innerRadius, iE)}`);\n }\n\n // Inner arc (reversed, CCW)\n segs.push(`A${innerRadius},${innerRadius},0,${largeI},0,${p(cx, cy, innerRadius, iS)}`);\n\n // Start edge close\n if (capStart) {\n // Semicircle cap from inner-start → outer-start, bulging away from center (CCW)\n segs.push(`A${capR},${capR},0,0,0,${p(cx, cy, outerRadius, sa)}`);\n } else {\n segs.push(`Q${cxIs},${cyIs},${pIsRad}`);\n }\n\n segs.push('Z');\n\n return segs.join('');\n}\n\nexport function arcCentroid(arc: Arc): { x: number; y: number } {\n const mid = (arc.startAngle + arc.endAngle) / 2;\n const r = (arc.outerRadius + arc.innerRadius) / 2;\n\n return {\n x: arc.centerX + r * Math.sin(mid),\n y: arc.centerY - r * Math.cos(mid),\n };\n}\n"],"mappings":"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"}