@primeui/chart-core 0.0.1-alpha.1

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 (299) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +1 -0
  3. package/dist/animations/index.d.mts +136 -0
  4. package/dist/animations/index.mjs +18 -0
  5. package/dist/annotation.utils-Bm0lOO1o.d.mts +290 -0
  6. package/dist/borderRadius.utils-Cz73LLR_.d.mts +54 -0
  7. package/dist/canvas-D4vigq47.d.mts +34 -0
  8. package/dist/canvas.utils-D2WHi2gL.d.mts +167 -0
  9. package/dist/cartesian/index.d.mts +94 -0
  10. package/dist/cartesian/index.mjs +93 -0
  11. package/dist/chunk-22ST6YPP.mjs +304 -0
  12. package/dist/chunk-2QK2KOBN.mjs +10 -0
  13. package/dist/chunk-2QRS4YQ5.mjs +18 -0
  14. package/dist/chunk-3FFJEX4A.mjs +261 -0
  15. package/dist/chunk-3IYSJ2U7.mjs +567 -0
  16. package/dist/chunk-3OZLP4I4.mjs +190 -0
  17. package/dist/chunk-3WEMHXZI.mjs +198 -0
  18. package/dist/chunk-3Z62EUJN.mjs +138 -0
  19. package/dist/chunk-4C6EVJ54.mjs +362 -0
  20. package/dist/chunk-53HW45JB.mjs +102 -0
  21. package/dist/chunk-55Y3WI6S.mjs +186 -0
  22. package/dist/chunk-5JCI2DEB.mjs +97 -0
  23. package/dist/chunk-66T4MRC5.mjs +113 -0
  24. package/dist/chunk-6HSEJLSR.mjs +376 -0
  25. package/dist/chunk-6STOLMCA.mjs +187 -0
  26. package/dist/chunk-7CMVDIOU.mjs +54 -0
  27. package/dist/chunk-7QQ6ETB4.mjs +228 -0
  28. package/dist/chunk-A6ZQZFL2.mjs +272 -0
  29. package/dist/chunk-ADKLH73T.mjs +1 -0
  30. package/dist/chunk-AGU3NG6D.mjs +22 -0
  31. package/dist/chunk-AHYIS6EB.mjs +230 -0
  32. package/dist/chunk-AP3UYWYT.mjs +4 -0
  33. package/dist/chunk-ARB5T6MP.mjs +326 -0
  34. package/dist/chunk-ARRGOEFX.mjs +585 -0
  35. package/dist/chunk-AUF4CHDP.mjs +422 -0
  36. package/dist/chunk-B4FTADAZ.mjs +561 -0
  37. package/dist/chunk-BABQKA6K.mjs +339 -0
  38. package/dist/chunk-BETFQBM2.mjs +197 -0
  39. package/dist/chunk-BKP26M4K.mjs +413 -0
  40. package/dist/chunk-BZN2QHGP.mjs +200 -0
  41. package/dist/chunk-C36VWQ7A.mjs +86 -0
  42. package/dist/chunk-CHW4RKY3.mjs +16 -0
  43. package/dist/chunk-CINXJIRR.mjs +120 -0
  44. package/dist/chunk-DN6AXQYZ.mjs +667 -0
  45. package/dist/chunk-DP2IZNN3.mjs +92 -0
  46. package/dist/chunk-DTWTCFRG.mjs +119 -0
  47. package/dist/chunk-EAMUNLRU.mjs +172 -0
  48. package/dist/chunk-EDAKJLNA.mjs +17 -0
  49. package/dist/chunk-ERVQB2VZ.mjs +59 -0
  50. package/dist/chunk-FFMT6OCO.mjs +92 -0
  51. package/dist/chunk-FHTC2YDB.mjs +102 -0
  52. package/dist/chunk-FRST55HY.mjs +16 -0
  53. package/dist/chunk-HDFGCN2F.mjs +132 -0
  54. package/dist/chunk-IEGLX7VL.mjs +42 -0
  55. package/dist/chunk-ILUWFYGY.mjs +220 -0
  56. package/dist/chunk-IXOWSEHO.mjs +114 -0
  57. package/dist/chunk-J4RI2C2G.mjs +172 -0
  58. package/dist/chunk-J65DBT4R.mjs +13 -0
  59. package/dist/chunk-JGOVWSKH.mjs +179 -0
  60. package/dist/chunk-JO7VACY2.mjs +25 -0
  61. package/dist/chunk-JWFBOPM6.mjs +122 -0
  62. package/dist/chunk-KNDZP446.mjs +895 -0
  63. package/dist/chunk-KP2TWD4Z.mjs +90 -0
  64. package/dist/chunk-KQIFO5I3.mjs +225 -0
  65. package/dist/chunk-KVDEROP6.mjs +59 -0
  66. package/dist/chunk-LKC7MZKK.mjs +87 -0
  67. package/dist/chunk-LVMDQ4OJ.mjs +305 -0
  68. package/dist/chunk-M7B3JF43.mjs +90 -0
  69. package/dist/chunk-MTGMXRNF.mjs +136 -0
  70. package/dist/chunk-N3TIT3OH.mjs +1040 -0
  71. package/dist/chunk-NHRK5KU2.mjs +890 -0
  72. package/dist/chunk-NKUYIWAP.mjs +243 -0
  73. package/dist/chunk-NPDZLYIF.mjs +238 -0
  74. package/dist/chunk-O2X6FF45.mjs +499 -0
  75. package/dist/chunk-OGJ6IIBW.mjs +176 -0
  76. package/dist/chunk-OHGCZZPZ.mjs +403 -0
  77. package/dist/chunk-OWW3K55O.mjs +351 -0
  78. package/dist/chunk-OXTFAWSK.mjs +60 -0
  79. package/dist/chunk-PLSDU3C2.mjs +890 -0
  80. package/dist/chunk-PRDVPOZX.mjs +223 -0
  81. package/dist/chunk-Q6PPVIHU.mjs +21 -0
  82. package/dist/chunk-QQBXUDM4.mjs +885 -0
  83. package/dist/chunk-QS76E3TD.mjs +111 -0
  84. package/dist/chunk-QWQ6HY4I.mjs +209 -0
  85. package/dist/chunk-R6Y3R7EW.mjs +135 -0
  86. package/dist/chunk-RBLZRT5K.mjs +190 -0
  87. package/dist/chunk-RO4N6YFS.mjs +167 -0
  88. package/dist/chunk-RQ3CKQOX.mjs +984 -0
  89. package/dist/chunk-SALTGZFR.mjs +208 -0
  90. package/dist/chunk-SANZPAJ4.mjs +14 -0
  91. package/dist/chunk-SDBPQ5CF.mjs +624 -0
  92. package/dist/chunk-SSLTFJ3U.mjs +364 -0
  93. package/dist/chunk-SXHVDJGF.mjs +77 -0
  94. package/dist/chunk-TA4MVAEX.mjs +243 -0
  95. package/dist/chunk-TAHCOZHF.mjs +1772 -0
  96. package/dist/chunk-TQ6S34QZ.mjs +152 -0
  97. package/dist/chunk-UPRXABX5.mjs +90 -0
  98. package/dist/chunk-VGLSBZDN.mjs +71 -0
  99. package/dist/chunk-VN7CKCSE.mjs +364 -0
  100. package/dist/chunk-VVI3OBPJ.mjs +524 -0
  101. package/dist/chunk-VWF57TS3.mjs +62 -0
  102. package/dist/chunk-WA3OVISZ.mjs +179 -0
  103. package/dist/chunk-WCG35U6M.mjs +964 -0
  104. package/dist/chunk-WFTX4AQJ.mjs +194 -0
  105. package/dist/chunk-WFVOQ2QZ.mjs +18 -0
  106. package/dist/chunk-WH3C3Y7P.mjs +149 -0
  107. package/dist/chunk-WPFUV7K3.mjs +488 -0
  108. package/dist/chunk-WRULPWHD.mjs +492 -0
  109. package/dist/chunk-WS64BZXT.mjs +1 -0
  110. package/dist/chunk-WY4AURRE.mjs +2419 -0
  111. package/dist/chunk-WYLILAOO.mjs +167 -0
  112. package/dist/chunk-X4D7FKUS.mjs +62 -0
  113. package/dist/chunk-X7T34OLW.mjs +139 -0
  114. package/dist/chunk-XIHBK5D3.mjs +68 -0
  115. package/dist/chunk-XQQCGFYB.mjs +50 -0
  116. package/dist/chunk-XTVE4P3L.mjs +214 -0
  117. package/dist/chunk-XUAASRXW.mjs +579 -0
  118. package/dist/chunk-Y3L3D4GQ.mjs +685 -0
  119. package/dist/chunk-YBJ56XJS.mjs +132 -0
  120. package/dist/chunk-ZQFK6CAE.mjs +1 -0
  121. package/dist/chunk-ZT2Z7ERM.mjs +874 -0
  122. package/dist/chunk-ZTL2FQEW.mjs +714 -0
  123. package/dist/circular/arc/index.d.mts +8 -0
  124. package/dist/circular/arc/index.mjs +3 -0
  125. package/dist/circular/index.d.mts +44 -0
  126. package/dist/circular/index.mjs +13 -0
  127. package/dist/collect.utils-DiKB4ciO.d.mts +12 -0
  128. package/dist/computeChartState-BTVIqwyO.d.mts +304 -0
  129. package/dist/controller-BJE1AZ3q.d.mts +82 -0
  130. package/dist/controller-BoNigQJr.d.mts +63 -0
  131. package/dist/controllers/index.d.mts +16 -0
  132. package/dist/controllers/index.mjs +110 -0
  133. package/dist/datalabel.utils-CkjGeB8S.d.mts +122 -0
  134. package/dist/decimation.utils-CcvJVhI4.d.mts +244 -0
  135. package/dist/geometry-DUUQJXVM.d.mts +60 -0
  136. package/dist/index-DseIZa1j.d.mts +167 -0
  137. package/dist/index.d.mts +88 -0
  138. package/dist/index.mjs +110 -0
  139. package/dist/orchestrator/index.d.mts +264 -0
  140. package/dist/orchestrator/index.mjs +33 -0
  141. package/dist/plugins/index.d.mts +18 -0
  142. package/dist/plugins/index.mjs +1 -0
  143. package/dist/property-animations-D433wXzz.d.mts +580 -0
  144. package/dist/property-store-NORUWFND.d.mts +17 -0
  145. package/dist/radial/index.d.mts +14 -0
  146. package/dist/radial/index.mjs +37 -0
  147. package/dist/renderers/axis/index.d.mts +39 -0
  148. package/dist/renderers/axis/index.mjs +8 -0
  149. package/dist/renderers/circular/index.d.mts +13 -0
  150. package/dist/renderers/circular/index.mjs +13 -0
  151. package/dist/renderers/index.d.mts +83 -0
  152. package/dist/renderers/index.mjs +75 -0
  153. package/dist/renderers/navigator/index.d.mts +103 -0
  154. package/dist/renderers/navigator/index.mjs +8 -0
  155. package/dist/resize.utils-D_2qm6rv.d.mts +142 -0
  156. package/dist/ring.utils-DXvrxMkU.d.mts +138 -0
  157. package/dist/scale-KFv30jqZ.d.mts +307 -0
  158. package/dist/scales-Drf8AIhL.d.mts +75 -0
  159. package/dist/series/bar/canvas/index.d.mts +8 -0
  160. package/dist/series/bar/canvas/index.mjs +10 -0
  161. package/dist/series/bar/controller/index.d.mts +105 -0
  162. package/dist/series/bar/controller/index.mjs +44 -0
  163. package/dist/series/bar/controller-canvas/index.d.mts +7 -0
  164. package/dist/series/bar/controller-canvas/index.mjs +49 -0
  165. package/dist/series/bar/controller-svg/index.d.mts +7 -0
  166. package/dist/series/bar/controller-svg/index.mjs +49 -0
  167. package/dist/series/bar/index.d.mts +60 -0
  168. package/dist/series/bar/index.mjs +13 -0
  169. package/dist/series/bar/svg/index.d.mts +8 -0
  170. package/dist/series/bar/svg/index.mjs +11 -0
  171. package/dist/series/candlestick/canvas/index.d.mts +8 -0
  172. package/dist/series/candlestick/canvas/index.mjs +8 -0
  173. package/dist/series/candlestick/controller/index.d.mts +123 -0
  174. package/dist/series/candlestick/controller/index.mjs +40 -0
  175. package/dist/series/candlestick/controller-canvas/index.d.mts +7 -0
  176. package/dist/series/candlestick/controller-canvas/index.mjs +45 -0
  177. package/dist/series/candlestick/controller-svg/index.d.mts +7 -0
  178. package/dist/series/candlestick/controller-svg/index.mjs +45 -0
  179. package/dist/series/candlestick/index.d.mts +11 -0
  180. package/dist/series/candlestick/index.mjs +10 -0
  181. package/dist/series/candlestick/svg/index.d.mts +8 -0
  182. package/dist/series/candlestick/svg/index.mjs +8 -0
  183. package/dist/series/heatmap/canvas/index.d.mts +16 -0
  184. package/dist/series/heatmap/canvas/index.mjs +9 -0
  185. package/dist/series/heatmap/controller/index.d.mts +110 -0
  186. package/dist/series/heatmap/controller/index.mjs +23 -0
  187. package/dist/series/heatmap/controller-canvas/index.d.mts +7 -0
  188. package/dist/series/heatmap/controller-canvas/index.mjs +28 -0
  189. package/dist/series/heatmap/controller-svg/index.d.mts +7 -0
  190. package/dist/series/heatmap/controller-svg/index.mjs +28 -0
  191. package/dist/series/heatmap/index.d.mts +34 -0
  192. package/dist/series/heatmap/index.mjs +13 -0
  193. package/dist/series/heatmap/svg/index.d.mts +15 -0
  194. package/dist/series/heatmap/svg/index.mjs +10 -0
  195. package/dist/series/line/canvas/index.d.mts +6 -0
  196. package/dist/series/line/canvas/index.mjs +9 -0
  197. package/dist/series/line/controller/index.d.mts +111 -0
  198. package/dist/series/line/controller/index.mjs +47 -0
  199. package/dist/series/line/controller-canvas/index.d.mts +7 -0
  200. package/dist/series/line/controller-canvas/index.mjs +54 -0
  201. package/dist/series/line/controller-svg/index.d.mts +7 -0
  202. package/dist/series/line/controller-svg/index.mjs +54 -0
  203. package/dist/series/line/index.d.mts +49 -0
  204. package/dist/series/line/index.mjs +13 -0
  205. package/dist/series/line/svg/index.d.mts +6 -0
  206. package/dist/series/line/svg/index.mjs +9 -0
  207. package/dist/series/pie/canvas/index.d.mts +8 -0
  208. package/dist/series/pie/canvas/index.mjs +10 -0
  209. package/dist/series/pie/controller/index.d.mts +174 -0
  210. package/dist/series/pie/controller/index.mjs +110 -0
  211. package/dist/series/pie/controller-canvas/index.d.mts +8 -0
  212. package/dist/series/pie/controller-canvas/index.mjs +119 -0
  213. package/dist/series/pie/controller-svg/index.d.mts +8 -0
  214. package/dist/series/pie/controller-svg/index.mjs +118 -0
  215. package/dist/series/pie/index.d.mts +59 -0
  216. package/dist/series/pie/index.mjs +15 -0
  217. package/dist/series/pie/svg/index.d.mts +6 -0
  218. package/dist/series/pie/svg/index.mjs +11 -0
  219. package/dist/series/polar/canvas/index.d.mts +6 -0
  220. package/dist/series/polar/canvas/index.mjs +7 -0
  221. package/dist/series/polar/controller/index.d.mts +102 -0
  222. package/dist/series/polar/controller/index.mjs +46 -0
  223. package/dist/series/polar/controller-canvas/index.d.mts +8 -0
  224. package/dist/series/polar/controller-canvas/index.mjs +52 -0
  225. package/dist/series/polar/controller-svg/index.d.mts +8 -0
  226. package/dist/series/polar/controller-svg/index.mjs +52 -0
  227. package/dist/series/polar/index.d.mts +25 -0
  228. package/dist/series/polar/index.mjs +16 -0
  229. package/dist/series/polar/svg/index.d.mts +10 -0
  230. package/dist/series/polar/svg/index.mjs +8 -0
  231. package/dist/series/radar/canvas/index.d.mts +6 -0
  232. package/dist/series/radar/canvas/index.mjs +8 -0
  233. package/dist/series/radar/controller/index.d.mts +121 -0
  234. package/dist/series/radar/controller/index.mjs +43 -0
  235. package/dist/series/radar/controller-canvas/index.d.mts +8 -0
  236. package/dist/series/radar/controller-canvas/index.mjs +51 -0
  237. package/dist/series/radar/controller-svg/index.d.mts +8 -0
  238. package/dist/series/radar/controller-svg/index.mjs +51 -0
  239. package/dist/series/radar/index.d.mts +40 -0
  240. package/dist/series/radar/index.mjs +13 -0
  241. package/dist/series/radar/svg/index.d.mts +12 -0
  242. package/dist/series/radar/svg/index.mjs +9 -0
  243. package/dist/series/scatter/canvas/index.d.mts +8 -0
  244. package/dist/series/scatter/canvas/index.mjs +11 -0
  245. package/dist/series/scatter/controller/index.d.mts +124 -0
  246. package/dist/series/scatter/controller/index.mjs +44 -0
  247. package/dist/series/scatter/controller-canvas/index.d.mts +7 -0
  248. package/dist/series/scatter/controller-canvas/index.mjs +51 -0
  249. package/dist/series/scatter/controller-svg/index.d.mts +7 -0
  250. package/dist/series/scatter/controller-svg/index.mjs +51 -0
  251. package/dist/series/scatter/index.d.mts +25 -0
  252. package/dist/series/scatter/index.mjs +14 -0
  253. package/dist/series/scatter/svg/index.d.mts +8 -0
  254. package/dist/series/scatter/svg/index.mjs +12 -0
  255. package/dist/series/treemap/canvas/index.d.mts +50 -0
  256. package/dist/series/treemap/canvas/index.mjs +10 -0
  257. package/dist/series/treemap/controller/index.d.mts +130 -0
  258. package/dist/series/treemap/controller/index.mjs +20 -0
  259. package/dist/series/treemap/controller-canvas/index.d.mts +7 -0
  260. package/dist/series/treemap/controller-canvas/index.mjs +25 -0
  261. package/dist/series/treemap/controller-svg/index.d.mts +7 -0
  262. package/dist/series/treemap/controller-svg/index.mjs +25 -0
  263. package/dist/series/treemap/index.d.mts +15 -0
  264. package/dist/series/treemap/index.mjs +12 -0
  265. package/dist/series/treemap/svg/index.d.mts +15 -0
  266. package/dist/series/treemap/svg/index.mjs +9 -0
  267. package/dist/slices-DtewiwJx.d.mts +72 -0
  268. package/dist/spatialIndex.utils-B_GJkotZ.d.mts +5 -0
  269. package/dist/squarify.utils-B9CQBpa1.d.mts +50 -0
  270. package/dist/stacking-CChuAcLN.d.mts +319 -0
  271. package/dist/streaming.utils-DH-g1gNP.d.mts +49 -0
  272. package/dist/sync/index.d.mts +130 -0
  273. package/dist/sync/index.mjs +5 -0
  274. package/dist/tooltip.renderer-D5wpSlBa.d.mts +210 -0
  275. package/dist/utils/color/index.d.mts +58 -0
  276. package/dist/utils/color/index.mjs +4 -0
  277. package/dist/utils/data/index.d.mts +180 -0
  278. package/dist/utils/data/index.mjs +7 -0
  279. package/dist/utils/export/index.d.mts +14 -0
  280. package/dist/utils/export/index.mjs +6 -0
  281. package/dist/utils/index.d.mts +49 -0
  282. package/dist/utils/index.mjs +29 -0
  283. package/dist/utils/interaction/index.d.mts +255 -0
  284. package/dist/utils/interaction/index.mjs +9 -0
  285. package/dist/utils/layout/index.d.mts +3 -0
  286. package/dist/utils/layout/index.mjs +10 -0
  287. package/dist/utils/math/index.d.mts +162 -0
  288. package/dist/utils/math/index.mjs +1 -0
  289. package/dist/utils/render/index.d.mts +19 -0
  290. package/dist/utils/render/index.mjs +3 -0
  291. package/dist/utils/specialized/index.d.mts +37 -0
  292. package/dist/utils/specialized/index.mjs +66 -0
  293. package/dist/utils/text/index.d.mts +39 -0
  294. package/dist/utils/text/index.mjs +8 -0
  295. package/dist/utils/theme/index.d.mts +295 -0
  296. package/dist/utils/theme/index.mjs +5 -0
  297. package/dist/utils/zoom/index.d.mts +90 -0
  298. package/dist/utils/zoom/index.mjs +3 -0
  299. package/package.json +56 -0
