@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 { computeDrillOutOrigin, computeZoomTransform } from './chunk-AGU3NG6D.mjs';
2
+ import { AnimatedScene, resolveAnimatedProps, TREEMAP_ANIMATABLE_PROPS } from './chunk-VN7CKCSE.mjs';
3
+ import { getCellLabelInfo } from './chunk-XIHBK5D3.mjs';
4
+ import { calculateTreemapLayout } from './chunk-VVI3OBPJ.mjs';
5
+ import { reconcileSvgChildren } from './chunk-KP2TWD4Z.mjs';
6
+ import { parseAnimationConfig, getEasing } from './chunk-3WEMHXZI.mjs';
7
+ import { raf, cancelRaf } from './chunk-EDAKJLNA.mjs';
8
+ import { buildAccessibilityRenderContext, generateSeriesDescription } from './chunk-OGJ6IIBW.mjs';
9
+ import { CHAR_WIDTH_RATIO } from './chunk-XTVE4P3L.mjs';
10
+ import { buildAncestorChain } from './chunk-WA3OVISZ.mjs';
11
+ import { configureCanvasHiDPI, materializeSvgNode, setAttr } from './chunk-SSLTFJ3U.mjs';
12
+
13
+ // src/series/treemap/controller/helpers.ts
14
+ function buildTreemapDataFingerprint(layouts) {
15
+ const parts = [];
16
+ for (const [id, { layout }] of layouts) {
17
+ const cellsDigest = layout.cells.map((c) => `${c.nodeId ?? c.index}=${c.value}`).join(",");
18
+ parts.push(`${id}:${layout.cells.length}:${cellsDigest}`);
19
+ }
20
+ return parts.join("|");
21
+ }
22
+ function buildTreemapChartAreaKey(chartArea) {
23
+ return `${chartArea.x},${chartArea.y},${chartArea.width},${chartArea.height}`;
24
+ }
25
+ function buildCellSceneTargets(layouts) {
26
+ const targets = /* @__PURE__ */ new Map();
27
+ for (const [datasetId, layout] of layouts) {
28
+ for (const cell of layout.cells) {
29
+ if (!cell.nodeId) continue;
30
+ const id = `${datasetId}::${cell.nodeId}`;
31
+ targets.set(id, {
32
+ x: cell.x,
33
+ y: cell.y,
34
+ width: cell.width,
35
+ height: cell.height,
36
+ color: cell.color,
37
+ label: cell.label,
38
+ secondaryLabel: cell.secondaryLabel,
39
+ value: cell.value,
40
+ index: cell.index,
41
+ nodeId: cell.nodeId,
42
+ hasChildren: cell.hasChildren ?? false,
43
+ depth: cell.depth ?? 0,
44
+ parentId: cell.parentId,
45
+ // Snap-only styling carriers — populated by renderer-time
46
+ // derivation, defaulted here since TreemapCell does not
47
+ // carry these fields directly.
48
+ opacity: 1,
49
+ borderColor: "",
50
+ borderStroke: 0,
51
+ borderDash: void 0
52
+ });
53
+ }
54
+ }
55
+ return targets;
56
+ }
57
+ function buildGroupBgSceneTargets(layouts) {
58
+ const targets = /* @__PURE__ */ new Map();
59
+ for (const [datasetId, layout] of layouts) {
60
+ for (const bg of layout.groupBackgrounds) {
61
+ const id = `${datasetId}::${bg.nodeId}`;
62
+ targets.set(id, {
63
+ x: bg.x,
64
+ y: bg.y,
65
+ width: bg.width,
66
+ height: bg.height,
67
+ color: bg.color,
68
+ label: bg.label,
69
+ value: bg.value,
70
+ index: bg.index,
71
+ nodeId: bg.nodeId,
72
+ depth: bg.depth
73
+ });
74
+ }
75
+ }
76
+ return targets;
77
+ }
78
+ function projectTreemapSceneFrame(cellScene, groupBgScene, targetLayouts) {
79
+ const targetCellByDataset = /* @__PURE__ */ new Map();
80
+ const targetBgByDataset = /* @__PURE__ */ new Map();
81
+ for (const [datasetId, layout] of targetLayouts) {
82
+ const cellMap = /* @__PURE__ */ new Map();
83
+ for (const c of layout.cells) {
84
+ if (c.nodeId) cellMap.set(c.nodeId, c);
85
+ }
86
+ targetCellByDataset.set(datasetId, cellMap);
87
+ const bgMap = /* @__PURE__ */ new Map();
88
+ for (const b of layout.groupBackgrounds) bgMap.set(b.nodeId, b);
89
+ targetBgByDataset.set(datasetId, bgMap);
90
+ }
91
+ const cellsByDataset = /* @__PURE__ */ new Map();
92
+ for (const el of cellScene.getElements()) {
93
+ const s = el.current;
94
+ const sep = el.id.indexOf("::");
95
+ if (sep < 0) continue;
96
+ const datasetId = el.id.slice(0, sep);
97
+ const targetCell = targetCellByDataset.get(datasetId)?.get(s.nodeId);
98
+ const cell = {
99
+ ...targetCell ?? {},
100
+ x: s.x,
101
+ y: s.y,
102
+ width: s.width,
103
+ height: s.height,
104
+ color: s.color,
105
+ label: s.label,
106
+ secondaryLabel: s.secondaryLabel,
107
+ value: s.value,
108
+ index: s.index,
109
+ nodeId: s.nodeId,
110
+ hasChildren: s.hasChildren,
111
+ depth: s.depth,
112
+ parentId: s.parentId
113
+ };
114
+ let arr = cellsByDataset.get(datasetId);
115
+ if (!arr) {
116
+ arr = [];
117
+ cellsByDataset.set(datasetId, arr);
118
+ }
119
+ arr.push(cell);
120
+ }
121
+ const bgsByDataset = /* @__PURE__ */ new Map();
122
+ for (const el of groupBgScene.getElements()) {
123
+ const s = el.current;
124
+ const sep = el.id.indexOf("::");
125
+ if (sep < 0) continue;
126
+ const datasetId = el.id.slice(0, sep);
127
+ const targetBg = targetBgByDataset.get(datasetId)?.get(s.nodeId);
128
+ const bg = {
129
+ ...targetBg ?? {},
130
+ x: s.x,
131
+ y: s.y,
132
+ width: s.width,
133
+ height: s.height,
134
+ color: s.color,
135
+ label: s.label,
136
+ value: s.value,
137
+ index: s.index,
138
+ nodeId: s.nodeId,
139
+ depth: s.depth
140
+ };
141
+ let arr = bgsByDataset.get(datasetId);
142
+ if (!arr) {
143
+ arr = [];
144
+ bgsByDataset.set(datasetId, arr);
145
+ }
146
+ arr.push(bg);
147
+ }
148
+ const frameLayouts = /* @__PURE__ */ new Map();
149
+ const datasetIds = /* @__PURE__ */ new Set([...targetLayouts.keys(), ...cellsByDataset.keys(), ...bgsByDataset.keys()]);
150
+ for (const datasetId of datasetIds) {
151
+ const targetLayout = targetLayouts.get(datasetId);
152
+ if (!targetLayout) continue;
153
+ const liveCells = cellsByDataset.get(datasetId) ?? [];
154
+ const liveBgs = bgsByDataset.get(datasetId) ?? [];
155
+ liveCells.sort((a, b) => a.index - b.index);
156
+ liveBgs.sort((a, b) => a.depth - b.depth);
157
+ frameLayouts.set(datasetId, {
158
+ ...targetLayout,
159
+ cells: liveCells,
160
+ groupBackgrounds: liveBgs
161
+ });
162
+ }
163
+ return frameLayouts;
164
+ }
165
+
166
+ // src/series/treemap/controller/types.ts
167
+ var CELL_REGISTRY = {
168
+ number: ["x", "y", "width", "height"],
169
+ color: ["color"]
170
+ };
171
+ var GROUP_BG_REGISTRY = {
172
+ number: ["x", "y", "width", "height"],
173
+ color: ["color"]
174
+ };
175
+
176
+ // src/series/treemap/controller/ids.ts
177
+ function assignStableIds(ctx, props) {
178
+ if (!props.data || props.data.length === 0) return props;
179
+ const categoryField = props.categoryField ?? "label";
180
+ const nodeIdField = props.nodeId;
181
+ const annotated = props.data.map((item, itemIndex) => {
182
+ const src = item;
183
+ const id = resolveId(ctx, src, categoryField, nodeIdField, itemIndex);
184
+ return { ...src, id };
185
+ });
186
+ return { ...props, data: annotated };
187
+ }
188
+ function resolveId(ctx, item, categoryField, nodeIdField, itemIndex) {
189
+ if (nodeIdField) {
190
+ const userId = item[nodeIdField];
191
+ if (userId != null) return String(userId);
192
+ }
193
+ const label = item[categoryField];
194
+ const key = label != null && label !== "" ? String(label) : `__anon_pos_${itemIndex}`;
195
+ let id = ctx._syntheticIds.get(key);
196
+ if (!id) {
197
+ id = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : `__synthetic_${++ctx._syntheticIdCounter}`;
198
+ ctx._syntheticIds.set(key, id);
199
+ }
200
+ ctx._syntheticIdLastSeenTick.set(key, ctx._syntheticIdTickCounter);
201
+ return id;
202
+ }
203
+
204
+ // src/series/treemap/controller/paint.ts
205
+ function buildTreemapSvgChildren(params) {
206
+ const children = [];
207
+ for (const [dsId, { props, layout }] of params.layoutMap) {
208
+ const node = params.paint.renderSvg(props, layout, { ...params.fontContext, interaction: params.interaction });
209
+ setAttr(node, "data-dataset", dsId);
210
+ if (params.accessibility?.enabled && params.accessibility.landmarkVerbosity === "all") {
211
+ setAttr(node, "role", "region");
212
+ setAttr(node, "aria-label", generateSeriesDescription(props.name ?? dsId, "treemap", layout.cells.length));
213
+ }
214
+ children.push(node);
215
+ }
216
+ return children;
217
+ }
218
+ function renderSvgGroup(ctx, group, layoutMap, fontContext, interaction, accessibility) {
219
+ const children = buildTreemapSvgChildren({ paint: ctx._paint, layoutMap, fontContext, interaction, accessibility });
220
+ group.replaceChildren(...children.map(materializeSvgNode));
221
+ }
222
+ function renderAllCanvas(ctx, c2d, layoutMap, fontContext, interaction) {
223
+ for (const [, { props, layout }] of layoutMap) {
224
+ ctx._paint.renderCanvas(props, layout, c2d, { ...fontContext, interaction });
225
+ }
226
+ renderCanvasCustomContent(ctx, c2d);
227
+ }
228
+ function renderCanvasCustomContent(ctx, c2d) {
229
+ ctx._paint.renderCanvasContent(c2d, ctx._layouts, ctx.onImageLoad ?? (() => {
230
+ }));
231
+ }
232
+ function renderSceneFrame(ctx, targetLayouts) {
233
+ const frameLayouts = projectTreemapSceneFrame(ctx._cellScene, ctx._groupBgScene, targetLayouts);
234
+ ctx._lastRenderedLayout = frameLayouts;
235
+ return frameLayouts;
236
+ }
237
+ function repaintCanvas(ctx, input, layoutMap, fontContext, interaction) {
238
+ const c2d = ctx.canvasEl?.getContext("2d");
239
+ if (!c2d) return;
240
+ c2d.clearRect(0, 0, input.width, input.height);
241
+ renderAllCanvas(ctx, c2d, layoutMap, fontContext, interaction);
242
+ const groupNodeId = ctx.hoveredGroupNodeId;
243
+ if (groupNodeId) {
244
+ for (const [, { layout }] of layoutMap) {
245
+ const bg = layout.groupBackgrounds.find((b) => b.nodeId === groupNodeId);
246
+ if (!bg) continue;
247
+ c2d.save();
248
+ c2d.fillStyle = "rgba(0,0,0,0.15)";
249
+ c2d.beginPath();
250
+ c2d.roundRect(bg.x, bg.y, bg.width, bg.height, 2);
251
+ c2d.fill();
252
+ c2d.strokeStyle = "rgba(255,255,255,0.6)";
253
+ c2d.lineWidth = 2;
254
+ c2d.beginPath();
255
+ c2d.roundRect(bg.x, bg.y, bg.width, bg.height, 2);
256
+ c2d.stroke();
257
+ c2d.restore();
258
+ break;
259
+ }
260
+ }
261
+ }
262
+ function applyHover(ctx, hover) {
263
+ const newIndex = hover.index;
264
+ if (newIndex === ctx._hoveredIndex) return;
265
+ ctx._hoveredIndex = newIndex;
266
+ const input = ctx.lastInput;
267
+ if (!input || ctx._layouts.size === 0) return;
268
+ const fontContext = { ...input.globalFont && { font: input.globalFont }, theme: input.theme };
269
+ const interaction = newIndex != null ? { hoveredIndex: newIndex } : void 0;
270
+ const liveLayoutMap = /* @__PURE__ */ new Map();
271
+ for (const [id, entry] of ctx._layouts) {
272
+ const liveLayout = ctx._lastRenderedLayout?.get(id) ?? entry.layout;
273
+ const overrides = ctx._propertyOverrides.get(id);
274
+ const mergedProps = overrides ? { ...entry.props, ...overrides } : entry.props;
275
+ liveLayoutMap.set(id, { props: mergedProps, layout: liveLayout });
276
+ }
277
+ if (input.renderer === "svg" && ctx.svgGroup) {
278
+ const children = buildTreemapSvgChildren({ paint: ctx._paint, layoutMap: liveLayoutMap, fontContext, interaction });
279
+ reconcileSvgChildren(ctx.svgGroup, children);
280
+ return;
281
+ }
282
+ if (input.renderer === "canvas") {
283
+ repaintCanvas(ctx, input, liveLayoutMap, fontContext, interaction);
284
+ }
285
+ }
286
+ function updateHoverOverlayCanvas(ctx, hit) {
287
+ if (ctx.lastInput?.renderer !== "canvas") return;
288
+ const groupNodeId = hit?.isGroupHit ? hit.nodeId ?? null : null;
289
+ if (ctx.hoveredGroupNodeId === groupNodeId) return;
290
+ ctx.hoveredGroupNodeId = groupNodeId;
291
+ const input = ctx.lastInput;
292
+ if (!input) return;
293
+ const fontContext = { ...input.globalFont && { font: input.globalFont }, theme: input.theme };
294
+ const interaction = ctx._hoveredIndex != null ? { hoveredIndex: ctx._hoveredIndex } : void 0;
295
+ const liveLayoutMap = /* @__PURE__ */ new Map();
296
+ for (const [id, entry] of ctx._layouts) {
297
+ const liveLayout = ctx._lastRenderedLayout?.get(id) ?? entry.layout;
298
+ const overrides = ctx._propertyOverrides.get(id);
299
+ const mergedProps = overrides ? { ...entry.props, ...overrides } : entry.props;
300
+ liveLayoutMap.set(id, { props: mergedProps, layout: liveLayout });
301
+ }
302
+ repaintCanvas(ctx, input, liveLayoutMap, fontContext, interaction);
303
+ }
304
+ function renderCurrentFrame(ctx) {
305
+ const input = ctx.lastInput;
306
+ if (!input || ctx._layouts.size === 0) return;
307
+ const fontContext = { ...input.globalFont && { font: input.globalFont }, theme: input.theme };
308
+ const targetLayouts = /* @__PURE__ */ new Map();
309
+ for (const [id, entry] of ctx._layouts) targetLayouts.set(id, entry.layout);
310
+ const frameLayouts = renderSceneFrame(ctx, targetLayouts);
311
+ const sceneLayoutMap = /* @__PURE__ */ new Map();
312
+ for (const [id, entry] of ctx._layouts) {
313
+ const live = frameLayouts.get(id) ?? entry.layout;
314
+ const overrides = ctx._propertyOverrides.get(id);
315
+ const mergedProps = overrides ? { ...entry.props, ...overrides } : entry.props;
316
+ sceneLayoutMap.set(id, { props: mergedProps, layout: live });
317
+ }
318
+ if (input.renderer === "svg" && ctx.svgGroup) {
319
+ renderSvgGroup(ctx, ctx.svgGroup, sceneLayoutMap, fontContext);
320
+ } else if (input.renderer === "canvas") {
321
+ const c2d = ctx.canvasEl?.getContext("2d");
322
+ if (!c2d) return;
323
+ c2d.clearRect(0, 0, input.width, input.height);
324
+ renderAllCanvas(ctx, c2d, sceneLayoutMap, fontContext);
325
+ }
326
+ ctx.onFrame?.();
327
+ }
328
+
329
+ // src/series/treemap/controller/index.ts
330
+ var TreemapRendererController = class {
331
+ constructor(paint) {
332
+ // Animation lifecycle — local raf clock + fingerprint for phase detection.
333
+ this._animRafId = null;
334
+ this._isInitial = true;
335
+ this._lastFingerprint = "";
336
+ // Geometry fingerprint (chartArea bounds) from the last update. A chartArea
337
+ // change — initial-mount layout settling (title/caption/breadcrumb heights
338
+ // measured after first paint) or a later resize — leaves the data
339
+ // fingerprint unchanged (cells keep the same `nodeId=value`), so it reads as
340
+ // a `static` re-fire even though the geometry moved. Tracked separately so
341
+ // the static early-return can tell a true no-op re-fire (skip, preserve the
342
+ // running animation) from a geometry change (must re-diff so `setTarget`
343
+ // retargets the in-flight entrance toward the corrected layout — otherwise
344
+ // the rendered scene settles at the stale geometry while hit-test/hover read
345
+ // the fresh `_layouts`, drawing groups as rows but hovering them as columns).
346
+ this._lastChartAreaKey = "";
347
+ // Per-dataset property-animation overrides resolved from AnimatedPropertyStore.
348
+ // Set by `applyPropertyAnimations()` each property-animation tick and merged
349
+ // into the rendered cell props uniformly across all cells of the dataset at
350
+ // every paint site (update's paint(), applyHover, updateHoverOverlayCanvas).
351
+ // Cleared by `destroy()`.
352
+ //
353
+ // Treemap's animatable registry is `{ number: ['opacity', 'borderStrokeWidth'], color: [] }`
354
+ // — both fields are FieldAccessor<unknown, number> on TreemapRenderProps, so
355
+ // a scalar override satisfies the prop type and the renderer's accessor
356
+ // resolution treats it as a uniform per-cell value.
357
+ //
358
+ // Step 10 keeps this per-dataset only. Per-cell granularity is Step 14.
359
+ //
360
+ // Dual-scene note: the override applies only to the cell scene's render
361
+ // props. Group backgrounds (`_groupBgScene`) are auto-styled from their
362
+ // parent containers and don't expose user-facing animatable properties,
363
+ // so they're intentionally left untouched.
364
+ this._propertyOverrides = /* @__PURE__ */ new Map();
365
+ this._layouts = /* @__PURE__ */ new Map();
366
+ // Synthetic-ID cache for flat data without user-supplied nodeIds. Keyed by
367
+ // content (label, or `__anon_${value}` fallback) so identity survives across
368
+ // value-only updates. Hierarchical nodes with user-provided nodeIds bypass
369
+ // this cache.
370
+ //
371
+ // Limitation: two items sharing a label collide on a single cache entry and
372
+ // both receive the same synthetic ID. Users with ambiguous labels should
373
+ // provide an explicit `nodeId` field.
374
+ this._syntheticIds = /* @__PURE__ */ new Map();
375
+ this._syntheticIdCounter = 0;
376
+ // Per-update tick counter + last-seen map so entries unused for N consecutive
377
+ // updates are evicted. Prevents unbounded growth in long-lived dashboards
378
+ // with rotating data.
379
+ this._syntheticIdLastSeenTick = /* @__PURE__ */ new Map();
380
+ this._syntheticIdTickCounter = 0;
381
+ // Per-dataset cache of the previous top-level squarify rects (with `_row`
382
+ // metadata). Threaded back into `calculateTreemapLayout` on the next
383
+ // update so `resquarify` can preserve row partitioning across value-only,
384
+ // rank-preserving updates. Only the top-level layout is cached today;
385
+ // hierarchical (recursive) subtrees fall back to plain squarify.
386
+ // TODO(Step 7): per-subtree resquarify for hierarchical data.
387
+ this._lastSquarifyLayouts = /* @__PURE__ */ new Map();
388
+ this.lastInput = null;
389
+ this.svgGroup = null;
390
+ this.svgWrapper = null;
391
+ this.canvasEl = null;
392
+ this.drillZoom = null;
393
+ this.hoveredGroupNodeId = null;
394
+ this._hoveredIndex = null;
395
+ this._interactByLeaf = true;
396
+ this._hasRenderContent = false;
397
+ this._dataFingerprint = "";
398
+ this._lastRenderedLayout = null;
399
+ this.onFrame = null;
400
+ /** Called when image finishes loading in canvas renderContent — wrappers set this */
401
+ this.onImageLoad = null;
402
+ this._paint = paint;
403
+ this._cellScene = new AnimatedScene({
404
+ // ENTER: cell grows from zero size at its target center (grow-from-center).
405
+ emptyState: (target) => ({
406
+ ...target,
407
+ x: target.x + target.width / 2,
408
+ y: target.y + target.height / 2,
409
+ width: 0,
410
+ height: 0
411
+ }),
412
+ // EXIT: cell shrinks to zero size at its current center.
413
+ exitEmptyState: (target) => ({
414
+ ...target,
415
+ x: target.x + target.width / 2,
416
+ y: target.y + target.height / 2,
417
+ width: 0,
418
+ height: 0
419
+ }),
420
+ registry: CELL_REGISTRY
421
+ });
422
+ this._groupBgScene = new AnimatedScene({
423
+ emptyState: (target) => ({
424
+ ...target,
425
+ x: target.x + target.width / 2,
426
+ y: target.y + target.height / 2,
427
+ width: 0,
428
+ height: 0
429
+ }),
430
+ exitEmptyState: (target) => ({
431
+ ...target,
432
+ x: target.x + target.width / 2,
433
+ y: target.y + target.height / 2,
434
+ width: 0,
435
+ height: 0
436
+ }),
437
+ registry: GROUP_BG_REGISTRY
438
+ });
439
+ }
440
+ // ================================================================
441
+ // PUBLIC API
442
+ // ================================================================
443
+ update(input) {
444
+ this.lastInput = input;
445
+ this.svgGroup = input.svgGroup ?? null;
446
+ this.svgWrapper = input.svgWrapper ?? null;
447
+ this.canvasEl = input.canvasEl ?? null;
448
+ const { datasets, datasetVisibility, chartArea, renderer, width, height, features, globalFont, theme } = input;
449
+ const fontContext = { ...globalFont && { font: globalFont }, theme };
450
+ const accessibility = buildAccessibilityRenderContext(features);
451
+ const layouts = /* @__PURE__ */ new Map();
452
+ for (const [id, ds] of datasets) {
453
+ if (ds.type !== "treemap" || !(datasetVisibility.get(id) ?? true)) continue;
454
+ const baseProps = ds.props;
455
+ const propsWithIds = this._assignStableIds(baseProps);
456
+ const props = input.drilldownEnabled ? { ...propsWithIds, drilldownParentId: input.drilldownParentId ?? void 0 } : propsWithIds;
457
+ const prevRects = this._lastSquarifyLayouts.get(id) ?? null;
458
+ const layout = calculateTreemapLayout(props, chartArea, input.theme, prevRects);
459
+ if (layout._squarifyRects) {
460
+ this._lastSquarifyLayouts.set(id, layout._squarifyRects);
461
+ } else {
462
+ this._lastSquarifyLayouts.delete(id);
463
+ }
464
+ layouts.set(id, { props, layout });
465
+ }
466
+ this._layouts = layouts;
467
+ this._interactByLeaf = true;
468
+ this._hasRenderContent = false;
469
+ for (const [, { props }] of layouts) {
470
+ if (props.interactByLeaf !== void 0) {
471
+ this._interactByLeaf = props.interactByLeaf;
472
+ break;
473
+ }
474
+ }
475
+ for (const [, { props }] of layouts) {
476
+ if (props.renderContent != null) {
477
+ this._hasRenderContent = true;
478
+ break;
479
+ }
480
+ }
481
+ this._dataFingerprint = buildTreemapDataFingerprint(layouts);
482
+ let totalCells = 0;
483
+ for (const [, { layout }] of layouts) totalCells += layout.cells.length;
484
+ if (layouts.size === 0 || totalCells === 0) {
485
+ this._cancelRaf();
486
+ this._cellScene.reset();
487
+ this._groupBgScene.reset();
488
+ this._lastFingerprint = "";
489
+ this._isInitial = true;
490
+ this._lastRenderedLayout = null;
491
+ if (renderer === "svg" && this.svgGroup) this.svgGroup.innerHTML = "";
492
+ return;
493
+ }
494
+ if (renderer === "canvas" && this.canvasEl && width > 0 && height > 0) {
495
+ configureCanvasHiDPI(this.canvasEl, width, height);
496
+ }
497
+ const animConfig = features.get("animation")?.props;
498
+ const { duration: animDuration, easing: animEasing } = parseAnimationConfig(animConfig);
499
+ const phase = this.drillZoom ? "entrance" : this._isInitial ? "entrance" : this._lastFingerprint !== "" && this._dataFingerprint !== "" && this._dataFingerprint !== this._lastFingerprint ? "update" : "static";
500
+ const chartAreaKey = buildTreemapChartAreaKey(chartArea);
501
+ const geometryChanged = chartAreaKey !== this._lastChartAreaKey;
502
+ this._lastChartAreaKey = chartAreaKey;
503
+ const resumeAnimation = phase === "static" && geometryChanged && this._animRafId !== null;
504
+ const targetLayouts = /* @__PURE__ */ new Map();
505
+ for (const [id, entry] of layouts) targetLayouts.set(id, entry.layout);
506
+ const cellTargets = buildCellSceneTargets(targetLayouts);
507
+ const bgTargets = buildGroupBgSceneTargets(targetLayouts);
508
+ const shouldAnimate = phase !== "static" && animDuration > 0;
509
+ const numbersDuration = shouldAnimate ? animDuration : 0;
510
+ const opts = {
511
+ numbers: { duration: numbersDuration, easing: animEasing },
512
+ colors: { duration: numbersDuration, easing: animEasing }
513
+ };
514
+ if (phase === "static" && this._animRafId !== null && !geometryChanged) {
515
+ this._commit(this._dataFingerprint);
516
+ this._syntheticIdTickCounter++;
517
+ const PRUNE_AGE2 = 10;
518
+ const cutoff2 = this._syntheticIdTickCounter - PRUNE_AGE2;
519
+ for (const [key, lastSeen] of this._syntheticIdLastSeenTick) {
520
+ if (lastSeen < cutoff2) {
521
+ this._syntheticIds.delete(key);
522
+ this._syntheticIdLastSeenTick.delete(key);
523
+ }
524
+ }
525
+ return;
526
+ }
527
+ this._cancelRaf();
528
+ this._cellScene.diff(cellTargets, opts);
529
+ this._groupBgScene.diff(bgTargets, opts);
530
+ const zoomInfo = this.drillZoom;
531
+ const zoomDuration = 400;
532
+ const zoomEasing = getEasing("easeOutCubic");
533
+ const zoomStartAt = shouldAnimate && zoomInfo ? performance.now() : 0;
534
+ const wantsSvgClipWipe = renderer === "svg" && this.svgWrapper && phase === "entrance" && !zoomInfo && shouldAnimate;
535
+ const wantsCanvasClipWipe = renderer === "canvas" && phase === "entrance" && !zoomInfo && shouldAnimate;
536
+ const wantsClipWipe = wantsSvgClipWipe || wantsCanvasClipWipe;
537
+ const wipeStartAt = wantsClipWipe ? performance.now() : 0;
538
+ const isZoomActive = (now) => zoomInfo !== null && shouldAnimate && now - zoomStartAt < zoomDuration;
539
+ const isWipeActive = (now) => wantsClipWipe && now - wipeStartAt < animDuration;
540
+ const wrapperBusy = (now) => isZoomActive(now) || isWipeActive(now);
541
+ if (renderer === "svg" && this.svgWrapper) {
542
+ this.svgWrapper.style.clipPath = "";
543
+ this.svgWrapper.removeAttribute("transform");
544
+ this.svgWrapper.style.opacity = "";
545
+ }
546
+ const paint = () => {
547
+ const frameLayouts = this._renderSceneFrame(targetLayouts);
548
+ const sceneLayoutMap = /* @__PURE__ */ new Map();
549
+ for (const [id, entry] of layouts) {
550
+ const live = frameLayouts.get(id) ?? entry.layout;
551
+ const overrides = this._propertyOverrides.get(id);
552
+ const mergedProps = overrides ? { ...entry.props, ...overrides } : entry.props;
553
+ sceneLayoutMap.set(id, { props: mergedProps, layout: live });
554
+ }
555
+ const hoverInteraction = this._hoveredIndex != null ? { hoveredIndex: this._hoveredIndex } : void 0;
556
+ if (renderer === "svg" && this.svgGroup) {
557
+ this.renderSvgGroup(this.svgGroup, sceneLayoutMap, fontContext, hoverInteraction, accessibility);
558
+ } else if (renderer === "canvas") {
559
+ const c = this.canvasEl?.getContext("2d");
560
+ if (!c) return;
561
+ const liveWidth = this.lastInput?.width ?? width;
562
+ const liveHeight = this.lastInput?.height ?? height;
563
+ c.clearRect(0, 0, liveWidth, liveHeight);
564
+ if (zoomInfo) {
565
+ const liveArea = this.lastInput?.chartArea ?? chartArea;
566
+ const elapsed = performance.now() - zoomStartAt;
567
+ const rawProgress = Math.min(1, Math.max(0, elapsed / zoomDuration)) ;
568
+ const zoomProgress = zoomEasing(rawProgress);
569
+ const { tx, ty, sx, sy } = computeZoomTransform(zoomInfo.cellRect, liveArea, zoomProgress);
570
+ c.save();
571
+ c.beginPath();
572
+ c.rect(liveArea.x, liveArea.y, liveArea.width, liveArea.height);
573
+ c.clip();
574
+ c.translate(tx, ty);
575
+ c.scale(sx, sy);
576
+ if (zoomInfo.direction === "out") c.globalAlpha = zoomProgress;
577
+ this.renderAllCanvas(c, sceneLayoutMap, fontContext, hoverInteraction);
578
+ c.restore();
579
+ } else if (wantsCanvasClipWipe) {
580
+ const liveArea = this.lastInput?.chartArea ?? chartArea;
581
+ const elapsed = performance.now() - wipeStartAt;
582
+ const rawProgress = animDuration > 0 ? Math.min(1, Math.max(0, elapsed / animDuration)) : 1;
583
+ const wipeProgress = animEasing(rawProgress);
584
+ c.save();
585
+ c.beginPath();
586
+ c.rect(liveArea.x, liveArea.y, liveArea.width * wipeProgress, liveArea.height);
587
+ c.clip();
588
+ this.renderAllCanvas(c, sceneLayoutMap, fontContext, hoverInteraction);
589
+ c.restore();
590
+ } else {
591
+ this.renderAllCanvas(c, sceneLayoutMap, fontContext, hoverInteraction);
592
+ }
593
+ }
594
+ };
595
+ const applyWrapperEffects = () => {
596
+ if (renderer !== "svg" || !this.svgWrapper) return;
597
+ const wrapper = this.svgWrapper;
598
+ if (zoomInfo) {
599
+ const area = this.lastInput?.chartArea ?? chartArea;
600
+ const elapsed = performance.now() - zoomStartAt;
601
+ const rawProgress = Math.min(1, Math.max(0, elapsed / zoomDuration)) ;
602
+ const zoomProgress = zoomEasing(rawProgress);
603
+ const { tx, ty, sx, sy } = computeZoomTransform(zoomInfo.cellRect, area, zoomProgress);
604
+ wrapper.setAttribute("transform", `translate(${tx},${ty}) scale(${sx},${sy})`);
605
+ if (zoomInfo.direction === "out") wrapper.style.opacity = String(zoomProgress);
606
+ return;
607
+ }
608
+ if (wantsSvgClipWipe) {
609
+ const elapsed = performance.now() - wipeStartAt;
610
+ const rawProgress = animDuration > 0 ? Math.min(1, Math.max(0, elapsed / animDuration)) : 1;
611
+ const wipeProgress = animEasing(rawProgress);
612
+ wrapper.style.clipPath = `inset(0 ${(1 - wipeProgress) * 100}% 0 0)`;
613
+ }
614
+ };
615
+ const clearWrapperEffects = () => {
616
+ if (zoomInfo) this.drillZoom = null;
617
+ if (renderer !== "svg" || !this.svgWrapper) return;
618
+ const wrapper = this.svgWrapper;
619
+ if (zoomInfo) {
620
+ wrapper.removeAttribute("transform");
621
+ wrapper.style.opacity = "";
622
+ }
623
+ if (wantsSvgClipWipe) {
624
+ wrapper.style.clipPath = "";
625
+ }
626
+ };
627
+ if (shouldAnimate || resumeAnimation) {
628
+ applyWrapperEffects();
629
+ paint();
630
+ const tick = (now) => {
631
+ this._animRafId = null;
632
+ const { allIdle: cellsIdle } = this._cellScene.tick(now);
633
+ const { allIdle: bgsIdle } = this._groupBgScene.tick(now);
634
+ applyWrapperEffects();
635
+ paint();
636
+ if (!cellsIdle || !bgsIdle || wrapperBusy(now)) {
637
+ this._animRafId = raf(tick);
638
+ } else {
639
+ clearWrapperEffects();
640
+ paint();
641
+ }
642
+ };
643
+ this._animRafId = raf(tick);
644
+ } else {
645
+ this._cellScene.tick(performance.now());
646
+ this._groupBgScene.tick(performance.now());
647
+ clearWrapperEffects();
648
+ paint();
649
+ }
650
+ this._commit(this._dataFingerprint);
651
+ this._syntheticIdTickCounter++;
652
+ const PRUNE_AGE = 10;
653
+ const cutoff = this._syntheticIdTickCounter - PRUNE_AGE;
654
+ for (const [key, lastSeen] of this._syntheticIdLastSeenTick) {
655
+ if (lastSeen < cutoff) {
656
+ this._syntheticIds.delete(key);
657
+ this._syntheticIdLastSeenTick.delete(key);
658
+ }
659
+ }
660
+ }
661
+ /** Set drilldown zoom animation state before calling update() */
662
+ setDrillZoom(cellRect, direction) {
663
+ this.drillZoom = { cellRect, direction };
664
+ this._resetPhase();
665
+ }
666
+ /** Prepare zoom-out (called before breadcrumb navigation) */
667
+ prepareDrillOut(chartArea) {
668
+ this.drillZoom = { cellRect: computeDrillOutOrigin(chartArea), direction: "out" };
669
+ this._resetPhase();
670
+ }
671
+ /** Find cell/header bounds by nodeId */
672
+ findCellRect(nodeId) {
673
+ for (const [, { layout }] of this._layouts) {
674
+ for (const cell of layout.cells) {
675
+ if (cell.nodeId === nodeId) return { x: cell.x, y: cell.y, width: cell.width, height: cell.height };
676
+ }
677
+ for (const header of layout.groupHeaders) {
678
+ if (header.nodeId === nodeId) return { x: header.x, y: header.y, width: header.width, height: header.height };
679
+ }
680
+ }
681
+ return null;
682
+ }
683
+ /**
684
+ * Handle a drilldown click: set zoom animation state and compute ancestor chain.
685
+ * Returns the data needed by framework wrappers to call drilldownState.drillInto().
686
+ * Returns null when drilldown is not applicable (no nodeId or no children).
687
+ */
688
+ buildDrillInto(hit, currentParentId) {
689
+ if (!hit.nodeId || !hit.hasChildren) return null;
690
+ const cellRect = this.findCellRect(hit.nodeId);
691
+ if (cellRect) this.setDrillZoom(cellRect, "in");
692
+ const ancestors = buildAncestorChain(hit.nodeId, this._layouts, currentParentId);
693
+ return { nodeId: hit.nodeId, label: hit.label, ancestors };
694
+ }
695
+ hitTest(x, y) {
696
+ for (const [datasetId, { layout }] of this._layouts) {
697
+ const isFlat = layout.groupBackgrounds.length === 0 && layout.groupHeaders.length === 0;
698
+ if (this._interactByLeaf || isFlat) {
699
+ for (const cell of layout.cells) {
700
+ if (x < cell.x || x > cell.x + cell.width || y < cell.y || y > cell.y + cell.height) continue;
701
+ if (isFlat) {
702
+ return { datasetId, index: cell.index, label: cell.label, value: cell.value, color: cell.color, nodeId: cell.nodeId, hasChildren: cell.hasChildren };
703
+ }
704
+ if (this._hasRenderContent && !cell.hasChildren) {
705
+ const LEAF_CONTENT_BAND_PX = 60;
706
+ if (y <= cell.y + Math.min(cell.height, LEAF_CONTENT_BAND_PX)) {
707
+ return { datasetId, index: cell.index, label: cell.label, value: cell.value, color: cell.color, nodeId: cell.nodeId, hasChildren: cell.hasChildren };
708
+ }
709
+ }
710
+ const info = this._hasRenderContent ? null : getCellLabelInfo(cell);
711
+ if (info && info.showPrimary) {
712
+ const cx = cell.x + cell.width / 2;
713
+ const cy = cell.y + cell.height / 2;
714
+ const textW = cell.label.length * CHAR_WIDTH_RATIO * info.fontSize;
715
+ const primaryY = info.showSecondary ? cy - info.fontSize * 0.4 : cy;
716
+ const halfH = info.fontSize * 0.6;
717
+ const blockTop = primaryY - halfH;
718
+ let blockBottom = primaryY + halfH;
719
+ if (info.showSecondary && cell.secondaryLabel) {
720
+ const secY = cy + info.fontSize * 0.6;
721
+ const secHalfH = info.secondaryFontSize * 0.6;
722
+ const secW = cell.secondaryLabel.length * CHAR_WIDTH_RATIO * info.secondaryFontSize;
723
+ blockBottom = secY + secHalfH;
724
+ if (x >= cx - secW / 2 && x <= cx + secW / 2 && y >= secY - secHalfH && y <= secY + secHalfH) {
725
+ return { datasetId, index: cell.index, label: cell.label, value: cell.value, color: cell.color, nodeId: cell.nodeId, hasChildren: cell.hasChildren };
726
+ }
727
+ }
728
+ if (x >= cx - textW / 2 && x <= cx + textW / 2 && y >= blockTop && y <= blockBottom) {
729
+ return { datasetId, index: cell.index, label: cell.label, value: cell.value, color: cell.color, nodeId: cell.nodeId, hasChildren: cell.hasChildren };
730
+ }
731
+ }
732
+ const sortedBgs2 = [...layout.groupBackgrounds].sort((a, b) => b.depth - a.depth);
733
+ const parentBg = sortedBgs2.find((bg) => x >= bg.x && x <= bg.x + bg.width && y >= bg.y && y <= bg.y + bg.height);
734
+ if (parentBg) {
735
+ return { datasetId, index: parentBg.index, label: parentBg.label, value: parentBg.value, color: parentBg.color, nodeId: parentBg.nodeId, hasChildren: true, isGroupHit: true };
736
+ }
737
+ return { datasetId, index: cell.index, label: cell.label, value: cell.value, color: cell.color, nodeId: cell.nodeId, hasChildren: cell.hasChildren };
738
+ }
739
+ }
740
+ for (const header of layout.groupHeaders) {
741
+ if (header.nodeId && x >= header.x && x <= header.x + header.width && y >= header.y && y <= header.y + header.height) {
742
+ return { datasetId, index: header.index, label: header.label, value: header.value, color: header.color, nodeId: header.nodeId, hasChildren: true };
743
+ }
744
+ }
745
+ const sortedBgs = [...layout.groupBackgrounds].sort((a, b) => b.depth - a.depth);
746
+ for (const bg of sortedBgs) {
747
+ if (x >= bg.x && x <= bg.x + bg.width && y >= bg.y && y <= bg.y + bg.height) {
748
+ return { datasetId, index: bg.index, label: bg.label, value: bg.value, color: bg.color, nodeId: bg.nodeId, hasChildren: true, isGroupHit: true };
749
+ }
750
+ }
751
+ }
752
+ return null;
753
+ }
754
+ /** Apply cell-level hover — lightweight repaint without full re-layout */
755
+ applyHover(hover) {
756
+ applyHover(this, hover);
757
+ }
758
+ /** Update hover overlay on canvas — for SVG, wrappers handle DOM overlay */
759
+ updateHoverOverlayCanvas(hit) {
760
+ updateHoverOverlayCanvas(this, hit);
761
+ }
762
+ get layouts() {
763
+ return this._layouts;
764
+ }
765
+ get hasData() {
766
+ return this._layouts.size > 0;
767
+ }
768
+ getColorScaleInfo() {
769
+ const first = this._layouts.values().next().value;
770
+ if (!first) return null;
771
+ const { resolvedColorScale, resolvedColorRange, valueRange } = first.layout;
772
+ if (!resolvedColorScale || !resolvedColorRange || !valueRange) return null;
773
+ return { colorScale: resolvedColorScale, colorRange: resolvedColorRange, min: valueRange[0], max: valueRange[1] };
774
+ }
775
+ destroy() {
776
+ this._cancelRaf();
777
+ this._cellScene.reset();
778
+ this._groupBgScene.reset();
779
+ this._lastRenderedLayout = null;
780
+ this._isInitial = true;
781
+ this._lastFingerprint = "";
782
+ this._syntheticIds.clear();
783
+ this._syntheticIdCounter = 0;
784
+ this._syntheticIdLastSeenTick.clear();
785
+ this._syntheticIdTickCounter = 0;
786
+ this._lastSquarifyLayouts.clear();
787
+ this._propertyOverrides.clear();
788
+ }
789
+ /**
790
+ * Apply animated property values without triggering a full layout cycle.
791
+ * Called from the property-animation framework wrapper each animation tick.
792
+ *
793
+ * Per-dataset: writes overrides into `_propertyOverrides` (or deletes the
794
+ * entry when the store has no live values for it), then triggers a
795
+ * frame re-render so the merged props paint into SVG/canvas. The overrides
796
+ * apply uniformly to all cells of the dataset — per-cell granularity is
797
+ * Step 14.
798
+ *
799
+ * Dual-scene note: only the cell scene's render props are affected. The
800
+ * `_groupBgScene` (group backgrounds) is intentionally untouched — group
801
+ * backgrounds are auto-styled from their parent containers and don't
802
+ * expose user-facing animatable properties.
803
+ */
804
+ applyPropertyAnimations(store) {
805
+ if (!this.lastInput || this._layouts.size === 0) return;
806
+ let appliedAny = false;
807
+ for (const datasetId of this._layouts.keys()) {
808
+ const overrides = resolveAnimatedProps(store, "treemap", datasetId, TREEMAP_ANIMATABLE_PROPS);
809
+ if (Object.keys(overrides).length === 0) {
810
+ if (this._propertyOverrides.delete(datasetId)) appliedAny = true;
811
+ continue;
812
+ }
813
+ appliedAny = true;
814
+ this._propertyOverrides.set(datasetId, overrides);
815
+ }
816
+ if (!appliedAny) return;
817
+ this._renderCurrentFrame();
818
+ }
819
+ /**
820
+ * Full re-render of the current scene state.
821
+ *
822
+ * Used by the property-animation framework wrapper: when a property
823
+ * animation completes and its override is released from the store,
824
+ * `renderFrameCycle()` re-paints from the now-cleared `_propertyOverrides`
825
+ * so SVG attributes / canvas paints snap back to base values (which can
826
+ * drift during in-place property patching).
827
+ */
828
+ renderFrameCycle() {
829
+ this._renderCurrentFrame();
830
+ }
831
+ /**
832
+ * Re-render the current scene state with the active property overrides
833
+ * merged into per-dataset props. Mirrors the static branch of `update()`'s
834
+ * `paint()` closure without re-running layout or scene diff.
835
+ */
836
+ _renderCurrentFrame() {
837
+ renderCurrentFrame(this);
838
+ }
839
+ // ================================================================
840
+ // PRIVATE
841
+ // ================================================================
842
+ /**
843
+ * Return a shallow-copied TreemapRenderProps whose `data` array contains
844
+ * `id`-populated clones of each item. User-provided `nodeId` values are
845
+ * preserved verbatim; flat-data items without one get a synthetic ID drawn
846
+ * from `_syntheticIds`, cached by content (label/value) so identity holds
847
+ * across value-only updates.
848
+ */
849
+ _assignStableIds(props) {
850
+ return assignStableIds(this, props);
851
+ }
852
+ _resolveId(item, categoryField, nodeIdField, itemIndex) {
853
+ return resolveId(this, item, categoryField, nodeIdField, itemIndex);
854
+ }
855
+ /** Cancel any in-flight raf. */
856
+ _cancelRaf() {
857
+ if (this._animRafId !== null) {
858
+ cancelRaf(this._animRafId);
859
+ this._animRafId = null;
860
+ }
861
+ }
862
+ /** Commit fingerprint for next-frame phase detection. */
863
+ _commit(fingerprint) {
864
+ this._isInitial = false;
865
+ this._lastFingerprint = fingerprint;
866
+ }
867
+ /** Reset phase state — used when drill-zoom/drill-out changes the data set. */
868
+ _resetPhase() {
869
+ this._isInitial = true;
870
+ this._lastFingerprint = "";
871
+ this._cancelRaf();
872
+ }
873
+ renderSvgGroup(group, layoutMap, fontContext, interaction, accessibility) {
874
+ renderSvgGroup(this, group, layoutMap, fontContext, interaction, accessibility);
875
+ }
876
+ renderAllCanvas(ctx, layoutMap, fontContext, interaction) {
877
+ renderAllCanvas(this, ctx, layoutMap, fontContext, interaction);
878
+ }
879
+ renderCanvasCustomContent(ctx) {
880
+ renderCanvasCustomContent(this, ctx);
881
+ }
882
+ _renderSceneFrame(targetLayouts) {
883
+ return renderSceneFrame(this, targetLayouts);
884
+ }
885
+ repaintCanvas(input, layoutMap, fontContext, interaction) {
886
+ repaintCanvas(this, input, layoutMap, fontContext, interaction);
887
+ }
888
+ };
889
+
890
+ export { TreemapRendererController };