@chipmobilesdk/rn-chart 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (373) hide show
  1. package/CHANGELOG.md +129 -0
  2. package/README.md +45 -3
  3. package/lib/commonjs/a11y/summary.js +190 -0
  4. package/lib/commonjs/a11y/summary.js.map +1 -0
  5. package/lib/commonjs/contract/datasource.js +64 -0
  6. package/lib/commonjs/contract/datasource.js.map +1 -0
  7. package/lib/commonjs/contract/distribution.js +45 -0
  8. package/lib/commonjs/contract/distribution.js.map +1 -0
  9. package/lib/commonjs/contract/errors.js +88 -0
  10. package/lib/commonjs/contract/errors.js.map +1 -0
  11. package/lib/commonjs/contract/format.js +133 -0
  12. package/lib/commonjs/contract/format.js.map +1 -0
  13. package/lib/commonjs/contract/interaction.js +24 -0
  14. package/lib/commonjs/contract/interaction.js.map +1 -0
  15. package/lib/commonjs/contract/marker.js +55 -0
  16. package/lib/commonjs/contract/marker.js.map +1 -0
  17. package/lib/commonjs/contract/props.js +6 -0
  18. package/lib/commonjs/contract/props.js.map +1 -0
  19. package/lib/commonjs/contract/state.js +68 -0
  20. package/lib/commonjs/contract/state.js.map +1 -0
  21. package/lib/commonjs/contract/strings.js +54 -0
  22. package/lib/commonjs/contract/strings.js.map +1 -0
  23. package/lib/commonjs/contract/theme.js +116 -0
  24. package/lib/commonjs/contract/theme.js.map +1 -0
  25. package/lib/commonjs/contract/value.js +112 -0
  26. package/lib/commonjs/contract/value.js.map +1 -0
  27. package/lib/commonjs/geometry/bar.js +257 -0
  28. package/lib/commonjs/geometry/bar.js.map +1 -0
  29. package/lib/commonjs/geometry/distribution.js +197 -0
  30. package/lib/commonjs/geometry/distribution.js.map +1 -0
  31. package/lib/commonjs/geometry/heatmap.js +186 -0
  32. package/lib/commonjs/geometry/heatmap.js.map +1 -0
  33. package/lib/commonjs/geometry/hitTest.js +117 -0
  34. package/lib/commonjs/geometry/hitTest.js.map +1 -0
  35. package/lib/commonjs/geometry/layout.js +134 -0
  36. package/lib/commonjs/geometry/layout.js.map +1 -0
  37. package/lib/commonjs/geometry/markers.js +59 -0
  38. package/lib/commonjs/geometry/markers.js.map +1 -0
  39. package/lib/commonjs/geometry/path.js +166 -0
  40. package/lib/commonjs/geometry/path.js.map +1 -0
  41. package/lib/commonjs/geometry/progress.js +203 -0
  42. package/lib/commonjs/geometry/progress.js.map +1 -0
  43. package/lib/commonjs/geometry/scale.js +127 -0
  44. package/lib/commonjs/geometry/scale.js.map +1 -0
  45. package/lib/commonjs/geometry/ticks.js +120 -0
  46. package/lib/commonjs/geometry/ticks.js.map +1 -0
  47. package/lib/commonjs/geometry/timeSeries.js +157 -0
  48. package/lib/commonjs/geometry/timeSeries.js.map +1 -0
  49. package/lib/commonjs/geometry/types.js +43 -0
  50. package/lib/commonjs/geometry/types.js.map +1 -0
  51. package/lib/commonjs/index.js +284 -0
  52. package/lib/commonjs/index.js.map +1 -0
  53. package/lib/commonjs/package.json +1 -0
  54. package/lib/commonjs/react/ChartBoundary.js +82 -0
  55. package/lib/commonjs/react/ChartBoundary.js.map +1 -0
  56. package/lib/commonjs/react/ChartFrame.js +270 -0
  57. package/lib/commonjs/react/ChartFrame.js.map +1 -0
  58. package/lib/commonjs/react/ChartLegend.js +242 -0
  59. package/lib/commonjs/react/ChartLegend.js.map +1 -0
  60. package/lib/commonjs/react/ChartPlot.js +62 -0
  61. package/lib/commonjs/react/ChartPlot.js.map +1 -0
  62. package/lib/commonjs/react/ChartStateOverlay.js +89 -0
  63. package/lib/commonjs/react/ChartStateOverlay.js.map +1 -0
  64. package/lib/commonjs/react/ChartThemeProvider.js +51 -0
  65. package/lib/commonjs/react/ChartThemeProvider.js.map +1 -0
  66. package/lib/commonjs/react/charts.js +108 -0
  67. package/lib/commonjs/react/charts.js.map +1 -0
  68. package/lib/commonjs/react/pointEvent.js +35 -0
  69. package/lib/commonjs/react/pointEvent.js.map +1 -0
  70. package/lib/commonjs/react/useChartA11y.js +97 -0
  71. package/lib/commonjs/react/useChartA11y.js.map +1 -0
  72. package/lib/commonjs/react/useChartFormatters.js +66 -0
  73. package/lib/commonjs/react/useChartFormatters.js.map +1 -0
  74. package/lib/commonjs/react/useChartLayout.js +100 -0
  75. package/lib/commonjs/react/useChartLayout.js.map +1 -0
  76. package/lib/commonjs/react/useChartSelection.js +131 -0
  77. package/lib/commonjs/react/useChartSelection.js.map +1 -0
  78. package/lib/commonjs/react/useChartStatus.js +74 -0
  79. package/lib/commonjs/react/useChartStatus.js.map +1 -0
  80. package/lib/commonjs/render/Axis.js +88 -0
  81. package/lib/commonjs/render/Axis.js.map +1 -0
  82. package/lib/commonjs/render/Marks.js +184 -0
  83. package/lib/commonjs/render/Marks.js.map +1 -0
  84. package/lib/commonjs/validation/budgets.js +106 -0
  85. package/lib/commonjs/validation/budgets.js.map +1 -0
  86. package/lib/commonjs/validation/validateDatasource.js +189 -0
  87. package/lib/commonjs/validation/validateDatasource.js.map +1 -0
  88. package/lib/module/a11y/summary.js +184 -0
  89. package/lib/module/a11y/summary.js.map +1 -0
  90. package/lib/module/contract/datasource.js +57 -0
  91. package/lib/module/contract/datasource.js.map +1 -0
  92. package/lib/module/contract/distribution.js +40 -0
  93. package/lib/module/contract/distribution.js.map +1 -0
  94. package/lib/module/contract/errors.js +80 -0
  95. package/lib/module/contract/errors.js.map +1 -0
  96. package/lib/module/contract/format.js +123 -0
  97. package/lib/module/contract/format.js.map +1 -0
  98. package/lib/module/contract/interaction.js +20 -0
  99. package/lib/module/contract/interaction.js.map +1 -0
  100. package/lib/module/contract/marker.js +49 -0
  101. package/lib/module/contract/marker.js.map +1 -0
  102. package/lib/module/contract/props.js +4 -0
  103. package/lib/module/contract/props.js.map +1 -0
  104. package/lib/module/contract/state.js +61 -0
  105. package/lib/module/contract/state.js.map +1 -0
  106. package/lib/module/contract/strings.js +49 -0
  107. package/lib/module/contract/strings.js.map +1 -0
  108. package/lib/module/contract/theme.js +109 -0
  109. package/lib/module/contract/theme.js.map +1 -0
  110. package/lib/module/contract/value.js +101 -0
  111. package/lib/module/contract/value.js.map +1 -0
  112. package/lib/module/geometry/bar.js +253 -0
  113. package/lib/module/geometry/bar.js.map +1 -0
  114. package/lib/module/geometry/distribution.js +193 -0
  115. package/lib/module/geometry/distribution.js.map +1 -0
  116. package/lib/module/geometry/heatmap.js +182 -0
  117. package/lib/module/geometry/heatmap.js.map +1 -0
  118. package/lib/module/geometry/hitTest.js +110 -0
  119. package/lib/module/geometry/hitTest.js.map +1 -0
  120. package/lib/module/geometry/layout.js +122 -0
  121. package/lib/module/geometry/layout.js.map +1 -0
  122. package/lib/module/geometry/markers.js +53 -0
  123. package/lib/module/geometry/markers.js.map +1 -0
  124. package/lib/module/geometry/path.js +157 -0
  125. package/lib/module/geometry/path.js.map +1 -0
  126. package/lib/module/geometry/progress.js +199 -0
  127. package/lib/module/geometry/progress.js.map +1 -0
  128. package/lib/module/geometry/scale.js +119 -0
  129. package/lib/module/geometry/scale.js.map +1 -0
  130. package/lib/module/geometry/ticks.js +112 -0
  131. package/lib/module/geometry/ticks.js.map +1 -0
  132. package/lib/module/geometry/timeSeries.js +153 -0
  133. package/lib/module/geometry/timeSeries.js.map +1 -0
  134. package/lib/module/geometry/types.js +39 -0
  135. package/lib/module/geometry/types.js.map +1 -0
  136. package/lib/module/index.js +85 -0
  137. package/lib/module/index.js.map +1 -0
  138. package/lib/module/package.json +1 -0
  139. package/lib/module/react/ChartBoundary.js +75 -0
  140. package/lib/module/react/ChartBoundary.js.map +1 -0
  141. package/lib/module/react/ChartFrame.js +263 -0
  142. package/lib/module/react/ChartFrame.js.map +1 -0
  143. package/lib/module/react/ChartLegend.js +234 -0
  144. package/lib/module/react/ChartLegend.js.map +1 -0
  145. package/lib/module/react/ChartPlot.js +56 -0
  146. package/lib/module/react/ChartPlot.js.map +1 -0
  147. package/lib/module/react/ChartStateOverlay.js +82 -0
  148. package/lib/module/react/ChartStateOverlay.js.map +1 -0
  149. package/lib/module/react/ChartThemeProvider.js +44 -0
  150. package/lib/module/react/ChartThemeProvider.js.map +1 -0
  151. package/lib/module/react/charts.js +102 -0
  152. package/lib/module/react/charts.js.map +1 -0
  153. package/lib/module/react/pointEvent.js +30 -0
  154. package/lib/module/react/pointEvent.js.map +1 -0
  155. package/lib/module/react/useChartA11y.js +92 -0
  156. package/lib/module/react/useChartA11y.js.map +1 -0
  157. package/lib/module/react/useChartFormatters.js +61 -0
  158. package/lib/module/react/useChartFormatters.js.map +1 -0
  159. package/lib/module/react/useChartLayout.js +95 -0
  160. package/lib/module/react/useChartLayout.js.map +1 -0
  161. package/lib/module/react/useChartSelection.js +125 -0
  162. package/lib/module/react/useChartSelection.js.map +1 -0
  163. package/lib/module/react/useChartStatus.js +69 -0
  164. package/lib/module/react/useChartStatus.js.map +1 -0
  165. package/lib/module/render/Axis.js +80 -0
  166. package/lib/module/render/Axis.js.map +1 -0
  167. package/lib/module/render/Marks.js +173 -0
  168. package/lib/module/render/Marks.js.map +1 -0
  169. package/lib/module/validation/budgets.js +97 -0
  170. package/lib/module/validation/budgets.js.map +1 -0
  171. package/lib/module/validation/validateDatasource.js +184 -0
  172. package/lib/module/validation/validateDatasource.js.map +1 -0
  173. package/lib/typescript/commonjs/a11y/summary.d.ts +38 -0
  174. package/lib/typescript/commonjs/a11y/summary.d.ts.map +1 -0
  175. package/lib/typescript/commonjs/contract/datasource.d.ts +94 -0
  176. package/lib/typescript/commonjs/contract/datasource.d.ts.map +1 -0
  177. package/lib/typescript/commonjs/contract/distribution.d.ts +17 -0
  178. package/lib/typescript/commonjs/contract/distribution.d.ts.map +1 -0
  179. package/lib/typescript/commonjs/contract/errors.d.ts +53 -0
  180. package/lib/typescript/commonjs/contract/errors.d.ts.map +1 -0
  181. package/lib/typescript/commonjs/contract/format.d.ts +63 -0
  182. package/lib/typescript/commonjs/contract/format.d.ts.map +1 -0
  183. package/lib/typescript/commonjs/contract/interaction.d.ts +53 -0
  184. package/lib/typescript/commonjs/contract/interaction.d.ts.map +1 -0
  185. package/lib/typescript/commonjs/contract/marker.d.ts +39 -0
  186. package/lib/typescript/commonjs/contract/marker.d.ts.map +1 -0
  187. package/lib/typescript/commonjs/contract/props.d.ts +58 -0
  188. package/lib/typescript/commonjs/contract/props.d.ts.map +1 -0
  189. package/lib/typescript/commonjs/contract/state.d.ts +45 -0
  190. package/lib/typescript/commonjs/contract/state.d.ts.map +1 -0
  191. package/lib/typescript/commonjs/contract/strings.d.ts +39 -0
  192. package/lib/typescript/commonjs/contract/strings.d.ts.map +1 -0
  193. package/lib/typescript/commonjs/contract/theme.d.ts +85 -0
  194. package/lib/typescript/commonjs/contract/theme.d.ts.map +1 -0
  195. package/lib/typescript/commonjs/contract/value.d.ts +69 -0
  196. package/lib/typescript/commonjs/contract/value.d.ts.map +1 -0
  197. package/lib/typescript/commonjs/geometry/bar.d.ts +18 -0
  198. package/lib/typescript/commonjs/geometry/bar.d.ts.map +1 -0
  199. package/lib/typescript/commonjs/geometry/distribution.d.ts +23 -0
  200. package/lib/typescript/commonjs/geometry/distribution.d.ts.map +1 -0
  201. package/lib/typescript/commonjs/geometry/heatmap.d.ts +24 -0
  202. package/lib/typescript/commonjs/geometry/heatmap.d.ts.map +1 -0
  203. package/lib/typescript/commonjs/geometry/hitTest.d.ts +68 -0
  204. package/lib/typescript/commonjs/geometry/hitTest.d.ts.map +1 -0
  205. package/lib/typescript/commonjs/geometry/layout.d.ts +67 -0
  206. package/lib/typescript/commonjs/geometry/layout.d.ts.map +1 -0
  207. package/lib/typescript/commonjs/geometry/markers.d.ts +29 -0
  208. package/lib/typescript/commonjs/geometry/markers.d.ts.map +1 -0
  209. package/lib/typescript/commonjs/geometry/path.d.ts +66 -0
  210. package/lib/typescript/commonjs/geometry/path.d.ts.map +1 -0
  211. package/lib/typescript/commonjs/geometry/progress.d.ts +17 -0
  212. package/lib/typescript/commonjs/geometry/progress.d.ts.map +1 -0
  213. package/lib/typescript/commonjs/geometry/scale.d.ts +55 -0
  214. package/lib/typescript/commonjs/geometry/scale.d.ts.map +1 -0
  215. package/lib/typescript/commonjs/geometry/ticks.d.ts +48 -0
  216. package/lib/typescript/commonjs/geometry/ticks.d.ts.map +1 -0
  217. package/lib/typescript/commonjs/geometry/timeSeries.d.ts +20 -0
  218. package/lib/typescript/commonjs/geometry/timeSeries.d.ts.map +1 -0
  219. package/lib/typescript/commonjs/geometry/types.d.ts +91 -0
  220. package/lib/typescript/commonjs/geometry/types.d.ts.map +1 -0
  221. package/lib/typescript/commonjs/index.d.ts +47 -0
  222. package/lib/typescript/commonjs/index.d.ts.map +1 -0
  223. package/lib/typescript/commonjs/package.json +1 -0
  224. package/lib/typescript/commonjs/react/ChartBoundary.d.ts +47 -0
  225. package/lib/typescript/commonjs/react/ChartBoundary.d.ts.map +1 -0
  226. package/lib/typescript/commonjs/react/ChartFrame.d.ts +31 -0
  227. package/lib/typescript/commonjs/react/ChartFrame.d.ts.map +1 -0
  228. package/lib/typescript/commonjs/react/ChartLegend.d.ts +31 -0
  229. package/lib/typescript/commonjs/react/ChartLegend.d.ts.map +1 -0
  230. package/lib/typescript/commonjs/react/ChartPlot.d.ts +19 -0
  231. package/lib/typescript/commonjs/react/ChartPlot.d.ts.map +1 -0
  232. package/lib/typescript/commonjs/react/ChartStateOverlay.d.ts +25 -0
  233. package/lib/typescript/commonjs/react/ChartStateOverlay.d.ts.map +1 -0
  234. package/lib/typescript/commonjs/react/ChartThemeProvider.d.ts +21 -0
  235. package/lib/typescript/commonjs/react/ChartThemeProvider.d.ts.map +1 -0
  236. package/lib/typescript/commonjs/react/charts.d.ts +51 -0
  237. package/lib/typescript/commonjs/react/charts.d.ts.map +1 -0
  238. package/lib/typescript/commonjs/react/pointEvent.d.ts +13 -0
  239. package/lib/typescript/commonjs/react/pointEvent.d.ts.map +1 -0
  240. package/lib/typescript/commonjs/react/useChartA11y.d.ts +37 -0
  241. package/lib/typescript/commonjs/react/useChartA11y.d.ts.map +1 -0
  242. package/lib/typescript/commonjs/react/useChartFormatters.d.ts +21 -0
  243. package/lib/typescript/commonjs/react/useChartFormatters.d.ts.map +1 -0
  244. package/lib/typescript/commonjs/react/useChartLayout.d.ts +27 -0
  245. package/lib/typescript/commonjs/react/useChartLayout.d.ts.map +1 -0
  246. package/lib/typescript/commonjs/react/useChartSelection.d.ts +52 -0
  247. package/lib/typescript/commonjs/react/useChartSelection.d.ts.map +1 -0
  248. package/lib/typescript/commonjs/react/useChartStatus.d.ts +22 -0
  249. package/lib/typescript/commonjs/react/useChartStatus.d.ts.map +1 -0
  250. package/lib/typescript/commonjs/render/Axis.d.ts +31 -0
  251. package/lib/typescript/commonjs/render/Axis.d.ts.map +1 -0
  252. package/lib/typescript/commonjs/render/Marks.d.ts +44 -0
  253. package/lib/typescript/commonjs/render/Marks.d.ts.map +1 -0
  254. package/lib/typescript/commonjs/validation/budgets.d.ts +24 -0
  255. package/lib/typescript/commonjs/validation/budgets.d.ts.map +1 -0
  256. package/lib/typescript/commonjs/validation/validateDatasource.d.ts +26 -0
  257. package/lib/typescript/commonjs/validation/validateDatasource.d.ts.map +1 -0
  258. package/lib/typescript/module/a11y/summary.d.ts +38 -0
  259. package/lib/typescript/module/a11y/summary.d.ts.map +1 -0
  260. package/lib/typescript/module/contract/datasource.d.ts +94 -0
  261. package/lib/typescript/module/contract/datasource.d.ts.map +1 -0
  262. package/lib/typescript/module/contract/distribution.d.ts +17 -0
  263. package/lib/typescript/module/contract/distribution.d.ts.map +1 -0
  264. package/lib/typescript/module/contract/errors.d.ts +53 -0
  265. package/lib/typescript/module/contract/errors.d.ts.map +1 -0
  266. package/lib/typescript/module/contract/format.d.ts +63 -0
  267. package/lib/typescript/module/contract/format.d.ts.map +1 -0
  268. package/lib/typescript/module/contract/interaction.d.ts +53 -0
  269. package/lib/typescript/module/contract/interaction.d.ts.map +1 -0
  270. package/lib/typescript/module/contract/marker.d.ts +39 -0
  271. package/lib/typescript/module/contract/marker.d.ts.map +1 -0
  272. package/lib/typescript/module/contract/props.d.ts +58 -0
  273. package/lib/typescript/module/contract/props.d.ts.map +1 -0
  274. package/lib/typescript/module/contract/state.d.ts +45 -0
  275. package/lib/typescript/module/contract/state.d.ts.map +1 -0
  276. package/lib/typescript/module/contract/strings.d.ts +39 -0
  277. package/lib/typescript/module/contract/strings.d.ts.map +1 -0
  278. package/lib/typescript/module/contract/theme.d.ts +85 -0
  279. package/lib/typescript/module/contract/theme.d.ts.map +1 -0
  280. package/lib/typescript/module/contract/value.d.ts +69 -0
  281. package/lib/typescript/module/contract/value.d.ts.map +1 -0
  282. package/lib/typescript/module/geometry/bar.d.ts +18 -0
  283. package/lib/typescript/module/geometry/bar.d.ts.map +1 -0
  284. package/lib/typescript/module/geometry/distribution.d.ts +23 -0
  285. package/lib/typescript/module/geometry/distribution.d.ts.map +1 -0
  286. package/lib/typescript/module/geometry/heatmap.d.ts +24 -0
  287. package/lib/typescript/module/geometry/heatmap.d.ts.map +1 -0
  288. package/lib/typescript/module/geometry/hitTest.d.ts +68 -0
  289. package/lib/typescript/module/geometry/hitTest.d.ts.map +1 -0
  290. package/lib/typescript/module/geometry/layout.d.ts +67 -0
  291. package/lib/typescript/module/geometry/layout.d.ts.map +1 -0
  292. package/lib/typescript/module/geometry/markers.d.ts +29 -0
  293. package/lib/typescript/module/geometry/markers.d.ts.map +1 -0
  294. package/lib/typescript/module/geometry/path.d.ts +66 -0
  295. package/lib/typescript/module/geometry/path.d.ts.map +1 -0
  296. package/lib/typescript/module/geometry/progress.d.ts +17 -0
  297. package/lib/typescript/module/geometry/progress.d.ts.map +1 -0
  298. package/lib/typescript/module/geometry/scale.d.ts +55 -0
  299. package/lib/typescript/module/geometry/scale.d.ts.map +1 -0
  300. package/lib/typescript/module/geometry/ticks.d.ts +48 -0
  301. package/lib/typescript/module/geometry/ticks.d.ts.map +1 -0
  302. package/lib/typescript/module/geometry/timeSeries.d.ts +20 -0
  303. package/lib/typescript/module/geometry/timeSeries.d.ts.map +1 -0
  304. package/lib/typescript/module/geometry/types.d.ts +91 -0
  305. package/lib/typescript/module/geometry/types.d.ts.map +1 -0
  306. package/lib/typescript/module/index.d.ts +47 -0
  307. package/lib/typescript/module/index.d.ts.map +1 -0
  308. package/lib/typescript/module/package.json +1 -0
  309. package/lib/typescript/module/react/ChartBoundary.d.ts +47 -0
  310. package/lib/typescript/module/react/ChartBoundary.d.ts.map +1 -0
  311. package/lib/typescript/module/react/ChartFrame.d.ts +31 -0
  312. package/lib/typescript/module/react/ChartFrame.d.ts.map +1 -0
  313. package/lib/typescript/module/react/ChartLegend.d.ts +31 -0
  314. package/lib/typescript/module/react/ChartLegend.d.ts.map +1 -0
  315. package/lib/typescript/module/react/ChartPlot.d.ts +19 -0
  316. package/lib/typescript/module/react/ChartPlot.d.ts.map +1 -0
  317. package/lib/typescript/module/react/ChartStateOverlay.d.ts +25 -0
  318. package/lib/typescript/module/react/ChartStateOverlay.d.ts.map +1 -0
  319. package/lib/typescript/module/react/ChartThemeProvider.d.ts +21 -0
  320. package/lib/typescript/module/react/ChartThemeProvider.d.ts.map +1 -0
  321. package/lib/typescript/module/react/charts.d.ts +51 -0
  322. package/lib/typescript/module/react/charts.d.ts.map +1 -0
  323. package/lib/typescript/module/react/pointEvent.d.ts +13 -0
  324. package/lib/typescript/module/react/pointEvent.d.ts.map +1 -0
  325. package/lib/typescript/module/react/useChartA11y.d.ts +37 -0
  326. package/lib/typescript/module/react/useChartA11y.d.ts.map +1 -0
  327. package/lib/typescript/module/react/useChartFormatters.d.ts +21 -0
  328. package/lib/typescript/module/react/useChartFormatters.d.ts.map +1 -0
  329. package/lib/typescript/module/react/useChartLayout.d.ts +27 -0
  330. package/lib/typescript/module/react/useChartLayout.d.ts.map +1 -0
  331. package/lib/typescript/module/react/useChartSelection.d.ts +52 -0
  332. package/lib/typescript/module/react/useChartSelection.d.ts.map +1 -0
  333. package/lib/typescript/module/react/useChartStatus.d.ts +22 -0
  334. package/lib/typescript/module/react/useChartStatus.d.ts.map +1 -0
  335. package/lib/typescript/module/render/Axis.d.ts +31 -0
  336. package/lib/typescript/module/render/Axis.d.ts.map +1 -0
  337. package/lib/typescript/module/render/Marks.d.ts +44 -0
  338. package/lib/typescript/module/render/Marks.d.ts.map +1 -0
  339. package/lib/typescript/module/validation/budgets.d.ts +24 -0
  340. package/lib/typescript/module/validation/budgets.d.ts.map +1 -0
  341. package/lib/typescript/module/validation/validateDatasource.d.ts +26 -0
  342. package/lib/typescript/module/validation/validateDatasource.d.ts.map +1 -0
  343. package/package.json +40 -15
  344. package/skills/sdk-rn-chart/SKILL.md +49 -14
  345. package/src/a11y/summary.ts +34 -15
  346. package/src/contract/distribution.ts +44 -0
  347. package/src/contract/errors.ts +6 -0
  348. package/src/contract/interaction.ts +2 -2
  349. package/src/contract/strings.ts +2 -0
  350. package/src/geometry/bar.ts +27 -16
  351. package/src/geometry/distribution.ts +11 -6
  352. package/src/geometry/heatmap.ts +34 -17
  353. package/src/geometry/hitTest.ts +35 -0
  354. package/src/geometry/progress.ts +0 -1
  355. package/src/geometry/ticks.ts +0 -13
  356. package/src/geometry/timeSeries.ts +7 -2
  357. package/src/geometry/types.ts +11 -0
  358. package/src/index.ts +4 -1
  359. package/src/react/ChartFrame.tsx +126 -373
  360. package/src/react/ChartLegend.tsx +60 -3
  361. package/src/react/ChartPlot.tsx +57 -0
  362. package/src/react/ChartStateOverlay.tsx +94 -0
  363. package/src/react/charts.tsx +27 -12
  364. package/src/react/pointEvent.ts +40 -0
  365. package/src/react/useChartA11y.ts +113 -0
  366. package/src/react/useChartFormatters.ts +105 -0
  367. package/src/react/useChartLayout.ts +5 -2
  368. package/src/react/useChartSelection.ts +77 -40
  369. package/src/react/useChartStatus.ts +85 -0
  370. package/src/render/Axis.tsx +26 -22
  371. package/src/render/Marks.tsx +2 -9
  372. package/src/validation/budgets.ts +6 -4
  373. package/src/validation/validateDatasource.ts +38 -14