@@ -0,0 +1,890 @@
1
+ import { resolveRadarLabels } from './chunk-UPRXABX5.mjs';
2
+ import { resolveSharedRadialGrid } from './chunk-TA4MVAEX.mjs';
3
+ import { calculateRadarLayout, hitTestRadar } from './chunk-A6ZQZFL2.mjs';
4
+ import { renderResolvedLabels } from './chunk-QQBXUDM4.mjs';
5
+ import { AnimatedScene, resolveAnimatedProps, RADAR_ANIMATABLE_PROPS } from './chunk-VN7CKCSE.mjs';
6
+ import { renderCustomMarkersCanvas } from './chunk-ZT2Z7ERM.mjs';
7
+ import { reconcileSvgChildren } from './chunk-KP2TWD4Z.mjs';
8
+ import { parseAnimationConfig } from './chunk-3WEMHXZI.mjs';
9
+ import { cancelRaf, raf } from './chunk-EDAKJLNA.mjs';
10
+ import { buildAccessibilityRenderContext, generateSeriesDescription } from './chunk-OGJ6IIBW.mjs';
11
+ import { collectItems } from './chunk-FFMT6OCO.mjs';
12
+ import { DEFAULT_HOVER_DIM_OPACITY, DEFAULT_HOVER_BRIGHTNESS } from './chunk-NKUYIWAP.mjs';
13
+ import { interpolateRadialGrid } from './chunk-WH3C3Y7P.mjs';
14
+ import { makeItemContext, defaultLightTheme, resolveSwatchColor, getPrimaryColor, getDefaultColor, FIELD_DEFAULTS } from './chunk-O2X6FF45.mjs';
15
+ import { setAttr, createSvgGroup, materializeSvgNode } from './chunk-SSLTFJ3U.mjs';
16
+ import { calculateNiceDomain } from './chunk-RQ3CKQOX.mjs';
17
+
18
+ // src/series/radar/controller/helpers.ts
19
+ function buildRadarFingerprint(layout, entries) {
20
+ const parts = [];
21
+ for (const sd of layout.series) {
22
+ const dsEntry = entries.find((e) => e.id === sd.id);
23
+ const visible = dsEntry?.visible ?? sd.visible;
24
+ const ptHash = sd.points.map((p2) => `${p2.categoryIndex}:${p2.value}:${Math.round(p2.x)}:${Math.round(p2.y)}`).join(",");
25
+ const p = dsEntry?.props;
26
+ const visualHash = `sm:${p?.showMarkers}|fo:${p?.fillOpacity}|lw:${p?.lineStrokeWidth}|ls:${p?.lineStyle}|cv:${p?.curve}|c:${sd.color}`;
27
+ parts.push(`${sd.id}|v:${visible}|${visualHash}|${ptHash}`);
28
+ }
29
+ parts.push(`dom:${layout.domain[0]},${layout.domain[1]}`);
30
+ parts.push(`r:${Math.round(layout.radius)}`);
31
+ const g = layout.grid;
32
+ parts.push(`grid:${g.shape}|${g.levels}|${g.color}|${g.opacity}|${g.width}|${g.style}`);
33
+ return parts.join("||");
34
+ }
35
+ function lerpSeriesFade(fade, now) {
36
+ if (fade.startTime === -1) {
37
+ return { fillOpacity: fade.fromFillOpacity, lineStrokeWidth: fade.fromLineStrokeWidth };
38
+ }
39
+ const elapsed = now - fade.startTime;
40
+ const raw = Math.max(0, Math.min(1, elapsed / Math.max(1, fade.duration)));
41
+ const p = fade.easing(raw);
42
+ return {
43
+ fillOpacity: fade.fromFillOpacity + (fade.toFillOpacity - fade.fromFillOpacity) * p,
44
+ lineStrokeWidth: fade.fromLineStrokeWidth + (fade.toLineStrokeWidth - fade.fromLineStrokeWidth) * p
45
+ };
46
+ }
47
+ function mergeRadarPropsWithOverrides(overrides, baseProps) {
48
+ if (!overrides || !baseProps) return baseProps;
49
+ return { ...baseProps, ...overrides };
50
+ }
51
+
52
+ // src/series/radar/controller/types.ts
53
+ var RADAR_POINT_REGISTRY = {
54
+ number: ["x", "y", "value", "baseX", "baseY", "baseValue"],
55
+ color: []
56
+ };
57
+ function pointKey(seriesId, categoryIndex) {
58
+ return `${seriesId}::${categoryIndex}`;
59
+ }
60
+
61
+ // src/series/radar/controller/paint.ts
62
+ function buildRadarSvgChildren(ctx, layout, entries, input) {
63
+ const children = [];
64
+ const context = input.chartId ? { chartId: input.chartId } : void 0;
65
+ const a11y = buildAccessibilityRenderContext(input.features);
66
+ for (let si = 0; si < layout.series.length; si++) {
67
+ const ds = entries[si];
68
+ const mergedProps = ds ? mergeRadarPropsWithOverrides(ctx._propertyOverrides.get(ds.id), ds.props) : void 0;
69
+ const node = ctx._paint.renderSvg(layout, si, ctx.hoverState, input.theme, ctx.effectConfig, mergedProps, void 0, context);
70
+ const sd = layout.series[si];
71
+ if (sd) setAttr(node, "data-dataset", sd.id);
72
+ if (sd && a11y?.enabled && a11y.landmarkVerbosity === "all") {
73
+ setAttr(node, "role", "region");
74
+ setAttr(node, "aria-label", generateSeriesDescription(mergedProps?.name ?? sd.id, "radar", sd.points.length));
75
+ }
76
+ children.push(node);
77
+ }
78
+ const lc = input.labelConfig;
79
+ if (lc) {
80
+ for (let si = 0; si < layout.series.length; si++) {
81
+ const sd = layout.series[si];
82
+ const ds = entries[si];
83
+ if (!sd.visible || !ds) continue;
84
+ const dsTotal = sd.points.reduce((sum, pt) => sum + Math.abs(pt.value), 0);
85
+ const labels = resolveRadarLabels(sd.points, layout.categories, sd.color ?? getDefaultColor(sd.seriesIdx, input.theme), dsTotal, layout.center, lc, ds.props.data);
86
+ const labelNode = createSvgGroup();
87
+ renderResolvedLabels(labels, lc, { renderer: "svg", svgGroup: labelNode, theme: input.theme });
88
+ setAttr(labelNode, "data-layer", `labels-${sd.id}`);
89
+ children.push(labelNode);
90
+ }
91
+ }
92
+ return children;
93
+ }
94
+ function renderToSvg(ctx, group, layout, entries, input) {
95
+ group.replaceChildren(...buildRadarSvgChildren(ctx, layout, entries, input).map(materializeSvgNode));
96
+ }
97
+ function renderCanvasContent(ctx, c2d) {
98
+ const layout = ctx.lastRenderedLayout ?? ctx._layout;
99
+ if (!layout || ctx._entries.length === 0) return;
100
+ for (let si = 0; si < layout.series.length; si++) {
101
+ const ds = ctx._entries[si];
102
+ const mergedProps = ds ? mergeRadarPropsWithOverrides(ctx._propertyOverrides.get(ds.id), ds.props) : void 0;
103
+ ctx._paint.renderCanvas(c2d, layout, si, ctx.hoverState, ctx.effectConfig, mergedProps, ctx.lastInput?.theme ?? defaultLightTheme);
104
+ }
105
+ const markerEntries = [];
106
+ for (let si = 0; si < layout.series.length; si++) {
107
+ const ds = ctx._entries[si];
108
+ const sd = layout.series[si];
109
+ if (!ds || !sd.visible) continue;
110
+ const renderMarkerFn = ds.props.renderMarker;
111
+ if (!renderMarkerFn) continue;
112
+ const mergedProps = mergeRadarPropsWithOverrides(ctx._propertyOverrides.get(ds.id), ds.props) ?? ds.props;
113
+ markerEntries.push({
114
+ dsId: ds.id,
115
+ renderMarker: renderMarkerFn,
116
+ visiblePoints: sd.points.map((pt, pi) => ({ x: pt.x, y: pt.y, dataIndex: pi, value: pt.value, category: layout.categories[pt.categoryIndex] })),
117
+ data: ds.props.data,
118
+ color: sd.color ?? getDefaultColor(sd.seriesIdx, ctx.lastInput?.theme ?? defaultLightTheme),
119
+ markerSize: typeof mergedProps.markerSize === "number" ? mergedProps.markerSize : 4,
120
+ effects: { dimOpacity: ctx.effectConfig.dimOpacity }
121
+ });
122
+ }
123
+ if (markerEntries.length > 0) {
124
+ renderCustomMarkersCanvas(c2d, markerEntries, ctx.hoverState);
125
+ }
126
+ const lc = ctx.lastInput?.labelConfig;
127
+ if (lc) {
128
+ for (let si = 0; si < layout.series.length; si++) {
129
+ const sd = layout.series[si];
130
+ const ds = ctx._entries[si];
131
+ if (!sd.visible || !ds) continue;
132
+ const dsTotal = sd.points.reduce((sum, pt) => sum + Math.abs(pt.value), 0);
133
+ const labels = resolveRadarLabels(sd.points, layout.categories, sd.color ?? getDefaultColor(sd.seriesIdx, ctx.lastInput?.theme ?? defaultLightTheme), dsTotal, layout.center, lc, ds.props.data);
134
+ renderResolvedLabels(labels, lc, { renderer: "canvas", ctx: c2d, theme: ctx.lastInput?.theme ?? defaultLightTheme });
135
+ }
136
+ }
137
+ }
138
+
139
+ // src/series/radar/controller/scene.ts
140
+ function fullReset(ctx) {
141
+ ctx._layout = null;
142
+ ctx.lastRenderedLayout = null;
143
+ setMarkerData(ctx, null);
144
+ if (ctx._animRafId !== null) {
145
+ cancelRaf(ctx._animRafId);
146
+ ctx._animRafId = null;
147
+ }
148
+ ctx._scene.reset();
149
+ ctx._seriesFades.clear();
150
+ ctx._seriesSettledStyle.clear();
151
+ ctx._gridLerp = null;
152
+ ctx._lastSettledDomain = null;
153
+ ctx._lastFingerprint = "";
154
+ ctx._firstRender = true;
155
+ ctx._propertyOverrides.clear();
156
+ }
157
+ function runAllHidden(ctx, features) {
158
+ const liveCount = ctx._scene.getElements().length;
159
+ const hasFades = ctx._seriesFades.size > 0;
160
+ if (liveCount === 0 && !hasFades) {
161
+ ctx._layout = null;
162
+ ctx.lastRenderedLayout = null;
163
+ setMarkerData(ctx, null);
164
+ if (ctx._animRafId !== null) {
165
+ cancelRaf(ctx._animRafId);
166
+ ctx._animRafId = null;
167
+ }
168
+ ctx._gridLerp = null;
169
+ ctx._lastFingerprint = "|EMPTY";
170
+ return;
171
+ }
172
+ const animConfig = features.get("animation")?.props;
173
+ const { enabled: animEnabled, duration, easing } = parseAnimationConfig(animConfig);
174
+ const shouldAnimate = animEnabled && duration > 0;
175
+ const fingerprint = "|EMPTY";
176
+ if (fingerprint === ctx._lastFingerprint) {
177
+ if (ctx._animRafId !== null) return;
178
+ return;
179
+ }
180
+ ctx._lastFingerprint = fingerprint;
181
+ if (ctx._animRafId !== null) {
182
+ cancelRaf(ctx._animRafId);
183
+ ctx._animRafId = null;
184
+ }
185
+ const opts = { numbers: { duration: shouldAnimate ? duration : 0, easing } };
186
+ ctx._scene.diff(/* @__PURE__ */ new Map(), opts);
187
+ const now = performance.now();
188
+ for (const [seriesId, settled] of ctx._seriesSettledStyle) {
189
+ if (settled.fillOpacity <= 1e-3 && settled.lineStrokeWidth <= 1e-3) continue;
190
+ let fromFill = settled.fillOpacity;
191
+ let fromStroke = settled.lineStrokeWidth;
192
+ const existing = ctx._seriesFades.get(seriesId);
193
+ if (existing) {
194
+ const lerped = lerpSeriesFade(existing, now);
195
+ fromFill = lerped.fillOpacity;
196
+ fromStroke = lerped.lineStrokeWidth;
197
+ }
198
+ ctx._seriesFades.set(seriesId, {
199
+ fromFillOpacity: fromFill,
200
+ toFillOpacity: 0,
201
+ fromLineStrokeWidth: fromStroke,
202
+ toLineStrokeWidth: 0,
203
+ startTime: -1,
204
+ duration: shouldAnimate ? duration : 0,
205
+ easing
206
+ });
207
+ }
208
+ ctx._gridLerp = null;
209
+ if (shouldAnimate) {
210
+ renderSceneFrame(ctx);
211
+ startAnimLoop(ctx);
212
+ } else {
213
+ ctx._scene.tick(performance.now());
214
+ if (ctx._scene.getElements().length === 0) {
215
+ ctx._layout = null;
216
+ setMarkerData(ctx, null);
217
+ }
218
+ ctx._seriesFades.clear();
219
+ renderSceneFrame(ctx);
220
+ }
221
+ }
222
+ function updateGridLerp(ctx, targetLayout, shouldAnimate, duration, easing, tickCount) {
223
+ const isPerSpoke = !!targetLayout.perSpokeDomains && targetLayout.perSpokeDomains.size > 0;
224
+ let targetDomain;
225
+ let targetGrid;
226
+ if (isPerSpoke) {
227
+ targetDomain = targetLayout.domain;
228
+ targetGrid = targetLayout.grid;
229
+ } else {
230
+ const resolved = resolveSharedRadialGrid(targetLayout.grid, targetLayout.domain, targetLayout.rawDataMax, targetLayout.radius, tickCount);
231
+ targetDomain = resolved.domain;
232
+ targetGrid = { ...targetLayout.grid, levels: resolved.levelValues.length, levelValues: resolved.levelValues, levelRadii: resolved.levelRadii };
233
+ }
234
+ const prevSettled = ctx._lastSettledDomain;
235
+ const domainChanged = !prevSettled || prevSettled[0] !== targetDomain[0] || prevSettled[1] !== targetDomain[1];
236
+ if (shouldAnimate && domainChanged && prevSettled) {
237
+ const fromDomain = ctx._gridLerp ? currentGridDomain(ctx) : prevSettled;
238
+ ctx._gridLerp = {
239
+ fromDomain,
240
+ toDomain: targetDomain,
241
+ targetGrid,
242
+ targetRadius: targetLayout.radius,
243
+ startTime: -1,
244
+ duration,
245
+ easing
246
+ };
247
+ } else {
248
+ ctx._gridLerp = null;
249
+ ctx._lastSettledDomain = targetDomain;
250
+ }
251
+ }
252
+ function currentGridDomain(ctx) {
253
+ if (!ctx._gridLerp) return ctx._lastSettledDomain ?? [0, 0];
254
+ const { fromDomain, toDomain, startTime, duration, easing } = ctx._gridLerp;
255
+ if (startTime === -1) return fromDomain;
256
+ const elapsed = performance.now() - startTime;
257
+ const raw = Math.max(0, Math.min(1, elapsed / duration));
258
+ const p = easing(raw);
259
+ return [fromDomain[0] + (toDomain[0] - fromDomain[0]) * p, fromDomain[1] + (toDomain[1] - fromDomain[1]) * p];
260
+ }
261
+ function buildLayoutFromScene(ctx, now) {
262
+ if (!ctx._layout) return null;
263
+ const elementsBySeries = /* @__PURE__ */ new Map();
264
+ for (const el of ctx._scene.getElements()) {
265
+ const s = el.current;
266
+ const list = elementsBySeries.get(s.seriesId);
267
+ if (list) list.push(s);
268
+ else elementsBySeries.set(s.seriesId, [s]);
269
+ }
270
+ const series = [];
271
+ for (const targetSd of ctx._layout.series) {
272
+ const stateList = elementsBySeries.get(targetSd.id);
273
+ if (!stateList || stateList.length === 0) {
274
+ continue;
275
+ }
276
+ stateList.sort((a, b) => a.categoryIndex - b.categoryIndex);
277
+ const points = stateList.map((s) => ({
278
+ x: s.x,
279
+ y: s.y,
280
+ value: s.value,
281
+ angle: s.angle,
282
+ categoryIndex: s.categoryIndex
283
+ }));
284
+ const basePoints = stateList[0].hasBase ? stateList.map((s) => ({
285
+ x: s.baseX,
286
+ y: s.baseY,
287
+ value: s.baseValue,
288
+ angle: s.angle,
289
+ categoryIndex: s.categoryIndex
290
+ })) : void 0;
291
+ let fillOpacity = targetSd.fillOpacity;
292
+ let lineStrokeWidth = targetSd.lineStrokeWidth;
293
+ const fade = ctx._seriesFades.get(targetSd.id);
294
+ if (fade) {
295
+ if (fade.startTime === -1) fade.startTime = now;
296
+ const lerped = lerpSeriesFade(fade, now);
297
+ fillOpacity = lerped.fillOpacity;
298
+ lineStrokeWidth = lerped.lineStrokeWidth;
299
+ } else if (!targetSd.visible) {
300
+ const settled = ctx._seriesSettledStyle.get(targetSd.id);
301
+ if (settled) {
302
+ fillOpacity = settled.fillOpacity;
303
+ lineStrokeWidth = settled.lineStrokeWidth;
304
+ }
305
+ }
306
+ const overrides = ctx._propertyOverrides.get(targetSd.id);
307
+ if (overrides) {
308
+ if (typeof overrides.fillOpacity === "number") fillOpacity = overrides.fillOpacity;
309
+ if (typeof overrides.lineStrokeWidth === "number") lineStrokeWidth = overrides.lineStrokeWidth;
310
+ }
311
+ series.push({
312
+ ...targetSd,
313
+ points,
314
+ basePoints,
315
+ visible: true,
316
+ // keep drawn during exit; opacity carries the fade
317
+ fillOpacity,
318
+ lineStrokeWidth
319
+ });
320
+ }
321
+ let grid = ctx._layout.grid;
322
+ let gridAnimating = false;
323
+ if (ctx._gridLerp) {
324
+ if (ctx._gridLerp.startTime === -1) ctx._gridLerp.startTime = now;
325
+ const elapsed = now - ctx._gridLerp.startTime;
326
+ const raw = Math.max(0, Math.min(1, elapsed / ctx._gridLerp.duration));
327
+ const p = ctx._gridLerp.easing(raw);
328
+ grid = interpolateRadialGrid(ctx._gridLerp.fromDomain, ctx._gridLerp.toDomain, ctx._gridLerp.targetGrid, ctx._gridLerp.targetRadius, p);
329
+ gridAnimating = true;
330
+ if (raw >= 1) {
331
+ ctx._lastSettledDomain = ctx._gridLerp.toDomain;
332
+ ctx._gridLerp = null;
333
+ }
334
+ }
335
+ return { ...ctx._layout, series, grid, gridAnimating };
336
+ }
337
+ function renderSceneFrame(ctx) {
338
+ const layout = buildLayoutFromScene(ctx, performance.now());
339
+ if (!layout || !ctx.lastInput) return;
340
+ ctx.lastRenderedLayout = layout;
341
+ setMarkerData(ctx, { layout, entries: ctx._entries });
342
+ if (ctx.lastInput.renderer === "svg" && ctx.svgGroup) {
343
+ renderToSvg(ctx, ctx.svgGroup, layout, ctx._entries, ctx.lastInput);
344
+ } else if (ctx.lastInput.renderer === "canvas") {
345
+ ctx.lastInput.requestRedraw?.();
346
+ }
347
+ }
348
+ function startAnimLoop(ctx) {
349
+ if (ctx._animRafId !== null) {
350
+ cancelRaf(ctx._animRafId);
351
+ }
352
+ const tick = (now) => {
353
+ ctx._animRafId = null;
354
+ const { allIdle } = ctx._scene.tick(now);
355
+ for (const [seriesId, fade] of [...ctx._seriesFades]) {
356
+ if (fade.startTime === -1) continue;
357
+ const elapsed = now - fade.startTime;
358
+ const raw = elapsed / Math.max(1, fade.duration);
359
+ if (raw >= 1) {
360
+ ctx._seriesSettledStyle.set(seriesId, {
361
+ fillOpacity: fade.toFillOpacity,
362
+ lineStrokeWidth: fade.toLineStrokeWidth
363
+ });
364
+ ctx._seriesFades.delete(seriesId);
365
+ }
366
+ }
367
+ renderSceneFrame(ctx);
368
+ ctx.onFrame?.();
369
+ const fadesActive = ctx._seriesFades.size > 0;
370
+ if (!allIdle || ctx._gridLerp !== null || fadesActive) {
371
+ ctx._animRafId = raf(tick);
372
+ }
373
+ };
374
+ ctx._animRafId = raf(tick);
375
+ }
376
+ function setMarkerData(ctx, data) {
377
+ ctx._markerData = data;
378
+ ctx.onMarkerDataChange?.(data);
379
+ }
380
+
381
+ // src/series/radar/controller/index.ts
382
+ function buildPerAxisDomains(entries, yAxes) {
383
+ if (!yAxes || yAxes.size === 0) return void 0;
384
+ const result = /* @__PURE__ */ new Map();
385
+ for (const [axisId, axis] of yAxes) {
386
+ const rawMin = axis.props.min;
387
+ const rawMax = axis.props.max;
388
+ const explicitMin = typeof rawMin === "number" ? rawMin : void 0;
389
+ const explicitMax = typeof rawMax === "number" ? rawMax : void 0;
390
+ const axisValues = [];
391
+ for (const ds of entries) {
392
+ if (!ds.visible) continue;
393
+ if (ds.props.yAxisId !== axisId) continue;
394
+ const data = ds.props.data;
395
+ const valueField = ds.props.valueField ?? FIELD_DEFAULTS.valueField;
396
+ if (!data || !valueField) continue;
397
+ for (let i = 0; i < data.length; i++) {
398
+ const item = data[i];
399
+ const v = typeof valueField === "function" ? valueField(makeItemContext(item, i)) : item[valueField];
400
+ if (typeof v === "number" && isFinite(v)) axisValues.push(v);
401
+ }
402
+ }
403
+ let domainMin;
404
+ let domainMax;
405
+ if (explicitMin !== void 0 && explicitMax !== void 0) {
406
+ domainMin = explicitMin;
407
+ domainMax = explicitMax;
408
+ } else {
409
+ const auto = axisValues.length ? calculateNiceDomain(axisValues, { includeZero: true, nice: true }) : [0, 1];
410
+ domainMin = explicitMin ?? auto[0];
411
+ domainMax = explicitMax ?? auto[1];
412
+ }
413
+ result.set(axisId, [domainMin, domainMax]);
414
+ }
415
+ return result.size ? result : void 0;
416
+ }
417
+ function buildPerSpokeDomains(entries, yAxes, categories, isStacked) {
418
+ if (!yAxes || yAxes.size === 0 || categories.length === 0) return void 0;
419
+ const yAxisByCategory = /* @__PURE__ */ new Map();
420
+ for (const axis of yAxes.values()) {
421
+ const cat = axis.props.category;
422
+ if (typeof cat === "string" && cat.length > 0) yAxisByCategory.set(cat, axis);
423
+ }
424
+ if (yAxisByCategory.size === 0) return void 0;
425
+ const valuesPerSpoke = categories.map(() => []);
426
+ if (isStacked) {
427
+ const stackedPerSpoke = new Array(categories.length).fill(0);
428
+ for (const ds of entries) {
429
+ if (!ds.visible) continue;
430
+ const data = ds.props.data;
431
+ const valueField = ds.props.valueField ?? FIELD_DEFAULTS.valueField;
432
+ const categoryField = ds.props.categoryField ?? FIELD_DEFAULTS.categoryField;
433
+ if (!data || !valueField || !categoryField) continue;
434
+ for (let i = 0; i < data.length; i++) {
435
+ const item = data[i];
436
+ const cat = typeof categoryField === "function" ? categoryField(makeItemContext(item, i)) : item[categoryField];
437
+ const v = typeof valueField === "function" ? valueField(makeItemContext(item, i)) : item[valueField];
438
+ const ci = categories.indexOf(cat);
439
+ if (ci < 0) continue;
440
+ if (typeof v !== "number" || !isFinite(v)) continue;
441
+ stackedPerSpoke[ci] += v;
442
+ }
443
+ }
444
+ for (let ci = 0; ci < categories.length; ci++) valuesPerSpoke[ci].push(stackedPerSpoke[ci]);
445
+ } else {
446
+ for (const ds of entries) {
447
+ if (!ds.visible) continue;
448
+ const data = ds.props.data;
449
+ const valueField = ds.props.valueField ?? FIELD_DEFAULTS.valueField;
450
+ const categoryField = ds.props.categoryField ?? FIELD_DEFAULTS.categoryField;
451
+ if (!data || !valueField || !categoryField) continue;
452
+ for (let i = 0; i < data.length; i++) {
453
+ const item = data[i];
454
+ const cat = typeof categoryField === "function" ? categoryField(makeItemContext(item, i)) : item[categoryField];
455
+ const v = typeof valueField === "function" ? valueField(makeItemContext(item, i)) : item[valueField];
456
+ const ci = categories.indexOf(cat);
457
+ if (ci < 0) continue;
458
+ if (typeof v !== "number" || !isFinite(v)) continue;
459
+ valuesPerSpoke[ci].push(v);
460
+ }
461
+ }
462
+ }
463
+ const result = /* @__PURE__ */ new Map();
464
+ for (let ci = 0; ci < categories.length; ci++) {
465
+ const declared = yAxisByCategory.get(categories[ci]);
466
+ const rawMin = declared ? declared.props.min : void 0;
467
+ const rawMax = declared ? declared.props.max : void 0;
468
+ const explicitMin = typeof rawMin === "number" ? rawMin : void 0;
469
+ const explicitMax = typeof rawMax === "number" ? rawMax : void 0;
470
+ let domainMin;
471
+ let domainMax;
472
+ if (explicitMin !== void 0 && explicitMax !== void 0) {
473
+ domainMin = explicitMin;
474
+ domainMax = explicitMax;
475
+ } else {
476
+ const auto = valuesPerSpoke[ci].length ? calculateNiceDomain(valuesPerSpoke[ci], { includeZero: true, nice: true }) : [0, 1];
477
+ domainMin = explicitMin ?? auto[0];
478
+ domainMax = explicitMax ?? auto[1];
479
+ }
480
+ result.set(ci, [domainMin, domainMax]);
481
+ }
482
+ return result;
483
+ }
484
+ var RadarRendererController = class {
485
+ constructor(paint) {
486
+ this._animRafId = null;
487
+ this._lastFingerprint = "";
488
+ /**
489
+ * Per-dataset property-animation overrides resolved from AnimatedPropertyStore.
490
+ * Set by `applyPropertyAnimations()` each property-animation tick and merged
491
+ * into the rendered output at two places:
492
+ * - `_buildLayoutFromScene` — fields that live on RadarSeriesData
493
+ * (fillOpacity, lineStrokeWidth) get merged into the per-frame layout.
494
+ * - `renderToSvg` / `renderCanvasContent` / `applyHover` — fields that
495
+ * the renderers read directly from `ds.props` (markerSize,
496
+ * borderStrokeWidth, lineDashOffset, opacity, tension) get spread onto
497
+ * a shim props object passed to the radar renderers.
498
+ *
499
+ * Tension note: radar's SVG children are rebuilt from the descriptor tree on
500
+ * every `_renderSceneFrame` — a full render goes through
501
+ * `replaceChildren(...buildRadarSvgChildren(...).map(materializeSvgNode))`,
502
+ * while hover diffs the same descriptors through `reconcileSvgChildren`. Either
503
+ * way the path `d` attribute is recomputed from the rebuilt descriptors when
504
+ * `tension` changes — no surgical `setAttribute('d', …)` patching is needed
505
+ * (unlike Line, whose SVG DOM is segmented per-dataset and patched in-place).
506
+ */
507
+ this._propertyOverrides = /* @__PURE__ */ new Map();
508
+ // First-render flag: lets emptyState collapse to center on first diff (matches
509
+ // createRadarEntranceLayout). After first diff, emptyState collapses to base
510
+ // (matches toggle-on "ring inflates from base").
511
+ this._firstRender = true;
512
+ // Captured before each diff() so the emptyState closure can read center.
513
+ this._activeCenter = { x: 0, y: 0 };
514
+ // Per-series opacity fade for stacked enter/exit. Non-stacked series don't fade.
515
+ this._seriesFades = /* @__PURE__ */ new Map();
516
+ // Last settled (non-fading) per-series fill/stroke values. Used as the
517
+ // starting point for the next fade.
518
+ this._seriesSettledStyle = /* @__PURE__ */ new Map();
519
+ // Grid lerp (radial axis rings + tick labels).
520
+ this._gridLerp = null;
521
+ this._lastSettledDomain = null;
522
+ // Target layout (reference; bars/points come from the scene per-frame).
523
+ this._layout = null;
524
+ // Last frame's rendered layout (read by hover repaint, hit-testing, grid consumers).
525
+ this.lastRenderedLayout = null;
526
+ this._entries = [];
527
+ this.hoverState = { datasetId: null, index: null };
528
+ this.effectConfig = { hoverBrightness: 1, dimOpacity: 1 };
529
+ this.lastInput = null;
530
+ this.svgGroup = null;
531
+ this._hasRadarDatasets = false;
532
+ this._markerData = null;
533
+ this.onFrame = null;
534
+ this.onMarkerDataChange = null;
535
+ this._paint = paint;
536
+ this._scene = new AnimatedScene({
537
+ // ENTER: on the very first diff, collapse outer + base both to center
538
+ // (matches createRadarEntranceLayout's "all points at center, value=0").
539
+ // After the first diff, collapse outer to base (matches toggle-on
540
+ // "stacked ring inflates from base"; non-stacked has baseX=center.x).
541
+ emptyState: (target) => {
542
+ if (this._firstRender) {
543
+ return {
544
+ ...target,
545
+ x: this._activeCenter.x,
546
+ y: this._activeCenter.y,
547
+ value: 0,
548
+ baseX: this._activeCenter.x,
549
+ baseY: this._activeCenter.y,
550
+ baseValue: 0
551
+ };
552
+ }
553
+ return { ...target, x: target.baseX, y: target.baseY, value: 0 };
554
+ },
555
+ // EXIT: collapse outer to base. For stacked this is the inner ring boundary;
556
+ // for non-stacked, baseX/baseY === center.x/center.y so collapse → center.
557
+ exitEmptyState: (target) => ({ ...target, x: target.baseX, y: target.baseY, value: 0 }),
558
+ registry: RADAR_POINT_REGISTRY
559
+ });
560
+ }
561
+ // ================================================================
562
+ // PUBLIC API
563
+ // ================================================================
564
+ update(input) {
565
+ this.lastInput = input;
566
+ this.svgGroup = input.svgGroup ?? null;
567
+ const { datasets, datasetVisibility, chartArea, features, globalFont, sharedContext, yAxes } = input;
568
+ this._hasRadarDatasets = Array.from(datasets.values()).some((ds) => ds.type === "radar");
569
+ if (!this._hasRadarDatasets) {
570
+ this._fullReset();
571
+ return;
572
+ }
573
+ const sortedDatasets = Array.from(datasets.entries()).sort(([, a], [, b]) => a.order - b.order);
574
+ const radarEntries = collectItems(sortedDatasets, datasetVisibility).radar;
575
+ if (radarEntries.length === 0) {
576
+ this._fullReset();
577
+ return;
578
+ }
579
+ this._entries = radarEntries;
580
+ const anyVisible = radarEntries.some((e) => e.visible);
581
+ if (!anyVisible) {
582
+ this._runAllHidden(features);
583
+ return;
584
+ }
585
+ const perAxisDomains = buildPerAxisDomains(radarEntries, yAxes);
586
+ const sharedCategoriesForDomain = sharedContext?.categories ?? Array.from(
587
+ new Set(
588
+ radarEntries.flatMap((ds) => {
589
+ const data = ds.props.data;
590
+ const cf = ds.props.categoryField;
591
+ if (!data || !cf) return [];
592
+ return data.map((item, i) => typeof cf === "function" ? cf(makeItemContext(item, i)) : item[cf]);
593
+ })
594
+ )
595
+ );
596
+ const isStacked = radarEntries.some((ds) => !!ds.props.stackId);
597
+ const perSpokeDomains = buildPerSpokeDomains(radarEntries, yAxes, sharedCategoriesForDomain, isStacked);
598
+ const referenceBoundaryValues = [];
599
+ for (const [key, feat] of features) {
600
+ if (typeof key === "string" && key.startsWith("referenceBand:")) {
601
+ const bp = feat.props;
602
+ if (bp.y1 != null) referenceBoundaryValues.push(bp.y1);
603
+ if (bp.y2 != null) referenceBoundaryValues.push(bp.y2);
604
+ } else if (typeof key === "string" && key.startsWith("referenceLine:")) {
605
+ const lp = feat.props;
606
+ if (lp.y != null) referenceBoundaryValues.push(lp.y);
607
+ }
608
+ }
609
+ const defaultYAxis = yAxes ? Array.from(yAxes.values()).find((a) => !a.props.category) : void 0;
610
+ const yAxisProps = defaultYAxis?.props;
611
+ const baseLayout = calculateRadarLayout(radarEntries, chartArea, globalFont, sharedContext?.categories, sharedContext?.domain, perAxisDomains, referenceBoundaryValues, perSpokeDomains, yAxisProps?.tickCount);
612
+ if (yAxisProps) {
613
+ const g = baseLayout.grid;
614
+ if (yAxisProps.gridShape) g.shape = yAxisProps.gridShape;
615
+ if (yAxisProps.gridColor !== void 0) g.color = yAxisProps.gridColor;
616
+ if (yAxisProps.gridOpacity !== void 0) g.opacity = yAxisProps.gridOpacity;
617
+ if (yAxisProps.gridStrokeWidth !== void 0) g.width = yAxisProps.gridStrokeWidth;
618
+ if (yAxisProps.gridStyle !== void 0) g.style = yAxisProps.gridStyle;
619
+ }
620
+ const targetLayout = {
621
+ ...baseLayout,
622
+ datasetIndex: 0
623
+ };
624
+ this._layout = targetLayout;
625
+ this._activeCenter = targetLayout.center;
626
+ const animConfig = features.get("animation")?.props;
627
+ const { enabled: animEnabled, duration, easing } = parseAnimationConfig(animConfig);
628
+ const fingerprint = buildRadarFingerprint(targetLayout, radarEntries);
629
+ const dataChanged = fingerprint !== this._lastFingerprint;
630
+ const shouldAnimate = animEnabled && duration > 0 && dataChanged;
631
+ if (!dataChanged) return;
632
+ if (this._animRafId !== null) {
633
+ cancelRaf(this._animRafId);
634
+ this._animRafId = null;
635
+ }
636
+ const sceneTargets = /* @__PURE__ */ new Map();
637
+ for (const sd of targetLayout.series) {
638
+ if (!sd.visible) continue;
639
+ const hasBase = !!sd.basePoints && sd.basePoints.length > 0;
640
+ for (let pi = 0; pi < sd.points.length; pi++) {
641
+ const p = sd.points[pi];
642
+ const base = hasBase ? sd.basePoints[pi] : null;
643
+ sceneTargets.set(pointKey(sd.id, p.categoryIndex), {
644
+ x: p.x,
645
+ y: p.y,
646
+ value: p.value,
647
+ baseX: base ? base.x : targetLayout.center.x,
648
+ baseY: base ? base.y : targetLayout.center.y,
649
+ baseValue: base ? base.value : 0,
650
+ seriesId: sd.id,
651
+ categoryIndex: p.categoryIndex,
652
+ angle: p.angle,
653
+ hasBase
654
+ });
655
+ }
656
+ }
657
+ const opts = { numbers: { duration: shouldAnimate ? duration : 0, easing } };
658
+ this._scene.diff(sceneTargets, opts);
659
+ this._lastFingerprint = fingerprint;
660
+ const now = performance.now();
661
+ for (const sd of targetLayout.series) {
662
+ const hasBase = !!sd.basePoints && sd.basePoints.length > 0;
663
+ const settled = this._seriesSettledStyle.get(sd.id);
664
+ if (!hasBase) {
665
+ this._seriesFades.delete(sd.id);
666
+ this._seriesSettledStyle.set(sd.id, { fillOpacity: sd.fillOpacity, lineStrokeWidth: sd.lineStrokeWidth });
667
+ continue;
668
+ }
669
+ const targetFill = sd.visible ? sd.fillOpacity : 0;
670
+ const targetStroke = sd.visible ? sd.lineStrokeWidth : 0;
671
+ const settledFill = settled?.fillOpacity ?? 0;
672
+ const settledStroke = settled?.lineStrokeWidth ?? 0;
673
+ if (Math.abs(settledFill - targetFill) < 1e-3 && Math.abs(settledStroke - targetStroke) < 1e-3) {
674
+ this._seriesFades.delete(sd.id);
675
+ if (sd.visible) {
676
+ this._seriesSettledStyle.set(sd.id, { fillOpacity: sd.fillOpacity, lineStrokeWidth: sd.lineStrokeWidth });
677
+ }
678
+ continue;
679
+ }
680
+ if (!shouldAnimate) {
681
+ this._seriesFades.delete(sd.id);
682
+ this._seriesSettledStyle.set(sd.id, { fillOpacity: targetFill, lineStrokeWidth: targetStroke });
683
+ continue;
684
+ }
685
+ let fromFill = settledFill;
686
+ let fromStroke = settledStroke;
687
+ const existing = this._seriesFades.get(sd.id);
688
+ if (existing) {
689
+ const lerped = lerpSeriesFade(existing, now);
690
+ fromFill = lerped.fillOpacity;
691
+ fromStroke = lerped.lineStrokeWidth;
692
+ }
693
+ this._seriesFades.set(sd.id, {
694
+ fromFillOpacity: fromFill,
695
+ toFillOpacity: targetFill,
696
+ fromLineStrokeWidth: fromStroke,
697
+ toLineStrokeWidth: targetStroke,
698
+ startTime: -1,
699
+ duration,
700
+ easing
701
+ });
702
+ }
703
+ const liveSeriesIds = new Set(targetLayout.series.map((s) => s.id));
704
+ for (const id of [...this._seriesFades.keys()]) {
705
+ if (!liveSeriesIds.has(id)) this._seriesFades.delete(id);
706
+ }
707
+ this._updateGridLerp(targetLayout, shouldAnimate, duration, easing, yAxisProps?.tickCount);
708
+ if (shouldAnimate) {
709
+ this._renderSceneFrame();
710
+ this._startAnimLoop();
711
+ } else {
712
+ this._scene.tick(performance.now());
713
+ this._renderSceneFrame();
714
+ }
715
+ this._firstRender = false;
716
+ }
717
+ applyHover(hover) {
718
+ const hoverConfig = this.lastInput?.hoverConfig;
719
+ this.hoverState = { datasetId: hover.datasetId, index: hover.index, axisIndex: hover.axisIndex ?? null };
720
+ this.effectConfig = hoverConfig ? { hoverBrightness: hoverConfig.brightness ?? DEFAULT_HOVER_BRIGHTNESS, dimOpacity: hoverConfig.dimOpacity ?? DEFAULT_HOVER_DIM_OPACITY } : { hoverBrightness: 1, dimOpacity: 1 };
721
+ const layout = this.lastRenderedLayout ?? this._layout;
722
+ if (!layout || this._entries.length === 0 || !this.lastInput) return;
723
+ if (this.lastInput.renderer === "svg" && this.svgGroup) {
724
+ if (this._animRafId !== null) return;
725
+ reconcileSvgChildren(this.svgGroup, buildRadarSvgChildren(this, layout, this._entries, this.lastInput));
726
+ } else if (this.lastInput.renderer === "canvas") {
727
+ this.lastInput.requestRedraw?.();
728
+ }
729
+ }
730
+ hitTest(x, y) {
731
+ if (!this._layout) return null;
732
+ return hitTestRadar(x, y, this._layout, this.lastInput?.theme ?? defaultLightTheme);
733
+ }
734
+ /**
735
+ * Shared-mode lookup: snap to the nearest spoke (categoryIndex) by angle and
736
+ * return every series' point at that spoke as `allSeries` (parity with
737
+ * cartesian bar/line shared tooltip).
738
+ */
739
+ findAllNearest(x, y) {
740
+ const layout = this.lastRenderedLayout ?? this._layout;
741
+ if (!layout || layout.series.length === 0 || layout.categories.length === 0) return null;
742
+ const dx = x - layout.center.x;
743
+ const dy = y - layout.center.y;
744
+ const dist = Math.sqrt(dx * dx + dy * dy);
745
+ if (dist > layout.radius * 1.15) return null;
746
+ let cursorAngle = Math.atan2(dx, -dy) * (180 / Math.PI);
747
+ if (cursorAngle < 0) cursorAngle += 360;
748
+ const angleStep = 360 / layout.categories.length;
749
+ const categoryIndex = Math.round(cursorAngle / angleStep) % layout.categories.length;
750
+ const label = layout.categories[categoryIndex] ?? "";
751
+ const allSeries = [];
752
+ let primary = null;
753
+ let bestDist = Infinity;
754
+ for (const sd of layout.series) {
755
+ if (!sd.visible) continue;
756
+ const pt = sd.points.find((p) => p.categoryIndex === categoryIndex);
757
+ if (!pt) continue;
758
+ allSeries.push({
759
+ datasetId: sd.id,
760
+ name: sd.name,
761
+ label,
762
+ color: sd.color ?? (sd.gradientColor ? getPrimaryColor(sd.gradientColor) : getDefaultColor(sd.seriesIdx, this.lastInput?.theme ?? defaultLightTheme)),
763
+ colorGradient: sd.gradientColor,
764
+ swatchColor: resolveSwatchColor({ color: sd.color ?? sd.gradientColor }, sd.seriesIdx, void 0, this.lastInput?.theme),
765
+ value: pt.value,
766
+ formattedValue: String(pt.value),
767
+ cursorFormattedValue: String(pt.value),
768
+ snapPixel: Math.sqrt((pt.x - layout.center.x) ** 2 + (pt.y - layout.center.y) ** 2)
769
+ });
770
+ const d = Math.sqrt((pt.x - x) ** 2 + (pt.y - y) ** 2);
771
+ if (d < bestDist) {
772
+ bestDist = d;
773
+ primary = {
774
+ datasetId: sd.id,
775
+ index: categoryIndex,
776
+ label,
777
+ value: pt.value,
778
+ color: sd.color ?? (sd.gradientColor ? getPrimaryColor(sd.gradientColor) : getDefaultColor(sd.seriesIdx, this.lastInput?.theme ?? defaultLightTheme)),
779
+ colorGradient: sd.gradientColor,
780
+ swatchColor: resolveSwatchColor({ color: sd.color ?? sd.gradientColor }, sd.seriesIdx, void 0, this.lastInput?.theme)
781
+ };
782
+ }
783
+ }
784
+ if (!primary) return null;
785
+ return { primary, allSeries };
786
+ }
787
+ renderCanvasContent(ctx) {
788
+ renderCanvasContent(this, ctx);
789
+ }
790
+ get hasData() {
791
+ return this._hasRadarDatasets;
792
+ }
793
+ get layout() {
794
+ return this.lastRenderedLayout ?? this._layout;
795
+ }
796
+ get markerData() {
797
+ return this._markerData;
798
+ }
799
+ destroy() {
800
+ if (this._animRafId !== null) {
801
+ cancelRaf(this._animRafId);
802
+ this._animRafId = null;
803
+ }
804
+ this._scene.reset();
805
+ this._seriesFades.clear();
806
+ this._seriesSettledStyle.clear();
807
+ this._gridLerp = null;
808
+ this._propertyOverrides.clear();
809
+ }
810
+ /**
811
+ * Apply animated property values without triggering a full layout cycle.
812
+ * Called from the property-animation framework wrapper (RadialRenderer)
813
+ * each animation tick.
814
+ *
815
+ * Per-dataset: writes overrides into `_propertyOverrides` (or deletes the
816
+ * entry when the store has no live values for it), then triggers a frame
817
+ * rebuild so `_buildLayoutFromScene` re-merges into the rendered series
818
+ * and `renderToSvg` / `renderCanvasContent` see the merged props.
819
+ *
820
+ * SVG: re-renders imperatively via `_renderSceneFrame`. The wholesale
821
+ * DOM rebuild covers the `tension` path-rebuild concern — when tension
822
+ * changes, `buildSmoothPath` / `buildPointsPath` get called fresh by the
823
+ * next `renderToSvg` pass. Canvas: calls `requestRedraw` so the canvas
824
+ * pipeline repaints with the merged props baked in.
825
+ */
826
+ applyPropertyAnimations(store) {
827
+ const layout = this._layout;
828
+ const input = this.lastInput;
829
+ if (!layout || !input) return;
830
+ let appliedAny = false;
831
+ for (const sd of layout.series) {
832
+ const overrides = resolveAnimatedProps(store, "radar", sd.id, RADAR_ANIMATABLE_PROPS);
833
+ if (Object.keys(overrides).length === 0) {
834
+ if (this._propertyOverrides.delete(sd.id)) appliedAny = true;
835
+ continue;
836
+ }
837
+ appliedAny = true;
838
+ this._propertyOverrides.set(sd.id, overrides);
839
+ }
840
+ if (!appliedAny) return;
841
+ this._renderSceneFrame();
842
+ }
843
+ /**
844
+ * Full re-render of the current scene state.
845
+ *
846
+ * Used by the property-animation framework wrapper: when a property
847
+ * animation completes and its override is released from the store,
848
+ * `_renderSceneFrame()` rebuilds the series from `_propertyOverrides`-
849
+ * cleared base values so SVG attributes snap back to the layout-derived
850
+ * defaults.
851
+ */
852
+ renderFrameCycle() {
853
+ this._renderSceneFrame();
854
+ }
855
+ // ================================================================
856
+ // PRIVATE — delegators to scene / paint sibling modules
857
+ // ================================================================
858
+ _fullReset() {
859
+ fullReset(this);
860
+ }
861
+ _runAllHidden(features) {
862
+ runAllHidden(this, features);
863
+ }
864
+ _updateGridLerp(targetLayout, shouldAnimate, duration, easing, tickCount) {
865
+ updateGridLerp(this, targetLayout, shouldAnimate, duration, easing, tickCount);
866
+ }
867
+ _currentGridDomain() {
868
+ return currentGridDomain(this);
869
+ }
870
+ _buildLayoutFromScene(now) {
871
+ return buildLayoutFromScene(this, now);
872
+ }
873
+ _renderSceneFrame() {
874
+ renderSceneFrame(this);
875
+ }
876
+ _startAnimLoop() {
877
+ startAnimLoop(this);
878
+ }
879
+ setMarkerData(data) {
880
+ setMarkerData(this, data);
881
+ }
882
+ buildRadarSvgChildren(layout, entries, input) {
883
+ return buildRadarSvgChildren(this, layout, entries, input);
884
+ }
885
+ renderToSvg(group, layout, entries, input) {
886
+ renderToSvg(this, group, layout, entries, input);
887
+ }
888
+ };
889
+
890
+ export { RadarRendererController };