@@ -18,18 +18,36 @@ accessibility support and enforced dataset budgets.
18
18
  - Shaping data to the datasource contract
19
19
  - Theming series colors or building a legend
20
20
  - Handling selection / interaction on a chart
21
- - A chart refuses to render a large dataset
21
+ - A chart is slower than expected, or a dataset is larger than its budget
22
+ - A formatter or a prop appears to have no effect
22
23
 
23
24
  ## Check what it deliberately does not do
24
25
 
25
26
  The README opens with `## What it does not do`. Read that first — it prevents building
26
27
  a feature this package intentionally excludes.
27
28
 
28
- ## Datasets are budgeted
29
+ ## Dataset budgets are a development warning, not a limit
29
30
 
30
- `DATASET_BUDGETS` and `checkBudget` enforce size limits so charts stay at 60 FPS on
31
- low-end devices. When a budget is exceeded, aggregate or window the data — do not raise
32
- the budget. See `## Dataset budgets`.
31
+ Nothing is enforced and nothing is refused: over budget a chart **still renders and
32
+ drops nothing**, warns once per chart in development, and in production does not even
33
+ measure the dataset. `DATASET_BUDGETS` and `checkBudget` are the figures and the check,
34
+ for a consumer that wants to aggregate or window its own data. Do not debug a "chart
35
+ refuses to render": no such behaviour exists. See `## Dataset budgets`.
36
+
37
+ ## Memoization has two requirements
38
+
39
+ `datasource` must be referentially stable, and so must each **formatter function**
40
+ (module scope, or `useCallback`). The `formatters` object itself may be inline, as may
41
+ `range={{ from, to }}` — those are compared by what they carry. An unstable datasource
42
+ or formatter rebuilds every scale and path string on each parent render.
43
+
44
+ ## What the numbers mean, where it is ambiguous
45
+
46
+ `DistributionChart` reads values as proportions (0..1, summing to 1) or as absolute
47
+ amounts, inferred from the data. Pass `valuesAre="absolute" | "proportions"` when counts
48
+ could be read as shares (two counts of `1`). Known values and instants must be finite:
49
+ `NaN` is a `nonFiniteValue` validation error, and a negative distribution segment is a
50
+ `negativeDistributionValue` one. Use `unknown()` for data you do not have.
33
51
 
34
52
  ## Chart theming is separate from app theming
35
53
 
@@ -38,18 +56,35 @@ Charts use `ChartThemeProvider` / `useChartTheme`, not the app-wide theme provid
38
56
 
39
57
  ## Public API
40
58
 
41
- Runtime:
59
+ Components — all five families are memoized, and all share `BaseChartProps`
60
+ (`datasource`, `status`, `stateContent`, `title`, `legend`, `theme`, `formatters`,
61
+ `strings`, `accessibility`, `height`, `style`, `footer`, selection and visibility
62
+ props):
42
63
 
43
- - `ChartThemeProvider`, `useChartTheme`, `defaultChartTheme`, `resolveSeriesColor`
44
- - `ChartLegend`, `buildLegendEntries`
45
- - `findTarget`, `isUsableTarget`, `readProgress`, `sameSelection`
46
- - `DATASET_BUDGETS`, `checkBudget`
47
- - `isChartError`
64
+ - `BarChart` (`grouping`), `TimeSeriesChart` (`range`), `DistributionChart` (`shape`,
65
+ `innerRadiusRatio`, `valuesAre`), `ProgressChart`, `HeatmapChart` (`buckets`)
66
+ - `ChartLegend`, `ColorScaleLegend`, `buildLegendEntries`, `ChartThemeProvider`
48
67
 
49
- Types: `MarkerKind`, `ProgressReading`, `ReferenceMarker`, `BudgetCheck`, `DatasetBudget`
68
+ Runtime:
50
69
 
51
- Use `sameSelection` for selection equality — comparing selection objects by reference
52
- causes redundant re-renders.
70
+ - `known`, `unknown`, `notApplicable`, `withheld`, `isKnown`, `isWithheld`, `sumKnown`,
71
+ `participatesInTotals`
72
+ - `useChartTheme`, `defaultChartTheme`, `resolveSeriesColor`
73
+ - `findTarget`, `isUsableTarget`, `readProgress`, `sameSelection`
74
+ - `resolveStatus`, `drawsData`, `suppressesInteraction`, `STATUS_PRECEDENCE`
75
+ - `formatValueDefault`, `formatPositionDefault`, `formatLegendDefault`, `seriesRef`,
76
+ `NON_VALUE_TEXT`
77
+ - `buildChartSummary`, `buildPointAnnouncement`, `buildTotalAnnouncement`
78
+ - `DATASET_BUDGETS`, `checkBudget`, `isChartError`, `chartStrings`
79
+ - `FAMILY_POSITION_KINDS`, `familyAcceptsPositionKind`, `resolveFormat`, `resolveUnit`
80
+
81
+ Types: `ValueState`, `ChartDatasource`, `Series`, `DataPoint`, `Position`, `ChartFamily`,
82
+ `ChartStatus`, `ChartError`, `SelectionRef`, `PointInteractionEvent`, `ChartFormatters`,
83
+ `ChartTheme`, `LegendEntry`, `ColorScale`, `DistributionValues`, `ChartStrings`,
84
+ `BudgetCheck`, `DatasetBudget`
85
+
86
+ Use `sameSelection` to compare two selections; comparing the objects by reference
87
+ reports a change that did not happen.
53
88
 
54
89
  ## Where the detail lives
55
90
 
@@ -8,7 +8,8 @@
8
8
  * Withheld values never enter a summary — that would leak exactly what the
9
9
  * withheld class exists to protect (FR-033).
10
10
  */
11
- import type { ChartDatasource, ChartFamily } from '../contract/datasource';
11
+ import type { ChartDatasource, ChartFamily, Position } from '../contract/datasource';
12
+ import { formatPositionDefault } from '../contract/format';
12
13
  import type { ReferenceMarker } from '../contract/marker';
13
14
  import type { ChartStatus } from '../contract/state';
14
15
  import { formatMessage } from '@chipmobilesdk/rn-core';
@@ -44,6 +45,8 @@ export interface SummaryInput<M = unknown> {
44
45
  readonly status: ChartStatus;
45
46
  readonly title?: string;
46
47
  readonly formatValue: (value: ValueState) => string;
48
+ /** How a position is spoken; the app's axis formatter when it has one. */
49
+ readonly formatPosition?: (position: Position) => string;
47
50
  readonly incomplete?: boolean;
48
51
  /** The texts to speak; the English defaults when omitted. */
49
52
  readonly strings?: ChartStrings;
@@ -53,9 +56,12 @@ function describeExtremes<M>(
53
56
  datasource: ChartDatasource<M>,
54
57
  formatValue: (v: ValueState) => string,
55
58
  strings: ChartStrings,
59
+ formatPosition: (position: Position) => string,
56
60
  ): string {
57
- let min: { label: string; value: number } | undefined;
58
- let max: { label: string; value: number } | undefined;
61
+ type Extreme = { label: () => string; value: number; point: unknown };
62
+ let min: Extreme | undefined;
63
+ let max: Extreme | undefined;
64
+ const several = datasource.series.length > 1;
59
65
 
60
66
  for (const series of datasource.series) {
61
67
  for (const point of series.points) {
@@ -63,18 +69,25 @@ function describeExtremes<M>(
63
69
  if (!isKnown(point.value)) {
64
70
  continue;
65
71
  }
66
- const label =
67
- point.position.kind === 'category'
68
- ? point.position.category
69
- : point.position.kind === 'matrix'
70
- ? `${point.position.row} ${point.position.column}`
71
- : series.label;
72
+ // Named by where the point is. A time series used to name both
73
+ // extremes after the series, so a one-series chart reported a single
74
+ // value and lost its lowest (CHT-07). Built lazily: only two are read.
75
+ const label = (): string => {
76
+ if (point.position.kind === 'category') {
77
+ return point.position.category;
78
+ }
79
+ if (point.position.kind === 'matrix') {
80
+ return `${point.position.row} ${point.position.column}`;
81
+ }
82
+ const at = formatPosition(point.position);
83
+ return several ? `${series.label} ${at}` : at;
84
+ };
72
85
 
73
86
  if (!min || point.value.value < min.value) {
74
- min = { label, value: point.value.value };
87
+ min = { label, value: point.value.value, point };
75
88
  }
76
89
  if (!max || point.value.value > max.value) {
77
- max = { label, value: point.value.value };
90
+ max = { label, value: point.value.value, point };
78
91
  }
79
92
  }
80
93
  }
@@ -83,14 +96,15 @@ function describeExtremes<M>(
83
96
  return '';
84
97
  }
85
98
  const maxText = formatValue({ kind: 'known', value: max.value });
86
- if (min.label === max.label) {
99
+ // One figure only when the highest and the lowest are the same point.
100
+ if (min.point === max.point) {
87
101
  return formatMessage(strings['chart.summary.single'], { value: maxText });
88
102
  }
89
103
 
90
104
  return formatMessage(strings['chart.summary.extremes'], {
91
- maxLabel: max.label,
105
+ maxLabel: max.label(),
92
106
  max: maxText,
93
- minLabel: min.label,
107
+ minLabel: min.label(),
94
108
  min: formatValue({ kind: 'known', value: min.value }),
95
109
  });
96
110
  }
@@ -149,7 +163,12 @@ export function buildChartSummary<M>(input: SummaryInput<M>): string {
149
163
  heading,
150
164
  statusPhrase,
151
165
  scale,
152
- describeExtremes(input.datasource, input.formatValue, strings),
166
+ describeExtremes(
167
+ input.datasource,
168
+ input.formatValue,
169
+ strings,
170
+ input.formatPosition ?? formatPositionDefault,
171
+ ),
153
172
  describeMarkers(input.datasource.markers, input.formatValue, strings),
154
173
  input.incomplete ? strings['chart.summary.incomplete'] : '',
155
174
  ];
@@ -0,0 +1,44 @@
1
+ /**
2
+ * What the numbers of a distribution mean (CHT-10).
3
+ *
4
+ * `proportions`: each value is already a share of the whole, in 0..1. A sum
5
+ * short of 1 is drawn short and reported incomplete. `absolute`: counts or
6
+ * amounts, normalised by their own total.
7
+ *
8
+ * Until 0.4.0 this was guessed from the values alone: anything in 0..1 was a
9
+ * proportion, so two segments counting 1 each drew two full circles on top of
10
+ * one another. The guess now also requires the shares to fit in one whole, and
11
+ * an app that knows can say so.
12
+ */
13
+ import type { ChartDatasource } from './datasource';
14
+ import { isKnown } from './value';
15
+
16
+ export type DistributionValues = 'proportions' | 'absolute';
17
+
18
+ export const DISTRIBUTION_SUM_TOLERANCE = 0.001;
19
+
20
+ export function resolveDistributionValues<M>(
21
+ datasource: ChartDatasource<M>,
22
+ declared?: DistributionValues,
23
+ ): DistributionValues {
24
+ if (declared !== undefined) {
25
+ return declared;
26
+ }
27
+ if (datasource.format?.kind === 'percent') {
28
+ return 'proportions';
29
+ }
30
+ let sum = 0;
31
+ for (const series of datasource.series) {
32
+ for (const point of series.points) {
33
+ if (!isKnown(point.value)) {
34
+ continue;
35
+ }
36
+ const value = point.value.value;
37
+ if (value < 0 || value > 1) {
38
+ return 'absolute';
39
+ }
40
+ sum += value;
41
+ }
42
+ }
43
+ return sum <= 1 + DISTRIBUTION_SUM_TOLERANCE ? 'proportions' : 'absolute';
44
+ }
@@ -18,6 +18,8 @@ export type ChartErrorCode =
18
18
  | 'familyPositionKindUnsupported'
19
19
  | 'inconsistentMatrix'
20
20
  | 'distributionNotWhole'
21
+ | 'nonFiniteValue'
22
+ | 'negativeDistributionValue'
21
23
  | 'declaredByApp'
22
24
  | 'renderException';
23
25
 
@@ -34,6 +36,10 @@ const MESSAGES: Readonly<Record<ChartErrorCode, string>> = {
34
36
  inconsistentMatrix: 'Matrix datasource rows and columns are inconsistent across points.',
35
37
  distributionNotWhole:
36
38
  'Distribution segments do not sum to the whole. The chart marks the total incomplete rather than rescaling.',
39
+ nonFiniteValue:
40
+ 'A known value or an instant is not a finite number. Use an unknown value for missing data.',
41
+ negativeDistributionValue:
42
+ 'A distribution segment has a negative value. A share of a whole cannot be negative.',
37
43
  declaredByApp: 'The application declared this chart to be in an error state.',
38
44
  renderException:
39
45
  'The chart failed while rendering and was contained. See the report for details.',
@@ -18,7 +18,7 @@ export interface SelectionRef {
18
18
  }
19
19
 
20
20
  export interface PointInteractionEvent<M = unknown> {
21
- readonly type: 'pointSelect' | 'segmentPress';
21
+ readonly type: 'pointSelect';
22
22
  readonly seriesId: string;
23
23
  readonly pointId: string;
24
24
  readonly value: ValueState;
@@ -27,7 +27,7 @@ export interface PointInteractionEvent<M = unknown> {
27
27
  }
28
28
 
29
29
  export interface SeriesInteractionEvent<M = unknown> {
30
- readonly type: 'seriesSelect' | 'visibilityChange';
30
+ readonly type: 'visibilityChange';
31
31
  readonly seriesId: string;
32
32
  readonly visible?: boolean;
33
33
  readonly metadata?: M;
@@ -41,6 +41,8 @@ export const chartStrings = defineMessages({
41
41
  'chart.state.noPermission': 'Not available',
42
42
  'chart.legend.hide': 'Hides this series',
43
43
  'chart.legend.show': 'Shows this series',
44
+ 'chart.legend.scale': 'Colour scale from {min} to {max}',
45
+ 'chart.note.incomplete': 'Some values are unavailable, so totals are incomplete.',
44
46
  },
45
47
  });
46
48
 
@@ -14,7 +14,7 @@ import { insetForAxes, plotBottom, plotRight } from './layout';
14
14
  import { horizontalMarkers, markerDomainValues } from './markers';
15
15
  import { rectBatchPath, type RectSpec } from './path';
16
16
  import { bandScale, domainFrom, linearScale, widenDegenerateDomain } from './scale';
17
- import { thinTicks, type Tick } from './ticks';
17
+ import { niceTickValues, thinTicks, type Tick } from './ticks';
18
18
  import type { GeometryInput, MarkPath, ResolvedGeometry } from './types';
19
19
 
20
20
  export type BarGrouping = 'grouped' | 'stacked';
@@ -75,21 +75,24 @@ function stackedDomainValues<M>(
75
75
  ): number[] {
76
76
  const values: number[] = [];
77
77
 
78
- for (const category of categories) {
79
- let positive = 0;
80
- let negative = 0;
81
-
82
- for (const series of visible) {
83
- const point = series.points.find(p => categoryKey(p.position) === category);
84
- if (point && isKnown(point.value)) {
85
- if (point.value.value >= 0) {
86
- positive += point.value.value;
87
- } else {
88
- negative += point.value.value;
89
- }
78
+ // One pass over the points instead of a search per category and series.
79
+ const positive = new Map<string, number>();
80
+ const negative = new Map<string, number>();
81
+ for (const series of visible) {
82
+ const counted = new Set<string>();
83
+ for (const point of series.points) {
84
+ const category = categoryKey(point.position);
85
+ // The first point of a series in a category is the one drawn there.
86
+ if (counted.has(category) || !isKnown(point.value)) {
87
+ continue;
90
88
  }
89
+ counted.add(category);
90
+ const sums = point.value.value >= 0 ? positive : negative;
91
+ sums.set(category, (sums.get(category) ?? 0) + point.value.value);
91
92
  }
92
- values.push(positive, negative);
93
+ }
94
+ for (const category of categories) {
95
+ values.push(positive.get(category) ?? 0, negative.get(category) ?? 0);
93
96
  }
94
97
 
95
98
  return values;
@@ -149,6 +152,13 @@ export function buildBarGeometry<M>(
149
152
  }
150
153
  }
151
154
 
155
+ // Instants have an order of their own. First-seen order put Tuesday before
156
+ // Monday when one series started a day late, and disagreed with the
157
+ // time-series chart drawn from the same datasource (CHT-20).
158
+ if (datasource.positionKind === 'instant') {
159
+ categories.sort((a, b) => Number(a) - Number(b));
160
+ }
161
+
152
162
  const visible = datasource.series.filter(s => !s.hidden);
153
163
  const excluded = countExcluded(datasource);
154
164
  const values = [
@@ -168,7 +178,8 @@ export function buildBarGeometry<M>(
168
178
  min: values.some(v => v < 0) ? padded.min : Math.max(padded.min, 0),
169
179
  max: values.some(v => v > 0) ? padded.max : Math.min(padded.max, 0),
170
180
  });
171
- const yTickValues = [domain.min, 0, domain.max].filter((v, i, arr) => arr.indexOf(v) === i);
181
+ // Round steps a reader can count in, not the padded extremes (105.3).
182
+ const yTickValues = niceTickValues(domain, 4);
172
183
  const xLabel = (c: string) =>
173
184
  datasource.positionKind === 'instant'
174
185
  ? input.formatInstant(Number(c))
@@ -219,7 +230,7 @@ export function buildBarGeometry<M>(
219
230
  y: top,
220
231
  width: barWidth,
221
232
  height,
222
- radius: options.radius,
233
+ radius: options.radius ?? input.radius?.bar,
223
234
  });
224
235
 
225
236
  hitRegions.push({
@@ -9,6 +9,7 @@
9
9
  * PURE. No React, no SVG.
10
10
  */
11
11
  import type { ChartDatasource } from '../contract/datasource';
12
+ import { resolveDistributionValues, type DistributionValues } from '../contract/distribution';
12
13
  import { segmentKey } from '../contract/theme';
13
14
  import { isKnown, isWithheld, sumKnown } from '../contract/value';
14
15
  import type { HitRegion } from './hitTest';
@@ -21,6 +22,8 @@ export interface DistributionOptions {
21
22
  readonly shape?: DistributionShape;
22
23
  /** Donut hole as a fraction of the outer radius. */
23
24
  readonly innerRadiusRatio?: number;
25
+ /** What the values mean; inferred from the data when omitted. */
26
+ readonly valuesAre?: DistributionValues;
24
27
  }
25
28
 
26
29
  const TAU = Math.PI * 2;
@@ -69,10 +72,11 @@ export function buildDistributionGeometry<M>(
69
72
  // Proportions supplied directly (each in 0..1, summing to ~1) are honoured
70
73
  // as given; absolute values are normalised by their own total. Either way we
71
74
  // never stretch a short sum to fill the circle.
72
- const suppliedAsProportions = segments.every(
73
- s => !isKnown(s.point.value) || (s.point.value.value >= 0 && s.point.value.value <= 1),
74
- );
75
- const denominator = suppliedAsProportions ? 1 : total.total;
75
+ const suppliedAsProportions =
76
+ resolveDistributionValues(datasource, options.valuesAre) === 'proportions';
77
+ // Shares declared as proportions that add up past the whole are normalised
78
+ // rather than drawn over one another.
79
+ const denominator = suppliedAsProportions ? Math.max(1, total.total) : total.total;
76
80
  const coverage = total.total / denominator;
77
81
  const incomplete = total.incomplete || coverage < 0.999;
78
82
 
@@ -88,7 +92,7 @@ export function buildDistributionGeometry<M>(
88
92
  let cursor = plot.x;
89
93
 
90
94
  for (const { series, point } of segments) {
91
- if (!isKnown(point.value)) {
95
+ if (!isKnown(point.value) || point.value.value < 0) {
92
96
  continue;
93
97
  }
94
98
  const fraction = point.value.value / denominator;
@@ -135,7 +139,7 @@ export function buildDistributionGeometry<M>(
135
139
  let angle = 0;
136
140
 
137
141
  for (const { series, point } of segments) {
138
- if (!isKnown(point.value)) {
142
+ if (!isKnown(point.value) || point.value.value < 0) {
139
143
  continue;
140
144
  }
141
145
 
@@ -180,6 +184,7 @@ export function buildDistributionGeometry<M>(
180
184
  pointId: point.id,
181
185
  x: cx + labelRadius * Math.cos(mid),
182
186
  y: cy + labelRadius * Math.sin(mid),
187
+ arc: { cx, cy, innerRadius, outerRadius, startAngle: start, endAngle: end },
183
188
  selectable: !isWithheld(point.value),
184
189
  });
185
190
  }
@@ -15,7 +15,9 @@
15
15
  import type { ChartDatasource } from '../contract/datasource';
16
16
  import { isKnown, isWithheld } from '../contract/value';
17
17
  import type { HitRegion } from './hitTest';
18
+ import { insetForAxes } from './layout';
18
19
  import { rectBatchPath, type RectSpec } from './path';
20
+ import { thinTicks } from './ticks';
19
21
  import type { GeometryInput, MarkPath, ResolvedGeometry } from './types';
20
22
 
21
23
  export interface HeatmapOptions {
@@ -30,8 +32,6 @@ export function buildHeatmapGeometry<M>(
30
32
  input: GeometryInput,
31
33
  options: HeatmapOptions = {},
32
34
  ): ResolvedGeometry {
33
- const { plot } = input;
34
-
35
35
  const rows: string[] = [];
36
36
  const columns: string[] = [];
37
37
  const rowSeen = new Set<string>();
@@ -53,9 +53,9 @@ export function buildHeatmapGeometry<M>(
53
53
  }
54
54
  }
55
55
 
56
- if (rows.length === 0 || columns.length === 0 || plot.width <= 0) {
56
+ if (rows.length === 0 || columns.length === 0 || input.plot.width <= 0) {
57
57
  return {
58
- plot,
58
+ plot: input.plot,
59
59
  paths: [],
60
60
  markers: [],
61
61
  labels: [],
@@ -66,6 +66,18 @@ export function buildHeatmapGeometry<M>(
66
66
  };
67
67
  }
68
68
 
69
+ // Row and column names are the heatmap's axes. The plot makes room for
70
+ // them; they were computed before and never drawn (CHT-15).
71
+ const columnLabels = columns.map(input.formatCategory);
72
+ const rowLabels = rows.map(input.formatCategory);
73
+ const plot = insetForAxes(input.plot, {
74
+ xLabels: columnLabels,
75
+ yLabels: rowLabels,
76
+ fontSize: input.fontSize,
77
+ });
78
+ const columnIndex = new Map(columns.map((column, index) => [column, index]));
79
+ const rowIndex = new Map(rows.map((row, index) => [row, index]));
80
+
69
81
  const gap = options.cellGap ?? 2;
70
82
  const cellWidth = plot.width / columns.length;
71
83
  const cellHeight = plot.height / rows.length;
@@ -102,18 +114,18 @@ export function buildHeatmapGeometry<M>(
102
114
  continue;
103
115
  }
104
116
 
105
- const colIndex = columns.indexOf(point.position.column);
106
- const rowIndex = rows.indexOf(point.position.row);
107
- if (colIndex < 0 || rowIndex < 0) {
117
+ const col = columnIndex.get(point.position.column);
118
+ const row = rowIndex.get(point.position.row);
119
+ if (col === undefined || row === undefined) {
108
120
  continue;
109
121
  }
110
122
 
111
123
  const rect: RectSpec = {
112
- x: plot.x + colIndex * cellWidth + gap / 2,
113
- y: plot.y + rowIndex * cellHeight + gap / 2,
124
+ x: plot.x + col * cellWidth + gap / 2,
125
+ y: plot.y + row * cellHeight + gap / 2,
114
126
  width: Math.max(0, cellWidth - gap),
115
127
  height: Math.max(0, cellHeight - gap),
116
- radius: options.cellRadius,
128
+ radius: options.cellRadius ?? input.radius?.cell,
117
129
  };
118
130
 
119
131
  if (isKnown(point.value)) {
@@ -173,17 +185,22 @@ export function buildHeatmapGeometry<M>(
173
185
  paths,
174
186
  markers: [],
175
187
  labels: [],
176
- xTicks: columns.map((c, i) => ({
177
- value: i,
178
- position: plot.x + i * cellWidth + cellWidth / 2,
179
- label: input.formatCategory(c),
180
- })),
181
- yTicks: rows.map((r, i) => ({
188
+ xTicks: thinTicks(
189
+ columnLabels.map((label, i) => ({
190
+ value: i,
191
+ position: plot.x + i * cellWidth + cellWidth / 2,
192
+ label,
193
+ })),
194
+ input.fontSize,
195
+ plot.width,
196
+ ),
197
+ yTicks: rowLabels.map((label, i) => ({
182
198
  value: i,
183
199
  position: plot.y + i * cellHeight + cellHeight / 2,
184
- label: input.formatCategory(r),
200
+ label,
185
201
  })),
186
202
  hitRegions,
203
+ ...(hasKnown ? { colorScale: { min, max, colors: ramp.slice(0, bucketCount) } } : {}),
187
204
  incomplete: excluded > 0,
188
205
  };
189
206
  }
@@ -23,6 +23,19 @@ export interface HitRegion {
23
23
  readonly width: number;
24
24
  readonly height: number;
25
25
  };
26
+ /**
27
+ * An arc segment: containment by radius and angle. Angles are radians,
28
+ * clockwise from twelve o'clock, as the distribution geometry draws them.
29
+ * A region with an arc is hit only inside it, never by proximity.
30
+ */
31
+ readonly arc?: {
32
+ readonly cx: number;
33
+ readonly cy: number;
34
+ readonly innerRadius: number;
35
+ readonly outerRadius: number;
36
+ readonly startAngle: number;
37
+ readonly endAngle: number;
38
+ };
26
39
  /**
27
40
  * False for points that must never be selectable: withheld values, and
28
41
  * anything the chart is not currently drawing (FR-053).
@@ -47,6 +60,20 @@ function inBounds(region: HitRegion, x: number, y: number): boolean {
47
60
  return x >= b.x && x <= b.x + b.width && y >= b.y && y <= b.y + b.height;
48
61
  }
49
62
 
63
+ const TAU = Math.PI * 2;
64
+
65
+ function inArc(arc: NonNullable<HitRegion['arc']>, x: number, y: number): boolean {
66
+ const dx = x - arc.cx;
67
+ const dy = y - arc.cy;
68
+ const radius = Math.sqrt(dx * dx + dy * dy);
69
+ if (radius < arc.innerRadius || radius > arc.outerRadius) {
70
+ return false;
71
+ }
72
+ // Clockwise from the top, the convention the arcs are drawn in.
73
+ const angle = (Math.atan2(dy, dx) + Math.PI / 2 + TAU) % TAU;
74
+ return angle >= arc.startAngle && angle < arc.endAngle;
75
+ }
76
+
50
77
  /**
51
78
  * Resolves a touch to a mark.
52
79
  *
@@ -70,6 +97,14 @@ export function hitTest(
70
97
  if (inBounds(region, x, y)) {
71
98
  return { seriesId: region.seriesId, pointId: region.pointId, distance: 0 };
72
99
  }
100
+ if (region.arc) {
101
+ // A large segment's edge is far from its midpoint, and a neighbour's
102
+ // midpoint can be nearer: only the segment under the finger counts.
103
+ if (inArc(region.arc, x, y)) {
104
+ return { seriesId: region.seriesId, pointId: region.pointId, distance: 0 };
105
+ }
106
+ continue;
107
+ }
73
108
 
74
109
  const dx = region.x - x;
75
110
  const dy = region.y - y;
@@ -17,7 +17,6 @@ import { rectSubpath } from './path';
17
17
  import type { GeometryInput, GeometryLabel, MarkerLine, MarkPath, ResolvedGeometry } from './types';
18
18
 
19
19
  export interface ProgressOptions {
20
- readonly orientation?: 'horizontal' | 'vertical';
21
20
  readonly trackRadius?: number;
22
21
  }
23
22
 
@@ -130,16 +130,3 @@ export function reserveAxisSpace(
130
130
  }
131
131
  return widest + LABEL_GUTTER;
132
132
  }
133
-
134
- /**
135
- * Shortens a label that cannot fit, signalling the truncation with an ellipsis.
136
- * Callers must expose the full value through an accessible label (FR-070).
137
- */
138
- export function truncateToWidth(text: string, fontSize: number, maxWidthPx: number): string {
139
- if (estimateTextWidth(text, fontSize) <= maxWidthPx) {
140
- return text;
141
- }
142
- const perChar = fontSize * AVERAGE_ADVANCE_RATIO;
143
- const fits = Math.max(1, Math.floor(maxWidthPx / perChar) - 1);
144
- return `${text.slice(0, fits)}…`;
145
- }
@@ -50,8 +50,13 @@ export function buildTimeSeriesGeometry<M>(
50
50
  const values: number[] = [];
51
51
  let excluded = 0;
52
52
 
53
+ // Sorted and windowed once per series; both passes below read the result.
54
+ const ordered = new Map(
55
+ datasource.series.map(series => [series, visiblePoints(series, options.range)] as const),
56
+ );
57
+
53
58
  for (const series of datasource.series) {
54
- for (const point of visiblePoints(series, options.range)) {
59
+ for (const point of ordered.get(series) ?? []) {
55
60
  if (point.position.kind === 'instant') {
56
61
  instants.push(point.position.at);
57
62
  }
@@ -104,7 +109,7 @@ export function buildTimeSeriesGeometry<M>(
104
109
 
105
110
  const pts: MaybePt[] = [];
106
111
 
107
- for (const point of visiblePoints(series, options.range)) {
112
+ for (const point of ordered.get(series) ?? []) {
108
113
  const at = point.position.kind === 'instant' ? point.position.at : 0;
109
114
  const px = x.project(at);
110
115
 
@@ -46,6 +46,13 @@ export interface GeometryLabel {
46
46
  readonly muted?: boolean;
47
47
  }
48
48
 
49
+ /** What a colour ramp runs from and to, for the legend that explains it. */
50
+ export interface ColorScale {
51
+ readonly min: number;
52
+ readonly max: number;
53
+ readonly colors: readonly string[];
54
+ }
55
+
49
56
  export interface ResolvedGeometry {
50
57
  readonly plot: PlotRect;
51
58
  readonly paths: readonly MarkPath[];
@@ -54,6 +61,8 @@ export interface ResolvedGeometry {
54
61
  readonly xTicks: readonly Tick[];
55
62
  readonly yTicks: readonly Tick[];
56
63
  readonly hitRegions: readonly HitRegion[];
64
+ /** Present when colour encodes a value, as in a heatmap. */
65
+ readonly colorScale?: ColorScale;
57
66
  /**
58
67
  * True when something was excluded from a total or proportion, so the chart
59
68
  * can say so rather than presenting a partial figure as whole (FR-013).
@@ -88,6 +97,8 @@ export interface GeometryInput {
88
97
  Record<'unknown' | 'notApplicable' | 'withheld', NonValueTexture>
89
98
  >;
90
99
  readonly heatmapRamp: readonly string[];
100
+ /** Corner radii from the theme, for bars and heatmap cells. */
101
+ readonly radius?: { readonly bar: number; readonly cell: number };
91
102
  readonly formatValue: (value: number) => string;
92
103
  readonly formatCategory: (raw: string) => string;
93
104
  readonly formatInstant: (at: number) => string;